Hexley Ball / RA8875_fork

Fork of RA8875 by David Smart

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GraphicsDisplay.cpp Source File

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 //#define DEBUG "GD"
00013 // ...
00014 // INFO("Stuff to show %d", var); // new-line is automatically appended
00015 //
00016 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
00017 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00018 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00019 #define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00020 static void HexDump(char * title, uint8_t * p, int count)
00021 {
00022     int i;
00023     char buf[100] = "0000: ";
00024     
00025     if (*title)
00026         INFO("%s", title);
00027     for (i=0; i<count; ) {
00028         sprintf(buf + strlen(buf), "%02X ", *(p+i));
00029         if ((++i & 0x0F) == 0x00) {
00030             INFO("%s", buf);
00031             if (i < count)
00032                 sprintf(buf, "%04X: ", i);
00033             else
00034                 buf[0] = '\0';
00035         }
00036     }
00037     if (strlen(buf))
00038         INFO("%s", buf);
00039 }
00040 #else
00041 #define INFO(x, ...)
00042 #define WARN(x, ...)
00043 #define ERR(x, ...)
00044 #define HexDump(a, b, c)
00045 #endif
00046 
00047 #ifdef LOCALFONT
00048 const unsigned char FONT8x8[97][8] = {
00049     0x08, 0x08, 0x08, 0X00, 0X00, 0X00, 0X00, 0X00, // columns, rows, num_bytes_per_char
00050     0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // space 0x20
00051     0x30, 0x78, 0x78, 0x30, 0x30, 0X00, 0x30, 0X00, // !
00052     0x6C, 0x6C, 0x6C, 0X00, 0X00, 0X00, 0X00, 0X00, // "
00053     0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0X00, // #
00054     0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0X00, // $
00055     0X00, 0x63, 0x66, 0x0C, 0x18, 0x33, 0x63, 0X00, // %
00056     0x1C, 0x36, 0x1C, 0x3B, 0x6E, 0x66, 0x3B, 0X00, // &
00057     0x30, 0x30, 0x60, 0X00, 0X00, 0X00, 0X00, 0X00, // '
00058     0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0X00, // (
00059     0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0X00, // )
00060     0X00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0X00, 0X00, // *
00061     0X00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0X00, 0X00, // +
00062     0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0x30, // ,
00063     0X00, 0X00, 0X00, 0x7E, 0X00, 0X00, 0X00, 0X00, // -
00064     0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0X00, // .
00065     0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0X00, // / (forward slash)
00066     0x3E, 0x63, 0x63, 0x6B, 0x63, 0x63, 0x3E, 0X00, // 0 0x30
00067     0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x7E, 0X00, // 1
00068     0x3C, 0x66, 0x06, 0x1C, 0x30, 0x66, 0x7E, 0X00, // 2
00069     0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0X00, // 3
00070     0x0E, 0x1E, 0x36, 0x66, 0x7F, 0x06, 0x0F, 0X00, // 4
00071     0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0X00, // 5
00072     0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0X00, // 6
00073     0x7E, 0x66, 0x06, 0x0C, 0x18, 0x18, 0x18, 0X00, // 7
00074     0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0X00, // 8
00075     0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0X00, // 9
00076     0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0X00, // :
00077     0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0x30, // ;
00078     0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0X00, // <
00079     0X00, 0X00, 0x7E, 0X00, 0X00, 0x7E, 0X00, 0X00, // =
00080     0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0X00, // >
00081     0x3C, 0x66, 0x06, 0x0C, 0x18, 0X00, 0x18, 0X00, // ?
00082     0x3E, 0x63, 0x6F, 0x69, 0x6F, 0x60, 0x3E, 0X00, // @ 0x40
00083     0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0X00, // A
00084     0x7E, 0x33, 0x33, 0x3E, 0x33, 0x33, 0x7E, 0X00, // B
00085     0x1E, 0x33, 0x60, 0x60, 0x60, 0x33, 0x1E, 0X00, // C
00086     0x7C, 0x36, 0x33, 0x33, 0x33, 0x36, 0x7C, 0X00, // D
00087     0x7F, 0x31, 0x34, 0x3C, 0x34, 0x31, 0x7F, 0X00, // E
00088     0x7F, 0x31, 0x34, 0x3C, 0x34, 0x30, 0x78, 0X00, // F
00089     0x1E, 0x33, 0x60, 0x60, 0x67, 0x33, 0x1F, 0X00, // G
00090     0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0X00, // H
00091     0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // I
00092     0x0F, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0X00, // J
00093     0x73, 0x33, 0x36, 0x3C, 0x36, 0x33, 0x73, 0X00, // K
00094     0x78, 0x30, 0x30, 0x30, 0x31, 0x33, 0x7F, 0X00, // L
00095     0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0X00, // M
00096     0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x63, 0X00, // N
00097     0x3E, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0X00, // O
00098     0x7E, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x78, 0X00, // P 0x50
00099     0x3C, 0x66, 0x66, 0x66, 0x6E, 0x3C, 0x0E, 0X00, // Q
00100     0x7E, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x73, 0X00, // R
00101     0x3C, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x3C, 0X00, // S
00102     0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // T
00103     0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0X00, // U
00104     0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // V
00105     0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0X00, // W
00106     0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0X00, // X
00107     0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0X00, // Y
00108     0x7F, 0x63, 0x46, 0x0C, 0x19, 0x33, 0x7F, 0X00, // Z
00109     0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0X00, // [
00110     0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0X00, // \ (back slash)
00111     0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0X00, // ]
00112     0x08, 0x1C, 0x36, 0x63, 0X00, 0X00, 0X00, 0X00, // ^
00113     0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0xFF, // _
00114     0x18, 0x18, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, // ` 0x60
00115     0X00, 0X00, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0X00, // a
00116     0x70, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x6E, 0X00, // b
00117     0X00, 0X00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0X00, // c
00118     0x0E, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3B, 0X00, // d
00119     0X00, 0X00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0X00, // e
00120     0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0X00, // f
00121     0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x7C, // g
00122     0x70, 0x30, 0x36, 0x3B, 0x33, 0x33, 0x73, 0X00, // h
00123     0x18, 0X00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0X00, // i
00124     0x06, 0X00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, // j
00125     0x70, 0x30, 0x33, 0x36, 0x3C, 0x36, 0x73, 0X00, // k
00126     0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // l
00127     0X00, 0X00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0X00, // m
00128     0X00, 0X00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0X00, // n
00129     0X00, 0X00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0X00, // o
00130     0X00, 0X00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78, // p
00131     0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F, // q
00132     0X00, 0X00, 0x6E, 0x3B, 0x33, 0x30, 0x78, 0X00, // r
00133     0X00, 0X00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0X00, // s
00134     0x08, 0x18, 0x3E, 0x18, 0x18, 0x1A, 0x0C, 0X00, // t
00135     0X00, 0X00, 0x66, 0x66, 0x66, 0x66, 0x3B, 0X00, // u
00136     0X00, 0X00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // v
00137     0X00, 0X00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0X00, // w
00138     0X00, 0X00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0X00, // x
00139     0X00, 0X00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x7C, // y
00140     0X00, 0X00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0X00, // z
00141     0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0X00, // {
00142     0x0C, 0x0C, 0x0C, 0X00, 0x0C, 0x0C, 0x0C, 0X00, // |
00143     0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0X00, // }
00144     0x3B, 0x6E, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // ~
00145     0x1C, 0x36, 0x36, 0x1C, 0X00, 0X00, 0X00, 0X00  // DEL
00146 }; 
00147 #endif // LOCALFONT
00148 
00149 char mytolower(char a) {
00150     if (a >= 'A' && a <= 'Z')
00151         return (a - 'A' + 'a');
00152     else
00153         return a;
00154 }
00155 /// mystrnicmp exists because not all compiler libraries have this function.
00156 ///
00157 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which
00158 /// is outside the scope of this C-portable set of functions.
00159 ///
00160 /// @param l is a pointer to the string on the left
00161 /// @param r is a pointer to the string on the right
00162 /// @param n is the number of characters to compare
00163 /// @returns -1 if l < r
00164 /// @returns 0 if l == r
00165 /// @returns +1 if l > r
00166 ///
00167 int mystrnicmp(const char *l, const char *r, size_t n) {
00168     int result = 0;
00169 
00170     if (n != 0) {
00171         do {
00172             result = mytolower(*l++) - mytolower(*r++);
00173         } while ((result == 0) && (*l != '\0') && (--n > 0));
00174     }
00175     if (result < -1)
00176         result = -1;
00177     else if (result > 1)
00178         result = 1;
00179     return result;
00180 }
00181 
00182 
00183 GraphicsDisplay::GraphicsDisplay(const char *name) 
00184     : TextDisplay(name)
00185 {
00186     font = NULL;
00187 }
00188 
00189 RetCode_t GraphicsDisplay::set_font(const unsigned char * _font)
00190 {
00191     font = _font;     // trusting them, but it might be good to put some checks in here...
00192     return noerror;
00193 }
00194 
00195 #ifdef LOCALFONT
00196 int GraphicsDisplay::character(int x, int y, int value)
00197 {
00198     if (value <= 0x1F && value >= 7F)
00199         return 0;
00200     
00201     return blitbit(x, y, FONT8X8[0][0], FONT8X8[0][1], 
00202         (char *)&(FONT8x8[value - 0x1F][0]));
00203 }
00204 #else
00205 int GraphicsDisplay::character(int x, int y, int c)
00206 {
00207     unsigned int offset;
00208     const unsigned char * charRecord;
00209  
00210     if (c <= 0x1F || c >= 0x7F)
00211         return 0;
00212     offset = font[0];                    // bytes / char
00213     charRecord = &font[((c - ' ') * offset) + 4];      // start of char bitmap
00214     return fontblit(x, y, font, charRecord);
00215 }
00216 #endif
00217 
00218 RetCode_t GraphicsDisplay::window(loc_t x, loc_t y, dim_t w, dim_t h)
00219 {
00220     // current pixel location
00221     _x = x;
00222     _y = y;
00223     // window settings
00224     _x1 = x;
00225     _x2 = x + w - 1;
00226     _y1 = y;
00227     _y2 = y + h - 1;
00228     return noerror;
00229 }
00230 
00231 void GraphicsDisplay::WindowMax(void)
00232 {
00233     window(0,0, width(),height());
00234 }
00235 
00236 RetCode_t GraphicsDisplay::putp(color_t color)
00237 {
00238     pixel(_x, _y, color);
00239     // update pixel location based on window settings
00240     _x++;
00241     if(_x > _x2) {
00242         _x = _x1;
00243         _y++;
00244         if(_y > _y2) {
00245             _y = _y1;
00246         }
00247     }
00248     return noerror;
00249 }
00250 
00251 void GraphicsDisplay::fill(int x, int y, int w, int h, color_t color)
00252 {
00253     fillrect(x,y, x+w, y+h, color);
00254 }
00255 
00256 RetCode_t GraphicsDisplay::cls()
00257 {
00258     fill(0, 0, width(), height(), _background);
00259     return noerror;
00260 }
00261 
00262 void GraphicsDisplay::blit(int x, int y, int w, int h, const int * color)
00263 {
00264     window(x, y, w, h);
00265     _StartGraphicsStream();
00266     for (int i=0; i<w*h; i++) {
00267         putp(color[i]);
00268     }
00269     _EndGraphicsStream();
00270     WindowMax();
00271 }
00272 
00273 #ifdef LOCALFONT
00274 int GraphicsDisplay::blitbit(int x, int y, int w, int h, const char * color)
00275 {
00276     _foreground = 0xFFFF;
00277     INFO("blitbit(%d,%d, %d,%d, %02X) [%04X,%04X]", x,y, w,h, *color, _foreground, _background);
00278     INFO("%lu  %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
00279         color,
00280         color[0], color[1], color[2], color[3], color[4], color[5], color[6], color[7], 
00281         color[8], color[9], color[10], color[11], color[12], color[13], color[14], color[15]);
00282     window(x, y, w, h);
00283     _StartGraphicsStream();
00284     for (int i = 0; i < w*h; i++) {
00285         char byte = color[i >> 3];
00286         int offset = i & 0x7;
00287         if (offset == 0)
00288             INFO(" %2d = %02X", i>>3, byte);
00289         int c = ((byte << offset) & 0x80) ? _foreground : _background;
00290         putp(c);
00291     }
00292     _EndGraphicsStream();
00293     WindowMax();
00294     return w;
00295 }
00296 #endif
00297 
00298 
00299 int GraphicsDisplay::fontblit(int x, int y, const unsigned char * fontTable, const unsigned char * fontChar)
00300 {
00301     //int fontWidth = font[1];                       // get hor size of font
00302     int fontHeight = font[2];                      // get vert size of font
00303     int bytesPerLine = font[3];                       // bytes per line
00304     int charWidth = fontChar[0];        // width of this character
00305     int px, py;
00306     
00307     //INFO("(%d,%d) %lu, %lu %X/%X", x,y, fontTable, fontChar, _foreground, _background);
00308     //INFO("char size (%d,%d)", charWidth, fontHeight);
00309     //HexDump("char", (uint8_t *)fontChar, 32);
00310     //INFO("(f,b) = (%04X,%04X)", _foreground, _background)
00311     window(x, y, charWidth, fontHeight);
00312     _StartGraphicsStream();
00313     //INFO("(f,b) = (%04X,%04X)", _foreground, _background)
00314     for (py = 0; py < fontHeight; py++) {
00315         int bitmask = 1 << (py & 7);
00316         
00317         for (px = 0; px < charWidth; px++) {
00318             int offset = (py / 8) + px * bytesPerLine;
00319             unsigned char byte = fontChar[offset + 1];  // skip the char's # bits wide value
00320             color_t c = (byte & bitmask) ? _foreground : _background;
00321             //INFO("(%2d,%2d) %02X & %02X => %04X [%04X,%04X]", px, py, byte, bitmask, c, _foreground, _background);
00322             //pixel(x+px, y+py, c);
00323             putp(c);
00324         }
00325     }
00326     _EndGraphicsStream();
00327     WindowMax();
00328     return charWidth;
00329 }
00330 
00331 // BMP Color Palette is BGRx
00332 //      BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000
00333 // RGB16 is
00334 //      RRRR RGGG GGGB BBBB
00335 // swap to little endian
00336 //      GGGB BBBB RRRR RGGG
00337 color_t GraphicsDisplay::RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i)
00338 {
00339     color_t c;
00340  
00341     c  = ((colorPalette[i].rgbBlue  >> 3) <<  0);
00342     c |= ((colorPalette[i].rgbGreen >> 2) <<  5);
00343     c |= ((colorPalette[i].rgbRed   >> 3) << 11);
00344     return c;
00345 }
00346 
00347 /// RRRR RGGG GGGB BBBB
00348 RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c)
00349 {
00350     RGBQUAD q;
00351     
00352     memset(&q, 0, sizeof(q));
00353     q.rgbBlue  = (c & 0x001F) << 3;      /* Blue value */
00354     q.rgbGreen = (c & 0x07E0) >> 3;      /* Green value */
00355     q.rgbRed   = (c & 0xF800) >> 8;      /* Red value */
00356     q.rgbReserved = 0;
00357     return q;
00358 }
00359 
00360 
00361 RetCode_t GraphicsDisplay::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
00362 {
00363     BITMAPFILEHEADER BMP_Header;
00364     BITMAPINFOHEADER BMP_Info;
00365     
00366     INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP);
00367     if (x >= 0 && x < width()
00368     && y >= 0 && y < height()
00369     && w > 0 && x + w <= width()
00370     && h > 0 && y + h <= height()) {
00371 
00372         BMP_Header.bfType = BF_TYPE;
00373         BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
00374         BMP_Header.bfReserved1 = 0;
00375         BMP_Header.bfReserved2 = 0;
00376         BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
00377         
00378         BMP_Info.biSize = sizeof(BMP_Info);
00379         BMP_Info.biWidth = w;
00380         BMP_Info.biHeight = h;
00381         BMP_Info.biPlanes = 1;
00382         BMP_Info.biBitCount = 24;
00383         BMP_Info.biCompression = BI_RGB;
00384         BMP_Info.biSizeImage = 0;
00385         BMP_Info.biXPelsPerMeter = 0;
00386         BMP_Info.biYPelsPerMeter = 0;
00387         BMP_Info.biClrUsed = 0;
00388         BMP_Info.biClrImportant = 0;
00389 
00390         INFO("Writing {%s}", Name_BMP);
00391         FILE *Image = fopen(Name_BMP, "wb");
00392         if (!Image) {
00393             ERR("File not found");
00394             return(file_not_found);
00395         }
00396 
00397         // Be optimistic - don't check for errors.
00398         //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
00399         fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
00400         //INFO("fwrite returned %d", r);
00401         
00402         //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
00403         fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
00404         //INFO("fwrite returned %d", r);
00405         
00406         int lineBufSize = ((24 * w + 7)/8);
00407         uint8_t * lineBuffer = (uint8_t *)malloc(lineBufSize);
00408         if (lineBuffer == NULL) {
00409             fclose(Image);
00410             ERR("Not enough RAM for lineBuffer");
00411             return(not_enough_ram);
00412         }
00413         color_t * pixelBuffer = (color_t *)malloc(w * sizeof(color_t));
00414         if (pixelBuffer == NULL) {
00415             fclose(Image);
00416             free(lineBuffer);
00417             ERR("Not enough RAM for pixelBuffer");
00418             return(not_enough_ram);
00419         }
00420         
00421         // Read the display from the last line toward the top
00422         // so we can write the file in one pass.
00423         for (int j = h - 1; j >= 0; j--) {
00424             // Read one line of pixels to a local buffer
00425             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
00426                 ERR("getPixelStream error, and no recovery handler...");
00427             }
00428             // Convert the local buffer to RGBQUAD format
00429             int lb = 0;
00430             for (int i=0; i<w; i++) {
00431                 color_t pixel = pixelBuffer[x+i];
00432                 // Scale to 24-bits
00433                 RGBQUAD q = RGB16ToRGBQuad(pixel);
00434                 lineBuffer[lb++] = q.rgbBlue;
00435                 lineBuffer[lb++] = q.rgbGreen;
00436                 lineBuffer[lb++] = q.rgbRed;
00437             }
00438             // Write to disk
00439             //HexDump("Line", lineBuffer, lineBufSize);
00440             fwrite(lineBuffer, sizeof(char), lb, Image);
00441         }
00442         fclose(Image);       
00443         INFO("Image closed"); 
00444         return noerror;
00445     } else {
00446         return bad_parameter;
00447     }
00448 }
00449 
00450 RetCode_t GraphicsDisplay::_RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image)
00451 {
00452     BITMAPINFOHEADER BMP_Info;
00453     RGBQUAD * colorPalette = NULL;
00454     int colorCount;
00455     uint8_t * lineBuffer = NULL;
00456     uint16_t BPP_t;
00457     uint32_t PixelWidth, PixelHeight;
00458     //uint32_t start_data;
00459     unsigned int    i, offset;
00460     int padd,j;
00461 
00462     // Now, Read the bitmap info header
00463     fread(&BMP_Info, 1, sizeof(BMP_Info), Image);
00464     //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
00465     BPP_t = BMP_Info.biBitCount;
00466     INFO("biBitCount %04X", BPP_t);
00467     if (BPP_t != 4 && BPP_t != 8 && BPP_t != 16 && BPP_t != 24) { // Support 4, 8, 16, 24-bits per pixel
00468         fclose(Image);
00469         return(not_supported_format);
00470     }
00471 
00472     PixelHeight = BMP_Info.biHeight;
00473     PixelWidth = BMP_Info.biWidth;
00474     if (PixelHeight > height() + y || PixelWidth > width() + x) {
00475         fclose(Image);
00476         return(image_too_big);
00477     }
00478     INFO("(%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight);
00479     if (BMP_Info.biBitCount <= 8) {
00480         int paletteSize;
00481         // Read the color palette
00482         colorCount = 1 << BMP_Info.biBitCount;
00483         paletteSize = sizeof(RGBQUAD) * colorCount;
00484         colorPalette = (RGBQUAD *)malloc(paletteSize);
00485         if (colorPalette == NULL) {
00486             fclose(Image);
00487             return(not_enough_ram);
00488         }
00489         fread(colorPalette, 1, paletteSize, Image);
00490         //HexDump("Color Palette", (uint8_t *)colorPalette, paletteSize);
00491     }
00492 
00493     int lineBufSize = ((BPP_t * PixelWidth + 7)/8);
00494     //INFO("BPP_t %d, PixelWidth %d, lineBufSize %d", BPP_t, PixelWidth, lineBufSize);
00495     lineBuffer = (uint8_t *)malloc(lineBufSize);
00496     if (lineBuffer == NULL) {
00497         free(colorPalette);
00498         fclose(Image);
00499         return(not_enough_ram);
00500     }
00501     color_t * pixelBuffer = (color_t *)malloc(PixelWidth * sizeof(color_t));
00502     if (pixelBuffer == NULL) {
00503         free(colorPalette);
00504         free(lineBuffer);
00505         fclose(Image);
00506         return(not_enough_ram);
00507     }
00508 
00509     // the Raw Data records are padded to a multiple of 4 bytes
00510     int recordSize = 2;
00511     if (BPP_t == 4) {
00512         recordSize = 1;
00513     } else if (BPP_t == 8) {
00514         recordSize = 1;
00515     } else if (BPP_t == 16) {
00516         recordSize = 2;
00517     } else if (BPP_t == 24) {
00518         recordSize = 3;
00519     }
00520     padd = -1;
00521     do {
00522         padd++;
00523     } while ((PixelWidth * recordSize + padd) % 4 != 0);
00524 
00525     // Define window for top to bottom and left to right so writing auto-wraps
00526     window(x,y, PixelWidth,PixelHeight);
00527     SetGraphicsCursor(x, y);
00528     _StartGraphicsStream();
00529     
00530     //start_data = BMP_Header.bfOffBits;
00531     //HexDump("Raw Data", (uint8_t *)&start_data, 32);
00532     //INFO("(%d,%d) (%d,%d), [%d,%d]", x,y, PixelWidth,PixelHeight, lineBufSize, padd);
00533     for (j = PixelHeight - 1; j >= 0; j--) {                //Lines bottom up
00534         offset = fileOffset + j * (lineBufSize + padd);     // start of line
00535         fseek(Image, offset, SEEK_SET);
00536         fread(lineBuffer, 1, lineBufSize, Image);           // read a line - slow !
00537         //INFO("offset: %6X", offset);
00538         for (i = 0; i < PixelWidth; i++) {                  // copy pixel data to TFT
00539             if (BPP_t == 4) {
00540                 uint8_t dPix = lineBuffer[i/2];
00541                 if ((i & 1) == 0)
00542                     dPix >>= 4;
00543                 dPix &= 0x0F;
00544                 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix);
00545                 //putp(RGBQuadToRGB16(colorPalette, dPix));
00546             } else if (BPP_t == 8) {
00547                 pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]);
00548                 //putp(RGBQuadToRGB16(colorPalette, lineBuffer[i]));
00549             } else if (BPP_t == 16) {
00550                 pixelBuffer[i] = lineBuffer[i];
00551                 //putp(lineBuffer[i]);
00552             } else if (BPP_t == 24) {
00553                 color_t color;
00554                 color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]);
00555                 pixelBuffer[i] = color;
00556                 //putp(color);
00557             }
00558         }
00559         pixelStream(pixelBuffer, PixelWidth, x, y++);
00560     }
00561     _EndGraphicsStream();
00562     WindowMax();
00563     free(lineBuffer);
00564     free(colorPalette);
00565     return (noerror);
00566 }
00567 
00568 
00569 RetCode_t GraphicsDisplay::RenderImageFile(loc_t x, loc_t y, const char *FileName)
00570 {
00571     if (mystrnicmp(FileName + strlen(FileName) - 4, ".bmp", 4) == 0) {
00572         return RenderBitmapFile(x,y,FileName);
00573     } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".ico", 4) == 0) {
00574         return RenderIconFile(x,y,FileName);
00575     } else {
00576         return not_supported_format;
00577     }
00578 }
00579 
00580 RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP)
00581 {
00582     BITMAPFILEHEADER BMP_Header;
00583 
00584     INFO("Opening {%s}", Name_BMP);
00585     FILE *Image = fopen(Name_BMP, "rb");
00586     if (!Image) {
00587         return(file_not_found);
00588     }
00589 
00590     fread(&BMP_Header, 1, sizeof(BMP_Header), Image);      // get the BMP Header
00591     INFO("bfType %04X", BMP_Header.bfType);
00592     //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
00593     if (BMP_Header.bfType != BF_TYPE) {
00594         fclose(Image);
00595         return(not_bmp_format);
00596     }
00597     RetCode_t rt = _RenderBitmap(x, y, BMP_Header.bfOffBits, Image);
00598     if (rt != noerror) {
00599         return rt;
00600     } else {
00601         fclose(Image);
00602         return (noerror);
00603     }
00604 }
00605 
00606 RetCode_t GraphicsDisplay::RenderIconFile(loc_t x, loc_t y, const char *Name_ICO)
00607 {
00608     ICOFILEHEADER ICO_Header;
00609     ICODIRENTRY ICO_DirEntry;
00610 
00611     INFO("Opening {%s}", Name_ICO);
00612     FILE *Image = fopen(Name_ICO, "rb");
00613     if (!Image) {
00614         return(file_not_found);
00615     }
00616 
00617     fread(&ICO_Header, 1, sizeof(ICO_Header), Image);      // get the BMP Header
00618     HexDump("ICO_Header", (uint8_t *)&ICO_Header, sizeof(ICO_Header));
00619     if (ICO_Header.Reserved_zero != 0
00620     || ICO_Header.icType != IC_TYPE
00621     || ICO_Header.icImageCount == 0) {
00622         fclose(Image);
00623         return(not_ico_format);
00624     }
00625 
00626     // Read ONLY the first of n possible directory entries.
00627     fread(&ICO_DirEntry, 1, sizeof(ICO_DirEntry), Image);
00628     HexDump("ICO_DirEntry", (uint8_t *)&ICO_DirEntry, sizeof(ICO_DirEntry));
00629     INFO("biBitCount %04X", ICO_DirEntry.biBitCount);
00630     if (ICO_DirEntry.biBitCount != 0) {     // Expecting this to be zero for ico
00631         fclose(Image);
00632         return(not_supported_format);
00633     }
00634 
00635     RetCode_t rt = _RenderBitmap(x, y, ICO_DirEntry.bfOffBits, Image);
00636     if (rt == noerror) {
00637         fclose(Image);
00638         return (noerror);
00639     } else {
00640         return rt;
00641     }
00642 }
00643 
00644 int GraphicsDisplay::columns()
00645 {
00646     return width() / 8;
00647 }
00648 
00649 int GraphicsDisplay::rows()
00650 {
00651     return height() / 8;
00652 }
00653 
00654