将System.Drawing.Icon转byte[]时色深丢失,如何修复?
修复图标序列化/反序列化后的颜色与色深丢失问题
嘿,我碰到过完全类似的问题!你的情况核心是图标序列化时没完整保留原生数据,加上MemoryStream.GetBuffer()的隐形坑,咱们一步步解决:
问题拆解
GetBuffer()的坑:这个方法返回的是MemoryStream的整个内部缓冲区(包含未被实际写入的空白字节),反序列化时这些无效字节会干扰Icon的解析,直接导致色深丢失、颜色异常。哪怕你试过ToArray(),如果没处理Icon本身的保存逻辑,也会出状况。Icon.Save()的局限性:直接对ExtractAssociatedIcon拿到的Icon调用Save,有时候只会保存图标集合中的某一个尺寸/色深版本,丢失了其他关键数据,还原后自然颜色不对。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
相关产品推荐
相关产品推荐

