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 (7781B)

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