我正在尝试在 C# 中以编程方式从 PNG 文件创建一个高质量的图标(意味着:适用于 Win Vista/7/8),以用作快捷方式图标。由于 Bitmap.GetHIcon() 函数不支持这些图标,并且我想避免外部依赖项或库,我目前正在使用我在 SO 上找到的稍微修改过的 ICO 编写器。我有工作代码,但在 Windows 显示这些图标的方式上遇到了一些故障。相关代码为:
// ImageFile contains the path to PNG file
public static String IcoFromImageFile(String ImageFile) {
//...
Image iconfile = Image.FromFile(ImageFile);
//Returns a correctly resized Bitmap
Bitmap bm = ResizeImage(256,256,iconfile);
SaveAsIcon(bm, NewIconFile);
return NewIconFile;
}
// From: https://stackoverflow.com/a/11448060/368354
public static 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
// Set to 0 for 256 px width/height
FS.WriteByte(0);
FS.WriteByte(0);
// Palette
FS.WriteByte(0);
// Reserved
FS.WriteByte(0);
// Number of color planes
FS.WriteByte(1); 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, System.Drawing.Imaging.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();
}
这可以编译并且可以工作,但是有一个问题。Windows 不正确地显示快捷方式上的图标。我也以编程方式执行此操作,但即使我手动执行此操作(通过文件属性、更改图标)也会发生。问题是图标被切断(图像本身正确显示)。这取决于图像,但通常只显示实际图标的 20% 左右。如果我在 XNView 之类的图像查看器中打开文件,它会完全正确地显示,但 MS Paint 不会。我制作了这个屏幕截图,以及一个正确显示的图标以供比较
我怀疑错误在于 ICO 保存方法,但即使在将它们与 Hex 编辑器中正常显示的 ICO 进行比较之后,标题也会正确写入,但 PNG 图像部分本身似乎不同。有人有想法吗?我也欢迎更好、更简单的解决方案。