2012-07-11 69 views
2

我需要编写一个程序,该程序将根据tileset图像生成108个图标组合(标准Windows .ico文件)。Bitmap.Save保存一个图标实际上保存了一个.png

我使用类System.Drawing.Bitmap构建每个combinaison,和我保存这样的:

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资源管理器可以正确显示。

我有这个结果,即使我没有在位图上做任何事情(我用newSave直接构建它,这给了我一个黑色的PNG)。

我在做什么错?

我也试过了,这给了我可怕的16级色的图标,但我宁愿避免这种情况的解决方案呢(使用手柄):

Icon NewIcon = Icon.FromHandle(IconBitmap.GetHicon()); 
FileStream FS = new FileStream(Path.Combine(Target, "Icon" + Counter + ".ico"), 
     FileMode.Create); 
NewIcon.Save(FS); 
+2

从[Microsoft支持](http://support.microsoft.com/default.aspx?scid=kb;en-us;q316563)看这个,看起来你运气不好。 – Steve 2012-07-11 14:27:23

+0

ICO是一种容器格式,可以接受PNG或位图编码的图像,因此您在那里看到的行为是正确的。对您来说,分享您的处理代码可能是值得的,这样我们就可以看到您是否在做任何会使您的图标无法正确显示的事情。另外,我认为显示PNG图像文件的能力只能从Vista开始,所以如果您使用的是XP或需要XP兼容性,那么您可能会失败。 – 2012-07-11 14:27:39

+2

可能的重复http://stackoverflow.com/questions/4042488/how-to-save-bitmap-as-icon – 2012-07-11 14:30:12

回答

0

这是真实的,ImageFormat.Icon不写,你的工作'd假设,.NET根本不支持写.ico文件,只是转储PNG数据。

CodeProject(和this one)(和another one)上有几个项目,并且允许您编写.ico文件,但实际上并不难。 file format非常直接,支持BMP和PNG数据。

3

我自己做了一个快速又脏的解决方法,我把它张贴在这里作为记录(它可能有助于需要快速解决方案的人,像我一样)。

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

它基于维基百科的ICO file format文章,有些失败并重试。

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(); 
} 
2

这里有一个简单的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)); 
    } 
}