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
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 }
Generated on Tue Jul 12 2022 17:28:36 by 1.7.2