Shows how to use a display and the onboard SD Card. Requires a display module with an adapter
Dependencies: DmTftLibrary SDFileSystem mbed
Diff: DmDrawBmpBase.cpp
- Revision:
- 0:ee27d4c12433
- Child:
- 3:030be860c83d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DmDrawBmpBase.cpp Tue May 20 15:42:31 2014 +0000 @@ -0,0 +1,252 @@ +/********************************************************************************************** + Copyright (c) 2014 DisplayModule. All rights reserved. + + Redistribution and use of this source code, part of this source code or any compiled binary + based on this source code is permitted as long as the above copyright notice and following + disclaimer is retained. + + DISCLAIMER: + THIS SOFTWARE IS SUPPLIED "AS IS" WITHOUT ANY WARRANTIES AND SUPPORT. DISPLAYMODULE ASSUMES + NO RESPONSIBILITY OR LIABILITY FOR THE USE OF THE SOFTWARE. + ********************************************************************************************/ + +#include "DmDrawBmpBase.h" + +bool DmDrawBmpBase::drawBitmap(DmTftBase& tft, uint16_t x, uint16_t y, readFunc func, uint32_t userData) { + _readFunc = func; + _userData = userData; + _readPos = 0; + + if (readBmpHeader()) { + if (IsValid565Bitmap()) { + return draw565Bitmap(tft, x, y); + } + if (IsValid888Bitmap()) { + return draw888Bitmap(tft, x, y); + } + } + return false; +} + +bool DmDrawBmpBase::draw888Bitmap(DmTftBase& tft, uint16_t x, uint16_t y) { + const uint8_t bytesPerPixel = 3; + uint32_t filePosition = _bitmapOffset; + uint8_t red, green, blue; + uint16_t row, column; + uint16_t bytesPerRow = (bytesPerPixel*_width + 3) & ~3; + uint8_t buff[20*bytesPerPixel]; + uint8_t buffPos = sizeof(buff); + + tft.select(); + tft.setAddress(x, y, x+_width-1, y+_height-1); + tft.unSelect(); + + for(row=0; row<_height; row++) { + _readPos = filePosition = _bitmapOffset + (_height - 1 -row ) * bytesPerRow; +// if(_imageFile.position() != filePosition) { +// tft.unSelect(); +// _imageFile.seek(filePosition); +// tft.select(); +// buffPos = sizeof(buff); +// } + buffPos = sizeof(buff); + + for(column=0; column<_width; column++) { + if (buffPos >= sizeof(buff)) { + tft.unSelect(); + _readFunc(_userData, buff, _readPos, sizeof(buff)); + _readPos += sizeof(buff); +// _imageFile.read(buff, sizeof(buff)); + tft.select(); + buffPos = 0; + } + + blue = buff[buffPos++]; + green = buff[buffPos++]; + red = buff[buffPos++]; + + tft.sendData(Convert888to565(red, green, blue)); + } + } + tft.unSelect(); + return true; +} + +bool DmDrawBmpBase::draw565Bitmap(DmTftBase& tft, uint16_t x, uint16_t y) { + const uint8_t bytesPerPixel = 2; + uint8_t buff[30*bytesPerPixel]; // Should be dividable by bytesPerPixel + uint8_t buffPos = sizeof(buff); + uint16_t bytesPerRow = (bytesPerPixel * _width + 3) & ~3; // bytes Per Row including padding to 4 bytes boundary + uint16_t paddingSize = bytesPerRow - (bytesPerPixel * _width); // paddingSize for each row + uint16_t height = -_height; // Change if load bottom-top + uint16_t pixel; + uint16_t row, column; + _readPos = _bitmapOffset; + + //_imageFile.seek(_bitmapOffset); + + tft.select(); + tft.setAddress(x, y, x+_width-1, y+height-1); + tft.unSelect(); + + for(row=0; row<height; row++) { + for(column=0; column<_width; column++) { + if (buffPos >= sizeof(buff)) { + tft.unSelect(); + _readFunc(_userData, buff, _readPos, sizeof(buff)); + _readPos += sizeof(buff); + //_imageFile.read(buff, sizeof(buff)); + tft.select(); + buffPos = 0; + } + pixel = buff[buffPos++] & 0xFF; + pixel |= buff[buffPos++] << 8; + tft.sendData(pixel); + } + + if ( paddingSize > 0 ) { // Check if there is padding in the file + if ((sizeof(buff) - buffPos) >= paddingSize) { // Most common case, the padding is in the buffer + buffPos += paddingSize; + } + else { // Padding is not in the buffer, we have to load the buffer from file + tft.unSelect(); + _readFunc(_userData, buff, _readPos, sizeof(buff)); + _readPos += sizeof(buff); +// _imageFile.read(buff, sizeof(buff)); + tft.select(); + buffPos = paddingSize-(sizeof(buff) - buffPos); // paddingSize (0-3) spaceLeftInBuffer (0-3) where spaceLeftInBuffer < paddingSize + } + } + } + tft.unSelect(); + + return true; +} + +void DmDrawBmpBase::printBmpHeaderInfo() { + printf("Image size: %d\n", _fileSize); + printf("Image offset: %d\n", _bitmapOffset); + printf("Image size: %d, %d\n", _width, _height); + printf("BitsPerPixel: %d\n",_bitsPerPixel); + printf("Compression: %d\n",_compression); + printf("Is 24-bit bmp: %d\n", IsValid888Bitmap()); + printf("Is 16-bit 565 bmp: %d\n", IsValid565Bitmap()); + printf("Has 565 color mask: %d\n", Is565ColorMask()); +} + +bool DmDrawBmpBase::readBmpHeader() { + if (read16() !=0x4D42){ // read magic byte + return false; + } + + _fileSize = read32(); + read32(); // Value depends on application which created the image + _bitmapOffset = read32(); + + // read DIB header + _headerSize = read32(); + _width = readInt32(); + _height = readInt32(); + + if (read16() != 1) { // number of color planes must be 1 + return false; + } + + _bitsPerPixel = read16(); + _compression = read32(); + + if (_bitmapOffset == 66 || _bitmapOffset == 70) { // V3 or v2 format + //setPosition(54); + _readPos = 54; + _redMask = read32(); + _greenMask = read32(); + _blueMask = read32(); + } + else { + _redMask = 0x00; + _greenMask = 0x00; + _blueMask = 0x00; + } + + if (!IsValid888Bitmap() && !IsValid565Bitmap()) + { + return false; + } + + return true; +} + +// In this context a valid bitmap +// - Stored bottom to top +// - 24-bit file +// - No compression +bool DmDrawBmpBase::IsValid888Bitmap() { + if (_height > 0 && _bitsPerPixel == 24 && _compression == 0) + { + return true; + } + return false; +} + +// In this context a valid bitmap +// - Stored top to bottom +// - 16-bit file +// - Compression 3 (BI_BITFIELDS) +// - Have a 565 Colormask +bool DmDrawBmpBase::IsValid565Bitmap() { + if (_height < 0 && _bitsPerPixel == 16 && _compression == 3 && Is565ColorMask()) + { + return true; + } + return false; +} + +bool DmDrawBmpBase::Is565ColorMask() { + if (_redMask == 0xF800 && _greenMask == 0x7E0 && _blueMask == 0x1F) + { + return true; + } + return false; +} + +int32_t DmDrawBmpBase::readInt32() { + int32_t d; + uint16_t b; + + b = read16(); + d = read16(); + d <<= 16; + d |= b; + return d; +} + +uint32_t DmDrawBmpBase::read32() { + uint32_t d; + uint16_t b; + + b = read16(); + d = read16(); + d <<= 16; + d |= b; + return d; +} + +uint16_t DmDrawBmpBase::read16() { + //uint16_t d; + //uint8_t b; + uint8_t buff[2]; + //b = _imageFile.read(); + //d = _imageFile.read(); + _readFunc(_userData, buff, _readPos, 2); + _readPos+=2; + //d <<= 8; + //d |= b; + //return d; + return (buff[1] << 8) | buff[0]; +} + +// http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888 +uint16_t DmDrawBmpBase::Convert888to565(uint8_t red, uint8_t green, uint8_t blue){ + return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); +} +