【问题标题】:Convert Icon to Png将图标转换为PNG
【发布时间】:2017-02-18 20:57:48
【问题描述】:

我正在使用以下代码(基于我在另一个答案中找到的内容)将图像(通常是添加到项目资源中的 PNG)转换为用于表单标题等的图标。

public static Icon IconFromImage(Image img)
{
    using (var bmp = new Bitmap(img))
    {
        Byte[] ba;
        using (var ms = new MemoryStream())
        {
            bmp.Save(ms, ImageFormat.Png);
            ms.Seek(0, SeekOrigin.Begin);
            ba = ms.ToArray();
        }

        using (var imgData = new MemoryStream())
        using (var writer = new BinaryWriter(imgData))
        {
            if (writer != null)
            {
                //Header (6 bytes)
                writer.Write((Byte)0);              // 0 reserved: set to 0
                writer.Write((Byte)0);              // 1 reserved: set to 0
                writer.Write((Int16)1);             // 2-3 image type: 1 = icon, 2 = cursor
                writer.Write((Int16)1);             // 4-5 number of images

                //Image entry #1 (16 bytes)
                writer.Write((Byte)bmp.Width);      // 0 image width
                writer.Write((Byte)bmp.Height);     // 1 image height
                writer.Write((Byte)0);              // 2 number of colors
                writer.Write((Byte)0);              // 3 reserved
                writer.Write((Int16)0);             // 4-5 color planes
                writer.Write((Int16)32);            // 6-7 bits per pixel
                writer.Write(ba.Length);            // 8-11 size of image data
                writer.Write(6 + 16);               // 12-15 offset to image data

                //Write image data
                writer.Write(ba);                   // PNG data must contain the whole PNG data file!

                writer.Flush();
                writer.Seek(0, SeekOrigin.Begin);

                return new Icon(imgData,16,16);
            }
        }
    }
    return null;
}

从图像到图标工作正常。但是有一个实例,我需要获取该表单的标题图标并从中获取图像。这曾经在我使用基于文件的实际 ICO 文件作为标题图像时起作用,但现在我使用转换代码来获取表单的图标,生成的 PNG 看起来很糟糕。

表单的标题图标:

使用Bitmap.FromHicon(new Icon(theForm.Icon, new Size(16, 16)).Handle) 渲染的图像: (注:以前用theForm.Icon.ToBitmap(),现在出错了)

我阅读了另一篇帖子的评论,其中一位用户表示,如果使用 PNG 来派生图标,那么返回图像将是不好的,“因为 PNG 具有不止一点的透明度”。如果这是我遇到的问题,那我该怎么办?

【问题讨论】:

  • var img = this.Icon.ToBitmap() 有什么问题?
  • 图标没有高质量的编码器。 Extract icon from file then save as .ico file with transparency 可能会回答你的问题
  • @RezaAghaei 通用版本似乎不喜欢 32bpp 规范。如果我将writer.Write((Int16)32) 更改为 24bpp,或者使用需要 16x16 大小的那个,那很好。我得到一个数组溢出异常。
  • @DonBoitnott 我用这个icon 作为我的FormIcon。然后使用this.pictureBox1.Image = this.Icon.ToBitmap();。质量完全可以接受。我错过了什么问题吗?
  • @RezaAghaei 是的,我想你做到了。这与ToBitmap() 无关。它与获取 PNG 文件有关,将其放入我提供的代码中,然后尝试将内存中的 ICO 恢复为 PNG,而不会影响质量。

标签: c# .net image winforms gdi+


【解决方案1】:

您可以使用IconBitmapDecoder 获取保留像素格式的图标流,并使用PngBitmapEncoder将该流保存在 png 图像中:

using System.Drawing;
using System.Windows.Media.Imaging;
class IconHelper
{
    public static Bitmap PngFromIcon(Icon icon)
    {
        Bitmap png = null;
        using (var iconStream = new System.IO.MemoryStream())
        {
            icon.Save(iconStream);
            var decoder = new IconBitmapDecoder(iconStream,
                BitmapCreateOptions.PreservePixelFormat,
                BitmapCacheOption.None);

            using (var pngSteam = new System.IO.MemoryStream())
            {
                var encoder = new PngBitmapEncoder();
                encoder.Frames.Add(decoder.Frames[0]);
                encoder.Save(pngSteam);
                png = (Bitmap)Bitmap.FromStream(pngSteam);
            }
        }
        return png;
    }
}

要使用这些类,您需要添加对PresentationCoreWindowsBaseSystem.Xaml 的引用。那么用法是:

this.pictureBox1.Image = IconHelper.PngFromIcon(this.Icon);

结果与您用于创建图标的原始 png 相同。

【讨论】:

  • 效果很好,Reza。非常感谢。顺便说一句,我不必包括System.Xaml
  • 我在 .NET 4.0 上检查它,我将使用 .NET 4.5 检查它。也许我错了。
  • 在 .NET 4.8 中是System.Drawing,而不是System.Xaml
【解决方案2】:

试试 Bitmap.FromHicon(this.Icon.Handle),你可能会得到更好的结果。如果 png 有压缩,至少 ToBitmap() 似乎会出错:Displaying an icon in a picturebox, http://community.sharpdevelop.net/forums/t/21851.aspx

【讨论】:

  • 我认为这基本上等同于theForm.Icon.ToBitmap(),当我可以通过将编码质量降低到 24bpp 来使其工作时,它并没有提供更好的结果。
  • 在这种情况下,我只是建议在您的表单上粘贴一个字段以携带原始位图,以便您可以从那里获取它:)
  • 我希望它不会变成那样。不应该,因为这在我使用“专业”图标之前有效。
猜你喜欢
  • 1970-01-01
  • 2016-02-15
  • 2020-06-15
  • 2012-06-01
  • 2017-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
相关资源
最近更新 更多