LCD LIB
Fork of RA8875 by
Embed:
(wiki syntax)
Show/hide line numbers
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 20:19:46 by 1.7.2