C# 组合系统.绘图.位图[]->;偶像

C# 组合系统.绘图.位图[]->;偶像,c#,icons,system.drawing,ico,C#,Icons,System.drawing,Ico,将图标拆分为其位图部分很容易: Bitmap icon16 = new Icon(combinedIcon, new Size(16, 16)).ToBitmap() 但是如何将多个位图对象合并为一个图标 Bitmap icon16, icon32, icon64; Icon combinedIcon = [...] 一般来说,图标对象我不是很清楚。它确实是一组多个图像。加载时,您可以将其拆分为位图部分。但是我没有看到任何创建多图标的方法。无法以一种明显的方式迭代、添加或删除位图部分,就像

将图标拆分为其
位图
部分很容易:

Bitmap icon16 = new Icon(combinedIcon, new Size(16, 16)).ToBitmap()
但是如何将多个
位图
对象合并为一个
图标

Bitmap icon16, icon32, icon64;
Icon combinedIcon = [...]


一般来说,
图标
对象我不是很清楚。它确实是一组多个图像。加载时,您可以将其拆分为
位图
部分。但是我没有看到任何创建多图标的方法。无法以一种明显的方式迭代、添加或删除
位图
部分,就像拥有一组位图一样,这似乎也很奇怪。

Net中的
图标
类非常初级,甚至无法访问实际图标格式的所有功能。最好将图标构造为字节流,然后将其加载为图标

我不久前研究过这种格式,它实际上接受png数据作为内部图像。请注意,所述图像的宽度或高度不能超过256像素,并且文件中的图像量以两个字节保存,因此不能超过
Int16.MaxValue
、0xFFFF或65535

代码应该如下所示:

public static Icon ConvertImagesToIco(Image[] images)
{
    if (images == null)
        throw new ArgumentNullException("images");
    Int32 imgCount = images.Length;
    if (imgCount == 0)
        throw new ArgumentException("No images given!", "images");
    if (imgCount > 0xFFFF)
        throw new ArgumentException("Too many images!", "images");
    using (MemoryStream ms = new MemoryStream())
    using (BinaryWriter iconWriter = new BinaryWriter(ms))
    {
        Byte[][] frameBytes = new Byte[imgCount][];
        // 0-1 reserved, 0
        iconWriter.Write((Int16)0);
        // 2-3 image type, 1 = icon, 2 = cursor
        iconWriter.Write((Int16)1);
        // 4-5 number of images
        iconWriter.Write((Int16)imgCount);
        // Calculate header size for first image data offset.
        Int32 offset = 6 + (16 * imgCount);
        for (Int32 i = 0; i < imgCount; ++i)
        {
            // Get image data
            Image curFrame = images[i];
            if (curFrame.Width > 256 || curFrame.Height > 256)
                throw new ArgumentException("Image too large!", "images");
            // for these three, 0 is interpreted as 256,
            // so the cast reducing 256 to 0 is no problem.
            Byte width = (Byte)curFrame.Width;
            Byte height = (Byte)curFrame.Height;
            Byte colors = (Byte)curFrame.Palette.Entries.Length;
            Int32 bpp;
            Byte[] frameData;
            using (MemoryStream pngMs = new MemoryStream())
            {
                curFrame.Save(pngMs, ImageFormat.Png);
                frameData = pngMs.ToArray();
            }
            // Get the colour depth to save in the icon info. This needs to be
            // fetched explicitly, since png does not support certain types
            // like 16bpp, so it will convert to the nearest valid on save.
            Byte colDepth = frameData[24];
            Byte colType = frameData[25];
            // I think .Net saving only supports colour types 2, 3 and 6 anyway.
            switch (colType)
            {
                case 2: bpp = 3 * colDepth; break; // RGB
                case 6: bpp = 4 * colDepth; break; // ARGB
                default: bpp = colDepth; break; // Indexed & greyscale
            }
            frameBytes[i] = frameData;
            Int32 imageLen = frameData.Length;
            // Write image entry
            // 0 image width. 
            iconWriter.Write(width);
            // 1 image height.
            iconWriter.Write(height);
            // 2 number of colors.
            iconWriter.Write(colors);
            // 3 reserved
            iconWriter.Write((Byte)0);
            // 4-5 color planes
            iconWriter.Write((Int16)0);
            // 6-7 bits per pixel
            iconWriter.Write((Int16)bpp);
            // 8-11 size of image data
            iconWriter.Write(imageLen);
            // 12-15 offset of image data
            iconWriter.Write(offset);
            offset += imageLen;
        }
        for (Int32 i = 0; i < imgCount; i++)
        {
            // Write image data
            // png data must contain the whole png data file
            iconWriter.Write(frameBytes[i]);
        }
        iconWriter.Flush();
        ms.Position = 0;
        return new Icon(ms);
    }
}
public静态图标转换器imagestoico(Image[]images)
{
如果(图像==null)
抛出新的异常(“图像”);
Int32 imgCount=images.Length;
如果(imgCount==0)
抛出新的ArgumentException(“未给出图像!”,“图像”);
如果(imgCount>0xFFFF)
抛出新的ArgumentException(“图像太多!”,“图像”);
使用(MemoryStream ms=new MemoryStream())
使用(BinaryWriter iconWriter=新的BinaryWriter(ms))
{
字节[][]帧字节=新字节[imgCount][];
//0-1保留,0
iconWriter.Write((Int16)0);
//2-3图像类型,1=图标,2=光标
iconWriter.Write((Int16)1);
//4-5图像数量
iconWriter.Write((Int16)imgCount);
//计算第一个图像数据偏移的标题大小。
Int32偏移量=6+(16*imgCount);
对于(Int32 i=0;i256 | | curFrame.Height>256)
抛出新的ArgumentException(“图像太大!”,“图像”);
//对于这三个,0被解释为256,
//因此,将强制转换减少256到0是没有问题的。
字节宽度=(字节)curFrame.width;
字节高度=(字节)curFrame.height;
字节颜色=(字节)curFrame.palete.Entries.Length;
int32bpp;
字节[]帧数据;
使用(MemoryStream pngMs=new MemoryStream())
{
保存(pngMs,ImageFormat.Png);
frameData=pngMs.ToArray();
}
//获取要保存在图标信息中的颜色深度。这需要
//显式获取,因为png不支持某些类型
//与16bpp类似,因此它将在保存时转换为最接近的有效值。
字节colDepth=帧数据[24];
Byte colType=frameData[25];
//我认为.Net存储只支持颜色类型2、3和6。
开关(colType)
{
案例2:bpp=3*colDepth;break;//RGB
案例6:bpp=4*colDepth;break;//ARGB
默认值:bpp=colDepth;break;//索引和灰度
}
frameBytes[i]=帧数据;
Int32 imageLen=frameData.Length;
//写入图像条目
//0图像宽度。
iconWriter.Write(宽度);
//1图像高度。
iconWriter.Write(高度);
//2多种颜色。
iconWriter.Write(颜色);
//3保留
iconWriter.Write((字节)0);
//4-5色平面
iconWriter.Write((Int16)0);
//每像素6-7位
iconWriter.Write((Int16)bpp);
//8-11图像数据的大小
iconWriter.Write(imageLen);
//12-15图像数据的偏移
iconWriter.Write(偏移量);
偏移量+=成像透镜;
}
对于(Int32 i=0;i
请注意,与其他
系统.绘图
图像格式不同,
图标
类不要求流保持打开状态;它只是从流中读取字节,并保持不变

png颜色深度信息可以找到,顺便说一句


如果您想将图标文件作为字节数组,或者想将其写入光盘,当然可以修改此代码以返回字节数组,甚至只是让它将内容写入作为参数给出的
流中,而不是在内部创建
内存流。

使用Vista的PNG支持并直接应用格式是一个很好的主意+这一个一个!不久前,我制作了一个工具,用于转换90年代的一系列游戏图形格式,在制作时,我注意到.Net对某些原生格式的支持非常差。这就是为什么我深入研究这些东西,为它们创建自己的加载和保存方法。哎呀,在转换为字节后做了>256次检查。现在修好了。