C#生成多尺寸bmp格式ICO圖標(biāo)代碼
代碼取自deepseek,且已經(jīng)過(guò)本地執(zhí)行測(cè)試
//.cs 文件類型,便于外部編輯時(shí)使用
// 引用必要的命名空間
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
// Quicker將會(huì)調(diào)用的函數(shù)。可以根據(jù)需要修改返回值類型。
public static void Exec(Quicker.Public.IStepContext context)
{
//var oldValue = context.GetVarValue("varName"); // 讀取動(dòng)作里的變量值
//MessageBox.Show(oldValue as string);
//context.SetVarValue("varName", "從腳本輸出的內(nèi)容。"); // 向變量里輸出值
//MessageBox.Show("Hello World!");
List<string> Paths = new List<string> {
@"D:\SoftwareCache\Microsoft VS Code\圖標(biāo)\合成\16X16.png",
@"D:\SoftwareCache\Microsoft VS Code\圖標(biāo)\合成\32X32.png",
@"D:\SoftwareCache\Microsoft VS Code\圖標(biāo)\合成\48X48.png"
};
IcoConverter.SaveAsLegacyIco(Paths,@"D:\SoftwareCache\Microsoft VS Code\圖標(biāo)\合成\test.ico");
}
//bmp格式寫(xiě)入
public static class IcoConverter
{
// ICO文件頭結(jié)構(gòu) [[2]]
[StructLayout(LayoutKind.Sequential)]
private struct IconDir
{
public ushort Reserved;
public ushort Type;
public ushort Count;
}
// ICO目錄項(xiàng)結(jié)構(gòu) [[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>
/// 將多個(gè)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()); // 頭部長(zhǎng)度 [[2]]
// 生成所有圖標(biāo)的BMP數(shù)據(jù)
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;
}
}
// 寫(xiě)入文件
using (var fs = new FileStream(outputPath, FileMode.Create))
using (var writer = new BinaryWriter(fs))
{
// 寫(xiě)入ICO頭部 [[2]]
writer.Write((ushort)0); // Reserved
writer.Write((ushort)1); // Type=ICO
writer.Write((ushort)entries.Count); // Image count
// 寫(xiě)入目錄項(xiàng)
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);
}
// 寫(xiě)入圖像數(shù)據(jù) [[11]]
foreach (var data in imageDataList)
{
writer.Write(data);
}
}
}
/// <summary>
/// 將Bitmap轉(zhuǎn)為ICO兼容的BMP格式數(shù)據(jù)
/// </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); // 位面數(shù)
writer.Write((ushort)32); // 位深
writer.Write(0); // 壓縮方式(無(wú)壓縮)
writer.Write(stride * height + ((width + 31) / 32 * 4) * height); // 圖像數(shù)據(jù)大小
writer.Write(0); // 水平分辨率
writer.Write(0); // 垂直分辨率
writer.Write(0); // 調(diào)色板顏色數(shù)
writer.Write(0); // 重要顏色數(shù)
}
// 計(jì)算掩碼參數(shù)
int maskStride = (width + 31) / 32 * 4;
int maskDataSize = maskStride * height;
int colorDataSize = stride * height;
var buffer = new byte[infoHeader.Length + colorDataSize + maskDataSize];
// 復(fù)制信息頭
Buffer.BlockCopy(infoHeader, 0, buffer, 0, infoHeader.Length);
// 復(fù)制顏色數(shù)據(jù)(逆序行)
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);
}
// 生成并復(fù)制掩碼數(shù)據(jù)
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++;
}
}
// 掩碼行逆序存儲(chǔ)
int destY = height - 1 - y;
Buffer.BlockCopy(maskRow, 0, maskData, destY * maskStride, maskStride);
}
return maskData;
}
}
生成的ICO在VS的效果顯示


浙公網(wǎng)安備 33010602011771號(hào)