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