KSM edits to RA8875

Dependents:   Liz_Test_Code

Revision:
164:76edd7d9cb68
Parent:
163:17526689a3ed
Child:
165:695c24cc5197
--- 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;