tags:

views:

386

answers:

1

What is the easiest way to convert and save a 32-bit Bitmap to a 1-bit (black/white) .bmp file in C#?

+1  A: 

This code will get the job done:

using System.Drawing.Imaging;
using System.Runtime.InteropServices;
...

public static Bitmap BitmapTo1Bpp(Bitmap img) {
  int w = img.Width;
  int h = img.Height;
  Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
  BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
  byte[] scan = new byte[(w + 7) / 8];
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (x % 8 == 0) scan[x / 8] = 0;
      Color c = img.GetPixel(x, y);
      if (c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8));
    }
    Marshal.Copy(scan, 0, (IntPtr)((long)data.Scan0 + data.Stride * y), scan.Length);
  }
  bmp.UnlockBits(data);
  return bmp;
}

You can speed it up, if necessary, by using unsafe code to replace the GetPixel() method.

Hans Passant
If you're already locking the bits you might as well Marshal.Copy all the data to a byte[] and do it all at once. That'll save you the getpixel and the repeated marshal.copy overhead.
Ron Warholic
It's not that simple, the ImageFormat of the source image matters.
Hans Passant
Ron, that wouldn't work if you have a non-minimal stride in the source image unless you have the same in the destination image.(Stride >= width * bytesPerPixel)
Danny Varod