/* Input: filename of a bitmap file * Output: byte array of the same bitmap with 1 bit per pixel * * Theoretically works with 8, 16, 24, or 32 bit input files; * I've only tested with 32. Returns null on 4bpp, file itself * if image is already 1bpp. * * Uncompressed DIB3 only. Returns null otherwise. * * May not deal well with an existing color palette. * * No support for endianess or negative height. */ public static byte[] To1bpp(string filename) { byte[] data = System.IO.File.ReadAllBytes(filename); int raw_loc = BitmapConverter.GetInt(data, 0xa, 0xd); int width = BitmapConverter.GetInt(data, 0x12, 0x15); int height = BitmapConverter.GetInt(data, 0x16, 0x19); int bpp = BitmapConverter.GetInt(data, 0x1c, 0x1d); int comp = BitmapConverter.GetInt(data, 0x1e, 0x21); // 1 bpp => done // 4 bpp => unimplemented if (bpp == 1) { return(data); } if (bpp == 4) { return(null); } // compression => unimplemented if (comp != 0) { return(null); } byte[,] pixels = new byte[width, height]; int raw_size = data.Length - raw_loc; int bytesPerRow = raw_size / height; /* read the existing pixel values into a * 2-dimensional array. */ int x = 0; int y = 0; int pix_size = bpp / 8; int pixcount = 0; for (int i = 0; i < raw_size; i += 0) { if (i > 0 && i % bytesPerRow == 0) { x = 0; y++; } if (x < width) { int pixel = BitmapConverter.GetInt(data, i + raw_loc, i + raw_loc + pix_size - 1); i += pix_size; pixel = pixel & 0xffffff; // no alpha if (pixel < 0xeeeeee) { pixels[x, y] = 1; } else { pixels[x, y] = 0; } pixcount++; } else { i++; // row padding } x++; } /* create a new byte array to hold 1 bit pixels * and add them all to it*/ int newRowBytes = (int)((width + 31) / 32.0) * 4; byte[] newdata = new byte[newRowBytes * height]; int bits = 0; for (int i = 0; i < newdata.Length; i++) { int x1 = (i % newRowBytes) * 8; int y1 = i / newRowBytes; int val = 0; for (int j = 0; j < 8; j++) { if (x1 + j >= width) // end of pixel row, rest gets padded { break; } val = val | ((pixels[x1 + j, y1]) << (7 - j)); bits++; } newdata[i] = (byte)val; } byte[] newbmp = new byte[14 + 40 + 8 + newdata.Length]; // BMP Header newbmp[0x0] = 0x42; newbmp[0x1] = 0x4D; BitmapConverter.PutInt(ref newbmp, newbmp.Length, 0x2, 0x5); // filesize BitmapConverter.PutInt(ref newbmp, 0, 0x6, 0x9); // irrelevant BitmapConverter.PutInt(ref newbmp, 14 + 40 + 8, 0xa, 0xd); // image data offset // DIB Header BitmapConverter.PutInt(ref newbmp, 40, 0xe, 0x11); // DIB3 BitmapConverter.PutInt(ref newbmp, width, 0x12, 0x15); BitmapConverter.PutInt(ref newbmp, height, 0x16, 0x19); BitmapConverter.PutInt(ref newbmp, 1, 0x1a, 0x1b); // planes, always 1 BitmapConverter.PutInt(ref newbmp, 1, 0x1c, 0x1d); // bpp BitmapConverter.PutInt(ref newbmp, 0, 0x1e, 0x21); // no compression BitmapConverter.PutInt(ref newbmp, newdata.Length, 0x22, 0x25); // image data size int dpi = (int)(72 * 39.97 + 0.5); BitmapConverter.PutInt(ref newbmp, dpi, 0x26, 0x29); // horizontal dpi BitmapConverter.PutInt(ref newbmp, dpi, 0x2a, 0x2d); // vertical dpi BitmapConverter.PutInt(ref newbmp, 2, 0x2e, 0x31); // number of colors BitmapConverter.PutInt(ref newbmp, 0, 0x32, 0x35); // usually ignored // Color Palette newbmp[0x36] = 0xff; // white newbmp[0x37] = 0xff; newbmp[0x38] = 0xff; newbmp[0x39] = 0x0; newbmp[0x3a] = 0x0; // black newbmp[0x3b] = 0x0; newbmp[0x3c] = 0x0; newbmp[0x3d] = 0x0; // raw image data Array.Copy(newdata, 0, newbmp, 0x3e, newdata.Length); return(newbmp); }