【问题标题】:Optimising PNG output from System.Drawing in .NET [closed]在.NET中优化System.Drawing的PNG输出[关闭]
【发布时间】:2014-05-31 21:18:10
【问题描述】:

我有一个例程读取图像,调整它的大小并将其放置在新的背景上(全新的位图,只是设置了大小)。

这一切都完美无缺,但现在我想减小它输出的 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();
}

【问题讨论】:

    标签: .net png system.drawing


    【解决方案1】:

    超级用户回答 How to read Fireworks PNG multilayer files without Fireworks 解释说 Fireworks 具有 PNG 扩展名,可以在 PNG 文件中存储多个图层。展平会移除多余的图层。鉴于文件最初不是在 Fireworks 中创建的,理论上“展平”应该对它们没有影响。我怀疑大小的减小是由于 Firework 的保存优化 PNG 文件。

    我用于 PNG 优化的工具有:

    1. 转换为PNG8:如果颜色很少(比如截图),那么我使用pngnqGIMP's 索引颜色模式来量化到256 种颜色。 PNG8 可以小于 PNG24 或 PNG32。详情请见PNG8 – The Clear Winner
    2. Optipng,一个快速的通用 PNG 优化器。 C# PNG Optimization Tutorial 详细介绍了如何从 C# 运行 optipng
    3. 最后,pngout 很慢,但通常(80-90% 的时间)会比 optipng 进一步压缩 PNG。不过首先运行 optipng,因为 optipng 会自动执行 pngout 不会尝试的其他优化。

    如果您对优化 PNG 文件感兴趣,PNG specification 非常简单,值得一看 Smallest possible transparent PNG。和规范一样,实现也出奇的简单,比如单文件,纯Python实现png.py (pypng)

    【讨论】:

    • 关于 Fireworks 及其扩展 - png 是由 .Net 框架从全新的位图和 jpeg 创建的,但是当加载到 Fireworks 中时,我仍然可以将两者作为单独的对象进行操作,直到我将所有内容展平从 Fireworks 导出,所以这里有比 Fireworks 扩展更多的东西,或者 .Net 支持它们......
    • 哞,把位图和jpg结合的代码能贴出来吗?我原以为在将 jpg 和位图都绘制到另一个位图之后,任何“图层”信息都将早已不复存在,而生成的 png 将是两者的组合。不是这样吗?
    • 乔纳森,我已经添加了代码:)
    • 老实说,我从来没有读过 PNG 规范(从来没有感兴趣 :))但我认为这可能是因为背景是在 PNG 中总是一个单独的层,内容覆盖在它上面?
    • 太棒了。感谢您的回答
    猜你喜欢
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 2010-12-05
    • 2010-09-21
    • 2016-11-16
    • 2011-01-29
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多