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