为了减少web服务的文件上传大小,我们将图像文件的高度/宽度限制为最大值。
对于JPG文件,这可以正常工作:(向下)图像调整大小会导致文件大小减小。
但对于PNG文件却不是这样:在大多数情况下,我们的代码会产生更大的文件大小:
procedure TFrmImageCheckAndResize.ResizePNGImage;
var
lSrcPNGImage, lTrgPNGImage: TdxPNGImage;
lSrcBitmap,lDestBitMap: TcxAlphaBitmap;
lNewWidth,lNewHeight: Integer;
lFactor: Real;
begin
lSrcPNGImage := TdxPNGImage.Create;
lSrcPNGImage.LoadFromFile(FFileName);
lSrcBitmap := TcxAlphaBitmap.CreateSize(lSrcPNGImage.Width, lSrcPNGImage.Height, True);
lSrcBitmap.Canvas.Draw(0, 0, lSrcPNGImage);
if lSrcPNGImage.Width > lSrcPNGImage.Height then
if lSrcPNGImage.Width > FEditImageRes.Value then
lFactor := lSrcPNGImage.Width
else
lFactor := 0
else
if lSrcPNGImage.Height > FEditImageRes.Value then
lFactor := lSrcPNGImage.Height
else
lFactor := 0;
if lFactor <> 0 then
begin
lFactor := lFactor / FEditImageRes.Value;
lNewWidth := Trunc(lSrcPNGImage.Width / lFactor);
lNewHeight := Trunc(lSrcPNGImage.Height / lFactor);
lDestBitMap := TcxAlphaBitmap.CreateSize(lNewWidth,lNewHeight, True);
cxSmoothResizeBitmap(lSrcBitMap, lDestBitMap, true);
lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lDestBitmap);
end
else
begin
lDestBitmap := nil; // Silence the compiler
lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lSrcBitmap);
end;
lTrgPNGImage.SaveToFile(StringReplace(FFileName,'.','_' + IntToStr(FEditImageRes.Value) + '.',[]));
lSrcBitmap.Free;
lDestBitmap.Free;
lTrgPNGImage.Free;
lSrcPNGImage.Free;
end;
FFileName
是从磁盘加载的图片,FEditImageRes.Value
包含我们减少的最大维度。
请注意,我们使用Developer Express组件,并且此代码维护alpha通道(透明度) 我也不喜欢。
我发布了ticket with DevExpress,但这不是他们代码中的问题。
我查看了其他软件的功能:
在Paint.Net中,如果我将上面的890 * 161截图缩小到512 * 93,我会看到混合结果,具体取决于用于调整大小的算法:
15.697 Original.png
21.904 Resized_BiCubic.png
19.995 Resized_Bilineair.png
22.905 Resized_Fant.png
6.729 Resized_NearestNeigbour.png
对于缩小为512 * 353的550x386照片,Paint.Net结果为:
375.229 Photo.png
419.122 Photo_Bicubic.png
402.277 Photo_Bilineair.png
407.959 Photo_Fant.png
416.619 Photo_NearestNeighbor.png
所以结果看起来很不可预测。
问题:
有什么我可以做的(更改为我的代码)以确保(大多数)调整大小的PNG文件实际上将减少文件大小?
答案 0 :(得分:4)
有些规则规定如何使用TPngImage
vcl.imaging.PngImage
获得最小的图像尺寸
首先,它有CompressionLevel
属性,你可以设置整数值0..9,0没有压缩全部,9是最好的压缩(但最慢的一个)。默认设置为7。注意:PNG始终无损,此设置仅影响保存图像所需的时间。
其次,Filters
属性,默认情况下,其值为[pfSub]
,但要实现最佳压缩,您应将其设置为[pfNone, pfSub, pfUp, pfAverage, pfPaeth]
。这些是预测滤波器,其应用于每行图像以便使用邻居之间的相关性以获得更好的压缩。设置完所有过滤器后,将尝试各个过滤器并使用最佳过滤器。
确保InterlaceMethod
属性设置为imNone。也许您的原始图像是隔行扫描的,在这种情况下,与非隔行扫描相比,文件大小增加了5..20%。
还有一种方法可以获得较小的图像尺寸,即将MaxIDATSize
属性增加到比图像尺寸更多的值。要点是,PNG像素数据存储在一个或多个IDAT块中,每个块的大小为4个字节,然后是其名称的4个字节('IDAT'),然后是数据,然后是4个字节的CRC。默认情况下,每个块的大小为65535字节,因此在大图像中,您将拥有大量的内容,每个块的浪费为12个字节。但这里的增幅非常小,只有0.2%,而不是那么多。
事实上,通过这样的设置,PNGImage可以生成相当小的文件,通常比Paint.NET小10..20%,但专业程序可以更好地压缩PNG。
关于调整大小。在尝试调整屏幕大小时,通常会出现较大的文件大小。原始屏幕截图几乎没有颜色,在你的情况下它是431,很多是因为渐变。有很多相同颜色的区域可以很好地保存。调整大小后,从一种颜色到另一种颜色的每次急剧过渡都会模糊,因此会产生更多“混合”颜色,因此压缩起来非常困难。如您所见,最近邻居的文件大小最小,因为它不会创建原始图像中没有的新颜色。
你的第二个例子,550x386照片在调整大小后必须有较小的文件大小,事实上,我已经设法压缩大小调整为512x353照片到303 kB。 Paint.net根本不使用预测过滤器,这就是它对照片和其他真彩色图像进行可怕压缩的原因。
答案 1 :(得分:1)