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_