/*
bmp2lcd.c
This program creates a graphic file that may be better suited for faster
loading on certain low-end LCD screens by simplifying the header and
converting from 24 bits to 16 (5 bits red, 6 bits green, 5 bits blue).
Output File:
4-byte width
4-byte height
width * height * 2 bytes of pixel data stored top-down, left-to-right
Compile: gcc -Wall -o bmp2lcd bmp2lcd.c
Usage: bmp2lcd [input file name] [output file name]
// License //
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#define BYTES_PER_PIXEL 3
typedef struct __attribute__((__packed__)) {
unsigned short bmpID;
unsigned int fileSize;
unsigned short reserved1;
unsigned short reserved2;
unsigned int offset;
unsigned int headerSize;
unsigned int width;
unsigned int height;
unsigned short compression;
unsigned short bitDepth;
} bitmapHeader;
FILE *inFile = NULL;
FILE *outFile = NULL;
bitmapHeader header;
unsigned char *picBuffer = NULL;
int readBitmapHeader()
{
int retVal = 0;
if( fread( &header, sizeof(bitmapHeader), 1, inFile) )
{
if( header.bmpID == 0x4d42 )
{
printf("offset: %u\n", header.offset);
printf("width: %u\n", header.width );
printf("height: %u\n", header.height );
printf("depth: %u\n", header.bitDepth );
if( header.bitDepth != 24 )
{
fprintf(stderr, "Must be a 24-bit graphic.\n");
}
else
retVal = 1;
}
}
return retVal;
}
int getMemory()
{
picBuffer = (unsigned char *) malloc( header.width * header.height * BYTES_PER_PIXEL );
if( ! picBuffer )
{
fprintf(stderr, "Unable to allocate memory.\n");
return 0;
}
return 1;
}
int doBitmapConversion()
{
int x, y;
int rowIndex;
unsigned short r, g, b, outColor;
// Write dimensions to output file
if( ! fwrite(&header.width, sizeof(unsigned int), 2, outFile) )
{
fprintf(stderr, "Error writing dimensions to output file.\n");
return 0;
}
// Go to start of pixel data
fseek(inFile, header.offset, SEEK_SET);
if( fread( picBuffer, header.width * header.height * BYTES_PER_PIXEL, 1, inFile) )
{
for(y = 0; y < header.height; y++ )
{
// Bitmaps are stored bottom-up, but I want to reverse that order
rowIndex = (header.height - y - 1) * header.width * BYTES_PER_PIXEL;
for(x = 0; x < header.width; x++ )
{
b = picBuffer[rowIndex++];
g = picBuffer[rowIndex++];
r = picBuffer[rowIndex++];
outColor = ((r>>3) << 11) | ((g>>2) << 5) | (b >> 3);
if( ! fwrite(&outColor, sizeof(unsigned short), 1, outFile) )
{
fprintf(stderr, "Error writing output file.\n");
return 0;
}
}
}
}
else
{
fprintf(stderr, "Error reading input file.\n");
return 0;
}
return 1;
}
void cleanUp()
{
if( inFile )
fclose(inFile);
if( outFile )
fclose(outFile);
if( picBuffer )
free( picBuffer );
}
int openInputFile(char *fileName)
{
inFile = fopen( fileName, "r" );
if( ! inFile )
{
fprintf(stderr, "Error opening input file.\n");
return 0;
}
return 1;
}
int openOutputFile(char *fileName)
{
outFile = fopen( fileName, "w" );
if( ! outFile )
{
fprintf(stderr, "Error opening output file.\n");
return 0;
}
return 1;
}
int main( int argc, char **argv )
{
if
(
argc == 3 && openInputFile(argv[1]) && openOutputFile(argv[2]) &&
readBitmapHeader() && getMemory() && doBitmapConversion()
)
{
printf("Bitmap successfully converted.\n");
}
else
{
if( argc == 3 ) {
printf("Failed to convert file.");
}
else {
printf("\nUsage:\n");
printf("------\n");
printf("bmp2lcd [input file name] [output file name]\n\n");
}
}
// Close files and release memory
cleanUp();
return 0;
}