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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GraphicsDisplay.cpp Source File

GraphicsDisplay.cpp

00001 /* mbed GraphicsDisplay Display Library Base Class
00002  * Copyright © 2007-2009 sford
00003  * Released under the MIT License: http://mbed.org/license/mit
00004  *
00005  * Derivative work by D.Smart 2014
00006  * 201807 Scalable soft-fonts and gif support
00007  *
00008  */
00009 
00010 #include "GraphicsDisplay.h"
00011 #include "Bitmap.h"
00012 #include "string.h"
00013 
00014 //#include "Utility.h"            // private memory manager
00015 #ifndef UTILITY_H
00016 #define swMalloc malloc         // use the standard
00017 #define swFree free
00018 #endif
00019 
00020 //#define DEBUG "GD  "
00021 // ...
00022 // INFO("Stuff to show %d", var); // new-line is automatically appended
00023 //
00024 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
00025 #define INFO(x, ...) std::printf("[INF %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00026 #define WARN(x, ...) std::printf("[WRN %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00027 #define ERR(x, ...)  std::printf("[ERR %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00028 static void HexDump(const char * title, const uint8_t * p, int count)
00029 {
00030     int i;
00031     char buf[100] = "0000: ";
00032 
00033     if (*title)
00034         INFO("%s", title);
00035     for (i=0; i<count; ) {
00036         sprintf(buf + strlen(buf), "%02X ", *(p+i));
00037         if ((++i & 0x0F) == 0x00) {
00038             INFO("%s", buf);
00039             if (i < count)
00040                 sprintf(buf, "%04X: ", i);
00041             else
00042                 buf[0] = '\0';
00043         }
00044     }
00045     if (strlen(buf))
00046         INFO("%s", buf);
00047 }
00048 #else
00049 #define INFO(x, ...)
00050 #define WARN(x, ...)
00051 #define ERR(x, ...)
00052 #define HexDump(a, b, c)
00053 #endif
00054 
00055 
00056 char mytolower(char a) {
00057     if (a >= 'A' && a <= 'Z')
00058         return (a - 'A' + 'a');
00059     else
00060         return a;
00061 }
00062 /// mystrnicmp exists because not all compiler libraries have this function.
00063 ///
00064 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which
00065 /// is outside the scope of this C-portable set of functions.
00066 ///
00067 /// @param l is a pointer to the string on the left
00068 /// @param r is a pointer to the string on the right
00069 /// @param n is the number of characters to compare
00070 /// @returns -1 if l < r
00071 /// @returns 0 if l == r
00072 /// @returns +1 if l > r
00073 ///
00074 int mystrnicmp(const char *l, const char *r, size_t n) {
00075     int result = 0;
00076 
00077     if (n != 0) {
00078         do {
00079             result = mytolower(*l++) - mytolower(*r++);
00080         } while ((result == 0) && (*l != '\0') && (--n > 0));
00081     }
00082     if (result < -1)
00083         result = -1;
00084     else if (result > 1)
00085         result = 1;
00086     return result;
00087 }
00088 
00089 
00090 GraphicsDisplay::GraphicsDisplay(const char *name)
00091     : TextDisplay(name)
00092 {
00093     font = NULL;
00094     img_x = 0;
00095     img_y = 0;
00096     _x = 0;
00097     _y = 0;
00098     fontScaleX = 0;
00099     fontScaleY = 0;
00100     memset(&screen_descriptor, 0, sizeof(gif_screen_descriptor_t));
00101     global_color_table = NULL;
00102     global_color_table_size = 0;
00103     local_color_table = NULL;
00104     local_color_table_size = 0;
00105     screen_descriptor_isvalid = false;
00106     memset(&windowrect, 0, sizeof(rect_t));
00107 }
00108 
00109 //GraphicsDisplay::~GraphicsDisplay()
00110 //{
00111 //}
00112 
00113 #if 0
00114 rect_t GraphicsDisplay::GetWindow() {
00115     return windowrect;
00116 }
00117 
00118 rect_t GraphicsDisplay::SetWindow(rect_t r)
00119 {
00120     return SetWindow(r.p1.x, r.p1.y, r.p2.x, r.p2.y);
00121 }
00122 
00123 rect_t GraphicsDisplay::SetWindow(loc_t x1, loc_t y1, loc_t x2, loc_t y2)
00124 {
00125     rect_t oldWin = windowrect;
00126     dim_t tempWidth, tempHeight;
00127     INFO("SetWindow(%d,%d)-(%d,%d)", x1, y1, x2, y2);
00128     // Correct the initial values (0,-1) - (0,-1)
00129     if (x2 == (loc_t)-1) x2 = width() - 1;
00130     if (y2 == (loc_t)-1) y2 = height() - 1;
00131     // Sanity check the parameters.
00132     if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0
00133         || x1 >= width() || y1 >= height()
00134         || x2 >= width() || y2 >= height()) {
00135         rect_t nullRect = { 0,0,0,0 };
00136         return nullRect;
00137     }
00138     switch (screen_orientation) {
00139     case rotate_0:
00140     case rotate_180:
00141         windowrect.p1.x = x1;
00142         windowrect.p1.y = y1;
00143         windowrect.p2.x = x2;
00144         windowrect.p2.y = y2;
00145         tempWidth = RAmax(virt_screenwidth, virt_screenheight);
00146         tempHeight = RAmin(virt_screenwidth, virt_screenheight);
00147         virt_screenwidth = tempWidth;
00148         virt_screenheight = tempHeight;
00149         //GraphicsDisplay::SetWindow(x1, y1, x2, y2);
00150         WriteCommandW(RA8875_HSAW0, x1);
00151         WriteCommandW(RA8875_VSAW0, y1);
00152         WriteCommandW(RA8875_HEAW0, x2);
00153         WriteCommandW(RA8875_VEAW0, y2);
00154         break;
00155     case rotate_90:
00156     case rotate_270:
00157         windowrect.p1.x = y1;
00158         windowrect.p1.y = x1;
00159         windowrect.p2.x = y2;
00160         windowrect.p2.y = x2;
00161         tempWidth = RAmin(virt_screenwidth, virt_screenheight);
00162         tempHeight = RAmax(virt_screenwidth, virt_screenheight);
00163         virt_screenwidth = tempWidth;
00164         virt_screenheight = tempHeight;
00165         //GraphicsDisplay::SetWindow(x1, y1, x2, y2);
00166         WriteCommandW(RA8875_HSAW0, y1);
00167         WriteCommandW(RA8875_VSAW0, x1);
00168         WriteCommandW(RA8875_HEAW0, y2);
00169         WriteCommandW(RA8875_VEAW0, x2);
00170         break;
00171     }
00172     return oldWin;
00173 }
00174 #endif
00175 
00176 RetCode_t GraphicsDisplay::SelectUserFont(const unsigned char * _font)
00177 {
00178     font = _font;     // trusting them, but it might be good to put some checks in here...
00179     return noerror;
00180 }
00181 
00182 int GraphicsDisplay::character(int x, int y, int c)
00183 {
00184     return fontblit(x, y, c);
00185 }
00186 
00187 RetCode_t GraphicsDisplay::_putp(color_t color)
00188 {
00189     rect_t win = GetWindow();
00190     pixel(_x, _y, color);
00191     // update pixel location based on window settings
00192     _x++;
00193     if(_x > win.p2.x) {
00194         _x = win.p1.x;
00195         _y++;
00196         if(_y > win.p2.y) {
00197             _y = win.p1.y;
00198         }
00199     }
00200     return noerror;
00201 }
00202 
00203 RetCode_t GraphicsDisplay::fill(loc_t x, loc_t y, dim_t w, dim_t h, color_t color)
00204 {
00205     return fillrect(x,y, x+w, y+h, color);
00206 }
00207 
00208 RetCode_t GraphicsDisplay::cls(uint16_t layers)
00209 {
00210     uint16_t oldLayer = 0;
00211     if (layers & 1) {
00212         oldLayer = SelectDrawingLayer(0);
00213         fill(0, 0, width(), height(), _background);
00214     }
00215     if (layers & 2) {
00216         oldLayer = SelectDrawingLayer(1);
00217         fill(0, 0, width(), height(), _background);
00218     }
00219     SelectDrawingLayer(oldLayer);
00220     return noerror;
00221 }
00222 
00223 
00224 RetCode_t GraphicsDisplay::blit(loc_t x, loc_t y, dim_t w, dim_t h, const int * color)
00225 {
00226     rect_t restore = SetWindow(x, y, x + w, y + h);
00227     _StartGraphicsStream();
00228     for (int i=0; i<w*h; i++) {
00229         _putp(color[i]);
00230     }
00231     _EndGraphicsStream();
00232     SetWindow(restore);
00233     return noerror;
00234 }
00235 
00236 // 8 byte "info" section
00237 //0x00,                // unknown    ????????
00238 //0x00,                // unknown    ????????
00239 //0x20,0x00,           // First char 32
00240 //0x7F,0x00,           // Last char  127
00241 //0x25,                // Font Height 37
00242 //0x00,                // Unknown      0  ????????
00243 //
00244 //0x01,0x88,0x01,0x00  // ' ' is  1 pixel  wide, data is at offset 0x0188
00245 //0x0B,0xAD,0x01,0x00  // '!' is 11 pixels wide, data is at offset 0x01AD
00246 //0x0D,0xF7,0x01,0x00  // '"' is 13 pixels wide, data is at offset 0x01F7
00247 //...
00248 //0x00,...             // ' ' data stream.
00249 //0x00,0x06,0x00,0x07,0x80,0x07,0xC0,0x07,0xC0,0x07,0xC0 // '!'
00250 //...
00251 
00252 
00253 const uint8_t * GraphicsDisplay::getCharMetrics(const unsigned char c, dim_t * width, dim_t * height)
00254 {
00255     uint16_t offsetToCharLookup;
00256     uint16_t firstChar = font[3] * 256 + font[2];
00257     uint16_t lastChar  = font[5] * 256 + font[4];
00258     dim_t charHeight = font[6];
00259     const unsigned char * charRecord;   // width, data, data, data, ...
00260 
00261     INFO("first:%d, last:%d, c:%02X '%c'", firstChar, lastChar, c, (c >= ' ' && c <= '~') ? c : '-');
00262     if (c < firstChar || c > lastChar)
00263         return NULL;       // advance zero pixels since it was unprintable...
00264 
00265     // 8 bytes of preamble to the first level lookup table
00266     offsetToCharLookup = 8 + 4 * (c - firstChar);    // 4-bytes: width(pixels), 16-bit offset from table start, 0
00267     dim_t charWidth = font[offsetToCharLookup];
00268     charRecord = font + font[offsetToCharLookup + 2] * 256 + font[offsetToCharLookup + 1];
00269     //INFO("hgt:%d, wdt:%d", charHeight, charWidth);
00270     if (width)
00271         *width = charWidth;
00272     if (height)
00273         *height = charHeight;
00274     return charRecord;
00275 }
00276 
00277 
00278 int GraphicsDisplay::fontblit(loc_t x, loc_t y, const unsigned char c)
00279 {
00280     const uint8_t * charRecord;         // pointer to char data; width, data, data, data, ...
00281     dim_t charWidth, charHeight;        // metrics for the raw char in the font table
00282     charRecord = getCharMetrics(c, &charWidth, &charHeight);
00283     if (charRecord) {
00284         INFO("wdt:%d, hgt:%d", charWidth, charHeight);
00285         booleanStream(x,y,charWidth, charHeight, charRecord);
00286         return charWidth * fontScaleX;
00287     } else {
00288         return 0;
00289     }
00290 }
00291 
00292 // BMP Color Palette is BGRx
00293 //      BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000
00294 // RGB16 is
00295 //      RRRR RGGG GGGB BBBB
00296 // swap to little endian
00297 //      GGGB BBBB RRRR RGGG
00298 color_t GraphicsDisplay::RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i)
00299 {
00300     color_t c;
00301 
00302     c  = ((colorPalette[i].rgbBlue  >> 3) <<  0);
00303     c |= ((colorPalette[i].rgbGreen >> 2) <<  5);
00304     c |= ((colorPalette[i].rgbRed   >> 3) << 11);
00305     return c;
00306 }
00307 
00308 // RGB16 little endian
00309 
00310 //      GGGB BBBB RRRR RGGG
00311 // swap
00312 //      RRRR RGGG GGGB BBBB
00313 //                RRRR R
00314 // extend to BMP Color Palette is BGRx
00315 //      BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000
00316 RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c)
00317 {
00318     RGBQUAD q;
00319 
00320     memset(&q, 0, sizeof(q));
00321     //c = (c << 8) | (c >> 8);    // swap
00322     q.rgbBlue  = ((c & 0x001F) << 3) | (c & 0x07);          /* Blue value */
00323     q.rgbGreen = ((c & 0x07E0) >> 3) | ((c >> 9) & 0x03);   /* Green value */
00324     q.rgbRed   = ((c & 0xF800) >> 8) | ((c >> 13) & 0x07);  /* Red value */
00325     q.rgbReserved = 0;
00326     return q;
00327 }
00328 
00329 RetCode_t GraphicsDisplay::_RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image, rect_t * infoOnly)
00330 {
00331     BITMAPINFOHEADER BMP_Info;
00332     RGBQUAD * colorPalette = NULL;
00333     int colorCount;
00334     uint8_t * lineBuffer = NULL;
00335     color_t * pixelBuffer = NULL;
00336     uint16_t BPP_t;
00337     dim_t PixelWidth, PixelHeight;
00338     unsigned int    i, offset;
00339     int padd,j;
00340     #ifdef DEBUG
00341     //uint32_t start_data;
00342     #endif
00343 
00344     // Now, Read the bitmap info header
00345     fread(&BMP_Info, 1, sizeof(BMP_Info), Image);
00346     //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
00347     BPP_t = BMP_Info.biBitCount;
00348     //INFO("biBitCount %04X", BPP_t);
00349     if (BPP_t != 1 && BPP_t != 4 && BPP_t != 8 && BPP_t != 16 && BPP_t != 24) { // Support 4, 8, 16, 24-bits per pixel
00350         fclose(Image);
00351         return(not_supported_format);
00352     }
00353     if (BMP_Info.biCompression != 0) {  // Only the "no comporession" option is supported.
00354         fclose(Image);
00355         return(not_supported_format);
00356     }
00357     PixelHeight = BMP_Info.biHeight;
00358     PixelWidth = BMP_Info.biWidth;
00359     //INFO("(%d x,%d h) (%d w,%d h) (%d w,%d h)", x,y, PixelWidth,PixelHeight, width(), height());
00360     if (infoOnly) {
00361         infoOnly->p1.x = x;
00362         infoOnly->p1.y = y;
00363         infoOnly->p2.x = x+PixelWidth-1;
00364         infoOnly->p2.y = y+PixelHeight-1;
00365         return (noerror);
00366     }
00367 
00368     if (PixelHeight > height() + y || PixelWidth > width() + x) {
00369         fclose(Image);
00370         ERR("too big: img: (%d,%d), xy: (%d,%d), screen: (%d,%d)\r\n",
00371             PixelWidth, PixelHeight, x, y, width(), height());
00372         return(image_too_big);
00373     }
00374     if (BMP_Info.biBitCount <= 8) {
00375         int paletteSize;
00376         // Read the color palette
00377         colorCount = 1 << BMP_Info.biBitCount;
00378         paletteSize = sizeof(RGBQUAD) * colorCount;
00379         colorPalette = (RGBQUAD *)swMalloc(paletteSize);
00380         if (colorPalette == NULL) {
00381             fclose(Image);
00382             return(not_enough_ram);
00383         }
00384         fread(colorPalette, 1, paletteSize, Image);
00385         //HexDump("Color Palette", (uint8_t *)colorPalette, paletteSize);
00386     }
00387 
00388     int lineBufSize = ((BPP_t * PixelWidth + 7)/8);
00389     //INFO("BPP_t %d, PixelWidth %d, lineBufSize %d", BPP_t, PixelWidth, lineBufSize);
00390     lineBuffer = (uint8_t *)swMalloc(lineBufSize);
00391     if (lineBuffer == NULL) {
00392         swFree(colorPalette);
00393         fclose(Image);
00394         return(not_enough_ram);
00395     }
00396     pixelBuffer = (color_t *)swMalloc(PixelWidth * sizeof(color_t));
00397     if (pixelBuffer == NULL) {
00398         swFree(lineBuffer);
00399         if (colorPalette)
00400             swFree(colorPalette);
00401         fclose(Image);
00402         return(not_enough_ram);
00403     }
00404 
00405     padd = (lineBufSize % 4);
00406     if (padd)
00407         padd = 4 - padd;
00408 
00409     // Define window for top to bottom and left to right so writing auto-wraps
00410     rect_t restore = SetWindow(x,y, x+PixelWidth-1,y+PixelHeight-1);
00411 //    SetGraphicsCursor(x, y);
00412 //    _StartGraphicsStream();
00413 
00414     //start_data = BMP_Info.bfOffBits;
00415     //HexDump("Raw Data", (uint8_t *)&start_data, 32);
00416     //INFO("(%d,%d) (%d,%d), [%d,%d]", x,y, PixelWidth,PixelHeight, lineBufSize, padd);
00417     for (j = PixelHeight - 1; j >= 0; j--) {                //Lines bottom up
00418         offset = fileOffset + j * (lineBufSize + padd);     // start of line
00419         fseek(Image, offset, SEEK_SET);
00420         fread(lineBuffer, 1, lineBufSize, Image);           // read a line - slow !
00421         //INFO("offset: %6X", offset);
00422         //HexDump("Line", lineBuffer, lineBufSize);
00423         for (i = 0; i < PixelWidth; i++) {                  // copy pixel data to TFT
00424             if (BPP_t == 1) {
00425                 uint8_t dPix = lineBuffer[i/8];
00426                 uint8_t bMask = 0x80 >> (i % 8);
00427                 uint8_t bit = (bMask & dPix) ? 0 : 1;
00428                 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, bit);
00429             } else if (BPP_t == 4) {
00430                 uint8_t dPix = lineBuffer[i/2];
00431                 if ((i & 1) == 0)
00432                     dPix >>= 4;
00433                 dPix &= 0x0F;
00434                 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix);
00435             } else if (BPP_t == 8) {
00436                 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]);
00437             } else if (BPP_t == 16) {
00438                 pixelBuffer[i] = lineBuffer[i];
00439             } else if (BPP_t == 24) {
00440                 color_t color;
00441                 color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]);
00442                 pixelBuffer[i] = color;
00443             }
00444         }
00445         pixelStream(pixelBuffer, PixelWidth, x, y++);
00446     }
00447 //    _EndGraphicsStream();
00448     SetWindow(restore);
00449     swFree(pixelBuffer);      // don't leak memory
00450     swFree(lineBuffer);
00451     if (colorPalette)
00452         swFree(colorPalette);
00453     return (noerror);
00454 }
00455 
00456 rect_t GraphicsDisplay::GetImageRect(loc_t x, loc_t y, const char* Filename)
00457 {
00458     rect_t r = { 0, 0, 0, 0 };
00459 
00460     RenderImageFile(x, y, Filename, &r);
00461     return r;
00462 }
00463 
00464 rect_t GraphicsDisplay::GetImageRect(point_t pt, const char* Filename)
00465 {
00466     rect_t r = { 0, 0, 0, 0 };
00467 
00468     RenderImageFile(pt, Filename, &r);
00469     return r;
00470 }
00471 
00472 RetCode_t GraphicsDisplay::RenderImageFile(point_t pt, const char* FileName, rect_t* getDim) {
00473     return RenderImageFile(pt.x, pt.y, FileName, getDim);
00474 }
00475 
00476 RetCode_t GraphicsDisplay::RenderImageFile(loc_t x, loc_t y, const char * FileName, rect_t * getDim) {
00477     if (mystrnicmp(FileName + strlen(FileName) - 4, ".bmp", 4) == 0) {
00478         return RenderBitmapFile(x, y, FileName, getDim);
00479     } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".jpg", 4) == 0) {
00480         if (getDim)
00481             return bad_parameter;
00482         return RenderJpegFile(x, y, FileName);
00483     } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".ico", 4) == 0) {
00484         if (getDim)
00485             return bad_parameter;
00486         return RenderIconFile(x, y, FileName);
00487     } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".gif", 4) == 0) {
00488         if (getDim)
00489             return bad_parameter;
00490         return RenderGIFFile(x, y, FileName);
00491     } else {
00492         return bad_parameter;
00493     }
00494 }
00495 
00496 RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP, rect_t * getDim)
00497 {
00498     BITMAPFILEHEADER BMP_Header;
00499 
00500     INFO("Opening {%s}", Name_BMP);
00501     FILE *Image = fopen(Name_BMP, "rb");
00502     if (!Image) {
00503         return(file_not_found);
00504     }
00505 
00506     fread(&BMP_Header, 1, sizeof(BMP_Header), Image);      // get the BMP Header
00507     INFO("bfType %04X, Header size: %d", BMP_Header.bfType, sizeof(BITMAPFILEHEADER));
00508     //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
00509     if (BMP_Header.bfType != BF_TYPE) {
00510         fclose(Image);
00511         return(not_bmp_format);
00512     }
00513     //INFO("bfOffits %04lX", BMP_Header.bfOffBits);
00514     RetCode_t rt = _RenderBitmap(x, y, BMP_Header.bfOffBits, Image, getDim);
00515     if (rt != noerror) {
00516         return rt;
00517     } else {
00518         fclose(Image);
00519         return (noerror);
00520     }
00521 }
00522 
00523 RetCode_t GraphicsDisplay::RenderJpegFile(loc_t x, loc_t y, const char *Name_JPG)
00524 {
00525     #define JPEG_WORK_SPACE_SIZE 3100   // Worst case requirements for the decompression
00526     JDEC * jdec;
00527     uint16_t * work;
00528     RetCode_t r = noerror;  // start optimistic
00529     FILE * fh = fopen(Name_JPG, "rb");
00530 
00531     if (!fh)
00532         return(file_not_found);
00533     //INFO("RenderJpegFile(%d,%d,%s)", x,y, Name_JPG);
00534     work = (uint16_t *)swMalloc(JPEG_WORK_SPACE_SIZE);
00535     if (work) {
00536         jdec = (JDEC *)swMalloc(sizeof(JDEC));
00537         if (jdec) {
00538             // Original
00539             //memset(work, 0, JPEG_WORK_SPACE_SIZE/sizeof(uint16_t));
00540             // Revised
00541             memset(work, 0, JPEG_WORK_SPACE_SIZE);
00542             memset(jdec, 0, sizeof(JDEC));
00543             r = (RetCode_t)jd_prepare(jdec, NULL, work, JPEG_WORK_SPACE_SIZE, fh);
00544             INFO("jd_prepare returned %d", r);
00545 
00546             if (r == noerror) {
00547                 img_x = x;  // save the origin for the privOutput function
00548                 img_y = y;
00549                 r = (RetCode_t)jd_decomp(jdec, NULL, 0);
00550             } else {
00551                 r = not_supported_format;   // error("jd_prepare error:%d", r);
00552             }
00553             swFree(jdec);
00554         } else {
00555             WARN("checkpoint");
00556             r = not_enough_ram;
00557         }
00558         swFree(work);
00559     } else {
00560         WARN("checkpoint");
00561         r = not_enough_ram;
00562     }
00563     fclose(fh);
00564     return r;   // error("jd_decomp error:%d", r);
00565 }
00566 
00567 RetCode_t GraphicsDisplay::RenderIconFile(loc_t x, loc_t y, const char *Name_ICO)
00568 {
00569     ICOFILEHEADER ICO_Header;
00570     ICODIRENTRY ICO_DirEntry;
00571 
00572     INFO("Opening {%s}", Name_ICO);
00573     FILE *Image = fopen(Name_ICO, "rb");
00574     if (!Image) {
00575         return(file_not_found);
00576     }
00577 
00578     fread(&ICO_Header, 1, sizeof(ICO_Header), Image);      // get the BMP Header
00579     HexDump("ICO_Header", (uint8_t *)&ICO_Header, sizeof(ICO_Header));
00580     if (ICO_Header.Reserved_zero != 0
00581     || ICO_Header.icType != IC_TYPE
00582     || ICO_Header.icImageCount == 0) {
00583         fclose(Image);
00584         return(not_ico_format);
00585     }
00586 
00587     // Read ONLY the first of n possible directory entries.
00588     fread(&ICO_DirEntry, 1, sizeof(ICO_DirEntry), Image);
00589     HexDump("ICO_DirEntry", (uint8_t *)&ICO_DirEntry, sizeof(ICO_DirEntry));
00590     INFO("biBitCount %04X", ICO_DirEntry.biBitCount);
00591     if (ICO_DirEntry.biBitCount != 0) {     // Expecting this to be zero for ico
00592         fclose(Image);
00593         return(not_supported_format);
00594     }
00595 
00596     RetCode_t rt = _RenderBitmap(x, y, ICO_DirEntry.bfOffBits, Image);
00597     if (rt == noerror) {
00598         fclose(Image);
00599         return (noerror);
00600     } else {
00601         return rt;
00602     }
00603 }
00604 
00605 int GraphicsDisplay::columns()
00606 {
00607     return width() / 8;
00608 }
00609 
00610 int GraphicsDisplay::rows()
00611 {
00612     return height() / 8;
00613 }