FireMonkey中PNG图片的压缩等级指定与8位格式保存方法
FireMonkey中PNG压缩等级与8位格式保存方案
我来帮你搞定FireMonkey里PNG压缩等级和8位格式保存的问题——刚好你用的是TBitmapCodecManager,还不能用外部库,咱们直接用Delphi原生API就能解决:
一、指定PNG压缩等级
首先得说,TBitmapCodecManager的Quality参数对PNG完全没用,毕竟PNG是无损格式。要设置压缩等级,咱们可以绕开它,直接用Delphi自带的TPNGImage(这不算外部库,是VCL/FMX共享的原生组件),它专门提供了CompressionLevel属性,范围是0(无压缩)到9(最高压缩),默认值是6。
修改你原来的代码,换成下面的实现:
begin var oStream := TMemoryStream.Create; var PNGImage := TPNGImage.Create; try // 把你的TBitmap对象赋值给PNGImage PNGImage.Assign(aBitmap); // 设置压缩等级,这里设为最高的9,你可以根据需求调整0-9之间的值 PNGImage.CompressionLevel := 9; // 保存到内存流 PNGImage.SaveToStream(oStream); oStream.Position := 0; // 这里可以用oStream做后续的存储或传输操作 finally oStream.Free; PNGImage.Free; end; end;
如果硬要坚持用TBitmapCodecManager,其实可以自定义编码参数,但步骤繁琐得多,不如直接用TPNGImage来得直接高效,而且完全符合你“不依赖外部库”的要求。
二、保存为8位PNG格式
你的图片是黑白带抗锯齿,8位索引色(256级灰度)完全足够,还能大幅减小文件体积。咱们需要把32位的TBitmap转换成8位调色板模式的PNG,具体步骤如下:
- 创建一个256级的灰度调色板,覆盖黑白到中间过渡的所有灰度值
- 把32位像素转换成对应的灰度索引
- 配置
TPNGImage为8位索引色格式 - 可选:同时设置压缩等级
下面是完整的可复用代码:
uses FMX.Graphics, FMX.Surfaces, Vcl.Imaging.pngimage, System.Math; procedure SaveAs8BitPNG(aBitmap: TBitmap; aStream: TStream; CompressionLevel: Integer = 6); var PNGImage: TPNGImage; Palette: array[0..255] of TRGBQuad; I: Integer; Surface: TBitmapSurface; X, Y: Integer; Pixel: TAlphaColor; Gray: Byte; begin PNGImage := TPNGImage.Create; Surface := TBitmapSurface.Create; try // 从输入的TBitmap获取像素表面 Surface.Assign(aBitmap); // 创建256级灰度调色板(0=纯黑,255=纯白) for I := 0 to 255 do begin Palette[I].rgbRed := I; Palette[I].rgbGreen := I; Palette[I].rgbBlue := I; Palette[I].rgbReserved := 0; end; // 初始化PNG为8位索引色格式 PNGImage.CreateBlank(COLOR_PALETTE, 8, Surface.Width, Surface.Height); // 应用我们创建的灰度调色板 PNGImage.Palette := Palette; // 如果你的图片不需要透明,保持False即可;如果有透明区域,设为True并调整调色板的透明索引 PNGImage.Transparent := False; // 遍历所有像素,将32位颜色转成8位灰度索引 for Y := 0 to Surface.Height - 1 do for X := 0 to Surface.Width - 1 do begin Pixel := Surface.Pixels[X, Y]; // 用标准灰度公式计算灰度值,保证抗锯齿过渡自然 Gray := Round(0.299 * TAlphaColorRec(Pixel).R + 0.587 * TAlphaColorRec(Pixel).G + 0.114 * TAlphaColorRec(Pixel).B); // 直接用灰度值作为调色板索引,因为调色板是灰度对应的 PNGImage.Pixels[X, Y] := Gray; end; // 确保压缩等级在0-9的有效范围内 PNGImage.CompressionLevel := Clamp(CompressionLevel, 0, 9); // 保存到目标流 PNGImage.SaveToStream(aStream); aStream.Position := 0; finally Surface.Free; PNGImage.Free; end; end; // 调用示例 procedure TYourForm.SaveBlackWhitePNG; var oStream: TMemoryStream; begin oStream := TMemoryStream.Create; try // 保存为8位PNG,同时设置最高压缩等级9 SaveAs8BitPNG(YourSourceBitmap, oStream, 9); // 这里可以把流保存到文件,或者做其他处理 oStream.SaveToFile('output_8bit.png'); finally oStream.Free; end; end;
补充说明
- 如果你的图片存在透明区域,可以将
PNGImage.Transparent设为True,并修改调色板中对应索引的rgbReserved值为255(表示完全透明) - 压缩等级可以根据需求调整,0是最快但体积最大,9是最慢但体积最小
内容的提问来源于stack exchange,提问作者Peter Jones




