Shows how to use a display and the onboard SD Card. Requires a display module with an adapter

Dependencies:   DmTftLibrary SDFileSystem mbed

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);
+}
+