代码取自deepseek,且已经过本地执行测试
//.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[]>();
uint currentOffset = 6 + (uint)(16 * bitmapPaths.Count()); // 头部长度 [[2]]
// 生成所有图标的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在VS的效果显示
来源链接:https://www.cnblogs.com/MingKongLing/p/18717069
© 版权声明
本站所有资源来自于网络,仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您(转载者)自己承担!
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
THE END
暂无评论内容