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 |
ESP32_SDcard_jpeg.ino (9558B)
1 // This sketch if for an ESP32, it draws Jpeg images pulled from an SD Card 2 // onto the TFT. 3 4 // As well as the TFT_eSPI library you will need the JPEG Decoder library. 5 // A copy can be downloaded here, it is based on the library by Makoto Kurauchi. 6 // https://github.com/Bodmer/JPEGDecoder 7 8 // Images on SD Card must be put in the root folder (top level) to be found 9 // Use the SD library examples to verify your SD Card interface works! 10 11 // The example images used to test this sketch can be found in the library 12 // JPEGDecoder/extras folder 13 //---------------------------------------------------------------------------------------------------- 14 15 #include <SPI.h> 16 17 #include <FS.h> 18 #include <SD.h> 19 20 #include <TFT_eSPI.h> 21 TFT_eSPI tft = TFT_eSPI(); 22 23 // JPEG decoder library 24 #include <JPEGDecoder.h> 25 26 //#################################################################################################### 27 // Setup 28 //#################################################################################################### 29 void setup() { 30 Serial.begin(115200); 31 32 // Set all chip selects high to avoid bus contention during initialisation of each peripheral 33 digitalWrite(22, HIGH); // Touch controller chip select (if used) 34 digitalWrite(15, HIGH); // TFT screen chip select 35 digitalWrite( 5, HIGH); // SD card chips select, must use GPIO 5 (ESP32 SS) 36 37 tft.begin(); 38 39 if (!SD.begin()) { 40 Serial.println("Card Mount Failed"); 41 return; 42 } 43 uint8_t cardType = SD.cardType(); 44 45 if (cardType == CARD_NONE) { 46 Serial.println("No SD card attached"); 47 return; 48 } 49 50 Serial.print("SD Card Type: "); 51 if (cardType == CARD_MMC) { 52 Serial.println("MMC"); 53 } else if (cardType == CARD_SD) { 54 Serial.println("SDSC"); 55 } else if (cardType == CARD_SDHC) { 56 Serial.println("SDHC"); 57 } else { 58 Serial.println("UNKNOWN"); 59 } 60 61 uint64_t cardSize = SD.cardSize() / (1024 * 1024); 62 Serial.printf("SD Card Size: %lluMB\n", cardSize); 63 64 Serial.println("initialisation done."); 65 } 66 67 //#################################################################################################### 68 // Main loop 69 //#################################################################################################### 70 void loop() { 71 72 tft.setRotation(2); // portrait 73 tft.fillScreen(random(0xFFFF)); 74 75 // The image is 300 x 300 pixels so we do some sums to position image in the middle of the screen! 76 // Doing this by reading the image width and height from the jpeg info is left as an exercise! 77 int x = (tft.width() - 300) / 2 - 1; 78 int y = (tft.height() - 300) / 2 - 1; 79 80 drawSdJpeg("/EagleEye.jpg", x, y); // This draws a jpeg pulled off the SD Card 81 delay(2000); 82 83 tft.setRotation(2); // portrait 84 tft.fillScreen(random(0xFFFF)); 85 drawSdJpeg("/Baboon40.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 86 delay(2000); 87 88 tft.setRotation(2); // portrait 89 tft.fillScreen(random(0xFFFF)); 90 drawSdJpeg("/lena20k.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 91 delay(2000); 92 93 tft.setRotation(1); // landscape 94 tft.fillScreen(random(0xFFFF)); 95 drawSdJpeg("/Mouse480.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 96 97 delay(2000); 98 99 while(1); // Wait here 100 } 101 102 //#################################################################################################### 103 // Draw a JPEG on the TFT pulled from SD Card 104 //#################################################################################################### 105 // xpos, ypos is top left corner of plotted image 106 void drawSdJpeg(const char *filename, int xpos, int ypos) { 107 108 // Open the named file (the Jpeg decoder library will close it) 109 File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 110 111 if ( !jpegFile ) { 112 Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 113 return; 114 } 115 116 Serial.println("==========================="); 117 Serial.print("Drawing file: "); Serial.println(filename); 118 Serial.println("==========================="); 119 120 // Use one of the following methods to initialise the decoder: 121 bool decoded = JpegDec.decodeSdFile(jpegFile); // Pass the SD file handle to the decoder, 122 //bool decoded = JpegDec.decodeSdFile(filename); // or pass the filename (String or character array) 123 124 if (decoded) { 125 // print information about the image to the serial port 126 jpegInfo(); 127 // render the image onto the screen at given coordinates 128 jpegRender(xpos, ypos); 129 } 130 else { 131 Serial.println("Jpeg file format not supported!"); 132 } 133 } 134 135 //#################################################################################################### 136 // Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit 137 //#################################################################################################### 138 // This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not 139 // fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders. 140 void jpegRender(int xpos, int ypos) { 141 142 //jpegInfo(); // Print information from the JPEG file (could comment this line out) 143 144 uint16_t *pImg; 145 uint16_t mcu_w = JpegDec.MCUWidth; 146 uint16_t mcu_h = JpegDec.MCUHeight; 147 uint32_t max_x = JpegDec.width; 148 uint32_t max_y = JpegDec.height; 149 150 bool swapBytes = tft.getSwapBytes(); 151 tft.setSwapBytes(true); 152 153 // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 154 // Typically these MCUs are 16x16 pixel blocks 155 // Determine the width and height of the right and bottom edge image blocks 156 uint32_t min_w = jpg_min(mcu_w, max_x % mcu_w); 157 uint32_t min_h = jpg_min(mcu_h, max_y % mcu_h); 158 159 // save the current image block size 160 uint32_t win_w = mcu_w; 161 uint32_t win_h = mcu_h; 162 163 // record the current time so we can measure how long it takes to draw an image 164 uint32_t drawTime = millis(); 165 166 // save the coordinate of the right and bottom edges to assist image cropping 167 // to the screen size 168 max_x += xpos; 169 max_y += ypos; 170 171 // Fetch data from the file, decode and display 172 while (JpegDec.read()) { // While there is more data in the file 173 pImg = JpegDec.pImage ; // Decode a MCU (Minimum Coding Unit, typically a 8x8 or 16x16 pixel block) 174 175 // Calculate coordinates of top left corner of current MCU 176 int mcu_x = JpegDec.MCUx * mcu_w + xpos; 177 int mcu_y = JpegDec.MCUy * mcu_h + ypos; 178 179 // check if the image block size needs to be changed for the right edge 180 if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 181 else win_w = min_w; 182 183 // check if the image block size needs to be changed for the bottom edge 184 if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 185 else win_h = min_h; 186 187 // copy pixels into a contiguous block 188 if (win_w != mcu_w) 189 { 190 uint16_t *cImg; 191 int p = 0; 192 cImg = pImg + win_w; 193 for (int h = 1; h < win_h; h++) 194 { 195 p += mcu_w; 196 for (int w = 0; w < win_w; w++) 197 { 198 *cImg = *(pImg + w + p); 199 cImg++; 200 } 201 } 202 } 203 204 // calculate how many pixels must be drawn 205 uint32_t mcu_pixels = win_w * win_h; 206 207 // draw image MCU block only if it will fit on the screen 208 if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()) 209 tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg); 210 else if ( (mcu_y + win_h) >= tft.height()) 211 JpegDec.abort(); // Image has run off bottom of screen so abort decoding 212 } 213 214 tft.setSwapBytes(swapBytes); 215 216 showTime(millis() - drawTime); // These lines are for sketch testing only 217 } 218 219 //#################################################################################################### 220 // Print image information to the serial port (optional) 221 //#################################################################################################### 222 // JpegDec.decodeFile(...) or JpegDec.decodeArray(...) must be called before this info is available! 223 void jpegInfo() { 224 225 // Print information extracted from the JPEG file 226 Serial.println("JPEG image info"); 227 Serial.println("==============="); 228 Serial.print("Width :"); 229 Serial.println(JpegDec.width); 230 Serial.print("Height :"); 231 Serial.println(JpegDec.height); 232 Serial.print("Components :"); 233 Serial.println(JpegDec.comps); 234 Serial.print("MCU / row :"); 235 Serial.println(JpegDec.MCUSPerRow); 236 Serial.print("MCU / col :"); 237 Serial.println(JpegDec.MCUSPerCol); 238 Serial.print("Scan type :"); 239 Serial.println(JpegDec.scanType); 240 Serial.print("MCU width :"); 241 Serial.println(JpegDec.MCUWidth); 242 Serial.print("MCU height :"); 243 Serial.println(JpegDec.MCUHeight); 244 Serial.println("==============="); 245 Serial.println(""); 246 } 247 248 //#################################################################################################### 249 // Show the execution time (optional) 250 //#################################################################################################### 251 // WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for 252 // sketch sizes greater than ~70KBytes because 16 bit address pointers are used in some libraries. 253 254 // The Due will work fine with the HX8357_Due library. 255 256 void showTime(uint32_t msTime) { 257 //tft.setCursor(0, 0); 258 //tft.setTextFont(1); 259 //tft.setTextSize(2); 260 //tft.setTextColor(TFT_WHITE, TFT_BLACK); 261 //tft.print(F(" JPEG drawn in ")); 262 //tft.print(msTime); 263 //tft.println(F(" ms ")); 264 Serial.print(F(" JPEG drawn in ")); 265 Serial.print(msTime); 266 Serial.println(F(" ms ")); 267 } 268