acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

BmpClass.h (8416B)

      1 /*******************************************************************************
      2  * BMP Class
      3  * 
      4  * Rewrite from: https://github.com/Jaycar-Electronics/Arduino-Picture-Frame.git
      5  ******************************************************************************/
      6 #ifndef _BMPCLASS_H_
      7 #define _BMPCLASS_H_
      8 
      9 /* Wio Terminal */
     10 #if defined(ARDUINO_ARCH_SAMD) && defined(SEEED_GROVE_UI_WIRELESS)
     11 #include <Seeed_FS.h>
     12 #elif defined(ESP32) || defined(ESP8266)
     13 #include <FS.h>
     14 #else
     15 #include <SD.h>
     16 #endif
     17 
     18 typedef void(BMP_DRAW_CALLBACK)(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h);
     19 
     20 class BmpClass
     21 {
     22 public:
     23     void draw(
     24         File *f, BMP_DRAW_CALLBACK *bmpDrawCallback, bool useBigEndian,
     25         int16_t x, int16_t y, int16_t widthLimit, int16_t heightLimit)
     26     {
     27         _bmpDrawCallback = bmpDrawCallback;
     28         _useBigEndian = useBigEndian;
     29         _heightLimit = heightLimit;
     30 
     31         int16_t u, v;
     32         uint32_t xend;
     33 
     34         getbmpparms(f);
     35 
     36         //validate bitmap
     37         if ((bmtype == 19778) && (bmwidth > 0) && (bmheight > 0) && (bmbpp > 0))
     38         {
     39             //centre image
     40             u = (widthLimit - bmwidth) / 2;
     41             v = (heightLimit - bmheight) / 2;
     42             u = (u < 0) ? x : x + u;
     43             v = (v < 0) ? y : y + v;
     44             xend = (bmwidth > widthLimit) ? widthLimit : bmwidth;
     45 
     46             bmpRow = (uint16_t *)malloc(xend * 2);
     47             if (!bmpRow)
     48             {
     49                 Serial.println(F("bmpRow malloc failed."));
     50             }
     51             if (bmbpp < 9)
     52             {
     53                 bmplt = (uint16_t *)malloc(bmpltsize * 2);
     54                 if (!bmplt)
     55                 {
     56                     Serial.println(F("bmplt malloc failed."));
     57                 }
     58                 bmloadplt(f); //load palette if palettized
     59                 drawbmpal(f, u, v, xend);
     60                 free(bmplt);
     61             }
     62             else if (bmbpp == 16)
     63             {
     64                 // TODO: bpp 16 should have 3 pixel types
     65                 drawbmRgb565(f, u, v, xend);
     66             }
     67             else
     68             {
     69                 drawbmtrue(f, u, v, xend);
     70             }
     71             free(bmpRow);
     72         }
     73     }
     74 
     75 private:
     76     void bmloadplt(File *f)
     77     {
     78         byte r, g, b;
     79         if (bmpltsize == 0)
     80         {
     81             bmpltsize = 1 << bmbpp; //load default palette size
     82         }
     83         f->seek(54); //palette position in type 0x28 bitmaps
     84         for (int16_t i = 0; i < bmpltsize; i++)
     85         {
     86             b = f->read();
     87             g = f->read();
     88             r = f->read();
     89             f->read(); //dummy byte
     90             bmplt[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
     91         }
     92     }
     93 
     94     void drawbmpal(File *f, int16_t u, int16_t v, uint32_t xend)
     95     {
     96         byte bmbitmask;
     97         int16_t i, ystart, bmppb, p, d;
     98         int16_t x, y;
     99         uint16_t c;
    100         bmbpl = ((bmbpp * bmwidth + 31) / 32) * 4; //bytes per line
    101         bmppb = 8 / bmbpp;                         //pixels/byte
    102         bmbitmask = ((1 << bmbpp) - 1);            //mask for each pixel
    103         ystart = 0;
    104         if (bmheight > _heightLimit)
    105         {
    106             ystart = bmheight - _heightLimit; //don't draw if it's outside screen
    107         }
    108         for (y = ystart; y < bmheight; y++)
    109         {                                   //invert in calculation (y=0 is bottom)
    110             f->seek(bmdataptr + y * bmbpl); //seek to start of line
    111             x = 0;
    112             p = 0;
    113             while (x < xend)
    114             {
    115                 if (p < 1)
    116                 {
    117                     d = f->read();
    118                     p = bmppb;
    119                 }
    120                 d = d << bmbpp;
    121                 c = bmplt[(bmbitmask & (d >> 8))];
    122                 bmpRow[x] = (_useBigEndian) ? ((c >> 8) | (c << 8)) : c;
    123 
    124                 p--;
    125                 x++;
    126             }
    127             _bmpDrawCallback(u, v + bmheight - 1 - y, bmpRow, xend, 1);
    128         }
    129     }
    130 
    131     // draw 16-bit colour (RGB565) bitmap
    132     void drawbmRgb565(File *f, int16_t u, int16_t v, uint32_t xend)
    133     {
    134         int16_t i, ystart;
    135         uint32_t x, y;
    136         byte lo, hi;
    137         bmbpl = ((bmbpp * bmwidth + 31) / 32) * 4; //bytes per line, due to 32bit chunks
    138         ystart = 0;
    139         if (bmheight > _heightLimit)
    140         {
    141             ystart = bmheight - _heightLimit; //don't draw if it's outside screen
    142         }
    143         Serial.println(xend);
    144         for (y = ystart; y < bmheight; y++)
    145         {                                   //invert in calculation (y=0 is bottom)
    146             f->seek(bmdataptr + (y * bmbpl)); //seek at start of line
    147             for (x = 0; x < xend; x++)
    148             {
    149                 lo = f->read();
    150                 hi = f->read();
    151                 if (_useBigEndian)
    152                 {
    153                     bmpRow[x] = hi | lo << 8;
    154                 }
    155                 else
    156                 {
    157                     bmpRow[x] = lo | hi << 8;
    158                 }
    159             }
    160             _bmpDrawCallback(u, v + bmheight - 1 - y, bmpRow, xend, 1);
    161         }
    162     }
    163 
    164     // draw true colour bitmap at (u,v) handles 24/32 not 16bpp yet
    165     void drawbmtrue(File *f, int16_t u, int16_t v, uint32_t xend)
    166     {
    167         int16_t i, ystart;
    168         uint32_t x, y;
    169         byte r, g, b;
    170         bmbpl = ((bmbpp * bmwidth + 31) / 32) * 4; //bytes per line, due to 32bit chunks
    171         ystart = 0;
    172         if (bmheight > _heightLimit)
    173         {
    174             ystart = bmheight - _heightLimit; //don't draw if it's outside screen
    175         }
    176         for (y = ystart; y < bmheight; y++)
    177         {                                   //invert in calculation (y=0 is bottom)
    178             f->seek(bmdataptr + y * bmbpl); //seek at start of line
    179             for (x = 0; x < xend; x++)
    180             {
    181                 b = f->read();
    182                 g = f->read();
    183                 r = f->read();
    184                 if (bmbpp == 32)
    185                 {
    186                     f->read(); //dummy byte for 32bit
    187                 }
    188                 bmpRow[x] = (_useBigEndian) ? ((r & 0xf8) | (g >> 5) | ((g & 0x1c) << 11) | ((b & 0xf8) << 5)) : (((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3));
    189             }
    190             _bmpDrawCallback(u, v + bmheight - 1 - y, bmpRow, xend, 1);
    191         }
    192     }
    193 
    194     void getbmpparms(File *f)
    195     {               //load into globals as ints-some parameters are 32 bit, but we can't handle this size anyway
    196         byte h[48]; //header is 54 bytes typically, but we don't need it all
    197         int16_t i;
    198         f->seek(0); //set start of file
    199         for (i = 0; i < 48; i++)
    200         {
    201             h[i] = f->read(); //read header
    202         }
    203         bmtype = h[0] + (h[1] << 8);      //offset 0 'BM'
    204         bmdataptr = h[10] + (h[11] << 8); //offset 0xA pointer to image data
    205         bmhdrsize = h[14] + (h[15] << 8); //dib header size (0x28 is usual)
    206         //files may vary here, if !=28, unsupported type, put default values
    207         bmwidth = 0;
    208         bmheight = 0;
    209         bmbpp = 0;
    210         bmpltsize = 0;
    211         if ((bmhdrsize == 0x28) || (bmhdrsize == 0x38))
    212         {
    213             bmwidth = h[18] + (h[19] << 8);   //width
    214             bmheight = h[22] + (h[23] << 8);  //height
    215             bmbpp = h[28] + (h[29] << 8);     //bits per pixel
    216             bmpltsize = h[46] + (h[47] << 8); //palette size
    217         }
    218         // Serial.printf("bmtype: %d, bmhdrsize: %d, bmwidth: %d, bmheight: %d, bmbpp: %d\n", bmtype, bmhdrsize, bmwidth, bmheight, bmbpp);
    219     }
    220 
    221     byte isbmp(char n[])
    222     { //check if bmp extension
    223         int16_t k;
    224         k = strlen(n);
    225         if (k < 5)
    226         {
    227             return 0; //name not long enough
    228         }
    229         if (n[k - 1] != 'P')
    230         {
    231             return 0;
    232         }
    233         if (n[k - 2] != 'M')
    234         {
    235             return 0;
    236         }
    237         if (n[k - 3] != 'B')
    238         {
    239             return 0;
    240         }
    241         if (n[k - 4] != '.')
    242         {
    243             return 0;
    244         }
    245         return 1; //passes all tests
    246     }
    247 
    248     BMP_DRAW_CALLBACK *_bmpDrawCallback;
    249     bool _useBigEndian;
    250     int16_t _heightLimit;
    251 
    252     uint16_t bmtype, bmdataptr;                              //from header
    253     uint32_t bmhdrsize, bmwidth, bmheight, bmbpp, bmpltsize; //from DIB Header
    254     uint16_t bmbpl;                                          //bytes per line- derived
    255     uint16_t *bmplt;                                        //palette- stored encoded for LCD
    256     uint16_t *bmpRow;
    257 };
    258 
    259 #endif // _BMPCLASS_H_