.NET System.Drawing 支援 8bpp 索引色彩模式,配合自訂調色盤可大幅減少檔案大小,適合顏色數有限的圖表、股票走勢圖等。
GetColorPalette)。public static ColorPalette GetColorPalette(uint colorCount) {
PixelFormat fmt = PixelFormat.Format1bppIndexed;
if (colorCount > 2) fmt = PixelFormat.Format4bppIndexed;
if (colorCount > 16) fmt = PixelFormat.Format8bppIndexed;
using (Bitmap bmp = new Bitmap(1, 1, fmt))
return bmp.Palette;
}
public static void SaveGIFWithNewColorTable(Image src, ColorPalette pal, string filename) {
int w = src.Width, h = src.Height;
Bitmap dst = new Bitmap(w, h, PixelFormat.Format8bppIndexed);
dst.Palette = pal;
// 將來源繪製到 32bpp 暫存位圖以便取像素
Bitmap tmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(tmp)) {
g.DrawImage(src, 0, 0, w, h);
}
// 鎖定位元資料
Rectangle rect = new Rectangle(0, 0, w, h);
BitmapData dstData = dst.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
BitmapData tmpData = tmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe {
byte* dstPtr = (byte*)dstData.Scan0;
byte* srcPtr = (byte*)tmpData.Scan0;
int dstStride = dstData.Stride;
int srcStride = tmpData.Stride;
for (int y = 0; y < h; y++) {
byte* dstRow = dstPtr + y * dstStride;
byte* srcRow = srcPtr + y * srcStride;
for (int x = 0; x < w; x++) {
// 取得 32bpp 像素顏色 (BGRA)
Color pixel = Color.FromArgb(srcRow[3], srcRow[2], srcRow[1], srcRow[0]);
srcRow += 4;
// 找顏色在調色盤索引
dstRow[x] = (byte)colorList.IndexOf(pixel);
}
}
}
dst.UnlockBits(dstData);
tmp.UnlockBits(tmpData);
dst.Save(filename, ImageFormat.Gif);
dst.Dispose(); tmp.Dispose();
}
逐像素 IndexOf 搜尋較慢,可改用 switch 或依顏色特徵值(如 G 通道)直接判斷索引,大幅提升速度。
原文提供完整專案原始碼,含灰階版本 SaveGIFWithNewGrayscale 供參考。