Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 RetCode_t GraphicsDisplay::SelectUserFont(const unsigned char * _font) 00114 { 00115 font = _font; // trusting them, but it might be good to put some checks in here... 00116 return noerror; 00117 } 00118 00119 int GraphicsDisplay::character(int x, int y, int c) 00120 { 00121 return fontblit(x, y, c); 00122 } 00123 00124 RetCode_t GraphicsDisplay::window(rect_t r) 00125 { 00126 return window(r.p1.x, r.p1.y, r.p2.x + 1 - r.p1.x, r.p2.y + 1 - r.p1.y); 00127 } 00128 00129 RetCode_t GraphicsDisplay::window(loc_t x, loc_t y, dim_t _width, dim_t _height) 00130 { 00131 if (_width == (dim_t)-1) 00132 _width = width() - x; 00133 if (_height == (dim_t)-1) 00134 _height = height() - y; 00135 00136 // Save the window metrics 00137 windowrect.p1.x = x; 00138 windowrect.p1.y = y; 00139 windowrect.p2.x = x + _width - 1; 00140 windowrect.p2.y = y + _height - 1; 00141 // current pixel location 00142 _x = x; 00143 _y = y; 00144 return noerror; 00145 } 00146 00147 RetCode_t GraphicsDisplay::WindowMax(void) 00148 { 00149 return window(0,0, width(),height()); 00150 } 00151 00152 RetCode_t GraphicsDisplay::_putp(color_t color) 00153 { 00154 pixel(_x, _y, color); 00155 // update pixel location based on window settings 00156 _x++; 00157 if(_x > windowrect.p2.x) { 00158 _x = windowrect.p1.x; 00159 _y++; 00160 if(_y > windowrect.p2.y) { 00161 _y = windowrect.p1.y; 00162 } 00163 } 00164 return noerror; 00165 } 00166 00167 RetCode_t GraphicsDisplay::fill(loc_t x, loc_t y, dim_t w, dim_t h, color_t color) 00168 { 00169 return fillrect(x,y, x+w, y+h, color); 00170 } 00171 00172 RetCode_t GraphicsDisplay::cls(uint16_t layers) 00173 { 00174 int restore = GetDrawingLayer(); 00175 if (layers & 1) { 00176 SelectDrawingLayer(0); 00177 fill(0, 0, width(), height(), _background); 00178 } 00179 if (layers & 2) { 00180 SelectDrawingLayer(1); 00181 fill(0, 0, width(), height(), _background); 00182 } 00183 SelectDrawingLayer(restore); 00184 return noerror; 00185 } 00186 00187 RetCode_t GraphicsDisplay::blit(loc_t x, loc_t y, dim_t w, dim_t h, const int * color) 00188 { 00189 rect_t restore = windowrect; 00190 window(x, y, w, h); 00191 _StartGraphicsStream(); 00192 for (int i=0; i<w*h; i++) { 00193 _putp(color[i]); 00194 } 00195 _EndGraphicsStream(); 00196 return window(restore); 00197 } 00198 00199 // 8 byte "info" section 00200 //0x00, // unknown ???????? 00201 //0x00, // unknown ???????? 00202 //0x20,0x00, // First char 32 00203 //0x7F,0x00, // Last char 127 00204 //0x25, // Font Height 37 00205 //0x00, // Unknown 0 ???????? 00206 // 00207 //0x01,0x88,0x01,0x00 // ' ' is 1 pixel wide, data is at offset 0x0188 00208 //0x0B,0xAD,0x01,0x00 // '!' is 11 pixels wide, data is at offset 0x01AD 00209 //0x0D,0xF7,0x01,0x00 // '"' is 13 pixels wide, data is at offset 0x01F7 00210 //... 00211 //0x00,... // ' ' data stream. 00212 //0x00,0x06,0x00,0x07,0x80,0x07,0xC0,0x07,0xC0,0x07,0xC0 // '!' 00213 //... 00214 00215 00216 const uint8_t * GraphicsDisplay::getCharMetrics(const unsigned char c, dim_t * width, dim_t * height) 00217 { 00218 uint16_t offsetToCharLookup; 00219 uint16_t firstChar = font[3] * 256 + font[2]; 00220 uint16_t lastChar = font[5] * 256 + font[4]; 00221 dim_t charHeight = font[6]; 00222 const unsigned char * charRecord; // width, data, data, data, ... 00223 00224 INFO("first:%d, last:%d, c:%d", firstChar, lastChar, c); 00225 if (c < firstChar || c > lastChar) 00226 return NULL; // advance zero pixels since it was unprintable... 00227 00228 // 8 bytes of preamble to the first level lookup table 00229 offsetToCharLookup = 8 + 4 * (c - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 00230 dim_t charWidth = font[offsetToCharLookup]; 00231 charRecord = font + font[offsetToCharLookup + 2] * 256 + font[offsetToCharLookup + 1]; 00232 //INFO("hgt:%d, wdt:%d", charHeight, charWidth); 00233 if (width) 00234 *width = charWidth; 00235 if (height) 00236 *height = charHeight; 00237 return charRecord; 00238 } 00239 00240 00241 int GraphicsDisplay::fontblit(loc_t x, loc_t y, const unsigned char c) 00242 { 00243 const uint8_t * charRecord; // pointer to char data; width, data, data, data, ... 00244 dim_t charWidth, charHeight; // metrics for the raw char in the font table 00245 charRecord = getCharMetrics(c, &charWidth, &charHeight); 00246 if (charRecord) { 00247 INFO("hgt:%d, wdt:%d", charHeight, charWidth); 00248 booleanStream(x,y,charWidth, charHeight, charRecord); 00249 return charWidth * fontScaleX; 00250 } else { 00251 return 0; 00252 } 00253 } 00254 00255 // BMP Color Palette is BGRx 00256 // BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000 00257 // RGB16 is 00258 // RRRR RGGG GGGB BBBB 00259 // swap to little endian 00260 // GGGB BBBB RRRR RGGG 00261 color_t GraphicsDisplay::RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i) 00262 { 00263 color_t c; 00264 00265 c = ((colorPalette[i].rgbBlue >> 3) << 0); 00266 c |= ((colorPalette[i].rgbGreen >> 2) << 5); 00267 c |= ((colorPalette[i].rgbRed >> 3) << 11); 00268 return c; 00269 } 00270 00271 // RGB16 little endian 00272 // GGGB BBBB RRRR RGGG 00273 // swap 00274 // RRRR RGGG GGGB BBBB 00275 // RRRR R 00276 // extend to BMP Color Palette is BGRx 00277 // BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000 00278 RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c) 00279 { 00280 RGBQUAD q; 00281 00282 memset(&q, 0, sizeof(q)); 00283 //c = (c << 8) | (c >> 8); // swap 00284 q.rgbBlue = ((c & 0x001F) << 3) | (c & 0x07); /* Blue value */ 00285 q.rgbGreen = ((c & 0x07E0) >> 3) | ((c >> 9) & 0x03); /* Green value */ 00286 q.rgbRed = ((c & 0xF800) >> 8) | ((c >> 13) & 0x07); /* Red value */ 00287 q.rgbReserved = 0; 00288 return q; 00289 } 00290 00291 RetCode_t GraphicsDisplay::_RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image, rect_t * infoOnly) 00292 { 00293 BITMAPINFOHEADER BMP_Info; 00294 RGBQUAD * colorPalette = NULL; 00295 int colorCount; 00296 uint8_t * lineBuffer = NULL; 00297 color_t * pixelBuffer = NULL; 00298 uint16_t BPP_t; 00299 dim_t PixelWidth, PixelHeight; 00300 unsigned int i, offset; 00301 int padd,j; 00302 #ifdef DEBUG 00303 //uint32_t start_data; 00304 #endif 00305 00306 // Now, Read the bitmap info header 00307 fread(&BMP_Info, 1, sizeof(BMP_Info), Image); 00308 HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 00309 BPP_t = BMP_Info.biBitCount; 00310 INFO("biBitCount %04X", BPP_t); 00311 if (BPP_t != 1 && BPP_t != 4 && BPP_t != 8 && BPP_t != 16 && BPP_t != 24) { // Support 4, 8, 16, 24-bits per pixel 00312 fclose(Image); 00313 return(not_supported_format); 00314 } 00315 if (BMP_Info.biCompression != 0) { // Only the "no comporession" option is supported. 00316 fclose(Image); 00317 return(not_supported_format); 00318 } 00319 PixelHeight = BMP_Info.biHeight; 00320 PixelWidth = BMP_Info.biWidth; 00321 INFO("(%d,%d) (%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight, width(), height()); 00322 if (infoOnly) { 00323 infoOnly->p1.x = x; 00324 infoOnly->p1.y = y; 00325 infoOnly->p2.x = x+PixelWidth; 00326 infoOnly->p2.y = y+PixelHeight; 00327 return (noerror); 00328 } 00329 00330 if (PixelHeight > height() + y || PixelWidth > width() + x) { 00331 fclose(Image); 00332 ERR("too big: img: (%d,%d), xy: (%d,%d), screen: (%d,%d)\r\n", 00333 PixelWidth, PixelHeight, x, y, width(), height()); 00334 return(image_too_big); 00335 } 00336 if (BMP_Info.biBitCount <= 8) { 00337 int paletteSize; 00338 // Read the color palette 00339 colorCount = 1 << BMP_Info.biBitCount; 00340 paletteSize = sizeof(RGBQUAD) * colorCount; 00341 colorPalette = (RGBQUAD *)swMalloc(paletteSize); 00342 if (colorPalette == NULL) { 00343 fclose(Image); 00344 return(not_enough_ram); 00345 } 00346 fread(colorPalette, 1, paletteSize, Image); 00347 HexDump("Color Palette", (uint8_t *)colorPalette, paletteSize); 00348 } 00349 00350 int lineBufSize = ((BPP_t * PixelWidth + 7)/8); 00351 INFO("BPP_t %d, PixelWidth %d, lineBufSize %d", BPP_t, PixelWidth, lineBufSize); 00352 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 00353 if (lineBuffer == NULL) { 00354 swFree(colorPalette); 00355 fclose(Image); 00356 return(not_enough_ram); 00357 } 00358 pixelBuffer = (color_t *)swMalloc(PixelWidth * sizeof(color_t)); 00359 if (pixelBuffer == NULL) { 00360 swFree(lineBuffer); 00361 if (colorPalette) 00362 swFree(colorPalette); 00363 fclose(Image); 00364 return(not_enough_ram); 00365 } 00366 00367 padd = (lineBufSize % 4); 00368 if (padd) 00369 padd = 4 - padd; 00370 00371 // Define window for top to bottom and left to right so writing auto-wraps 00372 rect_t restore = windowrect; 00373 window(x,y, PixelWidth,PixelHeight); 00374 // SetGraphicsCursor(x, y); 00375 // _StartGraphicsStream(); 00376 00377 //start_data = BMP_Info.bfOffBits; 00378 //HexDump("Raw Data", (uint8_t *)&start_data, 32); 00379 INFO("(%d,%d) (%d,%d), [%d,%d]", x,y, PixelWidth,PixelHeight, lineBufSize, padd); 00380 for (j = PixelHeight - 1; j >= 0; j--) { //Lines bottom up 00381 offset = fileOffset + j * (lineBufSize + padd); // start of line 00382 fseek(Image, offset, SEEK_SET); 00383 fread(lineBuffer, 1, lineBufSize, Image); // read a line - slow ! 00384 //INFO("offset: %6X", offset); 00385 //HexDump("Line", lineBuffer, lineBufSize); 00386 for (i = 0; i < PixelWidth; i++) { // copy pixel data to TFT 00387 if (BPP_t == 1) { 00388 uint8_t dPix = lineBuffer[i/8]; 00389 uint8_t bMask = 0x80 >> (i % 8); 00390 uint8_t bit = (bMask & dPix) ? 0 : 1; 00391 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, bit); 00392 } else if (BPP_t == 4) { 00393 uint8_t dPix = lineBuffer[i/2]; 00394 if ((i & 1) == 0) 00395 dPix >>= 4; 00396 dPix &= 0x0F; 00397 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix); 00398 } else if (BPP_t == 8) { 00399 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]); 00400 } else if (BPP_t == 16) { 00401 pixelBuffer[i] = lineBuffer[i]; 00402 } else if (BPP_t == 24) { 00403 color_t color; 00404 color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]); 00405 pixelBuffer[i] = color; 00406 } 00407 } 00408 pixelStream(pixelBuffer, PixelWidth, x, y++); 00409 } 00410 // _EndGraphicsStream(); 00411 window(restore); 00412 swFree(pixelBuffer); // don't leak memory 00413 swFree(lineBuffer); 00414 if (colorPalette) 00415 swFree(colorPalette); 00416 return (noerror); 00417 } 00418 00419 rect_t GraphicsDisplay::GetImageRect(loc_t x, loc_t y, const char *Filename) 00420 { 00421 rect_t r = { 0, 0, 0, 0}; 00422 00423 RenderImageFile(x,y,Filename, &r); 00424 return r; 00425 } 00426 00427 RetCode_t GraphicsDisplay::RenderImageFile(loc_t x, loc_t y, const char * FileName, rect_t * getDim) { 00428 if (mystrnicmp(FileName + strlen(FileName) - 4, ".bmp", 4) == 0) { 00429 return RenderBitmapFile(x, y, FileName, getDim); 00430 } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".jpg", 4) == 0) { 00431 if (getDim) 00432 return not_supported_format; 00433 return RenderJpegFile(x, y, FileName); 00434 } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".ico", 4) == 0) { 00435 if (getDim) 00436 return not_supported_format; 00437 return RenderIconFile(x, y, FileName); 00438 } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".gif", 4) == 0) { 00439 if (getDim) 00440 return not_supported_format; 00441 return RenderGIFFile(x, y, FileName); 00442 } else { 00443 return not_supported_format; 00444 } 00445 } 00446 00447 RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP, rect_t * getDim) 00448 { 00449 BITMAPFILEHEADER BMP_Header; 00450 00451 INFO("Opening {%s}", Name_BMP); 00452 FILE *Image = fopen(Name_BMP, "rb"); 00453 if (!Image) { 00454 return(file_not_found); 00455 } 00456 00457 fread(&BMP_Header, 1, sizeof(BMP_Header), Image); // get the BMP Header 00458 INFO("bfType %04X, Header size: %d", BMP_Header.bfType, sizeof(BITMAPFILEHEADER)); 00459 HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 00460 if (BMP_Header.bfType != BF_TYPE) { 00461 fclose(Image); 00462 return(not_bmp_format); 00463 } 00464 INFO("bfOffits %04X", BMP_Header.bfOffBits); 00465 RetCode_t rt = _RenderBitmap(x, y, BMP_Header.bfOffBits, Image, getDim); 00466 if (rt != noerror) { 00467 return rt; 00468 } else { 00469 fclose(Image); 00470 return (noerror); 00471 } 00472 } 00473 00474 RetCode_t GraphicsDisplay::RenderJpegFile(loc_t x, loc_t y, const char *Name_JPG) 00475 { 00476 #define JPEG_WORK_SPACE_SIZE 3100 // Worst case requirements for the decompression 00477 JDEC * jdec; 00478 uint16_t * work; 00479 RetCode_t r = noerror; // start optimistic 00480 FILE * fh = fopen(Name_JPG, "rb"); 00481 00482 if (!fh) 00483 return(file_not_found); 00484 //INFO("RenderJpegFile(%d,%d,%s)", x,y, Name_JPG); 00485 work = (uint16_t *)swMalloc(JPEG_WORK_SPACE_SIZE); 00486 if (work) { 00487 jdec = (JDEC *)swMalloc(sizeof(JDEC)); 00488 if (jdec) { 00489 // Original 00490 //memset(work, 0, JPEG_WORK_SPACE_SIZE/sizeof(uint16_t)); 00491 // Revised 00492 memset(work, 0, JPEG_WORK_SPACE_SIZE); 00493 memset(jdec, 0, sizeof(JDEC)); 00494 r = (RetCode_t)jd_prepare(jdec, NULL, work, JPEG_WORK_SPACE_SIZE, fh); 00495 INFO("jd_prepare returned %d", r); 00496 00497 if (r == noerror) { 00498 img_x = x; // save the origin for the privOutput function 00499 img_y = y; 00500 r = (RetCode_t)jd_decomp(jdec, NULL, 0); 00501 } else { 00502 r = not_supported_format; // error("jd_prepare error:%d", r); 00503 } 00504 swFree(jdec); 00505 } else { 00506 WARN("checkpoint"); 00507 r = not_enough_ram; 00508 } 00509 swFree(work); 00510 } else { 00511 WARN("checkpoint"); 00512 r = not_enough_ram; 00513 } 00514 fclose(fh); 00515 return r; // error("jd_decomp error:%d", r); 00516 } 00517 00518 RetCode_t GraphicsDisplay::RenderIconFile(loc_t x, loc_t y, const char *Name_ICO) 00519 { 00520 ICOFILEHEADER ICO_Header; 00521 ICODIRENTRY ICO_DirEntry; 00522 00523 INFO("Opening {%s}", Name_ICO); 00524 FILE *Image = fopen(Name_ICO, "rb"); 00525 if (!Image) { 00526 return(file_not_found); 00527 } 00528 00529 fread(&ICO_Header, 1, sizeof(ICO_Header), Image); // get the BMP Header 00530 HexDump("ICO_Header", (uint8_t *)&ICO_Header, sizeof(ICO_Header)); 00531 if (ICO_Header.Reserved_zero != 0 00532 || ICO_Header.icType != IC_TYPE 00533 || ICO_Header.icImageCount == 0) { 00534 fclose(Image); 00535 return(not_ico_format); 00536 } 00537 00538 // Read ONLY the first of n possible directory entries. 00539 fread(&ICO_DirEntry, 1, sizeof(ICO_DirEntry), Image); 00540 HexDump("ICO_DirEntry", (uint8_t *)&ICO_DirEntry, sizeof(ICO_DirEntry)); 00541 INFO("biBitCount %04X", ICO_DirEntry.biBitCount); 00542 if (ICO_DirEntry.biBitCount != 0) { // Expecting this to be zero for ico 00543 fclose(Image); 00544 return(not_supported_format); 00545 } 00546 00547 RetCode_t rt = _RenderBitmap(x, y, ICO_DirEntry.bfOffBits, Image); 00548 if (rt == noerror) { 00549 fclose(Image); 00550 return (noerror); 00551 } else { 00552 return rt; 00553 } 00554 } 00555 00556 int GraphicsDisplay::columns() 00557 { 00558 return width() / 8; 00559 } 00560 00561 int GraphicsDisplay::rows() 00562 { 00563 return height() / 8; 00564 }
Generated on Thu Jul 14 2022 02:03:21 by
1.7.2