代码来源:deepseek
注:这真是神器,虽然一天只能用两三次,但不用自己动手试错,实在是太方便了,一两次最多四五次代码就新鲜出炉,还不用找资料,最花时间的反而是因为自己看不懂代码,所以需要用其他ai来辅助自己理解意思。下面代码高亮来源syntaxhighlighter
说明:以下代码均可执行,已本地测试过。虽然说不出个所以然,毕竟没学过,全靠AI给力。
此为测试所用素材,均为PS导出的png
1.代码一
png格式生成多尺寸ICO
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Collections.Generic;
using System.Linq;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
// 加载不同尺寸的Bitmap
var images = new List<Bitmap>
{
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16x16.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32x32.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48x48.png")
};
// 生成ICO文件
IconCombiner.CreateIcon(images, @"D:\SoftwareCache\Microsoft VS Code\图标\合成\output.ico");
}
public class IconCombiner
{
public static void CreateIcon(IEnumerable<Bitmap> images, string outputPath)
{
var bitmaps = images.ToList();
if (bitmaps.Count == 0)
throw new ArgumentException("No images provided.");
using (var stream = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(stream))
{
// 写入ICO文件头
writer.Write((ushort)0); // 保留字
writer.Write((ushort)1); // 类型:ICO
writer.Write((ushort)bitmaps.Count); // 图像数量
int currentOffset = 6 + 16 * bitmaps.Count; // 第一个图像数据偏移
var entries = new List<byte[]>();
var imageDatas = new List<byte[]>();
foreach (var bmp in bitmaps)
{
// 转换为32位ARGB格式确保透明度
using (var convertedBmp = ConvertTo32bppArgb(bmp))
using (var ms = new MemoryStream())
{
convertedBmp.Save(ms, ImageFormat.Png);
byte[] pngData = ms.ToArray();
imageDatas.Add(pngData);
// 创建目录项
byte width = GetIconDimension(convertedBmp.Width);
byte height = GetIconDimension(convertedBmp.Height);
uint size = (uint)pngData.Length;
uint offset = (uint)currentOffset;
using (var entryMs = new MemoryStream())
using (var entryWriter = new BinaryWriter(entryMs))
{
entryWriter.Write(width);
entryWriter.Write(height);
entryWriter.Write((byte)0); // 调色板数量(无调色板)
entryWriter.Write((byte)0); // 保留
entryWriter.Write((ushort)1); // 颜色平面数
entryWriter.Write((ushort)32); // 每像素位数(32位ARGB)
entryWriter.Write(size);
entryWriter.Write(offset);
entries.Add(entryMs.ToArray());
}
currentOffset += (int)size;
}
}
// 写入所有目录项
foreach (var entry in entries)
writer.Write(entry);
// 写入所有PNG图像数据
foreach (var data in imageDatas)
writer.Write(data);
}
}
private static byte GetIconDimension(int dimension)
{
return (byte)(dimension >= 256 ? 0 : dimension);
}
private static Bitmap ConvertTo32bppArgb(Bitmap image)
{
Bitmap clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
using (Graphics gr = Graphics.FromImage(clone))
{
gr.DrawImage(image, new Rectangle(0, 0, clone.Width, clone.Height));
}
return clone;
}
}
ICO效果图以及在PE图标组效果图:
2.代码二
bmp格式生成多尺寸ICO(方式一)
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
// 加载不同尺寸的Bitmap
var bitmaps = new List<Bitmap>
{
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16x16.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32x32.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48x48.png")
};
// 合成ICO文件
IcoConverter.SaveAsLegacyIco(bitmaps, @"D:\SoftwareCache\Microsoft VS Code\图标\合成\bitok.ico");
}
public static class IcoConverter
{
// ICO文件头结构
[StructLayout(LayoutKind.Sequential)]
private struct IconDir
{
public ushort Reserved; // 必须为0
public ushort Type; // 1=ICO, 2=CUR
public ushort Count; // 图像数量
}
// ICO目录项结构
[StructLayout(LayoutKind.Sequential)]
private struct IconDirEntry
{
public byte Width; // 宽度(0=256)
public byte Height; // 高度(0=256)
public byte ColorCount; // 调色板颜色数(0=无调色板)
public byte Reserved; // 必须为0
public ushort Planes; // 颜色平面数(必须为1)
public ushort BitCount; // 位深度(如32)
public uint BytesInRes; // 图像数据总大小
public uint ImageOffset;// 数据偏移量
}
/// <summary>
/// 生成包含多个BMP格式图像的ICO文件
/// </summary>
public static void SaveAsLegacyIco(IEnumerable<Bitmap> bitmaps, string outputPath)
{
using (var stream = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(stream))
{
var entries = new List<IconDirEntry>();
var imageDataList = new List<byte[]>();
// 构建每个图像的BMP数据和目录项
uint currentOffset = (uint)(Marshal.SizeOf(typeof(IconDir)) + (uint)(Marshal.SizeOf(typeof(IconDirEntry)) * bitmaps.Count()));
foreach (var bmp in bitmaps)
{
var entry = new IconDirEntry();
var imageData = GenerateBmpEntry(bmp, ref entry);
entry.ImageOffset = currentOffset;
entries.Add(entry);
imageDataList.Add(imageData);
currentOffset += (uint)imageData.Length;
}
// 写入ICO文件头
writer.Write((ushort)0); // Reserved
writer.Write((ushort)1); // Type=ICO
writer.Write((ushort)entries.Count); // Count
// 写入目录项
foreach (var entry in entries)
{
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(entry.ImageOffset);
}
// 写入图像数据
foreach (var data in imageDataList)
{
writer.Write(data);
}
}
}
/// <summary>
/// 生成单个BMP格式的ICO图像数据(含掩码)
/// </summary>
private static byte[] GenerateBmpEntry(Bitmap bmp, ref IconDirEntry entry)
{
// 转换到32bpp ARGB格式(确保Alpha通道存在)
var bitmap32bpp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bitmap32bpp))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// 明确指定绘制尺寸防止缩放
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
}
// 获取BMP数据(移除BITMAPFILEHEADER)
var bmpBytes = GetBmpDataWithoutFileHeader(bitmap32bpp);
var maskBytes = GenerateMaskData(bitmap32bpp);
// 填充目录项信息
entry.Width = (byte)(bitmap32bpp.Width >= 256 ? 0 : bitmap32bpp.Width);
entry.Height = (byte)(bitmap32bpp.Height >= 256 ? 0 : bitmap32bpp.Height);
entry.ColorCount = 0; // 无调色板
entry.Reserved = 0;
entry.Planes = 1;
entry.BitCount = 32; // ARGB
entry.BytesInRes = (uint)(bmpBytes.Length + maskBytes.Length);
// 合并BMP数据和掩码数据
var imageData = new byte[bmpBytes.Length + maskBytes.Length];
Buffer.BlockCopy(bmpBytes, 0, imageData, 0, bmpBytes.Length);
Buffer.BlockCopy(maskBytes, 0, imageData, bmpBytes.Length, maskBytes.Length);
return imageData;
}
/// <summary>
/// 获取不带文件头的BMP数据(仅包含BITMAPINFOHEADER和像素)
/// </summary>
private static byte[] GetBmpDataWithoutFileHeader(Bitmap bmp)
{
// 克隆位图并设置正确的高度方向
using (var cloneBmp = new Bitmap(bmp))
{
//cloneBmp.RotateFlip(RotateFlipType.Rotate180FlipX); // 反转Y轴,此方式不用翻转,不清楚缘由
using (var ms = new MemoryStream())
{
cloneBmp.Save(ms, ImageFormat.Bmp);
var fullData = ms.ToArray();
// 移除BITMAPFILEHEADER (14 bytes)
byte[] dataWithoutHeader = new byte[fullData.Length - 14];
Buffer.BlockCopy(fullData, 14, dataWithoutHeader, 0, dataWithoutHeader.Length);
int height = BitConverter.ToInt32(dataWithoutHeader, 8);//获取原本数据的像素高度
// 将高度设为两倍表示包含掩码
byte[] negativeHeight = BitConverter.GetBytes(height*2);//Height*2 (包含掩码)
Buffer.BlockCopy(negativeHeight, 0, dataWithoutHeader, 8, 4);
return dataWithoutHeader;
}
}
}
/// <summary>
/// 生成AND掩码位图(1位/像素)----原本代码看不咋懂,所以找AI理解后微改并加上注释
/// </summary>
private static byte[] GenerateMaskData(Bitmap bmp)
{
//int maskStride = ((bmp.Width + 31) / 32) * 4;//32位图像是指一个像素的数据由32个bit构成
int maskStride = (int)Math.Ceiling(bmp.Width / 8.0);//一个掩码字节八个bit可以储存八个像素的透明状态,每个bit表示一个像素是否透明,也因此掩码字节数量(步长)必须包含当前行全部像素,因此改用进一法更直观
byte[] mask = new byte[maskStride * bmp.Height];
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
var color = bmp.GetPixel(x, y);
bool isTransparent = color.A < 128;//将alpha值范围一分为二简单的区分透明和不透明的像素
if (isTransparent)
{
int offset = y * maskStride + (x / 8);//获取用来表示对应像素所在掩码字节的索引(int自动去除小数)
// 将掩码位设置为1(对应透明区域)
mask[offset] |= (byte)(1 << (7 - (x % 8)));//生成一个指定位为1的字节,与索引对应字节执行位或运算,将指定bit位置的1写入到数组索引的字节中。先生成1的二进制数,%取模获取余数,然后从右往左移,右侧补零,所以需要7减取获取需要移动位置的位数。。。1 在二进制中是 0000 0001,因此只能左移。位与像素对应是从左往右。
}
}
}
return mask;
}
}
ICO效果图以及在PE图标组效果图:
3.代码三
bmp格式生成多尺寸ICO(方式二)
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
var bitmaps = new List<Bitmap>
{
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16x16.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32x32.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48x48.png")
};
IcoConverter.SaveAsLegacyIco(bitmaps, @"D:\SoftwareCache\Microsoft VS Code\图标\合成\bitmap.ico");
}
public static class IcoConverter
{
// ICO文件头结构 2
[StructLayout(LayoutKind.Sequential)]
private struct IconDir
{
public ushort Reserved;
public ushort Type;
public ushort Count;
}
// ICO目录项结构 2
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct IconDirEntry
{
public byte Width;
public byte Height;
public byte ColorCount;
public byte Reserved;
public ushort Planes;
public ushort BitCount;
public uint BytesInRes;
public uint ImageOffset;
}
/// <summary>
/// 将多个BMP合并为多帧ICO文件
/// </summary>
public static void SaveAsLegacyIco(IEnumerable<Bitmap> bitmaps, string outputPath)
{
var entries = new List<IconDirEntry>();
var imageDataList = new List<byte[]>();
// 生成所有图标的BMP数据
foreach (var bmp in bitmaps)
{
var data = GetBitmapData(bmp);
var entry = new IconDirEntry
{
Width = (byte)(bmp.Width >= 256 ? 0 : bmp.Width),
Height = (byte)(bmp.Height >= 256 ? 0 : bmp.Height),
ColorCount = 0,
Planes = 1,
BitCount = 32,
BytesInRes = (uint)data.Length,
ImageOffset = currentOffset
};
entries.Add(entry);
imageDataList.Add(data);
currentOffset += (uint)data.Length;
}
// 写入文件
using (var fs = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
// 写入ICO头部 2
writer.Write((ushort)0); // Reserved
writer.Write((ushort)1); // Type=ICO
writer.Write((ushort)entries.Count); // Image count
// 写入目录项
foreach (var entry in entries)
{
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(entry.ImageOffset);
}
// 写入图像数据 11
foreach (var data in imageDataList)
{
writer.Write(data);
}
}
}
/// <summary>
/// 将Bitmap转为ICO兼容的BMP格式数据
/// </summary>
private static byte[] GetBitmapData(Bitmap bmp)
{
// 确保位图格式为32bppARGB
var formattedBmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(formattedBmp))
{
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
}
// 获取位图数据
var bmpData = formattedBmp.LockBits(
new Rectangle(0, 0, formattedBmp.Width, formattedBmp.Height),
ImageLockMode.ReadOnly,
formattedBmp.PixelFormat);
try
{
// 构造BMP信息头
var infoHeader = new byte[40];
using (var ms = new MemoryStream(infoHeader))
using (var writer = new BinaryWriter(ms))
{
writer.Write(40); // Header size
writer.Write(bmp.Width); // Width
writer.Write(bmp.Height * 2); // Height*2 (包含掩码)
writer.Write((ushort)1); // Planes
writer.Write((ushort)32); // BitCount
writer.Write(0); // Compression
writer.Write(0); // ImageSize
writer.Write(0); // XPelsPerMeter
writer.Write(0); // YPelsPerMeter
writer.Write(0); // ColorsUsed
writer.Write(0); // ColorsImportant
}
// 计算像素数据的大小
int stride = bmpData.Stride;
int height = bmpData.Height;
int pixelDataSize = stride * height;
// 创建缓冲区,包含信息头和像素数据
var buffer = new byte[infoHeader.Length + pixelDataSize];
// 复制信息头到缓冲区
Buffer.BlockCopy(infoHeader, 0, buffer, 0, infoHeader.Length);
// 逐行逆序复制像素数据(解决镜像问题)
IntPtr ptr = bmpData.Scan0;
int offset = infoHeader.Length;
byte[] pixelData = new byte[pixelDataSize];
// 将像素数据复制到临时数组
Marshal.Copy(ptr, pixelData, 0, pixelDataSize);
// 逐行逆序复制到缓冲区
for (int y = height - 1; y >= 0; y--)
{
int sourceIndex = y * stride;
Buffer.BlockCopy(pixelData, sourceIndex, buffer, offset, stride);
offset += stride;
}
return buffer;
}
finally
{
formattedBmp.UnlockBits(bmpData);
}
}
}
ICO效果图以及在PE图标组效果图:
2-3.完美版bmp格式ICO代码(含有二三代码特点,并在deepseek的优化下,掩码完美配对)
完美版bmp格式ICO生成方式
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
List<string> Paths = new List<string> {
@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16X16.png",
@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32X32.png",
@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48X48.png"
};
IcoConverter.SaveAsLegacyIco(Paths,@"D:\SoftwareCache\Microsoft VS Code\图标\合成\test.ico");
}
//bmp格式写入
public static class IcoConverter
{
// ICO文件头结构 2
[StructLayout(LayoutKind.Sequential)]
private struct IconDir
{
public ushort Reserved;
public ushort Type;
public ushort Count;
}
// ICO目录项结构 2
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct IconDirEntry
{
public byte Width;
public byte Height;
public byte ColorCount;
public byte Reserved;
public ushort Planes;
public ushort BitCount;
public uint BytesInRes;
public uint ImageOffset;
}
/// <summary>
/// 将多个BMP合并为多帧ICO文件
/// </summary>
public static void SaveAsLegacyIco(IEnumerable<string> bitmapPaths, string outputPath)
{
var entries = new List<IconDirEntry>();
var imageDataList = new List<byte[]>();
// 生成所有图标的BMP数据
foreach (string bmpPath in bitmapPaths)
{
using (Bitmap bmp = new Bitmap(bmpPath)) //保证使用后即释放资源
{
var data = GetBitmapData(bmp);
var entry = new IconDirEntry
{
Width = (byte)(bmp.Width >= 256 ? 0 : bmp.Width),
Height = (byte)(bmp.Height >= 256 ? 0 : bmp.Height),
ColorCount = 0,
Planes = 1,
BitCount = 32,
BytesInRes = (uint)data.Length,
ImageOffset = currentOffset
};
entries.Add(entry);
imageDataList.Add(data);
currentOffset += (uint)data.Length;
}
}
// 写入文件
using (var fs = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
// 写入ICO头部 2
writer.Write((ushort)0); // Reserved
writer.Write((ushort)1); // Type=ICO
writer.Write((ushort)entries.Count); // Image count
// 写入目录项
foreach (var entry in entries)
{
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(entry.ImageOffset);
}
// 写入图像数据 11
foreach (var data in imageDataList)
{
writer.Write(data);
}
}
}
/// <summary>
/// 将Bitmap转为ICO兼容的BMP格式数据
/// </summary>
private static byte[] GetBitmapData(Bitmap bmp)
{
var formattedBmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(formattedBmp))
{
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
}
var bmpData = formattedBmp.LockBits(
new Rectangle(0, 0, formattedBmp.Width, formattedBmp.Height),
ImageLockMode.ReadOnly,
formattedBmp.PixelFormat);
try
{
int width = bmp.Width;
int height = bmp.Height;
int stride = bmpData.Stride;
// BMP信息头
var infoHeader = new byte[40];
using (var ms = new MemoryStream(infoHeader))
using (var writer = new BinaryWriter(ms))
{
writer.Write(40); // 信息头大小
writer.Write(width); // 宽度
writer.Write(height * 2); // 高度(颜色+掩码)
writer.Write((ushort)1); // 位面数
writer.Write((ushort)32); // 位深
writer.Write(0); // 压缩方式(无压缩)
writer.Write(stride * height + ((width + 31) / 32 * 4) * height); // 图像数据大小
writer.Write(0); // 水平分辨率
writer.Write(0); // 垂直分辨率
writer.Write(0); // 调色板颜色数
writer.Write(0); // 重要颜色数
}
// 计算掩码参数
int maskStride = (width + 31) / 32 * 4;
int maskDataSize = maskStride * height;
int colorDataSize = stride * height;
var buffer = new byte[infoHeader.Length + colorDataSize + maskDataSize];
// 复制信息头
Buffer.BlockCopy(infoHeader, 0, buffer, 0, infoHeader.Length);
// 复制颜色数据(逆序行)
byte[] colorData = new byte[colorDataSize];
Marshal.Copy(bmpData.Scan0, colorData, 0, colorDataSize);
int colorOffset = infoHeader.Length;
for (int y = 0; y < height; y++)
{
int srcIndex = y * stride;
int destIndex = colorOffset + (height - 1 - y) * stride;
Buffer.BlockCopy(colorData, srcIndex, buffer, destIndex, stride);
}
// 生成并复制掩码数据
byte[] maskData = GenerateMaskData(colorData, width, height, stride, maskStride);
Buffer.BlockCopy(maskData, 0, buffer, infoHeader.Length + colorDataSize, maskDataSize);
return buffer;
}
finally
{
formattedBmp.UnlockBits(bmpData);
formattedBmp.Dispose();
}
}
/// <summary>
/// 生成AND掩码位图(1位/像素)
/// </summary>
private static byte[] GenerateMaskData(byte[] colorData, int width, int height, int colorStride, int maskStride)
{
byte[] maskData = new byte[maskStride * height];
for (int y = 0; y < height; y++)
{
int srcY = y; // 原图的行
byte[] maskRow = new byte[maskStride];
int bitPos = 7;
int byteIndex = 0;
for (int x = 0; x < width; x++)
{
int pixelIndex = srcY * colorStride + x * 4;
byte alpha = colorData[pixelIndex + 3]; // Alpha通道
if (alpha == 0)
maskRow[byteIndex] |= (byte)(1 << bitPos);
if (--bitPos < 0)
{
bitPos = 7;
byteIndex++;
}
}
// 掩码行逆序存储
int destY = height - 1 - y;
Buffer.BlockCopy(maskRow, 0, maskData, destY * maskStride, maskStride);
}
return maskData;
}
}
ICO效果图以及在PE图标组效果图_以及在VS的显示效果:
4.代码四(最直接粗暴的方式,因此有瑕疵)
用于参照的单尺寸ICO生成方式
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Drawing;
using System.IO;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
BmpToIconConverter.ConvertBmpToIco(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16X16.png",@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16x16.ico",16,16);
BmpToIconConverter.ConvertBmpToIco(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32X32.png",@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32X32.ico",32,32);
BmpToIconConverter.ConvertBmpToIco(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48X48.png",@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48x48.ico",48,48);
}
public class BmpToIconConverter
{
public static void ConvertBmpToIco(string inputPath, string outputPath, int width, int height)
{
// 设置目标尺寸(如32x32)
Size size = new Size(width, height);
// 加载原始BMP文件
using (Bitmap sourceBmp = new Bitmap(inputPath))
{
// 调整图像尺寸
using (Bitmap resizedBmp = new Bitmap(sourceBmp, size))
{
// 从调整后的位图生成Icon对象
using (Icon icon = Icon.FromHandle(resizedBmp.GetHicon()))
{
// 保存为ICO文件
using (FileStream stream = new FileStream(outputPath, FileMode.Create))
{
icon.Save(stream);
}
}
}
}
}
}
ICO效果图以及在PE图标组效果图(有透明效果瑕疵,但是在桌面/资源管理器却显示正常):
bmp格式生成多尺寸ICO(方式三)___按上面修改出的多尺寸图标生成
//.cs 文件类型,便于外部编辑时使用
// 引用必要的命名空间
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
// Quicker将会调用的函数。可以根据需要修改返回值类型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 读取动作里的变量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "从脚本输出的内容。"); // 向变量里输出值
//MessageBox.Show("Hello World!");
var bitmaps = new List<Bitmap>
{
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\16x16.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\32x32.png"),
new Bitmap(@"D:\SoftwareCache\Microsoft VS Code\图标\合成\48x48.png")
};
// 合成ICO文件
SaveMultiIcon(bitmaps, @"D:\SoftwareCache\Microsoft VS Code\图标\合成\icoOK.ico");
}
public class IcoEntry
{
public byte Width; // 图标宽度(0 表示 256)
public byte Height; // 图标高度(0 表示 256)
public byte ColorCount; // 颜色数(0 表示未使用)
public byte Reserved; // 保留字段(必须为 0)
public ushort Planes; // 颜色平面数(通常为 1)
public ushort BitCount; // 每像素位数(1, 4, 8, 24, 32)
public uint BytesInRes; // 图像数据大小
public uint ImageOffset; // 图像数据偏移量
}
public static void SaveMultiIcon(List<Bitmap> bitmaps, string outputPath)
{
List<IcoEntry> entries = new List<IcoEntry>();
List<byte[]> imageDatas = new List<byte[]>();
uint currentOffset = 6 + (uint)(bitmaps.Count * 16); // ICO 头部 + 目录项大小
foreach (Bitmap bmp in bitmaps)
{
IntPtr hIcon = IntPtr.Zero;
try
{
hIcon = bmp.GetHicon();
using (Icon icon = Icon.FromHandle(hIcon))
using (MemoryStream ms = new MemoryStream())
{
icon.Save(ms); // 将 Icon 保存到内存流
ms.Position = 0;
using (BinaryReader reader = new BinaryReader(ms))
{
// 读取 ICO 头部
reader.ReadUInt16(); // Reserved (必须为 0)
reader.ReadUInt16(); // Type (1 表示 ICO)
ushort count = reader.ReadUInt16(); // 图像数量(应始终为 1)
// 读取目录项
IcoEntry entry = new IcoEntry
{
Width = reader.ReadByte(),
Height = reader.ReadByte(),
ColorCount = reader.ReadByte(),
Reserved = reader.ReadByte(),
Planes = reader.ReadUInt16(),
BitCount = reader.ReadUInt16(),
BytesInRes = reader.ReadUInt32(),
ImageOffset = reader.ReadUInt32()
};
// 读取图像数据
ms.Position = entry.ImageOffset;
byte[] data = reader.ReadBytes((int)entry.BytesInRes);
// 更新当前 entry 的 ImageOffset
entry.ImageOffset = currentOffset;
currentOffset += entry.BytesInRes;
entries.Add(entry);
imageDatas.Add(data);
}
}
}
finally
{
if (hIcon != IntPtr.Zero)
DestroyIcon(hIcon); // 清理图标句柄
}
}
// 写入合并后的 ICO 文件
using (var fs = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
// 写入 ICO 头部
writer.Write((ushort)0); // Reserved
writer.Write((ushort)1); // Type (1 表示 ICO)
writer.Write((ushort)entries.Count); // 图像数量
// 写入目录项
foreach (var entry in entries)
{
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(entry.ImageOffset);
}
// 写入图像数据
foreach (var data in imageDatas)
{
writer.Write(data);
}
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool DestroyIcon(IntPtr hIcon);
ICO效果图以及在PE图标组效果图(同样继承瑕疵):