// // mxToolKit (c) 1999 by Mete Ciragan // // file: mxBmp.cpp // implementation: all // last modified: Apr 15 1999, Mete Ciragan // copyright: The programs and associated files contained in this // distribution were developed by Mete Ciragan. The programs // are not in the public domain, but they are freely // distributable without licensing fees. These programs are // provided without guarantee or warrantee expressed or // implied. // lbmlib.c #include "mxtk/mxBmp.h" #include #include #include mxImage * mxBmpRead (const char *filename) { int i; FILE *pfile = 0; mxBitmapFileHeader bmfh; mxBitmapInfoHeader bmih; mxBitmapRGBQuad rgrgbPalette[256]; int cbBmpBits; byte *pbBmpBits; byte *pb, *pbPal = 0; int cbPalBytes; int biTrueWidth; mxImage *image = 0; // File exists? if ((pfile = fopen (filename, "rb")) == 0) return 0; // Read file header if (fread (&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1) goto GetOut; // Bogus file header check if (!(bmfh.bfReserved1 == 0 && bmfh.bfReserved2 == 0)) goto GetOut; // Read info header if (fread (&bmih, sizeof bmih, 1/*count*/, pfile) != 1) goto GetOut; // Bogus info header check if (!(bmih.biSize == sizeof bmih && bmih.biPlanes == 1)) goto GetOut; // Bogus bit depth? Only 8-bit supported. if (bmih.biBitCount != 8) goto GetOut; // Bogus compression? Only non-compressed supported. if (bmih.biCompression != 0) //BI_RGB) goto GetOut; // Figure out how many entires are actually in the table if (bmih.biClrUsed == 0) { bmih.biClrUsed = 256; cbPalBytes = (1 << bmih.biBitCount) * sizeof (mxBitmapRGBQuad); } else { cbPalBytes = bmih.biClrUsed * sizeof (mxBitmapRGBQuad); } // Read palette (bmih.biClrUsed entries) if (fread (rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1) goto GetOut; image = new mxImage (); if (!image) goto GetOut; if (!image->create (bmih.biWidth, bmih.biHeight, 8)) { delete image; goto GetOut; } pb = (byte *) image->palette; // Copy over used entries for (i = 0; i < (int) bmih.biClrUsed; i++) { *pb++ = rgrgbPalette[i].rgbRed; *pb++ = rgrgbPalette[i].rgbGreen; *pb++ = rgrgbPalette[i].rgbBlue; } // Fill in unused entires will 0,0,0 for (i = bmih.biClrUsed; i < 256; i++) { *pb++ = 0; *pb++ = 0; *pb++ = 0; } // Read bitmap bits (remainder of file) cbBmpBits = bmfh.bfSize - ftell (pfile); pb = (byte *) malloc (cbBmpBits * sizeof (byte)); if (pb == 0) { free (pbPal); goto GetOut; } if (fread (pb, cbBmpBits, 1/*count*/, pfile) != 1) { free (pb); free (pbPal); goto GetOut; } /* pbBmpBits = malloc(cbBmpBits); if (pbBmpBits == 0) { free (pb); free (pbPal); goto GetOut; } */ pbBmpBits = (byte *) image->data; // data is actually stored with the width being rounded up to a multiple of 4 biTrueWidth = (bmih.biWidth + 3) & ~3; // reverse the order of the data. pb += (bmih.biHeight - 1) * biTrueWidth; for(i = 0; i < bmih.biHeight; i++) { memmove (&pbBmpBits[biTrueWidth * i], pb, biTrueWidth); pb -= biTrueWidth; } pb += biTrueWidth; free (pb); GetOut: if (pfile) fclose (pfile); return image; } bool mxBmpWrite (const char *filename, mxImage *image) { int i; FILE *pfile = 0; mxBitmapFileHeader bmfh; mxBitmapInfoHeader bmih; mxBitmapRGBQuad rgrgbPalette[256]; int cbBmpBits; byte *pbBmpBits; byte *pb = 0; int cbPalBytes; int biTrueWidth; if (!image || !image->data || !image->palette) return false; // File exists? if ((pfile = fopen(filename, "wb")) == 0) return false; biTrueWidth = ((image->width + 3) & ~3); cbBmpBits = biTrueWidth * image->height; cbPalBytes = 256 * sizeof (mxBitmapRGBQuad); // Bogus file header check //bmfh.bfType = MAKEWORD( 'B', 'M' ); bmfh.bfType = (word) (('M' << 8) | 'B'); bmfh.bfSize = sizeof bmfh + sizeof bmih + cbBmpBits + cbPalBytes; bmfh.bfReserved1 = 0; bmfh.bfReserved2 = 0; bmfh.bfOffBits = sizeof bmfh + sizeof bmih + cbPalBytes; // Write file header if (fwrite (&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1) { fclose (pfile); return false; } // Size of structure bmih.biSize = sizeof bmih; // Width bmih.biWidth = biTrueWidth; // Height bmih.biHeight = image->height; // Only 1 plane bmih.biPlanes = 1; // Only 8-bit supported. bmih.biBitCount = 8; // Only non-compressed supported. bmih.biCompression = 0; //BI_RGB; bmih.biSizeImage = 0; // huh? bmih.biXPelsPerMeter = 0; bmih.biYPelsPerMeter = 0; // Always full palette bmih.biClrUsed = 256; bmih.biClrImportant = 0; // Write info header if (fwrite (&bmih, sizeof bmih, 1/*count*/, pfile) != 1) { fclose (pfile); return false; } // convert to expanded palette pb = (byte *) image->palette; // Copy over used entries for (i = 0; i < (int) bmih.biClrUsed; i++) { rgrgbPalette[i].rgbRed = *pb++; rgrgbPalette[i].rgbGreen = *pb++; rgrgbPalette[i].rgbBlue = *pb++; rgrgbPalette[i].rgbReserved = 0; } // Write palette (bmih.biClrUsed entries) cbPalBytes = bmih.biClrUsed * sizeof (mxBitmapRGBQuad); if (fwrite (rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1) { fclose (pfile); return false; } pbBmpBits = (byte *) malloc (cbBmpBits * sizeof (byte)); if (!pbBmpBits) { fclose (pfile); return false; } pb = (byte *) image->data; // reverse the order of the data. pb += (image->height - 1) * image->width; for(i = 0; i < bmih.biHeight; i++) { memmove (&pbBmpBits[biTrueWidth * i], pb, image->width); pb -= image->width; } // Write bitmap bits (remainder of file) if (fwrite (pbBmpBits, cbBmpBits, 1/*count*/, pfile) != 1) { free (pbBmpBits); fclose (pfile); return false; } free (pbBmpBits); fclose (pfile); return true; }