You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将System.Drawing.Icon转byte[]时色深丢失,如何修复?

修复图标序列化/反序列化后的颜色与色深丢失问题

嘿,我碰到过完全类似的问题!你的情况核心是图标序列化时没完整保留原生数据,加上MemoryStream.GetBuffer()的隐形坑,咱们一步步解决:

问题拆解

  1. GetBuffer()的坑:这个方法返回的是MemoryStream的整个内部缓冲区(包含未被实际写入的空白字节),反序列化时这些无效字节会干扰Icon的解析,直接导致色深丢失、颜色异常。哪怕你试过ToArray(),如果没处理Icon本身的保存逻辑,也会出状况。
  2. Icon.Save()的局限性:直接对ExtractAssociatedIcon拿到的Icon调用Save,有时候只会保存图标集合中的某一个尺寸/色深版本,丢失了其他关键数据,还原后自然颜色不对。
  3. ToBitmap()的透明通道问题:图标默认带Alpha透明,直接调用ToBitmap()会把透明区域填充为黑色,这是Bitmap默认的兼容行为。

完整修复代码

1. 修正序列化/反序列化方法

先换掉GetBuffer()改用ToArray(),同时克隆图标后再保存,确保完整导出所有图标数据:

public static byte[] ToByteArray(this Icon icon)
{
    using (var ms = new MemoryStream())
    {
        // 克隆图标,避免原图标资源锁定或状态异常导致保存不完整
        using (var clonedIcon = (Icon)icon.Clone())
        {
            clonedIcon.Save(ms);
            // 用ToArray()获取实际写入的有效字节,绝对不要用GetBuffer()
            return ms.ToArray();
        }
    }
}

public static Icon ToIcon(byte[] bytes)
{
    using (var ms = new MemoryStream(bytes))
    {
        return new Icon(ms);
    }
}

2. 修复ToBitmap()的黑色背景

如果需要把图标转成Bitmap并保留透明,给ToBitmap()加个透明处理:

public static Bitmap ToBitmapWithTransparency(this Icon icon)
{
    var bitmap = icon.ToBitmap();
    // 将默认的黑色背景转为透明
    bitmap.MakeTransparent();
    return bitmap;
}

3. 验证完整调用逻辑

替换方法后,你的原有调用逻辑可以直接复用,现在能完整保留图标所有信息:

public static void Func()
{
    Icon icon = System.Drawing.Icon.ExtractAssociatedIcon("filename");
    var iconBytes = icon.ToByteArray();
    //...... SOME LOGIC.......
    var restoredIcon = ToIcon(iconBytes);
    image.Source = restoredIcon.ToImageSource();
}

public static ImageSource ToImageSource(this Icon icon)
{
    ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon(
        icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
    return imageSource;
}

额外兜底方案

如果上述方法还是有问题(比如你提取的是特殊的多资源高色深图标),可以改用Windows API直接读取原始图标数据:

// 定义需要的Windows API
private static class NativeMethods
{
    [StructLayout(LayoutKind.Sequential)]
    public struct IconInfo
    {
        public bool fIcon;
        public int xHotspot;
        public int yHotspot;
        public IntPtr hbmMask;
        public IntPtr hbmColor;
    }

    [DllImport("user32.dll")]
    public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr CopyIcon(IntPtr hIcon);

    [DllImport("user32.dll")]
    public static extern bool DestroyIcon(IntPtr hIcon);
}

// 更底层的序列化方法
public static byte[] ToByteArrayRaw(this Icon icon)
{
    var iconHandle = NativeMethods.CopyIcon(icon.Handle);
    try
    {
        using (var ms = new MemoryStream())
        {
            using (var clonedIcon = Icon.FromHandle(iconHandle))
            {
                clonedIcon.Save(ms);
                return ms.ToArray();
            }
        }
    }
    finally
    {
        NativeMethods.DestroyIcon(iconHandle);
    }
}

这个方法通过复制图标句柄,确保拿到的是完整的图标资源,避免原图标被系统锁定导致的保存不完整。

内容的提问来源于stack exchange,提问作者Lilium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:48:44