KSM edits to RA8875
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 26 2022 07:46:24 by 1.7.2