C# 保存保存图标实际上保存了一个.png

C# 保存保存图标实际上保存了一个.png,c#,bitmap,icons,png,system.drawing,C#,Bitmap,Icons,Png,System.drawing,我需要写一个程序,将产生108个图标组合(标准的windows.ico文件)的基础上的瓷砖图像 我使用类System.Drawing.Bitmap来构建每个组合,并按如下方式保存它们: Bitmap IconBitmap = new Bitmap(16, 16); // Some processing, writing different parts of the source tileset // ... IconBitmap.Save(Path.Combine(TargetPath, "Ic

我需要写一个程序,将产生108个图标组合(标准的windows.ico文件)的基础上的瓷砖图像

我使用类System.Drawing.Bitmap来构建每个组合,并按如下方式保存它们:

Bitmap IconBitmap = new Bitmap(16, 16);
// Some processing, writing different parts of the source tileset
// ...
IconBitmap.Save(Path.Combine(TargetPath, "Icon" + Counter + ".ico"),
                ImageFormat.Icon);
但我发现保存的文件实际上是一个PNG。Windows资源管理器和Visual Studio都不能正确显示它,但GIMP可以,如果我在十六进制查看器中打开它,下面是我看到的:

00000000  89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52  ‰PNG........IHDR
00000010  00 00 00 10 00 00 00 10 08 06 00 00 00 1F F3 FF  ..............óÿ
00000020  61 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00  a....sRGB.®Î.é..
00000030  00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00  ..gAMA..±..üa...
00000040  00 09 70 48 59 73 00 00 0E C3 00 00 0E C3 01 C7  ..pHYs...Ã...Ã.Ç
00000050  6F A8 64 00 00 00 15 49 44 41 54 38 4F 63 60 18  o¨d....IDAT8Oc`.
00000060  05 A3 21 30 1A 02 A3 21 00 09 01 00 04 10 00 01  .£!0..£!........
00000070  72 A5 13 76 00 00 00 00 49 45 4E 44 AE 42 60 82  r¥.v....IEND®B`‚
如果我将.ico重命名为.png,Windows资源管理器也可以正确显示它

即使我对位图不做任何操作,我也会得到这个结果(我用
new
Save
直接构造它,这会给我一个黑色的png)

我做错了什么

我也尝试过这个,它给了我可怕的16色图标,但我还是希望避免这个解决方案(使用手柄):


确实,
ImageFormat.Icon
不能像您想象的那样进行写入,.NET不支持写入.ico文件,而只是转储PNG数据


在(和)(和)上有一些项目可以让您编写一个
.ico
文件,实际上并不难。它非常简单,支持BMP和PNG数据

确实,
ImageFormat.Icon
不能像您想象的那样用于写入,.NET根本不支持写入.ico文件,只是转储PNG数据


在(和)(和)上有一些项目可以让您编写一个
.ico
文件,实际上并不难。它非常简单,支持BMP和PNG数据

我自己做了一个快速而肮脏的解决方案,我将其发布在这里以供记录(它可能会帮助像我这样需要快速解决方案的人)

我不认为这是正确的答案,它不是一个真正的图标作者。 它只需使用PNG格式将32位ARGB位图写入ico文件(适用于Vista或更高版本)

它基于Wikipedia的文章,有些失败,请重试

void SaveAsIcon(Bitmap SourceBitmap, string FilePath)
{
    FileStream FS = new FileStream(FilePath, FileMode.Create);
    // ICO header
    FS.WriteByte(0); FS.WriteByte(0);
    FS.WriteByte(1); FS.WriteByte(0);
    FS.WriteByte(1); FS.WriteByte(0);

    // Image size
    FS.WriteByte((byte)SourceBitmap.Width);
    FS.WriteByte((byte)SourceBitmap.Height);
    // Palette
    FS.WriteByte(0);
    // Reserved
    FS.WriteByte(0);
    // Number of color planes
    FS.WriteByte(0); FS.WriteByte(0);
    // Bits per pixel
    FS.WriteByte(32); FS.WriteByte(0);

    // Data size, will be written after the data
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);

    // Offset to image data, fixed at 22
    FS.WriteByte(22);
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);

    // Writing actual data
    SourceBitmap.Save(FS, ImageFormat.Png);

    // Getting data length (file length minus header)
    long Len = FS.Length - 22;

    // Write it in the correct place
    FS.Seek(14, SeekOrigin.Begin);
    FS.WriteByte((byte)Len);
    FS.WriteByte((byte)(Len >> 8));

    FS.Close();
}

我自己做了一个快速而肮脏的解决办法,我把它贴在这里作为记录(它可能会帮助像我这样需要快速解决方案的人)

我不认为这是正确的答案,它不是一个真正的图标作者。 它只需使用PNG格式将32位ARGB位图写入ico文件(适用于Vista或更高版本)

它基于Wikipedia的文章,有些失败,请重试

void SaveAsIcon(Bitmap SourceBitmap, string FilePath)
{
    FileStream FS = new FileStream(FilePath, FileMode.Create);
    // ICO header
    FS.WriteByte(0); FS.WriteByte(0);
    FS.WriteByte(1); FS.WriteByte(0);
    FS.WriteByte(1); FS.WriteByte(0);

    // Image size
    FS.WriteByte((byte)SourceBitmap.Width);
    FS.WriteByte((byte)SourceBitmap.Height);
    // Palette
    FS.WriteByte(0);
    // Reserved
    FS.WriteByte(0);
    // Number of color planes
    FS.WriteByte(0); FS.WriteByte(0);
    // Bits per pixel
    FS.WriteByte(32); FS.WriteByte(0);

    // Data size, will be written after the data
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);

    // Offset to image data, fixed at 22
    FS.WriteByte(22);
    FS.WriteByte(0);
    FS.WriteByte(0);
    FS.WriteByte(0);

    // Writing actual data
    SourceBitmap.Save(FS, ImageFormat.Png);

    // Getting data length (file length minus header)
    long Len = FS.Length - 22;

    // Write it in the correct place
    FS.Seek(14, SeekOrigin.Begin);
    FS.WriteByte((byte)Len);
    FS.WriteByte((byte)(Len >> 8));

    FS.Close();
}

下面是我今天编写的一个简单的ICO文件编写器,它将多个
System.Drawing.Image
图像输出到一个文件中

// https://en.wikipedia.org/wiki/ICO_(file_format)

public static class IconWriter
{
    public static void Write(Stream stream, IReadOnlyList<Image> images)
    {
        if (images.Any(image => image.Width > 256 || image.Height > 256))
            throw new ArgumentException("Image cannot have height or width greater than 256px.", "images");

        //
        // ICONDIR structure
        //

        WriteInt16(stream, 0); // reserved
        WriteInt16(stream, 1); // image type (icon)
        WriteInt16(stream, (short) images.Count); // number of images

        var encodedImages = images.Select(image => new
        {
            image.Width,
            image.Height,
            Bytes = EncodeImagePng(image)
        }).ToList();

        //
        // ICONDIRENTRY structure
        //

        const int iconDirSize = 6;
        const int iconDirEntrySize = 16;

        var offset = iconDirSize + (images.Count*iconDirEntrySize);

        foreach (var image in encodedImages)
        {
            stream.WriteByte((byte) image.Width);
            stream.WriteByte((byte) image.Height);
            stream.WriteByte(0); // no pallete
            stream.WriteByte(0); // reserved
            WriteInt16(stream, 0); // no color planes
            WriteInt16(stream, 32); // 32 bpp

            // image data length
            WriteInt32(stream, image.Bytes.Length);

            // image data offset
            WriteInt32(stream, offset);

            offset += image.Bytes.Length;
        }

        //
        // Image data
        //

        foreach (var image in encodedImages)
            stream.Write(image.Bytes, 0, image.Bytes.Length);
    }

    private static byte[] EncodeImagePng(Image image)
    {
        var stream = new MemoryStream();
        image.Save(stream, ImageFormat.Png);
        return stream.ToArray();
    }

    private static void WriteInt16(Stream stream, short s)
    {
        stream.WriteByte((byte) s);
        stream.WriteByte((byte) (s >> 8));
    }

    private static void WriteInt32(Stream stream, int i)
    {
        stream.WriteByte((byte) i);
        stream.WriteByte((byte) (i >> 8));
        stream.WriteByte((byte) (i >> 16));
        stream.WriteByte((byte) (i >> 24));
    }
}
//https://en.wikipedia.org/wiki/ICO_(文件格式)
公共静态类IconWriter
{
公共静态无效写入(流、IReadOnlyList图像)
{
if(images.Any(image=>image.Width>256 | | image.Height>256))
抛出新ArgumentException(“图像的高度或宽度不能大于256px。”,“图像”);
//
//ICONDIR结构
//
WriteInt16(流,0);//保留
WriteInt16(流,1);//图像类型(图标)
WriteInt16(流,(短)图像。计数);//图像数
var encodedImages=images.Select(image=>new
{
图像。宽度,
图像,高度,
字节=编码图像PNG(图像)
}).ToList();
//
//不规则结构
//
常数int ICondersize=6;
常数int iconDirEntrySize=16;
var offset=iconDirSize+(images.Count*iconDirEntrySize);
foreach(编码图像中的var图像)
{
stream.WriteByte((字节)image.Width);
stream.WriteByte((字节)image.Height);
stream.WriteByte(0);//无托盘
stream.WriteByte(0);//保留
WriteInt16(流,0);//没有颜色平面
WriteInt16(流,32);//32 bpp
//图像数据长度
WriteInt32(流、图像、字节、长度);
//图像数据偏移
写入32(流、偏移);
偏移量+=image.Bytes.Length;
}
//
//图像数据
//
foreach(编码图像中的var图像)
stream.Write(image.Bytes,0,image.Bytes.Length);
}
私有静态字节[]EncodeImagePng(图像)
{
var stream=newmemoryStream();
保存(流,ImageFormat.Png);
返回流ToArray();
}
私有静态void WriteInt16(流,短s)
{
stream.WriteByte((字节)s);
stream.WriteByte((字节)(s>>8));
}
私有静态void WriteInt32(流,int i)
{
stream.WriteByte((字节)i);
stream.WriteByte((字节)(i>>8));
stream.WriteByte((字节)(i>>16));
stream.WriteByte((字节)(i>>24));
}
}

我今天编写了一个简单的ICO文件编写器,它将多个
System.Drawing.Image
图像输出到一个文件中

// https://en.wikipedia.org/wiki/ICO_(file_format)

public static class IconWriter
{
    public static void Write(Stream stream, IReadOnlyList<Image> images)
    {
        if (images.Any(image => image.Width > 256 || image.Height > 256))
            throw new ArgumentException("Image cannot have height or width greater than 256px.", "images");

        //
        // ICONDIR structure
        //

        WriteInt16(stream, 0); // reserved
        WriteInt16(stream, 1); // image type (icon)
        WriteInt16(stream, (short) images.Count); // number of images

        var encodedImages = images.Select(image => new
        {
            image.Width,
            image.Height,
            Bytes = EncodeImagePng(image)
        }).ToList();

        //
        // ICONDIRENTRY structure
        //

        const int iconDirSize = 6;
        const int iconDirEntrySize = 16;

        var offset = iconDirSize + (images.Count*iconDirEntrySize);

        foreach (var image in encodedImages)
        {
            stream.WriteByte((byte) image.Width);
            stream.WriteByte((byte) image.Height);
            stream.WriteByte(0); // no pallete
            stream.WriteByte(0); // reserved
            WriteInt16(stream, 0); // no color planes
            WriteInt16(stream, 32); // 32 bpp

            // image data length
            WriteInt32(stream, image.Bytes.Length);

            // image data offset
            WriteInt32(stream, offset);

            offset += image.Bytes.Length;
        }

        //
        // Image data
        //

        foreach (var image in encodedImages)
            stream.Write(image.Bytes, 0, image.Bytes.Length);
    }

    private static byte[] EncodeImagePng(Image image)
    {
        var stream = new MemoryStream();
        image.Save(stream, ImageFormat.Png);
        return stream.ToArray();
    }

    private static void WriteInt16(Stream stream, short s)
    {
        stream.WriteByte((byte) s);
        stream.WriteByte((byte) (s >> 8));
    }

    private static void WriteInt32(Stream stream, int i)
    {
        stream.WriteByte((byte) i);
        stream.WriteByte((byte) (i >> 8));
        stream.WriteByte((byte) (i >> 16));
        stream.WriteByte((byte) (i >> 24));
    }
}
//https://en.wikipedia.org/wiki/ICO_(文件格式)
公共静态类IconWriter
{
公共静态无效写入(流、IReadOnlyList图像)
{
if(images.Any(image=>image.Width>256 | | image.Height>256))
抛出新ArgumentException(“图像的高度或宽度不能大于256px。”,“图像”);
//
//ICONDIR结构
//
WriteInt16(流,0);//保留
WriteInt16(流,1);//图像类型(图标)
WriteInt16(流,(短)图像。计数);//图像数
var encodedImages=images.Select(image=>new
{
图像。宽度,
图像,高度,
字节=编码图像PNG(图像)
}).ToList();
//
//不规则结构
//
常数int ICondersize=6;
常数int iconDirEntrySize=16;
var offset=iconDirSize+(images.Count*iconDirEntrySize);
foreach(编码图像中的var图像)
{
stream.WriteByte((字节)image.Width);
stream.WriteByte((字节)image.H