Shows how to use a display, the onboard SD Card and the onboard SPI Flash. Requires a display module with direct Arduino pinning
Dependencies: DmTftLibrary SDFileSystem mbed
DmDrawBmpBase.cpp
- Committer:
- displaymodule
- Date:
- 2014-07-09
- Revision:
- 4:93ca338876e2
- Parent:
- 3:e1e1053e286f
File content as of revision 4:93ca338876e2:
/********************************************************************************************** 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; 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); uint16_t clipX = _width; uint16_t clipY = _height; //make sure image fits if ((x + clipX) > tft.width()) { clipX = tft.width() - x; } if ((y + clipY) > tft.height()) { clipY = tft.height() - y; } tft.select(); tft.setAddress(x, y, x+clipX-1, y+clipY-1); tft.unSelect(); for(row=0; row<_height; row++) { _readPos = _bitmapOffset + (_height - 1 -row ) * bytesPerRow; buffPos = sizeof(buff); for(column=0; column<_width; column++) { if (buffPos >= sizeof(buff)) { tft.unSelect(); _readFunc(_userData, buff, _readPos, sizeof(buff)); _readPos += sizeof(buff); tft.select(); buffPos = 0; } blue = buff[buffPos++]; green = buff[buffPos++]; red = buff[buffPos++]; if (row < clipY && column < clipX) { 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; uint16_t clipX = _width; uint16_t clipY = height; _readPos = _bitmapOffset; //_imageFile.seek(_bitmapOffset); //make sure image fits if ((x + clipX) > tft.width()) { clipX = tft.width() - x; } if ((y + clipY) > tft.height()) { clipY = tft.height() - y; } tft.select(); tft.setAddress(x, y, x+clipX-1, y+clipY-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; if (row < clipY && column < clipX) { 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); }