/* ip.cpp -- Image processing program Usage: ip input.bmp output.bmp commands... Input and output files are 24 bit uncompressed color bitmap images. Each command is a lowercase letter possibly followed by real number arguments: a C B - Replace each pixel x (in range 0 to 1) with Cx + B. c Cr Br Cg Bg Cb Bb - replace color pixels r,g,b as above. h L R - replace x with Lx + Ry where y is the pixel to the right of x. v T B - replace x with Tx + By where y is below x. r - rotate image 180 degrees. q N - quantize to N bits (0-7) g - gray scale: replace r,g,b triples each with (2r + 4g + b) / 7. Each operation is timed in seconds and clock cycles excluding I/O time. For example: ip lena.bmp out.bmp g h .5 .5 r q 6 reads lena.bmp, converts to greyscale, blurs horizontally, rotates and quantizes to 6 bits, and writes output to new file out.bmp. To compile with MINGW g++: nasm -f win32 ipa.asm g++ ip2.cpp ip2.obj -s -o ip2.exe DJGPP g++: nasm -f coff ipa.asm gxx ip2.cpp ipa.o -s -o ip2.exe Borland: nasm -f obj ip2.asm bcc32 ip2.cpp copy.obj Digital Mars: nasm -f obj ip2.asm sc ip2.cpp copy.obj */ #include #include #include // return low 32 bits of CPU counter extern "C" unsigned int rdtsc(); // Convert string to int scaled by 256 e.g. atop("0.5") returns 128 // Range is bounded to +-32K (input -127.997 to 127.997) int atop(const char* s) { int n=int(256*atof(s)); if (n<-32767) return -32767; if (n>32767) return 32767; return n; } // Horizotal filter, replace consectutive xy with Lx + Ry, y extern "C" void horiz(unsigned char* image, int imagesize, int L, int R); // Vertical filter, replace x above y with Tx + By extern "C" void vert(unsigned char* image, int imagesize, int width, int T, int B); // Adjust contrast (C) and brighness (B) of one color plane extern "C" void adjust(unsigned char* image, int padsize, int C, int B); // Rotate one color plane 180 deg. extern "C" void rotate(unsigned char* image, int padsize); // Quantize to n bits (n = 0 to 8) extern "C" void quantize(unsigned char* image, int imagesize, int n); // Convert to gray scale image extern "C" void grayscale(unsigned char *red, unsigned char* green, unsigned char* blue, int padsize); int main(int argc, char **argv) { // Check arguments if (argc < 3) { fprintf(stderr, "To process image in.bmp to out.bmp: ip in.bmp out.bmp commands...\n" "Commands are lowercase letters followed by real numbers:\n" " a C B - Replace each pixel x (in range 0 to 1) with Cx + B.\n" " c Cr Br Cg Bg Cb Bb - replace color pixels r,g,b as above.\n" " h L R - replace x with Lx + Ry where y is the pixel to the right of x.\n" " v T B - replace x with Tx + By where y is below x.\n" " r - rotate image 180 degrees.\n" " q N - quantize to N bits (0-7)\n" " g - gray scale: replace r,g,b triples each with (2r + 4g + b) / 7.\n"); exit(1); } // Open input FILE *f=fopen(argv[1],"rb"); if (!f) perror(argv[1]), exit(1); // Read 54 byte bmp header and check for errors. Must be 24 bit color, no // palatte, no compression, under 48 MB. char header[54]; int n=fread(header, 1, 54, f); if (n!=54) fprintf(stderr, "Input is too small (%d bytes)\n", n), exit(1); if (header[0]!='B' || header[1]!='M') fprintf(stderr, "Not BMP\n"), exit(1); const int imagesize=*(int*)(header+2)-54; printf("file size = %d\n", imagesize); if (imagesize<=0 || imagesize > 0x3000000) fprintf(stderr, "Image too big: %d bytes\n", imagesize), exit(1); if (*(int*)(header+10)!=54 || *(short*)(header+28)!=24) fprintf(stderr, "Not 24-bit color\n"), exit(1); if (*(int*)(header+30)!=0) fprintf(stderr, "Compression not supported\n"), exit(1); const int width=*(int*)(header+18); // original image size const int height=*(int*)(header+22); const int padwidth=(width+15)&-8; // padded size for processing const int padheight=(height+2)&-1; // round up to even number const int padsize=padwidth*padheight; // Read image, split into padded red, green, and blue planes, // each padwidth x padheight in size with at least one row of 0 pixels // at the bottom (beginning) and one column of 0 pixels on the right // edge (end) of each plane. Each color starts on a 8 byte boundary. printf("Reading %s, %d by %d padded to %d by %d\n", argv[1], width, height, padwidth, padheight); unsigned char *image = (unsigned char*)calloc(padsize*3+256, 1); if (!image) fprintf(stderr, "Out of memory\n"), exit(1); unsigned char *red = image+64-(((int)image) & 63)+padwidth; unsigned char *green = red+padsize; unsigned char *blue = green+padsize; printf("image=%p imagesize=%d red=%p green=%p blue=%p\n", image, imagesize, red, green, blue); for (int i=0; i0) { unsigned int cmd_clocks=rdtsc(); char command=argv[0][0]; ++argv; --argc; switch(command) { case 'a': if (argc>=2) { const int C=atop(argv[0]); const int B=atop(argv[1]); adjust(red, padsize*3, C, B); argc-=2; argv+=2; } break; case 'c': if (argc>=6) { adjust(red, padsize, atop(argv[0]), atop(argv[1])); adjust(green, padsize, atop(argv[2]), atop(argv[3])); adjust(blue, padsize, atop(argv[4]), atop(argv[5])); argc-=6; argv+=6; } break; case 'h': if (argc>=2) { horiz(red, padsize*3, atop(argv[0]), atop(argv[1])); argc-=2; argv+=2; } break; case 'v': if (argc>=2) { vert(red, padsize*3, padwidth, atop(argv[0]), atop(argv[1])); argc-=2; argv+=2; } break; case 'r': rotate(red, padsize); rotate(green, padsize); rotate(blue, padsize); break; case 'q': if (argc>=1) { int n=atoi(argv[0]); quantize(red, padsize*3, n); --argc; ++argv; } break; case 'g': grayscale(red, green, blue, padsize); break; default: printf("Unknown command %s\n", argv[-1]); } cmd_clocks=rdtsc()-cmd_clocks; total_rdtsc+=cmd_clocks; printf("%c in %d clocks (%d/pixel)\n", command, cmd_clocks, cmd_clocks/(imagesize/3)); } // Write output f=fopen(outfilename,"wb"); if (!f) perror(outfilename), exit(1); n=fwrite(header, 1, 54, f); for (int i=0; i