针对嵌入式图形界面的图片压缩,几种比较平衡的算法选择:

  1. RLE (Run Length Encoding) 变种
    • RLE-4: 4位游程编码,适合图标等色彩数较少的图像
    • SRLE (Sparse RLE): 稀疏型RLE,对于UI中大面积相同颜色区域效果很好
    • 优点:解码速度快,实现简单
    • 缺点:对于复杂图案压缩率较低
    • 特别适合:UI图标、按钮、简单图形界面元素
// RLE (Run-Length Encoding) Implementation
int rle_encode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;while (i < input_len) {unsigned char current = input[i];int count = 1;while (i + count < input_len && input[i + count] == current && count < 255) {count++;}output[output_len++] = count;output[output_len++] = current;i += count;}return output_len;
}int rle_decode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;while (i < input_len) {int count = input[i++];unsigned char value = input[i++];for (int j = 0; j < count; j++) {output[output_len++] = value;}}return output_len;
}
// SRLE (Simplified RLE) Implementation
int srle_encode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;while (i < input_len) {// Find runs of same valueunsigned char current = input[i];int run_length = 1;while (i + run_length < input_len && input[i + run_length] == current) {run_length++;}if (run_length >= 4) {// Encode runoutput[output_len++] = 0;  // Special markeroutput[output_len++] = run_length;output[output_len++] = current;i += run_length;} else {// Copy literaloutput[output_len++] = input[i++];}}return output_len;
}int srle_decode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;while (i < input_len) {if (input[i] == 0) {// Decode runint run_length = input[i + 1];unsigned char value = input[i + 2];for (int j = 0; j < run_length; j++) {output[output_len++] = value;}i += 3;} else {// Copy literaloutput[output_len++] = input[i++];}}return output_len;
}

  1. LZ77/LZSS 家族
    • miniLZO: 解压速度极快,压缩率适中
    • FastLZ: 比LZO稍慢但压缩率更好
    • 优点:解压快,压缩率适中,内存占用小
    • 缺点:压缩率不如复杂算法
    • 特别适合:需要快速解码的场景,如动态加载的UI资源
// Mini LZO-style Implementation
#define HASH_BITS 14
#define HASH_SIZE (1 << HASH_BITS)
#define HASH_MASK (HASH_SIZE - 1)
#define MIN_MATCH 3
#define MAX_MATCH 128int mini_lzo_encode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;unsigned short hash_table[HASH_SIZE] = {0};int i = 0;while (i < input_len) {// Look for a matchint hash = ((input[i] << 8) | input[i + 1]) & HASH_MASK;int match_pos = hash_table[hash];int match_len = 0;if (match_pos < i) {// Check match lengthwhile (match_len < MAX_MATCH && i + match_len < input_len && input[match_pos + match_len] == input[i + match_len]) {match_len++;}}if (match_len >= MIN_MATCH) {// Encode matchint match_dist = i - match_pos;output[output_len++] = ((match_len - MIN_MATCH) << 4) | ((match_dist >> 8) & 0x0F);output[output_len++] = match_dist & 0xFF;i += match_len;} else {// Encode literaloutput[output_len++] = input[i++];}// Update hash tablehash_table[hash] = i;}return output_len;
}int mini_lzo_decode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;unsigned short hash_table[HASH_SIZE] = {0};while (i < input_len) {unsigned char byte = input[i++];if (byte < 0x80) {  // literal byteoutput[output_len++] = byte;} else {  // compressed matchint len = (byte >> 4) + MIN_MATCH;int dist = ((byte & 0x0F) << 8) | input[i++];int match_pos = output_len - dist;for (int j = 0; j < len; j++) {output[output_len++] = output[match_pos + j];}}}return output_len;
}
// FastLZ-style Implementation
#define FASTLZ_HASH_LOG  13
#define FASTLZ_HASH_SIZE (1 << FASTLZ_HASH_LOG)
#define FASTLZ_HASH_MASK  (FASTLZ_HASH_SIZE - 1)int fastlz_encode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int hash_table[FASTLZ_HASH_SIZE] = {0};int i = 0;while (i < input_len) {// Compute hashint hash = (input[i] + (input[i + 1] << 4) + (input[i + 2] << 8)) & FASTLZ_HASH_MASK;int match_pos = hash_table[hash];int match_len = 0;if (match_pos < i) {// Check match lengthwhile (match_len < 264 && i + match_len < input_len && input[match_pos + match_len] == input[i + match_len]) {match_len++;}}if (match_len >= 3) {// Encode matchint match_dist = i - match_pos;if (match_len < 7) {output[output_len++] = ((match_len - 2) << 5) | ((match_dist >> 8) & 0x1F);} else {output[output_len++] = (7 << 5) | ((match_dist >> 8) & 0x1F);output[output_len++] = match_len - 7;}output[output_len++] = match_dist & 0xFF;i += match_len;} else {// Encode literaloutput[output_len++] = input[i++];}// Update hash tablehash_table[hash] = i;}return output_len;
}int fastlz_decode(const unsigned char *input, int input_len, unsigned char *output) {int output_len = 0;int i = 0;int hash_table[FASTLZ_HASH_SIZE] = {0};while (i < input_len) {unsigned char byte = input[i++];if (byte < 0x80) {  // literal byteoutput[output_len++] = byte;} else {  // compressed matchint len = (byte >> 5) + 3;int dist = ((byte & 0x1F) << 8) | input[i++];int match_pos = output_len - dist;for (int j = 0; j < len; j++) {output[output_len++] = output[match_pos + j];}}}return output_len;
}
  1. 特定图像压缩算法
    • QOI (Quite OK Image Format)
      • 压缩率接近PNG
      • 解码速度是PNG的3-4倍
      • 实现简单,代码量小
      • 特别适合:需要接近PNG效果但要求快速解码的场景
// QOI (Quite OK Image Format) style Implementation
typedef struct {unsigned char r, g, b, a;
} QOIPixel;#define QOI_HASH(p) (((p).r * 3 + (p).g * 5 + (p).b * 7 + (p).a * 11) & 63)int qoi_encode(const QOIPixel *input, int pixel_count, unsigned char *output) {int output_len = 0;QOIPixel index[64] = {0};QOIPixel prev = {0, 0, 0, 255};int run = 0;for (int i = 0; i < pixel_count; i++) {QOIPixel pixel = input[i];if (memcmp(&pixel, &prev, sizeof(QOIPixel)) == 0) {run++;if (run == 62 || i == pixel_count - 1) {output[output_len++] = 0xC0 | (run - 1);run = 0;}} else {if (run > 0) {output[output_len++] = 0xC0 | (run - 1);run = 0;}int index_pos = QOI_HASH(pixel);if (memcmp(&pixel, &index[index_pos], sizeof(QOIPixel)) == 0) {output[output_len++] = 0x00 | index_pos;} else {index[index_pos] = pixel;if (pixel.a == prev.a) {int vr = pixel.r - prev.r;int vg = pixel.g - prev.g;int vb = pixel.b - prev.b;if (vr > -3 && vr < 2 && vg > -3 && vg < 2 && vb > -3 && vb < 2) {output[output_len++] = 0x40 | ((vr + 2) << 4) | ((vg + 2) << 2) | (vb + 2);} else {output[output_len++] = 0xFE;output[output_len++] = pixel.r;output[output_len++] = pixel.g;output[output_len++] = pixel.b;}} else {output[output_len++] = 0xFF;output[output_len++] = pixel.r;output[output_len++] = pixel.g;output[output_len++] = pixel.b;output[output_len++] = pixel.a;}}}prev = pixel;}return output_len;
}int qoi_decode(const unsigned char *input, int input_len, QOIPixel *output) {int output_len = 0;QOIPixel index[64] = {0};QOIPixel prev = {0, 0, 0, 255};int i = 0;while (i < input_len) {unsigned char byte = input[i++];if (byte == 0xC0) {  // run-length encodingint run_len = (byte & 0x3F) + 1;for (int j = 0; j < run_len; j++) {output[output_len++] = prev;}} else {prev.r = byte;prev.g = input[i++];prev.b = input[i++];prev.a = input[i++];output[output_len++] = prev;}}return output_len;
}
  1. 混合算法
    • RLE + Huffman:
      • 先RLE预处理
      • 再进行Huffman编码
      • 优点:保持了不错的压缩率同时解码较快
      • 特别适合:图形界面中的大图片
#define MAX_TREE_NODES 512typedef struct {int frequency;int left;int right;unsigned char value;
} HuffmanNode;typedef struct {unsigned int code;int bits;
} HuffmanCode;void build_huffman_tree(const int *frequencies, HuffmanNode *nodes, int *node_count) {// Initialize leaf nodes*node_count = 0;for (int i = 0; i < 256; i++) {if (frequencies[i] > 0) {nodes[*node_count].frequency = frequencies[i];nodes[*node_count].value = (unsigned char)i;nodes[*node_count].left = -1;nodes[*node_count].right = -1;(*node_count)++;}}// Build treewhile (*node_count > 1) {// Find two nodes with lowest frequenciesint min1 = 0, min2 = 1;if (nodes[min1].frequency > nodes[min2].frequency) {int temp = min1;min1 = min2;min2 = temp;}for (int i = 2; i < *node_count; i++) {if (nodes[i].frequency < nodes[min1].frequency) {min2 = min1;min1 = i;} else if (nodes[i].frequency < nodes[min2].frequency) {min2 = i;}}// Create new internal nodeHuffmanNode new_node;new_node.frequency = nodes[min1].frequency + nodes[min2].frequency;new_node.left = min1;new_node.right = min2;// Replace first minimum with new node and remove second minimumnodes[min1] = new_node;nodes[min2] = nodes[--(*node_count)];}
}void generate_huffman_codes(const HuffmanNode *nodes, int node_count, HuffmanCode *codes, int node_index, unsigned int code, int bits) {if (nodes[node_index].left == -1 && nodes[node_index].right == -1) {// Leaf nodecodes[nodes[node_index].value].code = code;codes[nodes[node_index].value].bits = bits;} else {// Internal node - traverse left and rightgenerate_huffman_codes(nodes, node_count, codes, nodes[node_index].left, (code << 1), bits + 1);generate_huffman_codes(nodes, node_count, codes, nodes[node_index].right, (code << 1) | 1, bits + 1);}
}// Combined RLE + Huffman Implementation
int rle_huffman_encode(const unsigned char *input, int input_len, unsigned char *output) {// First perform RLEunsigned char *rle_buffer = (unsigned char *)malloc(input_len * 2);int rle_len = rle_encode(input, input_len, rle_buffer);// Calculate frequenciesint frequencies[256] = {0};for (int i = 0; i < rle_len; i++) {frequencies[rle_buffer[i]]++;}// Build Huffman tree and generate codesHuffmanNode nodes[MAX_TREE_NODES];int node_count;build_huffman_tree(frequencies, nodes, &node_count);HuffmanCode codes[256];generate_huffman_codes(nodes, node_count, codes, 0, 0, 0);// Write header (frequencies)int output_len = 0;memcpy(output, frequencies, sizeof(frequencies));output_len += sizeof(frequencies);// Encode dataunsigned int bit_buffer = 0;int bits_in_buffer = 0;for (int i = 0; i < rle_len; i++) {unsigned char symbol = rle_buffer[i];HuffmanCode code = codes[symbol];bit_buffer = (bit_buffer << code.bits) | code.code;bits_in_buffer += code.bits;while (bits_in_buffer >= 8) {output[output_len++] = (bit_buffer >> (bits_in_buffer - 8)) & 0xFF;bits_in_buffer -= 8;}}// Flush remaining bitsif (bits_in_buffer > 0) {output[output_len++] = (bit_buffer << (8 - bits_in_buffer)) & 0xFF;}free(rle_buffer);return output_len;
}int rle_huffman_decode(const unsigned char *input, int input_len, unsigned char *output) {int frequencies[256];memcpy(frequencies, input, sizeof(frequencies));input += sizeof(frequencies);HuffmanNode nodes[MAX_TREE_NODES];int node_count;build_huffman_tree(frequencies, nodes, &node_count);HuffmanCode codes[256];generate_huffman_codes(nodes, node_count, codes, 0, 0, 0);int output_len = 0;unsigned int bit_buffer = 0;int bits_in_buffer = 0;int rle_len = 0;unsigned char *rle_buffer = (unsigned char *)malloc(input_len * 2);int rle_output_len = 0;while (rle_len < input_len) {bit_buffer = (bit_buffer << 8) | input[rle_len++];bits_in_buffer += 8;while (bits_in_buffer >= 8) {unsigned char symbol = 0;for (symbol = 0; symbol < 256; symbol++) {if (codes[symbol].bits <= bits_in_buffer && (bit_buffer >> (bits_in_buffer - codes[symbol].bits)) == codes[symbol].code) {rle_buffer[rle_output_len++] = symbol;bits_in_buffer -= codes[symbol].bits;bit_buffer &= (1 << bits_in_buffer) - 1;break;}}}}int i = 0;while (i < rle_output_len) {int count = rle_buffer[i++];unsigned char value = rle_buffer[i++];for (int j = 0; j < count; j++) {output[output_len++] = value;}}free(rle_buffer);return output_len;
}

实际选择建议:

  1. 如果是简单UI元素(图标、按钮等):
    • 推荐使用 RLE-4 或 SRLE
    • 解码速度快,实现简单
    • 内存占用极小
  2. 如果是较大的界面背景图:
    • 推荐使用 QOI 或 miniLZO
    • 平衡了压缩率和解码速度
    • 内存占用可控
  3. 如果存储空间极其受限:
    • 推荐使用 miniz 或 RLE+Huffman
    • 获得更好的压缩率
    • 牺牲一定解码速度
  4. 如果需要动态加载很多图片:
    • 推荐使用 FastLZ 或 miniLZO
    • 快速解码确保界面响应流畅
    • 适中的压缩率

RLE-42x - 10x非常快图标、按钮、简单背景图
SRLE5x - 20x非常快大面积单色区域的背景图、按钮
miniLZO2x - 3x每秒 200 KB - 1 MB动态加载图像
FastLZ3x - 5x每秒 500 KB - 1 MB动态加载图像,较大 UI 元素
miniz (DEFLATE)5x - 10x每秒 200 KB - 500 KB存储空间受限,但 CPU 容量充足的场景
QOI2x - 3x每秒 1 MB - 3 MB需要快速解码且压缩率接近 PNG
RLE + Huffman3x - 8x每秒几百 KB - 1 MB背景图、大图片,包含重复区域

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频推拉流EasyDSS无人机直播技术巡查焚烧、烟火情况

焚烧作为一种常见的废弃物处理方式&#xff0c;往往会对环境造成严重污染。因此&#xff0c;减少焚烧、推广绿色能源和循环经济成为重要措施。通过加强森林防灭火队伍能力建设与长效机制建立&#xff0c;各地努力减少因焚烧引发的森林火灾&#xff0c;保护生态环境。 巡察烟火…

K8S对接ceph的RBD块存储

1 PG数量限制问题 1.1 原因分析 1.还是老样子&#xff0c;先创建存储池&#xff0c;在初始化为rbd。 [rootceph141~]# ceph osd pool create wenzhiyong-k8s 128 128 Error ERANGE: pg_num 128 size 3 for this pool would result in 295 cumulative PGs per OSD (2067 tot…

React Router 6的学习

安装react-router-dom npm i react-router-dom 支持不同的路由创建 createBrowserRouter 特点 推荐使用的方式&#xff0c;基于 HTML5 的 History API。支持用户友好的 URL&#xff0c;无需 #。适用于生产环境的绝大多数场景。 适用 使用现代浏览器&#xff0c;支持 pus…

微信小程序web-view 嵌套h5界面 实现文件预览效果

实现方法&#xff1a;(这里我是在小程序里面单独加了一个页面用来下载预览文件) 安装 使用方法请参考文档 npm 安装 npm install weixin-js-sdk import wx from weixin-js-sdk预览 h5界面代码 <u-button click"onclick" type"primary" :loading"…

HTTP 状态码大全

常见状态码 200 OK # 客户端请求成功 400 Bad Request # 客户端请求有语法错误 不能被服务器所理解 401 Unauthorized # 请求未经授权 这个状态代码必须和WWW- Authenticate 报头域一起使用 403 Forbidden # 服务器收到请求但是拒绝提供服务 404 Not Found # 请求资源不存…

一文详解TCP协议 [图文并茂, 明了易懂]

欢迎来到啊妮莫的学习小屋! 目录 什么是TCP协议 TCP协议特点✨ TCP报文格式 三次握手和四次挥手✨ 可靠性 效率性 基于字节流✨ 基于TCP的应用层协议 什么是TCP协议 TCP(传输控制协议, Transmission Control Protocol) 是一种面向连接的, 可靠的, 基于字节流的传输层通…

在Linux(ubuntu22.04)搭建rust开发环境

1.安装rust 1.安装curl: sudo apt install curl 2.安装rust最新版 curl --proto ‘https’ --tlsv1.2 https://sh.rustup.rs -sSf | sh 安装完成后出现&#xff1a;Rust is installed now. Great! 重启当前shell即可 3.检验是否安装成功 rustc --version 结果出现&…

UnityShaderLab 实现程序化形状(一)

1.实现一个长宽可变的矩形&#xff1a; 代码&#xff1a; fixed4 frag (v2f i) : SV_Target{return saturate(length(saturate(abs(i.uv - 0.5)-0.13)))/0.03;} 2.实现一个半径可变的圆形&#xff1a; 代码&#xff1a; fixed4 frag (v2f i) : SV_Target{return (distance(a…

如何解决压测过程中JMeter堆内存溢出问题

如何解决压测过程中JMeter堆内存溢出问题 背景一、为什么会堆内存溢出&#xff1f;二、解决堆内存溢出措施三、堆内存参数应该怎么调整&#xff1f;四、堆内存大小配置建议 背景 Windows环境下使用JMeter压测运行一段时间后&#xff0c;JMeter日志窗口报错“java.lang.OutOfMe…

宽字节注入

尽管现在呼吁所有的程序都使用unicode编码&#xff0c;所有的网站都使用utf-8编码&#xff0c;来一个统一的国际规范。但仍然有很多&#xff0c;包括国内及国外&#xff08;特别是非英语国家&#xff09;的一些cms&#xff0c;仍然使用着自己国家的一套编码&#xff0c;比如gbk…

Web APIsPIs第1章

WebApi阶段学习什么&#xff1f; WebApi是浏览器提供的一组接口 使用 JavaScript 去操作页面文档 和 浏览器 什么是 API API: 应用程序接口&#xff08;Application Programming Interface&#xff09; 接口&#xff1a;本质上就是各种函数&#xff0c;无需关心内部如何实现…

android——录制屏幕

录制屏幕 1、界面 2、核心代码 import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.app.Service import android.content.Context import android.content.Intent import android.graphics.Bi…

【Excel学习记录】01-认识Excel

1.之前的优秀软件Lotus-1-2-3 默认公式以等号开头 兼容Lotus-1-2-3的公式写法&#xff0c;不用写等号 &#xff1a; 文件→选项→高级→勾选&#xff1a;“转换Lotus-1-2-3公式(U)” 备注&#xff1a;对于大范围手动输入公式可以使用该选项&#xff0c;否则请不要勾选&#x…

短视频矩阵抖音SEO源码OEM独立部署

短视频优化矩阵源码涉及对抖音平台上的视频内容进行筛选与排序&#xff0c;目的是增强其在搜索引擎中的可见度&#xff0c;以便更多用户能够浏览到这些视频。而抖音SEO优化系统则是通过构建一个分析框架&#xff0c;来解析抖音上的用户数据、视频信息及标签等元素&#xff0c;并…

MySQL——buffer poll

为什么要有buffer poll&#xff1f; 如果没有buffer poll&#xff0c;每次读取数据的时候都是从磁盘上读的&#xff0c;这样效率是很差的的。 所以有了提高效率的方式&#xff0c;就加上了一个缓存——buffer poll 所以&#xff0c;当我们读取数据的时候就有以下的方式 当读…

生产慎用之调试日志对空间矢量数据批量插入的性能影响-以MybatisPlus为例

目录 前言 一、一些缘由 1、性能分析 二、插入方式调整 1、批量插入的实现 2、MP的批量插入实现 3、日志的配置 三、默认处理方式 1、基础程序代码 2、执行情况 四、提升调试日志等级 1、在logback中进行设置 2、提升后的效果 五、总结 前言 在现代软件开发中&#xff0c;性能优…

元宇宙时代的社交平台:Facebook的愿景与实践

随着科技的不断进步&#xff0c;元宇宙&#xff08;Metaverse&#xff09;这一概念逐渐走进了人们的视野。作为全球最大的社交平台之一&#xff0c;Facebook&#xff08;现Meta&#xff09;在这场元宇宙革命中扮演着重要角色。Meta不仅在不断扩展其社交平台的边界&#xff0c;还…

C# 小案例(IT资产管理系统)

开发工具&#xff1a;visual studio 2022 语言&#xff1a;C# 数据库&#xff1a;Sql Server 2008 页面展示 一、登录 二、主窗体 三、用户管理 四、资产管理 五、关于 Java版地址&#xff1a;基于若依开发物品管理系统(springbootvue)_若依物品管理系统-CSDN博客 Python版…

分布式日志系统设计

一、分布式日志系统定义 分布式日志系统是一种用于收集、存储和分析大规模分布式系统日志的系统。它可以帮助开发人员和系统管理员实时监控和调试系统&#xff0c;提高系统可靠性和可用性&#xff0c;同时也可以用于日志分析和故障排查。 二、简单设计思路 日志收集&#xff…

敏捷开发04:Scrum 中的 Product Backlog(产品待办列表) 详细介绍

Product Backlog 产品待办列表 在计划开发产品功能时&#xff0c;都希望产品功能上线后&#xff0c;用户能够喜欢并经常使用。 因此在开发产品新功能时&#xff0c;就要衡量哪些产品需求是对用户最有价值&#xff0c;这是最应该思考的问题。 然后把这些有价值的需求集合放在一…