简体   繁体   English

减少PNG存储空间

[英]Reduce PNG storage size

In order to reduce file upload sizes to a webservice, we limit height/width of image files to a maximum value. 为了减少文件上传到Web服务的大小,我们将图像文件的高度/宽度限制为最大值。
For JPG files this works fine: a (downward) image resize results in reduced file size. 对于JPG文件,这可以很好地工作:(向下)调整图像大小会减小文件的大小。

Not so for PNG files, though: in most cases our code results in larger file sizes: 不过,对于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 is the image loaded from disk, FEditImageRes.Value contains the largest dimension that we reduce to. FFileName是从磁盘加载的映像, FEditImageRes.Value包含我们减小到的最大尺寸。

Note that we use Developer Express components, and that this code maintains alpha channel (transparency). 请注意,我们使用Developer Express组件,并且此代码维护alpha通道(透明度)。
I'm not attached to either. 我也没有依恋。

I have posted a ticket with DevExpress , but it is not an issue in their code. 我已经用DevExpress发布了票证 ,但这不是他们代码中的问题。

I looked at what other software does: 我查看了其他软件的功能:

在此处输入图片说明

In Paint.Net, if I reduce the above 890*161 screenshot to 512*93 I see mixed results depending on the algorithm used for the resize: 在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

在此处输入图片说明

For this 550x386 photo reduced to 512*353, the Paint.Net results are: 对于将此550x386照片缩小为512 * 353,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

So it looks pretty unpredictable what the results are going to be. 因此,结果将是很难预测的。

Question: 题:
Is there anything I can do (change to my code) to ensure that (most) resized PNG files actually will have a reduced file size? 有什么我可以做的(更改我的代码),以确保(大多数)调整大小的PNG文件实际上将具有减小的文件大小?

Some rules how to get smallest image size possible with TPngImage from vcl.imaging.PngImage 一些规则如何从vcl.imaging.PngImage使用TPngImage获得最小的图像大小

Firstly, it has CompressionLevel property, you can set integer value 0..9, 0 is no compression ar all, 9 is best compression (but slowest one). 首先,它具有CompressionLevel属性,您可以设置整数值0..9,0表示完全不压缩,9表示最佳压缩(但最慢)。 By default 7 is set. 默认情况下,设置为7。 Note: PNG is always lossless, this setting affects only amount of time it takes to save image. 注意:PNG始终是无损的,此设置仅影响保存图像所需的时间。

Second, there is Filters property, by default, its value is [pfSub] , but to achieve best compression, you should set it to [pfNone, pfSub, pfUp, pfAverage, pfPaeth] . 其次,有Filters属性,默认情况下,其值为[pfSub] ,但是要实现最佳压缩效果,应将其设置为[pfNone, pfSub, pfUp, pfAverage, pfPaeth] These are prediction filters which are applied to each row of image in order to use correlation between neighbours to get better compression. 这些是应用于每个图像行的预测过滤器,以便使用相邻像素之间的相关性以获得更好的压缩效果。 When all the filters are set, each will be tried and the best one will be used. 设置所有过滤器后,将尝试每种过滤器,并使用最佳过滤器。

Make sure that InterlaceMethod property is set to imNone. 确保InterlaceMethod属性设置为imNone。 Maybe your original images were interlaced, in that case file size is increased 5..20% compared to non-interlaced. 也许原始图像是隔行扫描的,在这种情况下,与非隔行扫描相比,文件大小增加了5..20%。

There is one more possibility to get lower size of image, that's to increase MaxIDATSize property to value a bit more, than your image size. 还有一种方法可以减小图像尺寸,即增加MaxIDATSize属性使其值比图像尺寸大。 Point is, PNG pixel data is stored in one or more IDAT chunks, each one has 4 bytes of its size, then 4 bytes of its name ('IDAT'), then data and then 4 bytes of CRC. 重点是,PNG像素数据存储在一个或多个IDAT块中,每个块的大小为4个字节,然后是其名称的4个字节(“ IDAT”),然后是数据,然后是4个字节的CRC。 By default, size of each chunk is 65535 bytes, so in big image you'll have lots of them, and 12 bytes per chunk of waste. 默认情况下,每个块的大小为65535字节,因此在大图中,您将拥有很多块,每个块浪费12个字节。 But increase here is very small, 0.2%, not so much. 但是这里的增加很小,为0.2%,不是很大。

In fact, with such settings PNGImage makes pretty small files, usually 10..20% smaller then Paint.NET, but specialized programs can compresss PNG even better. 实际上,通过这样的设置,PNGImage可以生成很小的文件,通常比Paint.NET小10..20%,但是专用程序可以更好地压缩PNG。

About resizing. 关于调整大小。 When trying to resize screenshots, larger file size is often the case. 尝试调整屏幕截图大小时,通常会出现较大的文件大小。 Original screenshot has few colors, in your case it's 431, much because of gradients. 原始屏幕截图的颜色很少,在您的情况下为431,主要是因为渐变。 There are large areas of same color that are saved very well. 有很多相同颜色的区域保存得很好。 After resizing, each sharp transition from one color to another is blurred, so more "mixed" colors are created, it is really harder to compress. 调整大小后,从一种颜色到另一种颜色的每个尖锐过渡都变得模糊了,因此创建了更多的“混合”颜色,实际上很难压缩。 As you see, nearest neighbor results in smallest file size exactly because it doesn't create new colors which weren't in original image already. 如您所见,最接近的邻居恰好导致文件大小最小,因为它不会创建原始图像中还没有的新颜色。

Your second example, 550x386 photo MUST have lower file size after resizing, and indeed, I've managed to compress resized to 512x353 photo to 303 kB. 您的第二个示例550x386照片在调整大小后必须具有较小的文件大小,实际上,我已经设法将大小调整为512x353的照片压缩为303 kB。 Paint.net doesn't use prediction filters at all, that's why it has awful compression of photos and other true color images. Paint.net根本不使用预测过滤器,这就是为什么它对照片和其他真彩色图像进行了可怕的压缩的原因。

The best approach is to use a dedicated tool to reduce the png size. 最好的方法是使用专用工具来减小png大小。

Take a look at this page for some technical details about how png size may be optimized 查看此页面 ,了解有关如何优化png大小的一些技术细节

There are some tools which works very well, I used http://optipng.sourceforge.net 有一些工具效果很好,我使用了http://optipng.sourceforge.net

See also this comparison of png optimization tools . 另请参见png优化工具的此比较

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM