192 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*====================================================================================
 | |
|   This sketch contains support functions to render the Jpeg images.
 | |
| 
 | |
|   Created by Bodmer 15th Jan 2017
 | |
|   ==================================================================================*/
 | |
| 
 | |
| // Return the minimum of two values a and b
 | |
| #define minimum(a,b)     (((a) < (b)) ? (a) : (b))
 | |
| 
 | |
| //====================================================================================
 | |
| //   Opens the image file and prime the Jpeg decoder
 | |
| //====================================================================================
 | |
| void drawJpeg(const char *filename, int xpos, int ypos) {
 | |
| 
 | |
|   Serial.println("===========================");
 | |
|   Serial.print("Drawing file: "); Serial.println(filename);
 | |
|   Serial.println("===========================");
 | |
| 
 | |
|   // Open the named file (the Jpeg decoder library will close it after rendering image)
 | |
|   fs::File jpegFile = SPIFFS.open( filename, "r");    // File handle reference for SPIFFS
 | |
|   //  File jpegFile = SD.open( filename, FILE_READ);  // or, file handle reference for SD library
 | |
| 
 | |
|   if ( !jpegFile ) {
 | |
|     Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Use one of the three following methods to initialise the decoder:
 | |
|   //boolean decoded = JpegDec.decodeFsFile(jpegFile); // Pass a SPIFFS file handle to the decoder,
 | |
|   //boolean decoded = JpegDec.decodeSdFile(jpegFile); // or pass the SD file handle to the decoder,
 | |
|   boolean decoded = JpegDec.decodeFsFile(filename);  // or pass the filename (leading / distinguishes SPIFFS files)
 | |
|   // Note: the filename can be a String or character array type
 | |
|   if (decoded) {
 | |
|     // print information about the image to the serial port
 | |
|     jpegInfo();
 | |
| 
 | |
|     // render the image onto the screen at given coordinates
 | |
|     jpegRender(xpos, ypos);
 | |
|   }
 | |
|   else {
 | |
|     Serial.println("Jpeg file format not supported!");
 | |
|   }
 | |
| }
 | |
| 
 | |
| //====================================================================================
 | |
| //   Decode and render the Jpeg image onto the TFT screen
 | |
| //====================================================================================
 | |
| void jpegRender(int xpos, int ypos) {
 | |
| 
 | |
|   // retrieve infomration about the image
 | |
|   uint16_t  *pImg;
 | |
|   uint16_t mcu_w = JpegDec.MCUWidth;
 | |
|   uint16_t mcu_h = JpegDec.MCUHeight;
 | |
|   uint32_t max_x = JpegDec.width;
 | |
|   uint32_t max_y = JpegDec.height;
 | |
| 
 | |
|   // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
 | |
|   // Typically these MCUs are 16x16 pixel blocks
 | |
|   // Determine the width and height of the right and bottom edge image blocks
 | |
|   uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
 | |
|   uint32_t min_h = minimum(mcu_h, max_y % mcu_h);
 | |
| 
 | |
|   // save the current image block size
 | |
|   uint32_t win_w = mcu_w;
 | |
|   uint32_t win_h = mcu_h;
 | |
| 
 | |
|   // record the current time so we can measure how long it takes to draw an image
 | |
|   uint32_t drawTime = millis();
 | |
| 
 | |
|   // save the coordinate of the right and bottom edges to assist image cropping
 | |
|   // to the screen size
 | |
|   max_x += xpos;
 | |
|   max_y += ypos;
 | |
| 
 | |
|   // read each MCU block until there are no more
 | |
|   while ( JpegDec.readSwappedBytes()) { // Swap byte order so the SPI buffer can be used
 | |
| 
 | |
|     // save a pointer to the image block
 | |
|     pImg = JpegDec.pImage;
 | |
| 
 | |
|     // calculate where the image block should be drawn on the screen
 | |
|     int mcu_x = JpegDec.MCUx * mcu_w + xpos;  // Calculate coordinates of top left corner of current MCU
 | |
|     int mcu_y = JpegDec.MCUy * mcu_h + ypos;
 | |
| 
 | |
|     // check if the image block size needs to be changed for the right edge
 | |
|     if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
 | |
|     else win_w = min_w;
 | |
| 
 | |
|     // check if the image block size needs to be changed for the bottom edge
 | |
|     if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
 | |
|     else win_h = min_h;
 | |
| 
 | |
|     // copy pixels into a contiguous block
 | |
|     if (win_w != mcu_w)
 | |
|     {
 | |
|       uint16_t *cImg;
 | |
|       int p = 0;
 | |
|       cImg = pImg + win_w;
 | |
|       for (int h = 1; h < win_h; h++)
 | |
|       {
 | |
|         p += mcu_w;
 | |
|         for (int w = 0; w < win_w; w++)
 | |
|         {
 | |
|           *cImg = *(pImg + w + p);
 | |
|           cImg++;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // draw image MCU block only if it will fit on the screen
 | |
|     if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height())
 | |
|     {
 | |
|       tft.pushRect(mcu_x, mcu_y, win_w, win_h, pImg);
 | |
|     }
 | |
| 
 | |
|     else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort();
 | |
| 
 | |
|   }
 | |
| 
 | |
|   // calculate how long it took to draw the image
 | |
|   drawTime = millis() - drawTime; // Calculate the time it took
 | |
| 
 | |
|   // print the results to the serial port
 | |
|   Serial.print  ("Total render time was    : "); Serial.print(drawTime); Serial.println(" ms");
 | |
|   Serial.println("=====================================");
 | |
| 
 | |
| }
 | |
| 
 | |
| //====================================================================================
 | |
| //   Print information decoded from the Jpeg image
 | |
| //====================================================================================
 | |
| void jpegInfo() {
 | |
| 
 | |
|   Serial.println("===============");
 | |
|   Serial.println("JPEG image info");
 | |
|   Serial.println("===============");
 | |
|   Serial.print  ("Width      :"); Serial.println(JpegDec.width);
 | |
|   Serial.print  ("Height     :"); Serial.println(JpegDec.height);
 | |
|   Serial.print  ("Components :"); Serial.println(JpegDec.comps);
 | |
|   Serial.print  ("MCU / row  :"); Serial.println(JpegDec.MCUSPerRow);
 | |
|   Serial.print  ("MCU / col  :"); Serial.println(JpegDec.MCUSPerCol);
 | |
|   Serial.print  ("Scan type  :"); Serial.println(JpegDec.scanType);
 | |
|   Serial.print  ("MCU width  :"); Serial.println(JpegDec.MCUWidth);
 | |
|   Serial.print  ("MCU height :"); Serial.println(JpegDec.MCUHeight);
 | |
|   Serial.println("===============");
 | |
|   Serial.println("");
 | |
| }
 | |
| 
 | |
| //====================================================================================
 | |
| //   Open a Jpeg file and send it to the Serial port in a C array compatible format
 | |
| //====================================================================================
 | |
| void createArray(const char *filename) {
 | |
| 
 | |
|   // Open the named file
 | |
|   fs::File jpgFile = SPIFFS.open( filename, "r");    // File handle reference for SPIFFS
 | |
|   //  File jpgFile = SD.open( filename, FILE_READ);  // or, file handle reference for SD library
 | |
| 
 | |
|   if ( !jpgFile ) {
 | |
|     Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   uint8_t data;
 | |
|   byte line_len = 0;
 | |
|   Serial.println("");
 | |
|   Serial.println("// Generated by a JPEGDecoder library example sketch:");
 | |
|   Serial.println("// https://github.com/Bodmer/JPEGDecoder");
 | |
|   Serial.println("");
 | |
|   Serial.println("#include <pgmspace.h>");
 | |
|   Serial.println("// Remove leading / from array name!");
 | |
|   Serial.print  ("const uint8_t ");
 | |
|   while (*filename != '.') Serial.print(*filename++);
 | |
|   Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due
 | |
| 
 | |
|   while ( jpgFile.available()) {
 | |
| 
 | |
|     data = jpgFile.read();
 | |
|     Serial.print("0x"); if (abs(data) < 16) Serial.print("0");
 | |
|     Serial.print(data, HEX); Serial.print(",");// Add value and comma
 | |
|     line_len++;
 | |
|     if ( line_len >= 32) {
 | |
|       line_len = 0;
 | |
|       Serial.println();
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   Serial.println("};\r\n");
 | |
|   jpgFile.close();
 | |
| }
 | |
| //====================================================================================
 |