pos/is4c-nf/scale-drivers/drivers/NewMagellan/BitmapConverter.cs
using System;
using System.Reflection;
[assembly: AssemblyVersion("1.0.*")]
namespace BitmapBPP {
public class BitmapConverter {
/* 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) {
System.Console.WriteLine("bpp4 - abort");
return null;
}
// compression => unimplemented
if (comp != 0) {
System.Console.WriteLine("compressed - abort");
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 = y - (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;
}
public static byte[] Invert(byte[] bmp)
{
var start = 12 + 40 + 8 + 1;
for (var i=start; i<bmp.Length; i++) {
bmp[i] = (byte)(bmp[i] ^ 0xff);
}
return bmp;
}
// read an integer from a byte array
private static int GetInt(byte[] data, int start, int end){
int val = 0;
for(int i=start; i<=end; i++){
val = val | (data[i] << (8*(i-start)));
}
return val;
}
// write an integer into a byte array
private static void PutInt(ref byte[] ret, int val, int start, int end){
for(int i=start; i<end; i++){
ret[i] = (byte)(val & 0xff);
val = val >> 8;
}
}
// just static methods
public BitmapConverter(){}
// for testing
static public void Main(string[] args){
if (args.Length < 1){
System.Console.WriteLine("File name required");
}
else if (!System.IO.File.Exists(args[0])){
System.Console.WriteLine("File does not exist: "+args[0]);
}
else {
byte[] newbmp = BitmapConverter.To1bpp(args[0]);
if (args.Length > 1 && args[1] == "--invert") {
Console.WriteLine("Inverting");
newbmp = BitmapConverter.Invert(newbmp);
}
System.Console.WriteLine(newbmp);
System.IO.File.WriteAllBytes("out.bmp",newbmp);
}
}
}
}