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 |
TFT_flash_jpg.ino (8949B)
1 // Sketch to display images on a 480 x 320 ILI9486 Raspberry Pi 3.5" TFT (Waveshare design) 2 // which has a 16 bit serial interface based on 74HC04, 74HC4040 and 2 x 74HC4094 logic chips 3 4 // Renders images stored in an array in program (FLASH)JPEG images are stored in header files 5 // (see jpeg1.h etc) 6 7 // The sketch does not need the SD or sdFat libraries since it does not access an SD Card. 8 9 // As well as the TFT_eSPI library: 10 // https://github.com/Bodmer/TFT_eSPI 11 // the sketch need the JPEG Decoder library. This can be loaded via the Library Manager. 12 // or can be downloaded here: 13 // https://github.com/Bodmer/JPEGDecoder 14 15 //---------------------------------------------------------------------------------------------------- 16 17 #include <SPI.h> 18 #include <TFT_eSPI.h> 19 20 TFT_eSPI tft = TFT_eSPI(); 21 22 23 // JPEG decoder library 24 #include <JPEGDecoder.h> 25 26 // Return the minimum of two values a and b 27 #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 28 29 // Include the sketch header file that contains the image stored as an array of bytes 30 // More than one image array could be stored in each header file. 31 #include "jpeg1.h" 32 #include "jpeg2.h" 33 #include "jpeg3.h" 34 #include "jpeg4.h" 35 36 // Count how many times the image is drawn for test purposes 37 uint32_t icount = 0; 38 //---------------------------------------------------------------------------------------------------- 39 40 41 //#################################################################################################### 42 // Setup 43 //#################################################################################################### 44 void setup() { 45 Serial.begin(115200); 46 tft.begin(); 47 } 48 49 //#################################################################################################### 50 // Main loop 51 //#################################################################################################### 52 void loop() { 53 54 tft.setRotation(2); // portrait 55 tft.fillScreen(random(0xFFFF)); 56 57 // The image is 300 x 300 pixels so we do some sums to position image in the middle of the screen! 58 // Doing this by reading the image width and height from the jpeg info is left as an exercise! 59 int x = (tft.width() - 300) / 2 - 1; 60 int y = (tft.height() - 300) / 2 - 1; 61 62 drawArrayJpeg(EagleEye, sizeof(EagleEye), x, y); // Draw a jpeg image stored in memory at x,y 63 delay(2000); 64 65 66 tft.setRotation(2); // portrait 67 tft.fillScreen(random(0xFFFF)); 68 drawArrayJpeg(Baboon40, sizeof(Baboon40), 0, 0); // Draw a jpeg image stored in memory 69 delay(2000); 70 71 72 tft.setRotation(2); // portrait 73 tft.fillScreen(random(0xFFFF)); 74 drawArrayJpeg(lena20k, sizeof(lena20k), 0, 0); // Draw a jpeg image stored in memory 75 delay(2000); 76 77 tft.setRotation(1); // landscape 78 tft.fillScreen(random(0xFFFF)); 79 80 // This image will be deliberately cropped as it is 480 x 320 thes extends off the screen when plotted 81 // at coordinate 100,100 82 drawArrayJpeg(Mouse480, sizeof(Mouse480), 100, 100); // Draw a jpeg image stored in memory, test cropping 83 //drawArrayJpeg(Mouse480, sizeof(Mouse480), 0, 0); // Draw a jpeg image stored in memory 84 delay(2000); 85 } 86 87 //#################################################################################################### 88 // Draw a JPEG on the TFT pulled from a program memory array 89 //#################################################################################################### 90 void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) { 91 92 int x = xpos; 93 int y = ypos; 94 95 JpegDec.decodeArray(arrayname, array_size); 96 97 jpegInfo(); // Print information from the JPEG file (could comment this line out) 98 99 renderJPEG(x, y); 100 101 Serial.println("#########################"); 102 } 103 104 //#################################################################################################### 105 // Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit 106 //#################################################################################################### 107 // This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not 108 // fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders. 109 void renderJPEG(int xpos, int ypos) { 110 111 // retrieve infomration about the image 112 uint16_t *pImg; 113 uint16_t mcu_w = JpegDec.MCUWidth; 114 uint16_t mcu_h = JpegDec.MCUHeight; 115 uint32_t max_x = JpegDec.width; 116 uint32_t max_y = JpegDec.height; 117 118 // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 119 // Typically these MCUs are 16x16 pixel blocks 120 // Determine the width and height of the right and bottom edge image blocks 121 uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 122 uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 123 124 // save the current image block size 125 uint32_t win_w = mcu_w; 126 uint32_t win_h = mcu_h; 127 128 // record the current time so we can measure how long it takes to draw an image 129 uint32_t drawTime = millis(); 130 131 // save the coordinate of the right and bottom edges to assist image cropping 132 // to the screen size 133 max_x += xpos; 134 max_y += ypos; 135 136 // read each MCU block until there are no more 137 while (JpegDec.read()) { 138 139 // save a pointer to the image block 140 pImg = JpegDec.pImage ; 141 142 // calculate where the image block should be drawn on the screen 143 int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU 144 int mcu_y = JpegDec.MCUy * mcu_h + ypos; 145 146 // check if the image block size needs to be changed for the right edge 147 if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 148 else win_w = min_w; 149 150 // check if the image block size needs to be changed for the bottom edge 151 if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 152 else win_h = min_h; 153 154 // copy pixels into a contiguous block 155 if (win_w != mcu_w) 156 { 157 uint16_t *cImg; 158 int p = 0; 159 cImg = pImg + win_w; 160 for (int h = 1; h < win_h; h++) 161 { 162 p += mcu_w; 163 for (int w = 0; w < win_w; w++) 164 { 165 *cImg = *(pImg + w + p); 166 cImg++; 167 } 168 } 169 } 170 171 // calculate how many pixels must be drawn 172 uint32_t mcu_pixels = win_w * win_h; 173 174 tft.startWrite(); 175 176 // draw image MCU block only if it will fit on the screen 177 if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()) 178 { 179 180 // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 181 tft.setAddrWindow(mcu_x, mcu_y, win_w, win_h); 182 183 // Write all MCU pixels to the TFT window 184 while (mcu_pixels--) { 185 // Push each pixel to the TFT MCU area 186 tft.pushColor(*pImg++); 187 } 188 189 } 190 else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding 191 192 tft.endWrite(); 193 } 194 195 // calculate how long it took to draw the image 196 drawTime = millis() - drawTime; 197 198 // print the results to the serial port 199 Serial.print(F( "Total render time was : ")); Serial.print(drawTime); Serial.println(F(" ms")); 200 Serial.println(F("")); 201 } 202 203 //#################################################################################################### 204 // Print image information to the serial port (optional) 205 //#################################################################################################### 206 void jpegInfo() { 207 Serial.println(F("===============")); 208 Serial.println(F("JPEG image info")); 209 Serial.println(F("===============")); 210 Serial.print(F( "Width :")); Serial.println(JpegDec.width); 211 Serial.print(F( "Height :")); Serial.println(JpegDec.height); 212 Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 213 Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 214 Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 215 Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 216 Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 217 Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 218 Serial.println(F("===============")); 219 } 220 221 //#################################################################################################### 222 // Show the execution time (optional) 223 //#################################################################################################### 224 // WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for 225 // sketch sizes greater than ~70KBytes because 16 bit address pointers are used in some libraries. 226 227 // The Due will work fine with the HX8357_Due library. 228 229 void showTime(uint32_t msTime) { 230 //tft.setCursor(0, 0); 231 //tft.setTextFont(1); 232 //tft.setTextSize(2); 233 //tft.setTextColor(TFT_WHITE, TFT_BLACK); 234 //tft.print(F(" JPEG drawn in ")); 235 //tft.print(msTime); 236 //tft.println(F(" ms ")); 237 Serial.print(F(" JPEG drawn in ")); 238 Serial.print(msTime); 239 Serial.println(F(" ms ")); 240 } 241