asked on
int write8BitBmpFile(char *filename, unsigned int width, unsigned int height,
unsigned char *image)
{
BITMAPINFOHEADER bmpInfoHeader;
BITMAPFILEHEADER bmpFileHeader;
FILE *filep;
unsigned int row;
unsigned int extrabytes, bytesize;
unsigned char *paddedImage = NULL;
RGBQUAD palette[256];
unsigned int i;
unsigned int numPaletteEntries = 256;
// Create the palette - each pixel is an index into the palette
for (i = 0; i < numPaletteEntries; i++) {
palette[i].rgbRed = i;
palette[i].rgbGreen = i;
palette[i].rgbBlue = i;
palette[i].rgbReserved = 0;
}
/* The .bmp format requires that the image data is aligned on a 4 byte boundary. For 8 - bit bitmaps,
this means that the width of the bitmap must be a multiple of 4. This code determines
the extra padding needed to meet this requirement. */
extrabytes = (4 - width % 4) % 4;
// This is the size of the padded bitmap
bytesize = (width + extrabytes) * height;
// Fill the bitmap file header structure
bmpFileHeader.bfType = 'MB'; // Bitmap header
bmpFileHeader.bfSize = 0; // This can be 0 for BI_RGB bitmaps
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * numPaletteEntries;
// Fill the bitmap info structure
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 8; // 8 - bit bitmap
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biSizeImage = bytesize; // includes padding for 4 byte alignment
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = numPaletteEntries;
bmpInfoHeader.biClrImportant = 0;
// Open file
if ((filep = fopen(filename, "wb")) == NULL) {
printf("Error opening file %s\n", filename);
return FALSE;
}
// Write bmp file header
if (fwrite(&bmpFileHeader, 1, sizeof(BITMAPFILEHEADER), filep) < sizeof(BITMAPFILEHEADER)) {
printf("Error writing bitmap file header\n");
fclose(filep);
return FALSE;
}
// Write bmp info header
if (fwrite(&bmpInfoHeader, 1, sizeof(BITMAPINFOHEADER), filep) < sizeof(BITMAPINFOHEADER)) {
printf("Error writing bitmap info header\n");
fclose(filep);
return FALSE;
}
// Write bmp palette
if (fwrite(palette, 1, numPaletteEntries * sizeof(RGBQUAD), filep) < numPaletteEntries * sizeof(RGBQUAD)) {
printf("Error writing bitmap palette\n");
fclose(filep);
return FALSE;
}
// Allocate memory for some temporary storage
paddedImage = (unsigned char *)calloc(sizeof(unsigned char), bytesize);
if (paddedImage == NULL) {
printf("Error allocating memory \n");
fclose(filep);
return FALSE;
}
/* Flip image - bmp format is upside down. Also pad the paddedImage array so that the number
of pixels is aligned on a 4 byte boundary. */
for (row = 0; row < height; row++)
memcpy(&paddedImage[row * (width + extrabytes)], &image[(height - 1 - row) * width], width);
// Write bmp data
if (fwrite(paddedImage, 1, bytesize, filep) < bytesize) {
printf("Error writing bitmap data\n");
free(paddedImage);
fclose(filep);
return FALSE;
}
// Close file
fclose(filep);
free(paddedImage);
return TRUE;
}