Library to control a Graphics TFT connected to 4-wire SPI - revised for the Raio RA8875 Display Controller.

Dependents:   FRDM_RA8875_mPaint RA8875_Demo RA8875_KeyPadDemo SignalGenerator ... more

Fork of SPI_TFT by Peter Drescher

See Components - RA8875 Based Display

Enhanced touch-screen support - where it previous supported both the Resistive Touch and Capacitive Touch based on the FT5206 Touch Controller, now it also has support for the GSL1680 Touch Controller.

Offline Help Manual (Windows chm)

/media/uploads/WiredHome/ra8875.zip.bin (download, rename to .zip and unzip)

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Thu Feb 14 12:34:52 2019 +0000
Parent:
163:17526689a3ed
Child:
165:695c24cc5197
Commit message:
PrintScreen - 24-bit or 8-bit BMP format support. Improved documentation to the palette and the performance factors.

Changed in this revision

RA8875.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875.h Show annotated file Show diff for this revision Revisions of this file
--- a/RA8875.cpp	Wed Feb 13 04:20:12 2019 +0000
+++ b/RA8875.cpp	Thu Feb 14 12:34:52 2019 +0000
@@ -108,6 +108,11 @@
     uint8_t a;
 } rgbTrio_t;
 
+/// This is defined as a "Web-Safe" color palette of 216 colors. 
+///
+/// It is defined so it can be emitted into a BMP file as the color palette, and it is then used
+/// for downscaling from higher resolution color depth to an 8-bit format.
+///
 static const rgbTrio_t WebColorPalette[] = {
     {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x33,0xFF}, {0x00,0x00,0x66,0xFF}, {0x00,0x00,0x99,0xFF}, {0x00,0x00,0xCC,0xFF}, {0x00,0x00,0xFF,0xFF},
     {0x00,0x33,0x00,0xFF}, {0x00,0x33,0x33,0xFF}, {0x00,0x33,0x66,0xFF}, {0x00,0x33,0x99,0xFF}, {0x00,0x33,0xCC,0xFF}, {0x00,0x33,0xFF,0xFF},
@@ -155,13 +160,21 @@
     {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
 };
 
-#define sqr(a) (double)((a) * (a))
-
+#define sqr(a) ((a) * (a))
+
+/// Find the nearest color match in the lookup table.
+///
+/// The typical process is to find the difference between a given color and each entry in
+/// the table. The difference is defined as:
+///     diff = sqrt(sqr(r - table[i].r) + sqr(g - table[i].g) + sqr(b - table[i].b))
+/// The square root function is very CPU intensive, especially w/o a floating point unit,
+/// so that step is omitted to speed it up a bit.
+///
 static int FindNearestWebColor(uint8_t r, uint8_t g, uint8_t b) {
     int bestNdx = 0;
-    float bestDiff = sqrt(sqr(r - WebColorPalette[0].r) + sqr(g - WebColorPalette[0].g) + sqr(b - WebColorPalette[0].b));
+    float bestDiff = (sqr(r - WebColorPalette[0].r) + sqr(g - WebColorPalette[0].g) + sqr(b - WebColorPalette[0].b));
     for (int i=1; i<216; i++) {
-        float thisDiff = sqrt(sqr(r - WebColorPalette[i].r) + sqr(g - WebColorPalette[i].g) + sqr(b - WebColorPalette[i].b));
+        float thisDiff = (sqr(r - WebColorPalette[i].r) + sqr(g - WebColorPalette[i].g) + sqr(b - WebColorPalette[i].b));
         if (thisDiff < bestDiff) {
             bestDiff = thisDiff;
             bestNdx = i;
@@ -2137,7 +2150,7 @@
     return ((value + roundTo - 1) / roundTo) * roundTo;
 }
 
-RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h)
+RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, uint8_t bitsPerPixel)
 {
     BITMAPFILEHEADER BMP_Header;
     BITMAPINFOHEADER BMP_Info;
@@ -2145,33 +2158,49 @@
     color_t * pixelBuffer = NULL;
     color_t * pixelBuffer2 = NULL;
     
-    INFO("(%d,%d) - (%d,%d)", x,y,w,h);
+    INFO("(%d,%d)-(%d,%d)x%d", x,y,w,h,bitsPerPixel);
     if (x >= 0 && x < screenwidth
             && y >= 0 && y < screenheight
             && w > 0 && x + w <= screenwidth
             && h > 0 && y + h <= screenheight) {
-
         BMP_Header.bfType = BF_TYPE;
-        BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Info);
         BMP_Header.bfReserved1 = 0;
         BMP_Header.bfReserved2 = 0;
-        BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info);
+        switch (bitsPerPixel) {
+            case 24:
+                BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info);
+                BMP_Header.bfSize = (h * RoundUp(w * sizeof(RGBQUAD),4)) + BMP_Header.bfOffBits;
+                break;
+            case 8:
+            default:
+                BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette);
+                INFO("Initial Offset to Bitstream %X", BMP_Header.bfOffBits);
+                //if (BMP_Header.bfOffBits & 0x03) {
+                //    BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03));
+                //}
+                BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits;
+                break;
+        }
+        INFO("Offset to Bitstream %X", BMP_Header.bfOffBits);
 
         // Bytes in the line buffer
-        int lineBufSize = RoundUp(3 * w, 4);    // ((24 * w + 7)/8);
+        int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4);
         INFO("LineBufSize: %d", lineBufSize);
 
         BMP_Info.biSize = sizeof(BMP_Info);
         BMP_Info.biWidth = w;
         BMP_Info.biHeight = h;
         BMP_Info.biPlanes = 1;
-        BMP_Info.biBitCount = 24;
+        BMP_Info.biBitCount = bitsPerPixel;
         BMP_Info.biCompression = BI_RGB;
         BMP_Info.biSizeImage = lineBufSize * h;
         BMP_Info.biXPelsPerMeter = 0;
         BMP_Info.biYPelsPerMeter = 0;
-        BMP_Info.biClrUsed = 0;
-        BMP_Info.biClrImportant = 0;
+        // for 24-bit, there is no palette, so these are zero
+        // for 8-bit, there can be up to 256 RGB values in the palette
+        
+        BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]);    // for 8b/pixel
+        BMP_Info.biClrImportant = BMP_Info.biClrUsed;
 
         // Allocate the memory we need to proceed
         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
@@ -2207,6 +2236,7 @@
         }
 
         // Get the file primed...
+        /// @todo check return value for possibility of a fatal error
         privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
 
         // Be optimistic - don't check for errors.
@@ -2217,7 +2247,16 @@
         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
         //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
         privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
-
+        if (bitsPerPixel != 24) {
+            HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            //fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image);
+            privateCallback(WRITE, (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            if (0 && sizeof(WebColorPalette) % 4) {
+                const uint8_t padd[] = { 0, 0, 0 };
+                //fwrite(&padd, sizeof(char), (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4, Image);
+                privateCallback(WRITE, (uint8_t *)&padd, (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4);
+            }
+        }
         //color_t transparency = GetBackgroundTransparencyColor();
         LayerMode_T ltpr0 = GetLayerMode();
 
@@ -2253,8 +2292,8 @@
                     ERR("getPixelStream error, and no recovery handler...");
                 }
             }
-            INFO("1st Color: %04X", pixelBuffer[0]);
-            HexDump("Raster", (uint8_t *)pixelBuffer, w * 3);
+            INFO("Line: %3d", j);
+            //HexDump("Raster", (uint8_t *)pixelBuffer, w * sizeof(color_t));
             // Convert the local buffer to RGBQUAD format
             int lb = 0;
             for (int i=0; i<w; i++) {
@@ -2270,32 +2309,42 @@
                     case 2: // lighten-overlay  (@TODO Not supported yet)
                     case 6: // Floating Windows     (@TODO not sure how to support)
                     default: // Reserved...
+                        //lineBuffer[lb++] = q0.rgbBlue;
+                        //lineBuffer[lb++] = q0.rgbGreen;
+                        //lineBuffer[lb++] = q0.rgbRed;
+                        break;
+                    case 3: // transparent mode (@TODO Read the background color register for transparent)
+                    case 4: // boolean or
+                        q0.rgbBlue = q0.rgbBlue | q1.rgbBlue;
+                        q0.rgbGreen = q0.rgbGreen | q1.rgbGreen;
+                        q0.rgbRed = q0.rgbRed | q1.rgbRed;
+                        break;
+                    case 5: // boolean AND
+                        q0.rgbBlue = q0.rgbBlue & q1.rgbBlue;
+                        q0.rgbGreen = q0.rgbGreen & q1.rgbGreen;
+                        q0.rgbRed = q0.rgbRed & q1.rgbRed;
+                        break;
+                }
+                switch (bitsPerPixel) {
+                    case 24:
                         lineBuffer[lb++] = q0.rgbBlue;
                         lineBuffer[lb++] = q0.rgbGreen;
                         lineBuffer[lb++] = q0.rgbRed;
                         break;
-                    case 3: // transparent mode (@TODO Read the background color register for transparent)
-                    case 4: // boolean or
-                        lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
-                        lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
-                        lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
-                        break;
-                    case 5: // boolean AND
-                        lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
-                        lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
-                        lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
+                    case 8:
+                    default:
+                        lineBuffer[lb++] = FindNearestWebColor(q0.rgbRed,q0.rgbGreen,q0.rgbBlue);
                         break;
                 }
             }
-            if (j == h - 1) {
-                HexDump("LineBuffer", lineBuffer, lineBufSize);
-            }
+            //if (j == h - 1) {
+            //    HexDump("Line", lineBuffer, lineBufSize);
+            //}
             // Write to disk
             privateCallback(WRITE, (uint8_t *)lineBuffer, lineBufSize);
         }
         SelectDrawingLayer(prevLayer);
         privateCallback(CLOSE, NULL, 0);
-        
         #ifndef DOUBLEBUF
         if (pixelBuffer2)
             swFree(pixelBuffer2);
@@ -2311,6 +2360,7 @@
 }
 
 
+
 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP, uint8_t bitsPerPixel)
 {
     BITMAPFILEHEADER BMP_Header;
--- a/RA8875.h	Wed Feb 13 04:20:12 2019 +0000
+++ b/RA8875.h	Thu Feb 14 12:34:52 2019 +0000
@@ -329,7 +329,7 @@
         TP_Manual,             ///< Manual touch detection mode
     } tpmode_t;
 
-    /// printscreen callback commands
+    /// PrintScreen callback commands
     typedef enum
     {
         OPEN,       ///< command to open the file. cast uint32_t * to the buffer to get the total size to be written.
@@ -2677,6 +2677,8 @@
     /// @param[in] Name_BMP is the filename to write the image to.
     /// @param[in] bitsPerPixel is optional, defaults to 24, and only 
     ///             accepts the values 24, 8
+    ///             NOTE: The downscaling is CPU intensive, and the operation
+    ///             takes longer.
     /// @return success or error code.
     ///
     RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP, uint8_t bitsPerPixel = 24);
@@ -2701,9 +2703,13 @@
     /// @param[in] y is the top edge of the region to capture
     /// @param[in] w is the width of the region to capture
     /// @param[in] h is the height of the region to capture.
+    /// @param[in] bitsPerPixel is optional, defaults to 24, and only 
+    ///             accepts the values 24, 8
+    ///             NOTE: The downscaling is CPU intensive, and the operation
+    ///             takes longer.
     /// @return success or error code.
     ///
-    RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h);
+    RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, uint8_t bitsPerPixel = 24);
 
     
     /// PrintScreen callback registration.