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