优化 .NET 中 System.Drawing 的 PNG 输出
我有一个例程,它读取图像,调整其大小并将其放置在新背景上(全新的位图,只是设置了大小)。
这一切都工作得非常完美,但现在我想减小 PNG 文件的大小输出 - 如果我输出 JPEG 文件,我会得到我期望的 ~4K 左右的文件大小,但我的 PNG 文件大小超过 30K。
我知道我永远无法用 PNG 达到 JPEG 水平,但我认为我可以做得更好一点。
当我将输出的 PNG 加载到 Fireworks 中时,我注意到背景和调整大小的图像仍然是单独的层。在 Fireworks 中压平 PNG 可将文件大小减少 5 到 10K。
那么,首先有没有一种方法可以在输出时以编程方式压平 PNG?
其次,还有什么其他人可以推荐来减小 PNG 大小吗?
我使用 PNG 文件,因为我希望将背景保留为透明。
代码:
private static void ResizeImage(String ImageInPath, int MaxWidth, int MaxHeight, String ImageOutPath, Boolean PadImage, Color MyColour)
{
Bitmap MyImage = new Bitmap(ImageInPath);
Bitmap MyResizedImage = null;
int XPosition = 0;
int YPosition = 0;
float Ratio = MyImage.Width / (float)MyImage.Height;
int MyImageHeight = MyImage.Height;
int MyImageWidth = MyImage.Width;
if (MyImage.Width > MyImage.Height)
{
if (MyImage.Width > MaxWidth)
MyResizedImage = new Bitmap(MyImage, new Size(MaxWidth, (int)Math.Round(MaxWidth /
Ratio, 0)));
YPosition = (MaxHeight / 2) - (MyResizedImage.Height / 2);
}
else if (MyImage.Height > MyImage.Width)
{
if (MyImage.Height > MaxHeight)
MyResizedImage = new Bitmap(MyImage, new Size((int)Math.Round(MaxWidth * Ratio,
0), MaxHeight));
XPosition = (MaxWidth / 2) - (MyResizedImage.Width / 2);
}
if (PadImage)
{
Bitmap MyUnderlay = new Bitmap(MaxWidth, MaxHeight);
var Canvas = Graphics.FromImage(MyUnderlay);
Canvas.Clear(MyColour);
Canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
Canvas.DrawImage(MyResizedImage, XPosition, YPosition);
Canvas.Save();
if (MyColour == Color.Transparent)
{
MyUnderlay.Save(ImageOutPath + ".png", ImageFormat.Png);
}
else
{
MyUnderlay.Save(ImageOutPath, ImageFormat.Jpeg);
}
Canvas.Dispose();
MyUnderlay.Dispose();
}
else
{
MyResizedImage.Save(ImageOutPath, ImageFormat.Jpeg);
}
MyResizedImage.Dispose();
MyImage.Dispose();
}
I have a routine which reads in an image, resizes it and positions it on a new background (brand new bitmap, just the size is set).
This all works absolutely perfectly, but now I would like to reduce the size of the PNG files it outputs - if I output JPEG files, I get the ~4K or so file size I expect, but my PNG files are more than 30K in size.
I know that I will never get to JPEG levels with PNG, but I think I can do a bit better.
When I load the outputted PNGs into Fireworks, I note that the background and the resized image are still seperate layers. Flattening the PNG in Fireworks reduces the filesize by a good 5 to 10K.
So, firstly is there a way to programmatically flatten the PNG on output?
Secondly, is there anything else anyone can recommend to reduce the PNG size?
I am using PNG files, because I wish to retain the background as transparent.
Code:
private static void ResizeImage(String ImageInPath, int MaxWidth, int MaxHeight, String ImageOutPath, Boolean PadImage, Color MyColour)
{
Bitmap MyImage = new Bitmap(ImageInPath);
Bitmap MyResizedImage = null;
int XPosition = 0;
int YPosition = 0;
float Ratio = MyImage.Width / (float)MyImage.Height;
int MyImageHeight = MyImage.Height;
int MyImageWidth = MyImage.Width;
if (MyImage.Width > MyImage.Height)
{
if (MyImage.Width > MaxWidth)
MyResizedImage = new Bitmap(MyImage, new Size(MaxWidth, (int)Math.Round(MaxWidth /
Ratio, 0)));
YPosition = (MaxHeight / 2) - (MyResizedImage.Height / 2);
}
else if (MyImage.Height > MyImage.Width)
{
if (MyImage.Height > MaxHeight)
MyResizedImage = new Bitmap(MyImage, new Size((int)Math.Round(MaxWidth * Ratio,
0), MaxHeight));
XPosition = (MaxWidth / 2) - (MyResizedImage.Width / 2);
}
if (PadImage)
{
Bitmap MyUnderlay = new Bitmap(MaxWidth, MaxHeight);
var Canvas = Graphics.FromImage(MyUnderlay);
Canvas.Clear(MyColour);
Canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
Canvas.DrawImage(MyResizedImage, XPosition, YPosition);
Canvas.Save();
if (MyColour == Color.Transparent)
{
MyUnderlay.Save(ImageOutPath + ".png", ImageFormat.Png);
}
else
{
MyUnderlay.Save(ImageOutPath, ImageFormat.Jpeg);
}
Canvas.Dispose();
MyUnderlay.Dispose();
}
else
{
MyResizedImage.Save(ImageOutPath, ImageFormat.Jpeg);
}
MyResizedImage.Dispose();
MyImage.Dispose();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
超级用户的答案,如何阅读没有 Fireworks 的 Fireworks PNG 多层文件,解释 Fireworks 具有 PNG 扩展名,可以在 PNG 文件中存储多个图层。展平去除多余的层。鉴于这些文件最初不是在 Fireworks 中创建的,理论上“扁平化”应该对它们没有影响。我怀疑尺寸的减小是由于 Firework 对 PNG 文件进行了保存优化。
我用于 PNG 优化的工具是:
如果您对优化 PNG 文件感兴趣,PNG 规范 非常简单,而且值得一看尽可能小的透明 PNG。与规范一样,实现也非常简单,例如单个文件,纯 Python 实现 png.py (pypng)< /a>.
The Super User answer, How to read Fireworks PNG multilayer files without Fireworks, explains that Fireworks has PNG extensions to store multiple layers in a PNG file. Flattening removes the extra layers. Given that the files were not created in Fireworks in the first place, in theory "flattening" should have no effect on them. I suspect the reduction in size is due to Firework's save-optimize the PNG file.
The tools I use for PNG optimization are:
If you are interested in optimizing PNG files, the PNG specification is surprisingly straightforward, and it is worth taking a look at Smallest possible transparent PNG. Like the specification, implementations are also surprisingly simple, take for example, the single file, pure Python implementation png.py (pypng).