3、图像资源优化:压缩格式选择、图片尺寸裁剪与纹理图集
图像资源,往往是 TouchGFX 项目里最吃内存、最拖帧率的元凶。我见过太多团队,动画卡顿的第一反应是去调刷新率、改 DMA 配置,结果查到最后,罪魁祸首就是一张 4MB 的启动图。
这一章,咱们就专门啃这块硬骨头。我会把压缩格式、尺寸裁剪、纹理图集这三个手段拆开揉碎了讲。说白了,就是让你手里的每一张图,都变成「刚刚好」的状态——不多占一个字节,不浪费一个像素时钟。
核心原则: 图像优化的本质,是用「视觉无损」换取「性能增益」。你不需要让每张图都完美,只需要让用户看不出瑕疵。
3.1 压缩格式选择:L8 vs RGB565 vs ARGB8888
TouchGFX 支持三种主流像素格式。选对了,内存占用能直接砍掉一半以上。选错了,嗯……我见过有人用 ARGB8888 存纯色图标,白白浪费 75% 的带宽。
| 格式 | 每像素位数 | 色深 | Alpha 通道 | 典型场景 |
|---|---|---|---|---|
| ARGB8888 | 32 bpp | 16.7M 色 | 8 bit 全透明 | 照片、渐变背景、半透明叠加 |
| RGB565 | 16 bpp | 65K 色 | 无 | 图标、按钮、纯色块、非透明 UI 元素 |
| L8 | 8 bpp | 256 色 | 可选(占用额外调色板) | 低色数图标、字体纹理、风格化界面 |
我的选择习惯:
- 所有非透明的 UI 元素,一律用 RGB565。65K 色在 4.3 寸屏上根本看不出区别,但内存直接减半。
- 需要半透明或渐变的地方,才上 ARGB8888。比如弹窗遮罩、滑动返回的残影效果。
- L8 是个被低估的宝贝。我做过一个智能家居项目,所有图标只用 16 色,全部转成 L8 格式,整组图标从 800KB 缩到 80KB。你想想看,这差距有多大。
小技巧: 在 TouchGFX Designer 里,右键图片资源可以直接切换格式。切换后记得点「Run Simulator」预览一下——有些颜色在 RGB565 下会出现明显色带,这时候就得换回 ARGB8888。
3.2 图片尺寸裁剪:别让 MCU 做无用功
我曾经接手过一个项目,里面有一张 800×480 的全屏背景图,但实际内容只占了中间 400×300 的区域,四周全是纯白。你猜怎么着?TouchGFX 老老实实地把整张 800×480 的图加载到帧缓冲里,每次刷新都搬运 1.5MB 的数据——其中 70% 是没用的白色像素。
裁剪的核心逻辑:
- 物理裁剪: 在 Photoshop 或 GIMP 里,直接把图片裁到实际显示区域。别留多余边距。
- 逻辑裁剪: 如果一张图在运行时需要缩放或裁切,用 TouchGFX 的
Image控件的setScalingMode()配合setPosition()来裁剪,而不是加载完整大图。 - 对齐到 4 字节: 图片宽度最好是 4 的倍数。因为 TouchGFX 的帧缓冲是按 4 字节对齐的,不对齐的话,DMA 传输效率会下降。
注意: 不要为了省内存而把图片裁得太小,然后靠 TouchGFX 的
Scale 模式放大。放大后的模糊效果,比 RGB565 的色带还难看。我的经验是:裁剪后的尺寸,至少是显示尺寸的 0.8 倍。
3.3 纹理图集(Texture Atlas):把零散碎片拼成整块
纹理图集,说白了就是把一堆小图拼成一张大图。为什么这么做?因为 TouchGFX 在渲染时,每切换一次纹理,都会产生一次状态切换开销。如果你有 50 个小图标,每帧切换 50 次纹理,帧率直接腰斩。
纹理图集的好处:
- 减少纹理切换: 一次绑定,整组图标都能用。
- 提高缓存命中率: 大图在内存中是连续存储的,CPU 和 DMA 的预取效率更高。
- 降低碎片化: 小图分散加载容易造成内存碎片,拼成大图后一次性分配。
我建议的图集组织方式:
| 图集分组 | 包含内容 | 推荐格式 | 最大尺寸 |
|---|---|---|---|
| Icon Atlas | 所有导航图标、状态图标 | L8 或 RGB565 | 512×512 |
| Button Atlas | 按钮的 normal/pressed/disabled 状态 | RGB565 | 1024×512 |
| Background Atlas | 全屏背景、弹窗背景 | RGB565 或 ARGB8888 | 1024×1024 |
工具推荐: 我习惯用 TexturePacker 来生成图集。它支持直接导出 TouchGFX 的
.png 和 .tga 格式,还能自动生成坐标 JSON。在 TouchGFX Designer 里,把图集当成一张普通图片导入,然后用 Image 控件的 setBitmap() 配合 setXY() 来截取子图。
3.4 知识体系总览
下面这张图,把咱们这一章的核心逻辑串起来了。你可以把它当成一个决策流程——拿到一张图,先走哪一步,再走哪一步。
3.5 避坑指南
最后,分享几个我踩过的坑,希望能帮你省点 debug 时间。
- L8 的调色板陷阱: 我曾经把一张 256 色的 L8 图集用在 16 位屏上,结果颜色全乱了。后来才发现,L8 的调色板默认是 ARGB8888 格式的,如果你的屏只支持 RGB565,调色板里的颜色会被截断。解决办法:在 TouchGFX Designer 里手动指定调色板格式为 RGB565。
- 纹理图集的 padding: 拼图集时,子图之间至少留 2 像素的 padding。否则相邻图标的边缘会出现「串色」——因为纹理过滤时会采样到隔壁像素。我习惯用 TexturePacker 的
padding: 2选项。 - 不要迷信 ARGB8888: 有一次客户坚持所有图都用 ARGB8888,说「画质好」。结果动画帧率从 60fps 掉到 35fps。后来我做了个盲测,让 10 个人分辨 RGB565 和 ARGB8888 的图标差异——没人能看出来。从那以后,我就把「RGB565 优先」写进了团队规范。
重要提醒: 每次修改图像格式或尺寸后,一定要在目标硬件上跑一遍性能测试。模拟器上的帧率不能代表真机表现——因为模拟器用的是 PC 的显存和带宽,而你的 MCU 只有可怜的几 MB SRAM。