// // Simple tool to mirror and rotate a monochrome BMP. // // This is used as part of PCL to BMP file conversion. // // tvb 20-Jul-2001, revision 7 // #include #include #include #include #define STDERR stderr int Debug = 0; // // Define forward referenced function prototypes. // void BmpRead (FILE *File); void BmpWrite (FILE *File); int BmpValid (FILE *File, struct _BMP *Header); void BmpDump (struct _BMP *Header); int BitGet (char *BitArray, int BitIndex); void BitSet (char *BitArray, int BitIndex, int Value); void BmpRotate (char *OldBitMap, long OldWidth, long OldHeight, char *BitMap, long Width, long Height); // // Get arguments, read input file, write output file. // void main (int argc, char *argv[]) { FILE *Input; FILE *Output; // // Check arguments. // Debug = 0; if (argc > 1 && strcmp(argv[1], "/debug") == 0) { Debug = 1; argc -= 1; argv += 1; } if (argc < 3) { fprintf(STDERR, "Usage: %s port.bmp land.bmp\n", argv[0]); exit(1); } // // Read and validate input file. // Input = fopen(argv[1], "rb"); if (Input == NULL) { fprintf(STDERR, "Open error: %s\n", argv[1]); exit(1); } BmpRead(Input); fclose(Input); // // Rotate and write output file. // Output = fopen(argv[2], "wb"); if (Output == NULL) { fprintf(STDERR, "Create error: %s\n", argv[2]); exit(1); } BmpWrite(Output); fclose(Output); exit(0); } // // Define BMP file header. // #pragma pack(push, 1) typedef struct _BMP { char Type[2]; long FileSize; long Reserved; long DataOffset; long HeaderSize; long Width; long Height; short Planes; short BitsPerPixel; long CompressionType; long ImageSize; long xPixelsPerMeter; long yPixelsPerMeter; long ColorsUsed; long ColorsImportant; } BMP, *PBMP; #pragma pack(pop) // // The official size of the BMP header does not // include the first four members above. // #define HEADER_SIZE ( sizeof (BMP) - \ ( (char *)&(((PBMP)0)->HeaderSize) - (char *)(PBMP)0 ) ) // // Define macro to give 32-bit padded image width. // #define WIDTH32(width) ( ((width) + 31) / 32 * 32 ) // // Define BMP color map entry. // typedef struct _RGB { char Blue; char Green; char Red; char Unused; } RGB, *PRGB; typedef char * PCHAR; // // Define global data for original BMP file in memory. // typedef struct _BMP_FILE { PBMP Header; PRGB ColorMap; long ColorMapSize; PCHAR BitMap; } BMP_FILE, *PBMP_FILE; BMP_FILE Source; // // Read BMP file into memory. // void BmpRead (FILE *File) { PCHAR BitMap; PRGB ColorMap; long ColorMapSize; int Count; PBMP Header; long HeaderSize; long ImageSize; // // Allocate and read header. // HeaderSize = sizeof (BMP); Header = malloc(HeaderSize); if (Header == NULL) { fprintf(STDERR, "Header = malloc(%d) failed\n", HeaderSize); exit(1); } Count = fread(Header, HeaderSize, 1, File); if (Count != 1) { fprintf(STDERR, "Header read error\n"); exit(1); } // // Perform header sanity checks. // if (BmpValid(File, Header) == 0) { exit(1); } // // Allocate and read color map. // ColorMapSize = (1 << Header->BitsPerPixel) * sizeof(RGB); ColorMap = malloc(ColorMapSize); if (ColorMap == NULL) { fprintf(STDERR, "ColorMap = malloc(%d) failed\n", ColorMapSize); exit(1); } Count = fread(ColorMap, ColorMapSize, 1, File); if (Count != 1) { fprintf(STDERR, "ColorMap read error\n"); exit(1); } // // Allocate and read bit map. // ImageSize = WIDTH32(Header->Width) * Header->Height / 8; BitMap = malloc(ImageSize); if (BitMap == NULL) { fprintf(STDERR, "BitMap = malloc(%d) failed\n", ImageSize); exit(1); } Count = fread(BitMap, ImageSize, 1, File); if (Count != 1) { fprintf(STDERR, "BitMap read error\n"); exit(1); } // // Save global data. // Source.Header = Header; Source.ColorMap = ColorMap; Source.ColorMapSize = ColorMapSize; Source.BitMap = BitMap; return; } // // Perform header sanity checks. // int BmpValid (FILE *File, PBMP Header) { long ColorMapSize; long FileSize; long ImageSize; long DataOffsetSize; struct _stat st; if (Header->Type[0] != 'B' || Header->Type[1] != 'M') { fprintf(STDERR, "BMP: Invalid header type\n"); return 0; } if (Debug) { printf("Header:\n"); BmpDump(Header); } if (Header->Planes != 1) { fprintf(STDERR, "BMP: Expected Planes = 1 [ignored]\n"); /* return; */ } if (Header->BitsPerPixel != 1) { fprintf(STDERR, "BMP: Expected BitsPerPixel = 1 for this tool\n"); return 0; } ColorMapSize = (1 << Header->BitsPerPixel) * sizeof(RGB); if (Header->CompressionType != 0) { fprintf(STDERR, "BMP: Expected CompressionType = 0\n"); return 0; } if (Header->HeaderSize != HEADER_SIZE) { fprintf(STDERR, "BMP: Expected HeaderSize = %ld\n", HEADER_SIZE); return 0; } ImageSize = WIDTH32(Header->Width) * Header->Height / 8; if (Header->ImageSize != ImageSize) { fprintf(STDERR, "BMP: Expected ImageSize = %ld [ignored]\n", ImageSize); /* return; */ } DataOffsetSize = sizeof (BMP) + ColorMapSize; if (Header->DataOffset != DataOffsetSize) { fprintf(STDERR, "BMP: Expected DataOffset = %ld [ignored]\n", DataOffsetSize); /* return; */ } FileSize = sizeof (BMP) + ColorMapSize + ImageSize; if (Header->FileSize != FileSize) { fprintf(STDERR, "BMP: Expected FileSize = %ld [ignored]\n", FileSize); /* return; */ } if (_fstat(_fileno(File), &st) != 0) { fprintf(STDERR, "fstat failed\n"); return 0; } if (st.st_size > FileSize) { fprintf(STDERR, "BMP: Actual file size (%ld) too large by %ld bytes [ignored]\n", st.st_size, st.st_size - FileSize); /* return; */ } if (st.st_size < FileSize) { fprintf(STDERR, "BMP: Actual file size (%ld) too small by %ld bytes\n", st.st_size, FileSize - st.st_size); return 0; } return 1; } // // Write completed BMP file. // void BmpWrite (FILE *File) { int Count; PCHAR BitMap; PBMP Header; long HeaderSize; long ImageSize; int Width; int Height; // // Allocate new header, switching height and width. // // Recalculate image and file sizes since although the old // and new bitmaps will have the same number of pixels they // will not in general have the same number of bytes. This // is because each row in the bit map is padded to a multiple // of 32-bits wide (a DWORD). // HeaderSize = sizeof (BMP); Header = malloc(HeaderSize); if (Header == NULL) { fprintf(STDERR, "Header = malloc(%d) failed\n", HeaderSize); exit(1); } Width = Source.Header->Height; Height = Source.Header->Width; ImageSize = WIDTH32(Width) * Height / 8; Header->Type[0] = 'B'; Header->Type[1] = 'M'; Header->FileSize = sizeof (BMP) + Source.ColorMapSize + ImageSize; Header->Reserved = 0; Header->DataOffset = sizeof (BMP) + Source.ColorMapSize; Header->HeaderSize = HEADER_SIZE; Header->Width = Width; Header->Height = Height; Header->Planes = 1; Header->BitsPerPixel = 1; Header->CompressionType = 0; Header->ImageSize = ImageSize; Header->xPixelsPerMeter = 0; Header->yPixelsPerMeter = 0; Header->ColorsUsed = 2; Header->ColorsImportant = 2; // // Allocate bit map and rotate. // BitMap = malloc(ImageSize); if (BitMap == NULL) { fprintf(STDERR, "BitMap = malloc(%d) failed\n", ImageSize); exit(1); } BmpRotate(Source.BitMap, Source.Header->Width, Source.Header->Height, BitMap, Width, Height); // // Write new header. // HeaderSize = sizeof (BMP); Count = fwrite(Header, HeaderSize, 1, File); if (Count != 1) { fprintf(STDERR, "Header write error\n"); exit(1); } // // Write color map (same color map as original file). // Count = fwrite(Source.ColorMap, Source.ColorMapSize, 1, File); if (Count != 1) { fprintf(STDERR, "ColorMap write error\n"); exit(1); } // // Write new bit map. // Count = fwrite(BitMap, Header->ImageSize, 1, File); if (Count != 1) { fprintf(STDERR, "BitMap write error\n"); exit(1); } return; } // // Generate mirrored rotated bit map. // #define MIRROR_AND_ROTATE_90 void BmpRotate (PCHAR OldBitMap, long OldWidth, long OldHeight, PCHAR BitMap, long Width, long Height) { int Bit; int x, y; int OldWidth32; int Width32; Width32 = WIDTH32(Width); OldWidth32 = WIDTH32(OldWidth); // // Copy each bit so as to mirror and rotate left 90 degrees. // for (y = 0; y < Height; y += 1) { for (x = 0; x < Width32; x += 1) { if (x < Width) { Bit = BitGet(&OldBitMap[x * OldWidth32 >> 3], y); } else { Bit = 0; } #ifdef ROTATE_90 BitSet(&BitMap[y * Width32 >> 3], x, Bit); #endif #ifdef MIRROR_AND_ROTATE_90 BitSet(&BitMap[y * Width32 >> 3], Width32 - 1 - x, Bit); #endif } // Show progress. if (y % 100 == 0) { printf("."); } } printf("\n"); return; } // // Bit vector get function. // int BitGet (char *BitArray, int BitIndex) { int Mask = 1 << (7 - (BitIndex & 7)); return (BitArray[BitIndex >> 3] & Mask) != 0; } // // Bit vector set function. // void BitSet (char *BitArray, int BitIndex, int Value) { int Mask = 1 << (7 - (BitIndex & 7)); if (Value) { BitArray[BitIndex >> 3] |= Mask; } else { BitArray[BitIndex >> 3] &= ~Mask; } return; } // // Dump header fields. // void BmpDump (PBMP Header) { printf(" '%c%c' Type[]\n", Header->Type[0], Header->Type[1]); printf(" %8ld FileSize\n", Header->FileSize); printf(" %8ld Reserved\n", Header->Reserved); printf(" %8ld DataOffset\n", Header->DataOffset); printf(" %8ld HeaderSize\n", Header->HeaderSize); printf(" %8ld Width\n", Header->Width); printf(" %8ld Height\n", Header->Height); printf(" %8d Planes\n", Header->Planes); printf(" %8d BitsPerPixel\n", Header->BitsPerPixel); printf(" %8ld CompressionType\n", Header->CompressionType); printf(" %8ld ImageSize\n", Header->ImageSize); printf(" %8ld xPixelsPerMeter\n", Header->xPixelsPerMeter); printf(" %8ld yPixelsPerMeter\n", Header->yPixelsPerMeter); printf(" %8ld ColorsUsed\n", Header->ColorsUsed); printf(" %8ld ColorsImportant\n", Header->ColorsImportant); return; }