You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
5.7 KiB
276 lines
5.7 KiB
5 years ago
|
//
|
||
|
// 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|