/* This code is ripped from Autotrace-0.29. Small modifications by pts. */ /* input-bmp.ci: reads any bitmap I could get for testing */ #ifdef __GNUC__ #ifndef __clang__ #pragma implementation #endif #endif #include #include #include /* #include "types.h" */ #include "at_bitmap.h" /* #include "message.h" */ /* #include "xstd.h" */ /* #include "input-bmp.h" */ #define MAXCOLORS 256 /* #define Image long */ #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0) struct Bitmap_File_Head_Struct { char zzMagic[2]; /* 00 "BM" */ unsigned long bfSize; /* 02 */ unsigned short zzHotX; /* 06 */ unsigned short zzHotY; /* 08 */ unsigned long bfOffs; /* 0A */ unsigned long biSize; /* 0E */ } Bitmap_File_Head; struct Bitmap_Head_Struct { unsigned long biWidth; /* 12 */ unsigned long biHeight; /* 16 */ unsigned short biPlanes; /* 1A */ unsigned short biBitCnt; /* 1C */ unsigned long biCompr; /* 1E */ unsigned long biSizeIm; /* 22 */ unsigned long biXPels; /* 26 */ unsigned long biYPels; /* 2A */ unsigned long biClrUsed; /* 2E */ unsigned long biClrImp; /* 32 */ /* 36 */ } Bitmap_Head; static long ToL (unsigned char *); static short ToS (unsigned char *); static int ReadColorMap (FILE *, unsigned char[256][3], int, int, int *); static unsigned char *ReadImage (FILE *, int, int, unsigned char[256][3], int, int, int, int); #if PTS_SAM2P bitmap_type bmp_load_image (FILE* filename) #else bitmap_type bmp_load_image (at_string filename) #endif { FILE *fd; unsigned char buffer[64]; int ColormapSize, rowbytes, Maps=0, Grey; unsigned char ColorMap[256][3]; bitmap_type image; #if PTS_SAM2P /**** pts ****/ fd=filename; #else fd = fopen (filename, "rb"); if (!fd) FATAL1 ("Can't open \"%s\"\n", filename); #endif /* It is a File. Now is it a Bitmap? Read the shortest possible header.*/ if (!ReadOK(fd, buffer, 18) || (strncmp((const char *)buffer,"BM",2))) #if PTS_SAM2P /**** pts ****/ FATALP ("BMP: Not a valid BMP file"); #else FATAL ("Not a valid BMP file %s\n"); #endif /* bring them to the right byteorder. Not too nice, but it should work */ Bitmap_File_Head.bfSize = ToL (&buffer[0x02]); Bitmap_File_Head.zzHotX = ToS (&buffer[0x06]); Bitmap_File_Head.zzHotY = ToS (&buffer[0x08]); Bitmap_File_Head.bfOffs = ToL (&buffer[0x0a]); Bitmap_File_Head.biSize = ToL (&buffer[0x0e]); /* What kind of bitmap is it? */ if (Bitmap_File_Head.biSize == 12) /* OS/2 1.x ? */ { if (!ReadOK (fd, buffer, 8)) FATALP ("BMP: Error reading BMP file header #1"); Bitmap_Head.biWidth = ToS (&buffer[0x00]); /* 12 */ Bitmap_Head.biHeight = ToS (&buffer[0x02]); /* 14 */ Bitmap_Head.biPlanes = ToS (&buffer[0x04]); /* 16 */ Bitmap_Head.biBitCnt = ToS (&buffer[0x06]); /* 18 */ Bitmap_Head.biCompr = 0; Bitmap_Head.biSizeIm = 0; Bitmap_Head.biXPels = Bitmap_Head.biYPels = 0; Bitmap_Head.biClrUsed = 0; Maps = 3; } else if (Bitmap_File_Head.biSize == 40) /* Windows 3.x */ { if (!ReadOK (fd, buffer, Bitmap_File_Head.biSize - 4)) FATALP ("BMP: Error reading BMP file header #2"); Bitmap_Head.biWidth =ToL (&buffer[0x00]); /* 12 */ Bitmap_Head.biHeight =ToL (&buffer[0x04]); /* 16 */ Bitmap_Head.biPlanes =ToS (&buffer[0x08]); /* 1A */ Bitmap_Head.biBitCnt =ToS (&buffer[0x0A]); /* 1C */ Bitmap_Head.biCompr =ToL (&buffer[0x0C]); /* 1E */ Bitmap_Head.biSizeIm =ToL (&buffer[0x10]); /* 22 */ Bitmap_Head.biXPels =ToL (&buffer[0x14]); /* 26 */ Bitmap_Head.biYPels =ToL (&buffer[0x18]); /* 2A */ Bitmap_Head.biClrUsed =ToL (&buffer[0x1C]); /* 2E */ Bitmap_Head.biClrImp =ToL (&buffer[0x20]); /* 32 */ /* 36 */ Maps = 4; } else if (Bitmap_File_Head.biSize <= 64) /* Probably OS/2 2.x */ { if (!ReadOK (fd, buffer, Bitmap_File_Head.biSize - 4)) FATALP ("BMP: Error reading BMP file header #3"); Bitmap_Head.biWidth =ToL (&buffer[0x00]); /* 12 */ Bitmap_Head.biHeight =ToL (&buffer[0x04]); /* 16 */ Bitmap_Head.biPlanes =ToS (&buffer[0x08]); /* 1A */ Bitmap_Head.biBitCnt =ToS (&buffer[0x0A]); /* 1C */ Bitmap_Head.biCompr =ToL (&buffer[0x0C]); /* 1E */ Bitmap_Head.biSizeIm =ToL (&buffer[0x10]); /* 22 */ Bitmap_Head.biXPels =ToL (&buffer[0x14]); /* 26 */ Bitmap_Head.biYPels =ToL (&buffer[0x18]); /* 2A */ Bitmap_Head.biClrUsed =ToL (&buffer[0x1C]); /* 2E */ Bitmap_Head.biClrImp =ToL (&buffer[0x20]); /* 32 */ /* 36 */ Maps = 3; } else FATALP ("BMP: Error reading BMP file header #4"); /* Valid options 1, 4, 8, 16, 24, 32 */ /* 16 is awful, we should probably shoot whoever invented it */ /* There should be some colors used! */ ColormapSize = (Bitmap_File_Head.bfOffs - Bitmap_File_Head.biSize - 14) / Maps; if ((Bitmap_Head.biClrUsed == 0) && (Bitmap_Head.biBitCnt <= 8)) Bitmap_Head.biClrUsed = ColormapSize; /* Sanity checks */ if (Bitmap_Head.biHeight == 0 || Bitmap_Head.biWidth == 0) FATALP ("BMP: Error reading BMP file header #5"); if (Bitmap_Head.biPlanes != 1) FATALP ("BMP: Error reading BMP file header #6"); if (ColormapSize > 256 || Bitmap_Head.biClrUsed > 256) FATALP ("BMP: Error reading BMP file header #7"); /* Windows and OS/2 declare filler so that rows are a multiple of * word length (32 bits == 4 bytes) */ rowbytes= ( (Bitmap_Head.biWidth * Bitmap_Head.biBitCnt - 1) / 32) * 4 + 4; #ifdef DEBUG printf("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, Comp: %u, Zeile: %u\n", Bitmap_File_Head.bfSize,Bitmap_Head.biClrUsed,Bitmap_Head.biBitCnt,Bitmap_Head.biWidth, Bitmap_Head.biHeight, Bitmap_Head.biCompr, rowbytes); #endif /* Get the Colormap */ if (ReadColorMap (fd, ColorMap, ColormapSize, Maps, &Grey) == -1) FATALP ("BMP: Cannot read the colormap"); #ifdef DEBUG printf("Colormap read\n"); #endif /* Get the Image and return the ID or -1 on error*/ image.bitmap = ReadImage (fd, Bitmap_Head.biWidth, Bitmap_Head.biHeight, ColorMap, Bitmap_Head.biBitCnt, Bitmap_Head.biCompr, rowbytes, Grey); BITMAP_WIDTH (image) = (at_dimen_t) Bitmap_Head.biWidth; BITMAP_HEIGHT (image) = (at_dimen_t) Bitmap_Head.biHeight; BITMAP_PLANES (image) = Grey ? 1 : 3; return (image); } static int ReadColorMap (FILE *fd, unsigned char buffer[256][3], int number, int size, int *grey) { int i; unsigned char rgb[4]; *grey=(number>2); for (i = 0; i < number ; i++) { if (!ReadOK (fd, rgb, size)) FATALP ("BMP: Bad colormap"); /* Bitmap save the colors in another order! But change only once! */ buffer[i][0] = rgb[2]; buffer[i][1] = rgb[1]; buffer[i][2] = rgb[0]; *grey = ((*grey) && (rgb[0]==rgb[1]) && (rgb[1]==rgb[2])); } return 0; } static unsigned char* ReadImage (FILE *fd, int width, int height, unsigned char cmap[256][3], int bpp, int compression, int rowbytes, int grey) { unsigned char v,howmuch; int xpos = 0, ypos = 0; unsigned char *image; unsigned char *temp, *buffer; long rowstride, channels; unsigned short rgb; int i, j; if (bpp >= 16) /* color image */ { XMALLOCT (image, unsigned char*, width * height * 3 * sizeof (unsigned char)); channels = 3; } else if (grey) /* grey image */ { XMALLOCT (image, unsigned char*, width * height * 1 * sizeof (unsigned char)); channels = 1; } else /* indexed image */ { XMALLOCT (image, unsigned char*, width * height * 1 * sizeof (unsigned char)); channels = 1; } XMALLOCT (buffer, unsigned char*, rowbytes); rowstride = width * channels; ypos = height - 1; /* Bitmaps begin in the lower left corner */ switch (bpp) { case 32: { while (ReadOK (fd, buffer, rowbytes)) { temp = image + (ypos * rowstride); for (xpos= 0; xpos < width; ++xpos) { *(temp++)= buffer[xpos * 4 + 2]; *(temp++)= buffer[xpos * 4 + 1]; *(temp++)= buffer[xpos * 4]; } --ypos; /* next line */ } } break; case 24: { while (ReadOK (fd, buffer, rowbytes)) { temp = image + (ypos * rowstride); for (xpos= 0; xpos < width; ++xpos) { *(temp++)= buffer[xpos * 3 + 2]; *(temp++)= buffer[xpos * 3 + 1]; *(temp++)= buffer[xpos * 3]; } --ypos; /* next line */ } } break; case 16: { while (ReadOK (fd, buffer, rowbytes)) { temp = image + (ypos * rowstride); for (xpos= 0; xpos < width; ++xpos) { rgb= ToS(&buffer[xpos * 2]); *(temp++)= (unsigned char)(((rgb >> 10) & 0x1f) * 8); *(temp++)= (unsigned char)(((rgb >> 5) & 0x1f) * 8); *(temp++)= (unsigned char)(((rgb) & 0x1f) * 8); } --ypos; /* next line */ } } break; case 8: case 4: case 1: { if (compression == 0) { while (ReadOK (fd, &v, 1)) { for (i = 1; (i <= (8 / bpp)) && (xpos < width); i++, xpos++) { temp = (unsigned char*) (image + (ypos * rowstride) + (xpos * channels)); *temp= (unsigned char)(( v & ( ((1<> (8-(i*bpp))); } if (xpos == width) { (void) ReadOK (fd, buffer, rowbytes - 1 - (width * bpp - 1) / 8); ypos--; xpos = 0; } if (ypos < 0) break; } break; } else { while (ypos >= 0 && xpos <= width) { (void) ReadOK (fd, buffer, 2); if ((unsigned char) buffer[0] != 0) /* Count + Color - record */ { for (j = 0; ((unsigned char) j < (unsigned char) buffer[0]) && (xpos < width);) { #ifdef DEBUG2 printf("%u %u | ",xpos,width); #endif for (i = 1; ((i <= (8 / bpp)) && (xpos < width) && ((unsigned char) j < (unsigned char) buffer[0])); i++, xpos++, j++) { temp = image + (ypos * rowstride) + (xpos * channels); *temp = (unsigned char) ((buffer[1] & (((1<> (8 - (i * bpp))); } } } if (((unsigned char) buffer[0] == 0) && ((unsigned char) buffer[1] > 2)) /* uncompressed record */ { howmuch = buffer[1]; for (j = 0; j < howmuch; j += (8 / bpp)) { (void) ReadOK (fd, &v, 1); i = 1; while ((i <= (8 / bpp)) && (xpos < width)) { temp = image + (ypos * rowstride) + (xpos * channels); *temp = (unsigned char) ((v & (((1<> (8-(i*bpp))); i++; xpos++; } } if ((howmuch % 2) && (bpp==4)) howmuch++; if ((howmuch / (8 / bpp)) % 2) (void) ReadOK (fd, &v, 1); /*if odd(x div (8 div bpp )) then blockread(f,z^,1);*/ } if (((unsigned char) buffer[0] == 0) && ((unsigned char) buffer[1]==0)) /* Line end */ { ypos--; xpos = 0; } if (((unsigned char) buffer[0]==0) && ((unsigned char) buffer[1]==1)) /* Bitmap end */ { break; } if (((unsigned char) buffer[0]==0) && ((unsigned char) buffer[1]==2)) /* Deltarecord */ { (void) ReadOK (fd, buffer, 2); xpos += (unsigned char) buffer[0]; ypos -= (unsigned char) buffer[1]; } } break; } } break; default: /* This is very bad, we should not be here */ ; } /* fclose (fd); */ if (bpp <= 8) { unsigned char *temp2, *temp3; unsigned char index; temp2 = temp = image; XMALLOCT (image, unsigned char*, width * height * 3 * sizeof (unsigned char)); temp3 = image; for (ypos = 0; ypos < height; ypos++) { for (xpos = 0; xpos < width; xpos++) { index = *temp2++; *temp3++ = cmap[index][0]; if (!grey) { *temp3++ = cmap[index][1]; *temp3++ = cmap[index][2]; } } } XFREE (temp); } XFREE (buffer); return image; } #if 0 /**** pts ****/ FILE *errorfile; char *prog_name = "bmp"; char *filename; int interactive_bmp; #endif static long ToL (unsigned char *puffer) { return (puffer[0] | puffer[1]<<8 | puffer[2]<<16 | puffer[3]<<24); } static short ToS (unsigned char *puffer) { return ((short)(puffer[0] | puffer[1]<<8)); }