原始灰階位元組陣列 (每像素 1 byte, 0-255) 轉為 `Format8bppIndexed` Bitmap,需處理:調色盤建立、行資料 4-byte 對齊 (DWord padding)、垂直翻轉 (BMP 由下而上儲存)。
public static Bitmap CreateGrayscaleBitmap(byte[] pixelData, int width, int height)
{
// 1. 建立 8bpp 空白位圖 (自動含預設調色盤)
var bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
// 2. 存入記憶體流取得 BMP 標頭/調色盤位移
using (var ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Bmp);
ms.Flush();
// 3. 計算行對齊位移
int stride = ((width * 8 + 31) / 32) * 4; // 4-byte 對齊後的行位元組數
int padding = stride - width;
int dataOffset = ReadInt32(ms, 10); // BMP 檔頭第 10 位元組起為資料位移
// 4. 重寫調色盤 (0-255 灰階)
int paletteStart = 54; // 標準 BMP: 14+40=54
int paletteEnd = dataOffset;
ms.Position = paletteStart;
for (int i = 0; i < 256; i++)
{
byte v = (byte)i;
ms.Write(new byte[] { v, v, v, 0 }, 0, 4); // BGR + 保留
}
// 5. 準備最終像素資料 (含 padding、垂直翻轉)
byte[] finalData = new byte[stride * height];
for (int srcY = height - 1; srcY >= 0; srcY--)
{
int dstY = height - 1 - srcY;
int srcOffset = srcY * width;
int dstOffset = dstY * stride;
Buffer.BlockCopy(pixelData, srcOffset, finalData, dstOffset, width);
// padding 區域已為 0 (new byte[] 預設)
}
// 6. 寫入像素資料
ms.Position = dataOffset;
ms.Write(finalData, 0, finalData.Length);
ms.Flush();
// 7. 從記憶體流建立最終 Bitmap
ms.Position = 0;
return new Bitmap(ms);
}
}
static int ReadInt32(MemoryStream ms, int pos)
{
ms.Position = pos;
byte[] buf = new byte[4];
ms.Read(buf, 0, 4);
return BitConverter.ToInt32(buf, 0);
}