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