Reputation: 421
I want to convert 24 bit bmp files to RGB565 format to write to a serial TFT colour display.
The size of the 24bit bmp will always be 320x240 pixels as my TFT display is 320x240
Has anyone any experience of doing this? It could be C/C++, Shell, Python, Java Script and so on...
Upvotes: 3
Views: 5357
Reputation: 208043
I would use either NetPBM (much smaller and lighter-weight) or ImageMagick (much bigger installation) to convert the BMP
into a format that is simple to parse and then use Perl to convert that to RGB565 format.
I assume you are planning to write the RGB565 data to a frame buffer, so you would do something like:
./bmp2rgb565 image.bmp > /dev/fb1
So, save the following as bmp2rgb565
:
#!/bin/bash
################################################################################
# bmp2rgb565
# Mark Setchell
################################################################################
if [ $# -ne 1 ]; then
echo Usage: $0 image.bmp
exit 1
fi
file=$1
# Use NetPBM's "bmptopnm" to convert BMP to PNM for easy reading
# You could use ImageMagick: convert "$file" PNM: | perl ...
bmptopnm "$file" 2> /dev/null |
perl -e '
my $debug=0; # Change to 1 for debugging
# Discard first 3 lines of PNM header:
# P3
# 320 240
# 255
my $line=<STDIN>; $line=<STDIN>; $line=<STDIN>;
# Read file, 3 RGB bytes at a time
{
local $/ = \3;
while(my $pixel=<STDIN>){
# Extract 8-bit R,G and B from pixel
my ($r,$g,$b)=unpack("CCC",$pixel);
printf("R/G/B: %d/%d/%d\n",$r,$g,$b) if $debug;
# Convert to RGB565
my $r5=$r>>3;
my $g6=$g>>2;
my $b5=$b>>3;
my $rgb565 = ($r5<<11) | ($g6<<5) | $b5;
# Convert to little-endian 16-bit (VAX order) and write 2 bytes
my $v=pack("v",$rgb565);
syswrite(STDOUT,$v,2);
}
}
'
I don't have a frame buffer handy to test, but it should be pretty close.
Note that you could make the code more robust by starting off with:
convert "$file" -depth 8 -resize 320x240\! PNM: | perl ...
which would make sure the image always matches the framebuffer size, and that it is 8-bit and not 16-bit. You may also want a -flip
or -flop
in there if the BMP
image is upside-down or back-to-front.
Note that if you use ImageMagick convert
, the code will work for GIFs, TIFFs, JPEGs, PNGs and around 150 other formats as well as BMP.
Note that if you want to test the code, you can generate a black image with ImageMagick like this:
convert -size 320x240 xc:black BMP3:black.bmp
and then look for a bunch of zeroes in the output if you run:
./bmp2rgb565 black.bmp | xxd -g2
Likewise, you can generate a white image and look for a bunch of ff
s:
convert -size 320x240 xc:red BMP3:white.bmp
And so on with red, green and blue:
convert -size 320x240 xc:red BMP3:red.bmp
convert -size 320x240 xc:lime BMP3:green.bmp
convert -size 320x240 xc:blue BMP3:blue.bmp
# Or make a cyan-magenta gradient image
convert -size 320x240 gradient:cyan-magenta cyan-magenta-gradient.bmp
Example:
./RGB565 red.bmp | xxd -g2 | more
00000000: 00f8 00f8 00f8 00f8 00f8 00f8 00f8 00f8 ................
00000010: 00f8 00f8 00f8 00f8 00f8 00f8 00f8 00f8 ................
Example:
./RGB565 blue.bmp | xxd -g2 | more
00000000: 1f00 1f00 1f00 1f00 1f00 1f00 1f00 1f00 ................
00000010: 1f00 1f00 1f00 1f00 1f00 1f00 1f00 1f00 ................
Keywords: RGB565, rgb565, framebuffer, frame-buffer, pack, unpack, Perl, BMP, PGM, image, Raspberry Pi, RASPI
Upvotes: 2
Reputation: 5421
I'm assuming you simply want to stream out the pixel data without any headers or additional data.
The core of the problem has already been described here.
If you want to implement it for yourself, the following approach will probably help:
After opening the file, yout need to skip the BMP header by reading the bfOffBits
value (see this BMP format description), the easiest way would probably be to implement it in C by reading into a struct that matches the BMP header.
(Note: This only works because the dimensions of the image are divisible by 4! Check the format description for more details)
Then seek forward by bfOffBits
and while the file has not ended, transform three consecutive bytes (uint8_t
) to one 16 bit value (uint16_t
) by using the approach from the question I mentioned above. The basic C file operations you would need are fopen, fclose, fread, fwrite, fgetc/fgetwc, fputc/fputwc
and fseek
Upvotes: 0
Reputation: 2191
To convert to RGB565 you can use ImageMagick:
convert test.png -resize 320x200 -ordered-dither threshold,32,64,32 test2.png
In what format do you need the output to be?
Upvotes: 0