Bitmap.Save to save an icon actually saves a .png

后端 未结 3 1863

I need to write a program that will generate 108 combinaisons of icons (standard windows .ico files) based on a tileset image.

I use the class System.Drawing.Bitmap

相关标签:
3条回答
  • 2021-01-14 05:49

    It's true that the ImageFormat.Icon does not work for writing as you'd suppose, .NET simply does not support writing .ico files and simply dumps the PNG data.

    There are a few projects on CodeProject (and this one) (and another one) and that let you write an .ico file, it's actually not that hard. The file format is pretty straight-forward, and supports BMP and PNG data.

    0 讨论(0)
  • 2021-01-14 06:01

    I made a quick-and-dirty workaround myself, I post it here for the record (it might help someone that need a quick solution, like me).

    I won't accept this as the correct answer, it's not an actual icon writer. It just write a 32bits ARGB bitmap into an ico file, using PNG format (works on Vista or later)

    It is based on the ICO file format article from Wikipedia, and some fails and retry.

    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();
    }
    
    0 讨论(0)
  • Here's a simple ICO file writer I wrote today that outputs multiple System.Drawing.Image images to a file.

    // 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));
        }
    }
    
    0 讨论(0)
提交回复
热议问题