I wrote this small utility last night to convert 24-bit bitmaps, which somewhat inconveniently load from the bottom up, into a 16-bit, top-down format that can be directly loaded into the graphic memory of the small LCD I’m working with (see more here). The result is a pretty drastic increase in load speed, not to mention the smaller file size.
There is some general error checking, but I didn’t go overboard. Source code below.
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#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;
}

Pingback: Touch Screen Shield for Arduino UNO | misc.ws
Hi,
Thanks, great tool and articles about the touch screen.
Concerning the code above. I just want to mention (for other people) that I ran into problems with GCC 4.8.1, it apears like it ignores the (__packed__) attribute. With GCC 4.8.3, no problems.
This could be a problem for people who are using the MiniGW installer, because the latest still ships with GCC 4.8.1…
Thank you, Gunter. I appreciate the feedback and assistance.
where should i keep this file……………….
hello, I need to display a image but its displaying it in bad quality, how could I add this code to my code?
thanks
How do I use this?
a note to people who need this:
If you’re compiling with mingw you should pass -mno-ms-bitfields to gcc or the utility will not work
The program is not working for me. It says that my image is not 24-bit but it is. Someone knows what’s going on? I am using Windows to run the converter.
I receve a error