グレースケールで保存したPNGのPixelFormatは何になる?2「Format8bppIndexed」

C# コンピュータ
C#

PixelFormatにFormat8bppIndexedというフォーマットがありました。8bppですので8bitのグレースケールを扱うフォーマットだと思われますので試してみたいと思います。

元画像(カラー)

ソースコード

namespace RGBtoGray;

using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
    static Bitmap RGB2Gray(Bitmap color)
    {
        int width = color.Width;
        int height = color.Height;
        // Format8bppIndexed
        var gray = new Bitmap(width, height, PixelFormat.Format8bppIndexed);

        var rect = new Rectangle(0, 0, width, height);
        var cData = color.LockBits(rect, ImageLockMode.ReadOnly, color.PixelFormat);
        int channel = Bitmap.GetPixelFormatSize(color.PixelFormat) / 8;
        var cStride = Math.Abs(cData.Stride);
        byte[] cPixels = new byte[cStride * height];
        Marshal.Copy(cData.Scan0, cPixels, 0, cPixels.Length);

        var gData = gray.LockBits(rect, ImageLockMode.ReadWrite, gray.PixelFormat);
        var gStride = Math.Abs(gData.Stride);
        byte[] gPixels = new byte[gStride * height];

        for (int y = 0; y<height; y++)
        {
            int ci = cStride * y;
            int gi = gStride * y;

            for (int x = 0; x < width; x++)
            {
                gPixels[gi + x] = cPixels[ci + x * channel];
            }
        }

        Marshal.Copy(gPixels, 0, gData.Scan0, gPixels.Length);

        color.UnlockBits(cData);
        gray.UnlockBits(gData);

        return gray;
    }
    public Form1()
    {
        InitializeComponent();

        var src = new Bitmap(@"C:\Users\PC01114\Pictures\202211011619.PNG");
        var dst = RGB2Gray(src);
        var picbox = new PictureBox
        {
            Image = dst,
            Dock = DockStyle.Fill,
        };
        Controls.Add(picbox);
    }
}

結果

カラー画像の1チャンネル分から8bit画像を生成したのでグレースケールで表示されることを期待したのですが、色がついています。それもなかなかユニークな色使いです。
調べたところパレットを設定していないため、このような色になっているようです。
プログラムを修正してみます。

namespace RGBtoGray;

using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public partial class Form1 : Form
{
    static Bitmap RGB2Gray(Bitmap color)
    {
        int width = color.Width;
        int height = color.Height;
        // Format8bppIndexed
        var gray = new Bitmap(width, height, PixelFormat.Format8bppIndexed);

        var rect = new Rectangle(0, 0, width, height);
        var cData = color.LockBits(rect, ImageLockMode.ReadOnly, color.PixelFormat);
        int channel = Bitmap.GetPixelFormatSize(color.PixelFormat) / 8;
        var cStride = Math.Abs(cData.Stride);
        byte[] cPixels = new byte[cStride * height];
        Marshal.Copy(cData.Scan0, cPixels, 0, cPixels.Length);

        var gData = gray.LockBits(rect, ImageLockMode.ReadWrite, gray.PixelFormat);
        var gStride = Math.Abs(gData.Stride);
        byte[] gPixels = new byte[gStride * height];

        for (int y = 0; y<height; y++)
        {
            int ci = cStride * y;
            int gi = gStride * y;

            for (int x = 0; x < width; x++)
            {
                gPixels[gi + x] = cPixels[ci + x * channel];
            }
        }

        Marshal.Copy(gPixels, 0, gData.Scan0, gPixels.Length);

        color.UnlockBits(cData);
        gray.UnlockBits(gData);

        // パレットの設定
        var pallet = gray.Palette;
        for(int i = 0; i < 255; i++)
        {
            pallet.Entries[i] = Color.FromArgb(i, i, i);
        }
        gray.Palette = pallet;

        return gray;
    }
    public Form1()
    {
        InitializeComponent();

        var src = new Bitmap(@"C:\Users\PC01114\Pictures\202211011619.PNG");
        var dst = RGB2Gray(src);
        dst.Save(@"c:\output.png", ImageFormat.Png);
        var picbox = new PictureBox
        {
            Image = dst,
            Dock = DockStyle.Fill,
        };
        Controls.Add(picbox);
    }
}

結果

パレットを設定したところグレースケールになりました。ちなみに画像をファイルに保存しプロパティを見たところ8bitで保存されていました。

コメント