├── extras ├── tiger.jpg ├── Baboon20.jpg ├── Baboon40.jpg ├── EagleEye.jpg ├── Mouse480.jpg ├── arduino.jpg └── lena20k.jpg ├── examples ├── Adafruit_GFX │ ├── Huzzah_Jpeg │ │ ├── data │ │ │ ├── Lena.jpg │ │ │ ├── Mouse.jpg │ │ │ ├── BaboonL.jpg │ │ │ ├── BaboonP.jpg │ │ │ └── EagleEye.jpg │ │ ├── SPIFFS_functions.ino │ │ ├── Huzzah_Jpeg.ino │ │ └── JPEG_functions.ino │ └── NodeMCU_Jpeg │ │ ├── data │ │ ├── Mouse.jpg │ │ ├── BaboonL.jpg │ │ ├── BaboonP.jpg │ │ └── EagleEye.jpg │ │ ├── SPIFFS_functions.ino │ │ ├── NodeMCU_Jpeg.ino │ │ └── JPEG_functions.ino ├── Other libraries │ ├── SPIFFS_Jpeg │ │ ├── Data │ │ │ ├── tiger.jpg │ │ │ └── Baboon40.jpg │ │ ├── SPIFFS_functions.ino │ │ ├── SPIFFS_Jpeg.ino │ │ └── JPEG_functions.ino │ ├── NodeMCU_Jpeg_ESP │ │ ├── data │ │ │ └── BaboonL.jpg │ │ ├── SPIFFS_functions.ino │ │ ├── NodeMCU_Jpeg_ESP.ino │ │ └── JPEG_functions.ino │ └── Mega and Due │ │ ├── TFT_flash_jpg │ │ ├── TFT_flash_jpg.ino │ │ └── jpeg2.h │ │ └── TFT_SDcard_jpg │ │ └── TFT_SDcard_jpg.ino ├── MCUFRIEND_kbv │ └── jpeg_kbv │ │ ├── jpeg_kbv.ino │ │ └── JPEG_Functions.ino ├── ILI9341_due │ └── Due_SD_Jpeg │ │ ├── Due_SD_Jpeg.ino │ │ └── JPEG_functions.ino ├── UTFT │ ├── UTFT_SD_Jpeg │ │ ├── UTFT_SD_Jpeg.ino │ │ └── Jpeg_utilities.ino │ └── UTFT_Flash_Jpeg │ │ └── UTFT_Flash_Jpeg.ino └── Arduino TFT │ └── TFT_Jpeg │ └── TFT_Jpeg.ino ├── library.properties ├── library.json ├── keywords.txt ├── license.txt ├── src ├── User_Config.h ├── JPEGDecoder.h ├── picojpeg.h └── JPEGDecoder.cpp └── README.md /extras/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/tiger.jpg -------------------------------------------------------------------------------- /extras/Baboon20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/Baboon20.jpg -------------------------------------------------------------------------------- /extras/Baboon40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/Baboon40.jpg -------------------------------------------------------------------------------- /extras/EagleEye.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/EagleEye.jpg -------------------------------------------------------------------------------- /extras/Mouse480.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/Mouse480.jpg -------------------------------------------------------------------------------- /extras/arduino.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/arduino.jpg -------------------------------------------------------------------------------- /extras/lena20k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/extras/lena20k.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/data/Lena.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/Huzzah_Jpeg/data/Lena.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/data/Mouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/Huzzah_Jpeg/data/Mouse.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/data/Mouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/NodeMCU_Jpeg/data/Mouse.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/data/BaboonL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/Huzzah_Jpeg/data/BaboonL.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/data/BaboonP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/Huzzah_Jpeg/data/BaboonP.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/data/EagleEye.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/Huzzah_Jpeg/data/EagleEye.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/data/BaboonL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/NodeMCU_Jpeg/data/BaboonL.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/data/BaboonP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/NodeMCU_Jpeg/data/BaboonP.jpg -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/data/EagleEye.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Adafruit_GFX/NodeMCU_Jpeg/data/EagleEye.jpg -------------------------------------------------------------------------------- /examples/Other libraries/SPIFFS_Jpeg/Data/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Other libraries/SPIFFS_Jpeg/Data/tiger.jpg -------------------------------------------------------------------------------- /examples/Other libraries/SPIFFS_Jpeg/Data/Baboon40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Other libraries/SPIFFS_Jpeg/Data/Baboon40.jpg -------------------------------------------------------------------------------- /examples/Other libraries/NodeMCU_Jpeg_ESP/data/BaboonL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/JPEGDecoder/HEAD/examples/Other libraries/NodeMCU_Jpeg_ESP/data/BaboonL.jpg -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=JPEGDecoder 2 | version=2.0.0 3 | author=Bodmer , Makoto Kurauchi, Rich Geldreich 4 | maintainer=Bodmer 5 | sentence= Jpeg decoder tested with Arduino Mega, Arduino Due and ESP8266 based NodeMCU 1.0 6 | paragraph=Decodes jpeg images stored in arrays, SD card files and SPIFFS files 7 | category=Display 8 | url=https://github.com/Bodmer/JPEGDecoder 9 | architectures=* 10 | includes=JPEGDecoder.h 11 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JPEGDecoder", 3 | "version": "2.0.0", 4 | "keywords": "jpeg, jpg, decoder, TFT", 5 | "description": "A JPEG decoder library, tested on Mega, Due and ESP8266", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/Bodmer/JPEGDecoder.git" 10 | }, 11 | "authors": 12 | [ 13 | { 14 | "name": "Bodmer", 15 | "email": "bodmer@anola.net", 16 | "maintainer": true 17 | }, 18 | { 19 | "name": "Makoto Kurauchi", 20 | "url": "http://yushakobo.jp" 21 | }, 22 | { 23 | "name": "Rich Geldreich", 24 | "email": "richgel99@gmail.com" 25 | } 26 | ], 27 | "frameworks": "arduino", 28 | "platforms": ["atmelavr","atmelsam","espressif8266"] 29 | } 30 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | ####################################### 5 | # Datatypes (KEYWORD1) 6 | ####################################### 7 | 8 | JPEGDecoder KEYWORD1 9 | 10 | ####################################### 11 | # Methods and Functions (KEYWORD2) 12 | ####################################### 13 | 14 | JpegDec KEYWORD2 15 | pImage KEYWORD2 16 | width KEYWORD2 17 | height KEYWORD2 18 | comps KEYWORD2 19 | MCUSPerRow KEYWORD2 20 | MCUSPerCol KEYWORD2 21 | scanType KEYWORD2 22 | MCUWidth KEYWORD2 23 | MCUHeight KEYWORD2 24 | MCUx KEYWORD2 25 | MCUy KEYWORD2 26 | JPEGDecoder KEYWORD2 27 | decode KEYWORD2 28 | decodeFile KEYWORD2 29 | decodeSdFile KEYWORD2 30 | decodeFsFile KEYWORD2 31 | decodeArray KEYWORD2 32 | available KEYWORD2 33 | abort KEYWORD2 34 | read KEYWORD2 35 | readSwappedBytes KEYWORD2 36 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/SPIFFS_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions for the ESP6266 SPIFFS filing system 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | //==================================================================================== 8 | // Print a SPIFFS directory list (root directory) 9 | //==================================================================================== 10 | 11 | void listFiles(void) { 12 | Serial.println(); 13 | Serial.println("SPIFFS files found:"); 14 | 15 | fs::Dir dir = SPIFFS.openDir("/"); // Root directory 16 | String line = "====================================="; 17 | 18 | Serial.println(line); 19 | Serial.println(" File name Size"); 20 | Serial.println(line); 21 | 22 | while (dir.next()) { 23 | String fileName = dir.fileName(); 24 | Serial.print(fileName); 25 | int spaces = 25 - fileName.length(); // Tabulate nicely 26 | while (spaces--) Serial.print(" "); 27 | fs::File f = dir.openFile("r"); 28 | Serial.print(f.size()); Serial.println(" bytes"); 29 | } 30 | 31 | Serial.println(line); 32 | Serial.println(); 33 | delay(1000); 34 | } 35 | //==================================================================================== 36 | 37 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/SPIFFS_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions for the ESP6266 SPIFFS filing system 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | //==================================================================================== 8 | // Print a SPIFFS directory list (root directory) 9 | //==================================================================================== 10 | 11 | void listFiles(void) { 12 | Serial.println(); 13 | Serial.println("SPIFFS files found:"); 14 | 15 | fs::Dir dir = SPIFFS.openDir("/"); // Root directory 16 | String line = "====================================="; 17 | 18 | Serial.println(line); 19 | Serial.println(" File name Size"); 20 | Serial.println(line); 21 | 22 | while (dir.next()) { 23 | String fileName = dir.fileName(); 24 | Serial.print(fileName); 25 | int spaces = 25 - fileName.length(); // Tabulate nicely 26 | while (spaces--) Serial.print(" "); 27 | fs::File f = dir.openFile("r"); 28 | Serial.print(f.size()); Serial.println(" bytes"); 29 | } 30 | 31 | Serial.println(line); 32 | Serial.println(); 33 | delay(1000); 34 | } 35 | //==================================================================================== 36 | 37 | -------------------------------------------------------------------------------- /examples/Other libraries/NodeMCU_Jpeg_ESP/SPIFFS_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions for the ESP6266 SPIFFS filing system 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | //==================================================================================== 8 | // Print a SPIFFS directory list (root directory) 9 | //==================================================================================== 10 | 11 | void listFiles(void) { 12 | Serial.println(); 13 | Serial.println("SPIFFS files found:"); 14 | 15 | fs::Dir dir = SPIFFS.openDir("/"); // Root directory 16 | String line = "====================================="; 17 | 18 | Serial.println(line); 19 | Serial.println(" File name Size"); 20 | Serial.println(line); 21 | 22 | while (dir.next()) { 23 | String fileName = dir.fileName(); 24 | Serial.print(fileName); 25 | int spaces = 25 - fileName.length(); // Tabulate nicely 26 | while (spaces--) Serial.print(" "); 27 | fs::File f = dir.openFile("r"); 28 | Serial.print(f.size()); Serial.println(" bytes"); 29 | } 30 | 31 | Serial.println(line); 32 | Serial.println(); 33 | delay(1000); 34 | } 35 | //==================================================================================== 36 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | 2 | Arduino JPEGDecoder library 3 | =========================== 4 | 5 | The original picojpeg.c and picojepeg.h code used in this Arduino library is hosted here: 6 | https://code.google.com/archive/p/picojpeg/ 7 | 8 | The JPEGDecoder library has been developed from the Arduino library by Makoto Kurauchi here: 9 | https://github.com/MakotoKurauchi/JPEGDecoder 10 | 11 | The library has been developed and debugged by Bodmer and is hosted here: 12 | https://github.com/Bodmer/JPEGDecoder 13 | 14 | The picojpeg code and the developed library is dual licensed as both public domain and 15 | (where public domain is not acceptable) the MIT license: 16 | 17 | 18 | picojeg code: Copyright 2013 Rich Geldreich 19 | Arduino JPEGDecoder library: Copyright 2019 Makoto Kurauchi, Bodmer 20 | 21 | MIT license: 22 | 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 24 | associated documentation files (the "Software"), to deal in the Software without restriction, 25 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 26 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in all copies or 30 | substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 33 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 34 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 35 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | -------------------------------------------------------------------------------- /src/User_Config.h: -------------------------------------------------------------------------------- 1 | // Comment out the next #defines if you are not using an SD Card to store the JPEGs 2 | // Commenting out the line is NOT essential but will save some FLASH space if 3 | // SD Card access is not needed. Note: use of SdFat is currently untested! 4 | 5 | #define LOAD_SD_LIBRARY // Default SD Card library 6 | //#define LOAD_SDFAT_LIBRARY // Use SdFat library instead, so SD Card SPI can be bit bashed 7 | 8 | 9 | // Note for ESP8266 users: 10 | // If the sketch uses SPIFFS and has included FS.h without defining FS_NO_GLOBALS first 11 | // then the JPEGDecoder library will NOT load the SD or SdFat libraries. Use lines thus 12 | // in your sketch (see the examples included in the JPEGDecoder library): 13 | /* 14 | #define FS_NO_GLOBALS 15 | #include 16 | 17 | // You will then need to directly reference the SPIFFS File type thus in the sketch, e.g.: 18 | 19 | fs::File jpegFile = SPIFFS.open( filename, "r"); // Example 20 | 21 | // This will then allow the default method of using the SD library File type to be used 22 | // in the same sketch, e.g.: 23 | 24 | File jpegFile = SD.open( filename, FILE_READ); 25 | 26 | */ 27 | 28 | // This is all to avoid a redefinition of 'class fs::File' error due to a conflict between the 29 | // duplicate definitions in the SD library and the SPIFFS library. 30 | 31 | 32 | #ifdef ARDUINO_ARCH_ESP8266 33 | // Uncomment out the next #define if you want the bytes swapped in the image blocks 34 | // returned by read(). 35 | 36 | // Swapping the bytes is only needed to use the ESP8266 SPI library writePattern() 37 | // member function and it is better to use readSwappedBytes() instead of read() in 38 | // the sketch. Images will look psychedelic with wrong colours if the SPI transmit byte 39 | // order is not right for your sketch! 40 | 41 | #define SWAP_BYTES // Deprecated, only included for backwards compatibility 42 | #endif 43 | -------------------------------------------------------------------------------- /examples/MCUFRIEND_kbv/jpeg_kbv/jpeg_kbv.ino: -------------------------------------------------------------------------------- 1 | // This sketch draws a Jpeg file stored in an array onto the TFT screen using the 2 | // MCUFRIEND_kbv library: 3 | // https://github.com/prenticedavid/MCUFRIEND_kbv 4 | 5 | // The MCUFRIEND_kbv library is compatible with many different screens with 6 | // different pixelwidths and heights. 7 | 8 | // This sketch renders a 240 x 320 pixel image on the screen in portrait orientation. 9 | // It has been tested on a Mega and Due with an 8 bit ILI9481 3.5" TFT shield. 10 | // Note: an UNO does not have enough memory to run this sketch. 11 | 12 | // Created by Bodmer 5th Feb 2017 13 | 14 | #include 15 | #include 16 | MCUFRIEND_kbv tft; 17 | 18 | #include // Not used in this example 19 | 20 | #include // JPEG decoder library 21 | 22 | // Include the sketch header file that contains the image stored as an array of bytes 23 | // More than one image array could be stored in each header file. 24 | #include "jpeg1.h" 25 | 26 | uint16_t ID; 27 | 28 | void setup(void) 29 | { 30 | Serial.begin(9600); 31 | tft.reset(); 32 | ID = tft.readID(); 33 | Serial.print("TFT ID = 0x"); 34 | Serial.println(ID, HEX); 35 | // if (ID == 0x00D3) ID = 0x9481; // write-only shield 36 | if (ID == 0x00D3) ID = 0x9486; // write-only shield 37 | tft.begin(ID); 38 | tft.setRotation(0); 39 | } 40 | 41 | void loop(void) 42 | { 43 | uint32_t clearTime = millis(); 44 | tft.fillScreen(random(0x10000)); 45 | clearTime = millis() - clearTime; // Calculate the time it took 46 | 47 | // print the results to the serial port 48 | Serial.print(F( "Total clear time was : ")); Serial.print(clearTime); Serial.println(F(" ms")); 49 | Serial.println(F("")); 50 | 51 | // Draw a jpeg image stored in memory 52 | drawArrayJpeg(Baboon, sizeof(Baboon), 0, 0); 53 | 54 | delay(5000); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /examples/Other libraries/SPIFFS_Jpeg/SPIFFS_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions for the ESP6266 SPIFFS filing system 3 | 4 | Created by Bodmer 15th Jan 2017 5 | Updated by Bodmer to support ESP32 with SPIFFS Jan 2018 6 | ==================================================================================*/ 7 | 8 | //==================================================================================== 9 | // Print a SPIFFS directory list (root directory) 10 | //==================================================================================== 11 | #ifdef ARDUINO_ARCH_ESP8266 12 | void listFiles(void) { 13 | Serial.println(); 14 | Serial.println("SPIFFS files found:"); 15 | 16 | fs::Dir dir = SPIFFS.openDir("/"); // Root directory 17 | String line = "====================================="; 18 | 19 | Serial.println(line); 20 | Serial.println(" File name Size"); 21 | Serial.println(line); 22 | 23 | while (dir.next()) { 24 | String fileName = dir.fileName(); 25 | Serial.print(fileName); 26 | int spaces = 21 - fileName.length(); // Tabulate nicely 27 | while (spaces--) Serial.print(" "); 28 | 29 | fs::File f = dir.openFile("r"); 30 | String fileSize = (String) f.size(); 31 | spaces = 10 - fileSize.length(); // Tabulate nicely 32 | while (spaces--) Serial.print(" "); 33 | Serial.println(fileSize + " bytes"); 34 | } 35 | 36 | Serial.println(line); 37 | Serial.println(); 38 | delay(1000); 39 | } 40 | #endif 41 | 42 | //==================================================================================== 43 | 44 | #ifdef ESP32 45 | 46 | void listFiles(void) { 47 | listDir(SPIFFS, "/", 0); 48 | } 49 | 50 | void listDir(fs::FS &fs, const char * dirname, uint8_t levels) { 51 | 52 | Serial.println(); 53 | Serial.println("SPIFFS files found:"); 54 | 55 | Serial.printf("Listing directory: %s\n", "/"); 56 | String line = "====================================="; 57 | 58 | Serial.println(line); 59 | Serial.println(" File name Size"); 60 | Serial.println(line); 61 | 62 | fs::File root = fs.open(dirname); 63 | if (!root) { 64 | Serial.println("Failed to open directory"); 65 | return; 66 | } 67 | if (!root.isDirectory()) { 68 | Serial.println("Not a directory"); 69 | return; 70 | } 71 | 72 | fs::File file = root.openNextFile(); 73 | while (file) { 74 | 75 | if (file.isDirectory()) { 76 | Serial.print("DIR : "); 77 | String fileName = file.name(); 78 | Serial.print(fileName); 79 | if (levels) { 80 | listDir(fs, file.name(), levels - 1); 81 | } 82 | } else { 83 | String fileName = file.name(); 84 | Serial.print(" " + fileName); 85 | int spaces = 20 - fileName.length(); // Tabulate nicely 86 | while (spaces--) Serial.print(" "); 87 | String fileSize = (String) file.size(); 88 | spaces = 10 - fileSize.length(); // Tabulate nicely 89 | while (spaces--) Serial.print(" "); 90 | Serial.println(fileSize + " bytes"); 91 | } 92 | 93 | file = root.openNextFile(); 94 | } 95 | 96 | Serial.println(line); 97 | Serial.println(); 98 | delay(1000); 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /examples/ILI9341_due/Due_SD_Jpeg/Due_SD_Jpeg.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch is based on the sdFatTftBitmap example sketch from the ILI9341_due library. 3 | 4 | See: http://marekburiak.github.io/ILI9341_due/ 5 | 6 | Adapted by Bodmer 20th January 2017 to incorporate the JPEGDecoder library and draw 7 | Jpeg images that have been stored on an SD card. 8 | 9 | It is compatible with the Mega and Due boards, modify the defined CS, DC pins 10 | for the TFT and SD connections to suit your setup. 11 | 12 | You can generate your own Jpeg images from digital photographs by cropping and resizing 13 | by using commonly available picture/image editors such as Paint or IrfanView. 14 | The example image used by the sketch is in the extras folder in the JPEGDecoder library, 15 | copy the "arduino.jpg" file to the SD card. 16 | 17 | See: https://github.com/Bodmer/JPEGDecoder 18 | 19 | The Arduino IDE's built in SD library is used: 20 | 21 | https://www.arduino.cc/en/reference/SD 22 | */ 23 | 24 | // IMPORTANT: Edit the ILI9341_due_config.h to select: 25 | // #define ILI9341_SPI_MODE_NORMAL // uses SPI library 26 | // this sketch will not work if the Due DMA or SPI extended mode is enabled. 27 | // Use the hardware SPI lines MOSI, MISO and SCK to interface with both the TFT and 28 | // the SD card. 29 | 30 | //==================================================================================== 31 | // libraries 32 | //==================================================================================== 33 | 34 | #include 35 | #include // Use the Arduino IDE built-in SD library 36 | 37 | #include 38 | #include 39 | 40 | #include // JPEG decoder library 41 | 42 | 43 | //==================================================================================== 44 | // defines 45 | //==================================================================================== 46 | 47 | #define TFT_RST 8 // Reset for TFT 48 | #define TFT_DC 9 // Command/Data for TFT 49 | #define TFT_CS 10 // Chip Select for TFT 50 | 51 | #define SD_CS 4 // Chip Select for SD card 52 | 53 | #define TFT_BLACK 0x0000 54 | #define TFT_WHITE 0xFFFF 55 | 56 | //==================================================================================== 57 | // setup 58 | //==================================================================================== 59 | 60 | ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, TFT_RST); 61 | 62 | void setup() 63 | { 64 | Serial.begin(9600); 65 | 66 | // Make sure the SD card chip select is high before we initialise the TFT 67 | pinMode(SD_CS, OUTPUT); 68 | digitalWrite(SD_CS, HIGH); 69 | 70 | // Initialise the TFT 71 | tft.begin(); 72 | tft.fillScreen(TFT_BLACK); 73 | 74 | Serial.print(F("Initialising SD card...")); 75 | 76 | if (!SD.begin(SD_CS)){ 77 | Serial.println(F("failed!")); 78 | return; 79 | } 80 | Serial.println(F("OK!")); 81 | } 82 | 83 | 84 | //==================================================================================== 85 | // loop 86 | //==================================================================================== 87 | 88 | void loop() 89 | { 90 | tft.setRotation((iliRotation)0); // Landscape orientation 91 | 92 | // draw Arduino logo at a random position 93 | drawJpeg( "arduino.jpg", random(tft.width() - 160), random(tft.height() - 128) ); 94 | 95 | delay(2000); 96 | 97 | tft.fillScreen(random(0xFFFF)); 98 | } 99 | 100 | -------------------------------------------------------------------------------- /examples/UTFT/UTFT_SD_Jpeg/UTFT_SD_Jpeg.ino: -------------------------------------------------------------------------------- 1 | // This sketch draws Jpeg files stored on an SD card on a TFT screen, it is based on the UTFT_Bitmap 2 | // by Henning Karlsen. 3 | // web: http://www.RinkyDinkElectronics.com/ 4 | // 5 | // This demo uses an Arduino Due and a 320x240 ILI9341 SPI based TFT screen. 6 | // The demo should also run on an Arduino Mega, but it will be slower 7 | /* 8 | By default the UTFT library does not configure the Gamma curve settings for the ILI9341 TFT, 9 | so photo images may not render well. To correct this ensure the set Gamma curve section 10 | in initlcd.h (library folder UTFT\tft_drivers\ili9341\s5p\initlcd.h) is NOT commented out. 11 | 12 | You can generate your own Jpeg images from digital photographs by cropping and resizing 13 | by using commonly available picture/image editors such as Paint or IrfanView. 14 | */ 15 | 16 | // The latest JPEGDecoder library can be found here: 17 | // https://github.com/Bodmer/JPEGDecoder 18 | 19 | // Information on JPEG compression can be found here: 20 | // https://en.wikipedia.org/wiki/JPEG 21 | 22 | 23 | 24 | //==================================================================================== 25 | // libraries 26 | //==================================================================================== 27 | 28 | #include 29 | #include // Use the Arduino IDE built-in SD library 30 | 31 | #include 32 | 33 | #include // JPEG decoder library 34 | 35 | 36 | //==================================================================================== 37 | // definitions 38 | //==================================================================================== 39 | 40 | // Set the pins to the correct ones for your SPI TFT 41 | // ------------------------------------------------------------ 42 | #define TFT_SDA 7 // Do not use hardware SPI MOSI pin 43 | #define TFT_SCL 6 // Do not use hardware SPI SCK pin 44 | #define TFT_CS 10 // Chip Select for TFT 45 | #define TFT_RS 9 // Register select (also called DC) 46 | #define TFT_RST 8 // uncomment if you have ILI9340 47 | 48 | // SD card connects to hardware SPI pins MOSI, MISO and SCK and the following chip select 49 | #define SD_CS 4 // Chip Select for SD card 50 | 51 | // this function determines the minimum of two numbers 52 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 53 | 54 | 55 | //==================================================================================== 56 | // setup 57 | //==================================================================================== 58 | 59 | // Remember to change the model parameter to suit your display module! 60 | UTFT myGLCD(ILI9341_S5P,TFT_SDA, TFT_SCL, TFT_CS, TFT_RST, TFT_RS); 61 | 62 | void setup() 63 | { 64 | Serial.begin(9600); 65 | 66 | myGLCD.InitLCD(PORTRAIT); // The test image is for a portrait orientation 67 | 68 | myGLCD.fillScr(255, 255, 255); 69 | 70 | // Initialise the SD card interface, check it is OK 71 | Serial.print(F("Initialising SD card...")); 72 | 73 | if (!SD.begin(SD_CS)){ 74 | Serial.println(F("failed!")); 75 | return; 76 | } 77 | Serial.println(F("OK!")); 78 | } 79 | 80 | 81 | //==================================================================================== 82 | // loop 83 | //==================================================================================== 84 | 85 | void loop() 86 | { 87 | // draw jpeg image at 0,0 88 | jpegDraw( "tiger.jpg", 0, 0 ); 89 | 90 | // draw Arduino logo at a random position within the screen area 91 | jpegDraw( "arduino.jpg", random(myGLCD.getDisplayXSize() - 160), random(myGLCD.getDisplayYSize() - 128) ); 92 | 93 | delay(5000); 94 | } 95 | 96 | //==================================================================================== 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino JPEGDecoder library 2 | =========== 3 | 4 | News: October 2019 - *I have created a new Arduino compatible [Jpeg decoder library here.](https://github.com/Bodmer/TJpg_Decoder) This new library is based on TinyJpegDec, this is 60% faster on 32bit processors, it also has a much simpler interface.* 5 | 6 | This Arduino library supports the rendering of Jpeg files stored both on SD card and in arrays within program memory (FLASH) onto a TFT display. In addition images stored in the LittleFS Flash filing system or "PROGMEM" arrays can be used with the RP2040, ESP8266 and ESP32 processors. For the ESP8266 use board Core 2.3.0 (or later) in the Arduino IDE to avoid File definition conflicts if the SPIFFS and SD libraries are used together. 7 | 8 | The library works on the Arduino Due, ESP32 and ESP8266 (e.g. NodeMCU 1.0). Users have also reported success with the STM32 based processor boards. 9 | 10 | Example images can be found in the "extras" folder. 11 | 12 | Jpeg files must be in 24bit format (8 bit not supported). Jpeg files in the "Progressive" format (where image data is compressed in multiple passes with progressively higher detail) are not supported either since this would require much more memory. 13 | 14 | High Jpeg compression ratios work best on images with smooth colour changes, however the Baboon40.jpg image at only 23.8 KBytes renders quite nicely. Typically a 480x320 image can be compressed without much degradation to less than 32 KBytes, in comparison a 24 bit BMP image would occupy 461 KBytes! For comaprison the 480 x 320 Mouse480 image has been to compressed to a mere 6.45 Kbytes! 15 | 16 | When storing the jpeg in a memory array bear in mind the Arduino AVR processors (e.g. Mega2560 and Xmega) have a maximum 32767 byte limit for the maximum size of an array (32 KBytes minus 1 byte). 17 | 18 | The decompression of Jpeg images needs more RAM than an UNO provides, thus this library is targetted at processors with more RAM. The library has been tested with Arduino Due and ESP8266/ESP32 based boards. 19 | 20 | The decompression of Jpegs involves a lot of maths, so it takes a Due about ~1.3s to render a fullscreen (480x320 pixel) image and the Mega will take ~5s to do the same. The time for smaller images will reduce roughly pro-rata with the total pixel count. An ESP8266 running at 160MHz and 40MHz SPI coupled to a 320x240 ILI9341 display can render a Jpeg in as little as 240ms. 21 | 22 | This library supports either the SD library (and SdFat for Due). The SdFat allows a bit-bashed SPI interface to an SD Card which can be convenient for example on pins 50, 51 and 52 of a Due (on Mega these are hardware SPI). 23 | 24 | The library has been tested with the 1.8.1 version of the Arduino IDE and may generate error messages at compile time on other versions because "#ifdef \_\_AVR\_\_" is used to distinguish between the Mega and Due and select the correct libraries. 25 | 26 | The library has been tested with 3.2" and 3.0" displays based on the HX8357B, HX8357C and ILI9481 driver chips with a 16 bit parallel interface. Adapting the example sketch for other TFT drivers and their graphics libraries should be quite easy if they support either setWindow() or SetAddrWindow() and pushColor() functions as found in the Adafruit_GFX library. 27 | 28 | The Arduino Mega is not recommended as it does not reliably decode some jpeg images possibly due to a shortage of RAM. The Due will work fine with much bigger image sets in FLASH. 29 | 30 | The ESP8266 and ESP32 has been tested with an ILI9341 library using the SPI interface, with Jpeg images stored in SPIFFS and in Flash arrays. 31 | 32 | SD and SPIFFS filenames can be in String or character array format. File handles can also be used. 33 | 34 | This library has been based on the excellent picojpeg code and the Arduino library port by Makoto Kurauchi here: 35 | https://github.com/MakotoKurauchi/JPEGDecoder 36 | 37 | 38 | Makoto's original Readme below: 39 | ============================== 40 | 41 | JPEG Decoder for Arduino 42 | 43 | 概要 44 | ---- 45 | Arduino 用 JPEG デコーダです。デコーダ部には [picojpeg](https://code.google.com/p/picojpeg/) を使用しています。 46 | 47 | サンプルコード 48 | ---- 49 | ###SerialCsvOut 50 | 51 | SD カード上の JPEG ファイルをブロックごとにデコードし、シリアルから CSV を出力します。 52 | 53 | 変更履歴 54 | ---- 55 | V0.01 - 最初のリリース 56 | -------------------------------------------------------------------------------- /src/JPEGDecoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | JPEGDecoder.h 3 | 4 | JPEG Decoder for Arduino 5 | Public domain, Makoto Kurauchi 6 | 7 | Adapted by Bodmer for use with a TFT screen 8 | 9 | Latest version here: 10 | https://github.com/Bodmer/JPEGDecoder 11 | 12 | */ 13 | 14 | #ifndef JPEGDECODER_H 15 | #define JPEGDECODER_H 16 | 17 | #ifndef JPEGDECODER_SETUP_LOADED // Lets PlatformIO users define settings in 18 | // platformio.ini 19 | #include "User_Config.h" 20 | #endif // JPEGDECODER_SETUP_LOADED 21 | 22 | #include "Arduino.h" 23 | 24 | #ifdef __AVR__ 25 | #include 26 | #undef PROGMEM 27 | #define PROGMEM __attribute__((section(".fini2"))) 28 | #endif 29 | 30 | #ifdef ESP32 // SDFAT library not compatible with ESP32 31 | //#undef LOAD_SD_LIBRARY 32 | #undef LOAD_SDFAT_LIBRARY 33 | #endif 34 | 35 | // New ESP8266 board package uses ARDUINO_ARCH_ESP8266 36 | // old package defined ESP8266 37 | #if defined (ESP8266) 38 | #ifndef ARDUINO_ARCH_ESP8266 39 | #define ARDUINO_ARCH_ESP8266 40 | #endif 41 | #endif 42 | 43 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 44 | #define LOAD_FLASH_FS 45 | #include 46 | #include 47 | #include 48 | #define SPIFFS LittleFS 49 | #elif defined (ARDUINO_ARCH_RP2040) 50 | #define LOAD_FLASH_FS 51 | #include 52 | #include 53 | #define SPIFFS LittleFS 54 | #define TJPGD_LOAD_FFS 55 | #endif 56 | 57 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 58 | #ifdef LOAD_SDFAT_LIBRARY 59 | #include // Alternative where we might need to bit bash the SPI 60 | #else 61 | #include // Default 62 | #endif 63 | #endif 64 | 65 | 66 | #include "picojpeg.h" 67 | 68 | enum { 69 | JPEG_ARRAY = 0, 70 | JPEG_FS_FILE, 71 | JPEG_SD_FILE 72 | }; 73 | 74 | //#define DEBUG 75 | 76 | //------------------------------------------------------------------------------ 77 | #ifndef jpg_min 78 | #define jpg_min(a,b) (((a) < (b)) ? (a) : (b)) 79 | #endif 80 | 81 | //------------------------------------------------------------------------------ 82 | typedef unsigned char uint8; 83 | typedef unsigned int uint; 84 | //------------------------------------------------------------------------------ 85 | 86 | class JPEGDecoder { 87 | 88 | private: 89 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 90 | File g_pInFileSd; 91 | #endif 92 | #ifdef LOAD_FLASH_FS 93 | fs::File g_pInFileFs; 94 | #endif 95 | pjpeg_scan_type_t scan_type; 96 | pjpeg_image_info_t image_info; 97 | 98 | int is_available; 99 | int mcu_x; 100 | int mcu_y; 101 | uint g_nInFileSize; 102 | uint g_nInFileOfs; 103 | uint row_pitch; 104 | uint decoded_width, decoded_height; 105 | uint row_blocks_per_mcu, col_blocks_per_mcu; 106 | uint8 status; 107 | uint8 jpg_source = 0; 108 | uint8_t* jpg_data; 109 | 110 | static uint8 pjpeg_callback(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data); 111 | uint8 pjpeg_need_bytes_callback(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data); 112 | int decode_mcu(void); 113 | int decodeCommon(void); 114 | public: 115 | 116 | uint16_t *pImage; 117 | JPEGDecoder *thisPtr; 118 | 119 | int width; 120 | int height; 121 | int comps; 122 | int MCUSPerRow; 123 | int MCUSPerCol; 124 | pjpeg_scan_type_t scanType; 125 | int MCUWidth; 126 | int MCUHeight; 127 | int MCUx; 128 | int MCUy; 129 | 130 | JPEGDecoder(); 131 | ~JPEGDecoder(); 132 | 133 | int available(void); 134 | int read(void); 135 | int readSwappedBytes(void); 136 | 137 | int decodeFile (const char *pFilename); 138 | int decodeFile (const String& pFilename); 139 | 140 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 141 | int decodeSdFile (const char *pFilename); 142 | int decodeSdFile (const String& pFilename); 143 | int decodeSdFile (File g_pInFile); 144 | #endif 145 | 146 | #ifdef LOAD_FLASH_FS 147 | int decodeFsFile (const char *pFilename); 148 | int decodeFsFile (const String& pFilename); 149 | int decodeFsFile (fs::File g_pInFile); 150 | #endif 151 | 152 | int decodeArray(const uint8_t array[], uint32_t array_size); 153 | void abort(void); 154 | 155 | }; 156 | 157 | extern JPEGDecoder JpegDec; 158 | 159 | #endif // JPEGDECODER_H 160 | -------------------------------------------------------------------------------- /src/picojpeg.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // picojpeg - Public domain, Rich Geldreich 3 | //------------------------------------------------------------------------------ 4 | #ifndef PICOJPEG_H 5 | #define PICOJPEG_H 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | // Error codes 12 | enum 13 | { 14 | PJPG_NO_MORE_BLOCKS = 1, 15 | PJPG_BAD_DHT_COUNTS, 16 | PJPG_BAD_DHT_INDEX, 17 | PJPG_BAD_DHT_MARKER, 18 | PJPG_BAD_DQT_MARKER, 19 | PJPG_BAD_DQT_TABLE, 20 | PJPG_BAD_PRECISION, 21 | PJPG_BAD_HEIGHT, 22 | PJPG_BAD_WIDTH, 23 | PJPG_TOO_MANY_COMPONENTS, 24 | PJPG_BAD_SOF_LENGTH, 25 | PJPG_BAD_VARIABLE_MARKER, 26 | PJPG_BAD_DRI_LENGTH, 27 | PJPG_BAD_SOS_LENGTH, 28 | PJPG_BAD_SOS_COMP_ID, 29 | PJPG_W_EXTRA_BYTES_BEFORE_MARKER, 30 | PJPG_NO_ARITHMITIC_SUPPORT, 31 | PJPG_UNEXPECTED_MARKER, 32 | PJPG_NOT_JPEG, 33 | PJPG_UNSUPPORTED_MARKER, 34 | PJPG_BAD_DQT_LENGTH, 35 | PJPG_TOO_MANY_BLOCKS, 36 | PJPG_UNDEFINED_QUANT_TABLE, 37 | PJPG_UNDEFINED_HUFF_TABLE, 38 | PJPG_NOT_SINGLE_SCAN, 39 | PJPG_UNSUPPORTED_COLORSPACE, 40 | PJPG_UNSUPPORTED_SAMP_FACTORS, 41 | PJPG_DECODE_ERROR, 42 | PJPG_BAD_RESTART_MARKER, 43 | PJPG_ASSERTION_ERROR, 44 | PJPG_BAD_SOS_SPECTRAL, 45 | PJPG_BAD_SOS_SUCCESSIVE, 46 | PJPG_STREAM_READ_ERROR, 47 | PJPG_NOTENOUGHMEM, 48 | PJPG_UNSUPPORTED_COMP_IDENT, 49 | PJPG_UNSUPPORTED_QUANT_TABLE, 50 | PJPG_UNSUPPORTED_MODE, // picojpeg doesn't support progressive JPEG's 51 | }; 52 | 53 | // Scan types 54 | typedef enum 55 | { 56 | PJPG_GRAYSCALE, 57 | PJPG_YH1V1, 58 | PJPG_YH2V1, 59 | PJPG_YH1V2, 60 | PJPG_YH2V2 61 | } pjpeg_scan_type_t; 62 | 63 | typedef struct 64 | { 65 | // Image resolution 66 | int m_width; 67 | int m_height; 68 | 69 | // Number of components (1 or 3) 70 | int m_comps; 71 | 72 | // Total number of minimum coded units (MCU's) per row/col. 73 | int m_MCUSPerRow; 74 | int m_MCUSPerCol; 75 | 76 | // Scan type 77 | pjpeg_scan_type_t m_scanType; 78 | 79 | // MCU width/height in pixels (each is either 8 or 16 depending on the scan type) 80 | int m_MCUWidth; 81 | int m_MCUHeight; 82 | 83 | // m_pMCUBufR, m_pMCUBufG, and m_pMCUBufB are pointers to internal MCU Y or RGB pixel component buffers. 84 | // Each time pjpegDecodeMCU() is called successfully these buffers will be filled with 8x8 pixel blocks of Y or RGB pixels. 85 | // Each MCU consists of (m_MCUWidth/8)*(m_MCUHeight/8) Y/RGB blocks: 1 for greyscale/no subsampling, 2 for H1V2/H2V1, or 4 blocks for H2V2 sampling factors. 86 | // Each block is a contiguous array of 64 (8x8) bytes of a single component: either Y for grayscale images, or R, G or B components for color images. 87 | // 88 | // The 8x8 pixel blocks are organized in these byte arrays like this: 89 | // 90 | // PJPG_GRAYSCALE: Each MCU is decoded to a single block of 8x8 grayscale pixels. 91 | // Only the values in m_pMCUBufR are valid. Each 8 bytes is a row of pixels (raster order: left to right, top to bottom) from the 8x8 block. 92 | // 93 | // PJPG_H1V1: Each MCU contains is decoded to a single block of 8x8 RGB pixels. 94 | // 95 | // PJPG_YH2V1: Each MCU is decoded to 2 blocks, or 16x8 pixels. 96 | // The 2 RGB blocks are at byte offsets: 0, 64 97 | // 98 | // PJPG_YH1V2: Each MCU is decoded to 2 blocks, or 8x16 pixels. 99 | // The 2 RGB blocks are at byte offsets: 0, 100 | // 128 101 | // 102 | // PJPG_YH2V2: Each MCU is decoded to 4 blocks, or 16x16 pixels. 103 | // The 2x2 block array is organized at byte offsets: 0, 64, 104 | // 128, 192 105 | // 106 | // It is up to the caller to copy or blit these pixels from these buffers into the destination bitmap. 107 | unsigned char *m_pMCUBufR; 108 | unsigned char *m_pMCUBufG; 109 | unsigned char *m_pMCUBufB; 110 | } pjpeg_image_info_t; 111 | 112 | typedef unsigned char (*pjpeg_need_bytes_callback_t)(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data); 113 | 114 | // Initializes the decompressor. Returns 0 on success, or one of the above error codes on failure. 115 | // pNeed_bytes_callback will be called to fill the decompressor's internal input buffer. 116 | // If reduce is 1, only the first pixel of each block will be decoded. This mode is much faster because it skips the AC dequantization, IDCT and chroma upsampling of every image pixel. 117 | // Not thread safe. 118 | unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data, unsigned char reduce); 119 | 120 | // Decompresses the file's next MCU. Returns 0 on success, PJPG_NO_MORE_BLOCKS if no more blocks are available, or an error code. 121 | // Must be called a total of m_MCUSPerRow*m_MCUSPerCol times to completely decompress the image. 122 | // Not thread safe. 123 | unsigned char pjpeg_decode_mcu(void); 124 | 125 | #ifdef __cplusplus 126 | } 127 | #endif 128 | 129 | #endif // PICOJPEG_H 130 | -------------------------------------------------------------------------------- /examples/Other libraries/NodeMCU_Jpeg_ESP/NodeMCU_Jpeg_ESP.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | 3 | This sketch demonstrates loading images which have been stored as files in the 4 | built-in FLASH memory on a NodeMCU 1.0 (ESP8266 based, ESP-12E Module) rendering the 5 | images onto a ILI9341 SPI 320 x 240 pixel TFT screen. 6 | 7 | Images are stored in the SPI FLASH Filing System (SPIFFS), which effectively 8 | functions like a tiny "hard drive". This filing system is built into the ESP8266 9 | Core that can be loaded from the IDE "Boards manager" menu option. This is at 10 | version 2.3.0 at the time of sketch creation. 11 | 12 | The size of the SPIFFS partition can be set in the IDE. Typically most sketches 13 | easily fit within 1 Mbyte so a 3 Mbyte SPIFS partition can be used, in which 14 | case it can contain 100's of Jpeg full screem images. 15 | 16 | The NodeMCU, TFT and sketch works with the library here: 17 | https://github.com/Bodmer/TFT_eSPI 18 | 19 | The Jpeg library can be found here: 20 | https://github.com/Bodmer/JPEGDecoder 21 | 22 | Images in the Jpeg format can be created using Paint or IrfanView or other picture 23 | editting software. 24 | 25 | Place the images inside the sketch folder, in a folder called "Data". Then upload 26 | all the files in the folder using the Arduino IDE "ESP8266 Sketch Data Upload" option 27 | in the "Tools" menu: 28 | http://www.esp8266.com/viewtopic.php?f=32&t=10081 29 | https://github.com/esp8266/arduino-esp8266fs-plugin/releases 30 | 31 | This takes some time, but the SPIFFS content is not altered when a new sketch is 32 | uploaded, so there is no need to upload the same files again! 33 | Note: If open, you must close the "Serial Monitor" window to upload data to SPIFFS! 34 | 35 | This sketch includes example images in the Data folder. 36 | 37 | Saving images, uploading and rendering on the TFT screen couldn't be much easier! 38 | 39 | The typical setup for a NodeMCU1.0 (ESP-12 Module) is : 40 | 41 | Display SDO/MISO to NodeMCU pin D6 <<<<<< This is not used by this sketch 42 | Display LED to NodeMCU pin 5V or 3.3V 43 | Display SCK to NodeMCU pin D5 44 | Display SDI/MOSI to NodeMCU pin D7 45 | Display DC/RS (or AO) to NodeMCU pin D3 46 | Display RESET to NodeMCU pin D4 <<<<<< Or connect to NodeMCU RST pin 47 | Display CS to NodeMCU pin D8 48 | Display GND to NodeMCU pin GND (0V) 49 | Display VCC to NodeMCU pin 5V or 3.3V 50 | 51 | Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin 52 | If 5V is not available at a pin you can use 3.3V but backlight brightness 53 | will be lower. 54 | 55 | If the TFT RESET signal is connected to the NodeMCU RST line then define the pin 56 | in the TFT library User_Config.h file as negative so the library ignores it, 57 | e.g. TFT_RST -1 58 | 59 | Created by Bodmer 24th Jan 2017 - Tested in Arduino IDE 1.8.13 esp8266 Core 2.7.4 60 | ==================================================================================*/ 61 | 62 | //==================================================================================== 63 | // Libraries 64 | //==================================================================================== 65 | // Call up the SPIFFS FLASH filing system this is part of the ESP Core 66 | #define FS_NO_GLOBALS 67 | #include 68 | 69 | // JPEG decoder library 70 | #include 71 | 72 | // SPI library, built into IDE 73 | #include 74 | 75 | // Call up the TFT library 76 | #include // Hardware-specific library for ESP8266 77 | // The TFT control pins are set in the User_Setup.h file <<<<<<<<<<<<<<<<< NOTE! 78 | // that can be found in the "src" folder of the library 79 | 80 | // Invoke TFT library 81 | TFT_eSPI tft = TFT_eSPI(); 82 | 83 | //==================================================================================== 84 | // Setup 85 | //==================================================================================== 86 | void setup() 87 | { 88 | Serial.begin(250000); // Used for messages and the C array generator 89 | 90 | delay(10); 91 | Serial.println("NodeMCU decoder test!"); 92 | 93 | tft.begin(); 94 | tft.setRotation(0); // 0 & 2 Portrait. 1 & 3 landscape 95 | tft.fillScreen(TFT_BLACK); 96 | 97 | if (!SPIFFS.begin()) { 98 | Serial.println("SPIFFS initialisation failed!"); 99 | while (1) yield(); // Stay here twiddling thumbs waiting 100 | } 101 | Serial.println("\r\nInitialisation done."); 102 | listFiles(); // Lists the files so you can see what is in the SPIFFS 103 | 104 | } 105 | 106 | //==================================================================================== 107 | // Loop 108 | //==================================================================================== 109 | void loop() 110 | { 111 | // Note the / before the SPIFFS file name must be present, this means the file is in 112 | // the root directory of the SPIFFS, e.g. "/Tiger.jpg" 113 | 114 | tft.setRotation(1); // landscape 115 | tft.fillScreen(random(0xFFFF)); 116 | 117 | //tft.fillScreen(random(0xFFFF)); 118 | drawJpeg("/BaboonL.jpg", 0, 0); 119 | delay(2000); 120 | 121 | while(1) yield(); // Stay here 122 | } 123 | //==================================================================================== 124 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/Huzzah_Jpeg.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | 3 | This sketch demonstrates loading images which have been stored as files in the 4 | built-in FLASH memory on a Adafruit Huzzah(ESP8266 based) rendering them on a TFT screen 5 | that uses a ILI9341 driver chip with SPI interface. 6 | 7 | The images are stored in the SPI FLASH Filing System (SPIFFS), which effectively 8 | functions like a tiny "hard drive". This filing system is built into the ESP8266 9 | Core that can be loaded from the IDE "Boards manager" menu option. This is at 10 | version 2.3.0 at the time of sketch creation. 11 | 12 | The size of the SPIFFS partition can be set in the IDE as 1Mbyte or 3Mbytes. Either 13 | will work with this sketch. Typically most sketches easily fit within 1 Mbyte so a 14 | 3 Mbyte SPIFS partition can be used, in which case it can contain ~18 full screen 15 | 320 x 240 raw images (150 Kbytes each). 16 | 17 | The NodeMCU, TFT and sketch works with the libraries here: 18 | https://github.com/adafruit/Adafruit-GFX-Library 19 | https://github.com/adafruit/Adafruit_ILI9341 20 | 21 | The Jpeg library can be found here: 22 | https://github.com/Bodmer/JPEGDecoder 23 | 24 | Images in the Jpeg format can be created using Paint or IrfanView or other picture 25 | editting software. 26 | 27 | Place the images inside the sketch folder, in a folder called "Data". Then upload 28 | all the files in the folder using the Arduino IDE "ESP8266 Sketch Data Upload" option 29 | in the "Tools" menu: 30 | http://www.esp8266.com/viewtopic.php?f=32&t=10081 31 | https://github.com/esp8266/arduino-esp8266fs-plugin/releases 32 | 33 | This takes some time, but the SPIFFS content is not altered when a new sketch is 34 | uploaded, so there is no need to upload the same files again! 35 | Note: If open, you must close the "Serial Monitor" window for it to upload! 36 | 37 | The IDE will not copy the "data" folder with the sketch if you save the sketch under 38 | another name. It is necessary to manually make a copy and place it in the sketch 39 | folder. 40 | 41 | This sketch includes example images in the Data folder. 42 | 43 | Saving images, uploading and rendering on the TFT screen couldn't be much easier! 44 | 45 | Created by Bodmer 24th Jan 2017 - Tested in Arduino IDE 1.8.0 esp8266 Core 2.3.0 46 | ==================================================================================*/ 47 | 48 | //==================================================================================== 49 | // Libraries 50 | //==================================================================================== 51 | // Call up the SPIFFS FLASH filing system this is part of the ESP Core 52 | #define FS_NO_GLOBALS 53 | #include 54 | 55 | // JPEG decoder library 56 | #include 57 | 58 | #include 59 | 60 | // Call up the TFT libraries 61 | #include 62 | #include 63 | 64 | #define STMPE_CS 16 // D0 65 | #define TFT_CS 0 // D3 66 | #define TFT_DC 15 // D8 67 | #define TFT_RST -1 // Not used 68 | #define SD_CS 2 // D4 69 | 70 | /* There are for a NodeMCU board 71 | #define TFT_CS D8 // Chip select control pin 72 | #define TFT_DC D3 // Data Command control pin 73 | #define TFT_RST D4 // Reset pin (could connect to Arduino RESET pin) 74 | */ 75 | 76 | #define TFT_BLACK 0 77 | 78 | // Invoke TFT library with TFT signal pins 79 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); 80 | 81 | 82 | //==================================================================================== 83 | // Setup 84 | //==================================================================================== 85 | void setup() 86 | { 87 | Serial.begin(115200); // Used for messages 88 | 89 | delay(10); 90 | Serial.println("FeatherWing decoder test!"); 91 | 92 | tft.begin(); 93 | tft.setRotation(0); // 0 & 2 Portrait. 1 & 3 landscape 94 | tft.fillScreen(TFT_BLACK); 95 | 96 | if (!SPIFFS.begin()) { 97 | Serial.println("SPIFFS initialisation failed!"); 98 | while (1) yield(); // Stay here twiddling thumbs waiting 99 | } 100 | Serial.println("\r\nInitialisation done."); 101 | listFiles(); // Lists the files so you can see what is in the SPIFFS 102 | 103 | } 104 | 105 | //==================================================================================== 106 | // Loop 107 | //==================================================================================== 108 | void loop() 109 | { 110 | // Note the / before the SPIFFS file name must be present, this means the file is in 111 | // the root directory of the SPIFFS, e.g. "/Tiger.jpg" for a file called "Tiger.jpg" 112 | 113 | tft.setRotation(0); // portrait 114 | tft.fillScreen(random(0xFFFF)); 115 | 116 | drawFSJpeg("/EagleEye.jpg", 0, 0); 117 | delay(2000); 118 | 119 | // This is quite a famous picture used for testing image compression algorithms 120 | drawFSJpeg("/Lena.jpg", 0, 0); 121 | delay(2000); 122 | 123 | //tft.fillScreen(random(0xFFFF)); 124 | drawFSJpeg("/BaboonP.jpg", 0, 0); 125 | delay(2000); 126 | 127 | tft.setRotation(1); // landscape 128 | //tft.fillScreen(random(0xFFFF)); 129 | drawFSJpeg("/Mouse.jpg", 0, 0); 130 | delay(2000); 131 | 132 | //tft.fillScreen(random(0xFFFF)); 133 | drawFSJpeg("/BaboonL.jpg", 0, 0); 134 | delay(2000); 135 | } 136 | //==================================================================================== 137 | 138 | -------------------------------------------------------------------------------- /examples/Other libraries/SPIFFS_Jpeg/SPIFFS_Jpeg.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | 3 | This sketch demonstrates loading images which have been stored as files in the 4 | built-in FLASH memory on a NodeMCU 1.0 (ESP8266 based, ESP-12E Module) or ESP32 5 | board, rendering the images onto a ILI9341 SPI 320 x 240 pixel TFT screen. 6 | 7 | The images are stored in the SPI FLASH Filing System (SPIFFS), which effectively 8 | functions like a tiny "hard drive". This filing system is built into the ESP8266 9 | Core that can be loaded from the IDE "Boards manager" menu option. This is at 10 | version 2.3.0 at the time of sketch creation. 11 | 12 | The size of the SPIFFS partition can be set in the IDE as 1Mbyte or 3Mbytes. Either 13 | will work with this sketch. Typically most sketches easily fit within 1 Mbyte so a 14 | 3 Mbyte SPIFS partition can be used, in which case it can contain ~18 full screen 15 | 320 x 240 raw images (150 Kbytes each) or 100's of Jpeg full screem images. 16 | 17 | The ESP8266 or ESP32 with the TFT and sketch works with the library here: 18 | https://github.com/Bodmer/TFT_eSPI 19 | 20 | The Jpeg library can be found here: 21 | https://github.com/Bodmer/JPEGDecoder 22 | 23 | Images in the Jpeg format can be created using Paint or IrfanView or other picture 24 | editting software. 25 | 26 | Place the images inside the sketch folder, in a folder called "Data". Then upload 27 | all the files in the folder using the Arduino IDE "ESP8266 Sketch Data Upload" or 28 | "ESP32 Sketch Data Upload" option in the "Tools" menu: 29 | http://www.esp8266.com/viewtopic.php?f=32&t=10081 30 | https://github.com/esp8266/arduino-esp8266fs-plugin/releases 31 | 32 | https://github.com/me-no-dev/arduino-esp32fs-plugin 33 | 34 | Upload takes some time, but the SPIFFS content is not altered when a new sketch is 35 | uploaded, so there is no need to upload the same files again! 36 | Note: If open, you must close the "Serial Monitor" window to upload data to SPIFFS! 37 | 38 | The IDE will not copy the "data" folder with the sketch if you save the sketch under 39 | another name. It is necessary to manually make a copy and place it in the sketch 40 | folder. 41 | 42 | The sketch may crash on an ESP32 if the jpeg file does not exist in the SPIFFS 43 | 44 | This sketch includes example images in the Data folder. 45 | 46 | Saving images, uploading and rendering on the TFT screen couldn't be much easier! 47 | 48 | The typical setup for a NodeMCU1.0 (ESP-12 Module) is : 49 | 50 | Display SDO/MISO to NodeMCU pin D6 <<<<<< This is not used by this sketch 51 | Display LED to NodeMCU pin 5V or 3.3V 52 | Display SCK to NodeMCU pin D5 53 | Display SDI/MOSI to NodeMCU pin D7 54 | Display DC/RS (or AO) to NodeMCU pin D3 55 | Display RESET to NodeMCU pin D4 <<<<<< Or connect to NodeMCU RST pin 56 | Display CS to NodeMCU pin D8 57 | Display GND to NodeMCU pin GND (0V) 58 | Display VCC to NodeMCU pin 5V or 3.3V 59 | 60 | Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin 61 | If 5V is not available at a pin you can use 3.3V but backlight brightness 62 | will be lower. 63 | 64 | If the TFT RESET signal is connected to the NodeMCU RST line then define the pin 65 | in the TFT library User_Config.h file as negative so the library ignores it, 66 | e.g. TFT_RST -1 67 | 68 | Created by Bodmer 24th Jan 2017 - Tested in Arduino IDE 1.8.0 esp8266 Core 2.3.0 69 | ==================================================================================*/ 70 | 71 | //==================================================================================== 72 | // Libraries 73 | //==================================================================================== 74 | // Call up the SPIFFS FLASH filing system this is part of the ESP Core 75 | #define FS_NO_GLOBALS 76 | #include 77 | 78 | #ifdef ESP32 79 | #include "SPIFFS.h" // ESP32 only 80 | #endif 81 | 82 | // JPEG decoder library 83 | #include 84 | 85 | #include // Hardware-specific library 86 | 87 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 88 | 89 | 90 | //==================================================================================== 91 | // Setup 92 | //==================================================================================== 93 | void setup() 94 | { 95 | Serial.begin(250000); // Used for messages and the C array generator 96 | 97 | delay(10); 98 | Serial.println("NodeMCU decoder test!"); 99 | 100 | tft.begin(); 101 | tft.setRotation(0); // 0 & 2 Portrait. 1 & 3 landscape 102 | tft.fillScreen(TFT_BLACK); 103 | 104 | if (!SPIFFS.begin()) { 105 | Serial.println("SPIFFS initialisation failed!"); 106 | while (1) yield(); // Stay here twiddling thumbs waiting 107 | } 108 | Serial.println("\r\nInitialisation done."); 109 | listFiles(); // Lists the files so you can see what is in the SPIFFS 110 | 111 | } 112 | 113 | //==================================================================================== 114 | // Loop 115 | //==================================================================================== 116 | void loop() 117 | { 118 | // Note the / before the SPIFFS file name must be present, this means the file is in 119 | // the root directory of the SPIFFS, e.g. "/tiger.jpg" for a file called "tiger.jpg" 120 | 121 | tft.setRotation(0); // portrait 122 | tft.fillScreen(random(0xFFFF)); 123 | 124 | drawJpeg("/tiger.jpg", 0 , 0); // 240 x 320 image 125 | //drawJpeg("/Baboon40.jpg", 0, 0); // 320 x 480 image 126 | delay(2000); 127 | 128 | //createArray("/tiger.jpg"); 129 | //delay(2000); 130 | //while(1) yield(); // Stay here 131 | } 132 | //==================================================================================== 133 | 134 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/NodeMCU_Jpeg.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | 3 | This sketch demonstrates loading images which have been stored as files in the 4 | built-in FLASH memory on a NodeMCU 1.0 (ESP8266 based, ESP-12E Module) rendering the 5 | images onto a ILI9341 SPI 320 x 240 pixel TFT screen. 6 | 7 | The images are stored in the SPI FLASH Filing System (SPIFFS), which effectively 8 | functions like a tiny "hard drive". This filing system is built into the ESP8266 9 | Core that can be loaded from the IDE "Boards manager" menu option. This is at 10 | version 2.3.0 at the time of sketch creation. 11 | 12 | The size of the SPIFFS partition can be set in the IDE as 1Mbyte or 3Mbytes. Either 13 | will work with this sketch. Typically most sketches easily fit within 1 Mbyte so a 14 | 3 Mbyte SPIFS partition can be used, in which case it can contain ~18 full screen 15 | 320 x 240 raw images (150 Kbytes each) or 100's of Jpeg full screem images. 16 | 17 | The NodeMCU, TFT and sketch works with the libraries here: 18 | https://github.com/adafruit/Adafruit-GFX-Library 19 | https://github.com/adafruit/Adafruit_ILI9341 20 | 21 | The Jpeg library can be found here: 22 | https://github.com/Bodmer/JPEGDecoder 23 | 24 | Images in the Jpeg format can be created using Paint or IrfanView or other picture 25 | editting software. 26 | 27 | Place the images inside the sketch folder, in a folder called "Data". Then upload 28 | all the files in the folder using the Arduino IDE "ESP8266 Sketch Data Upload" option 29 | in the "Tools" menu: 30 | http://www.esp8266.com/viewtopic.php?f=32&t=10081 31 | https://github.com/esp8266/arduino-esp8266fs-plugin/releases 32 | 33 | This takes some time, but the SPIFFS content is not altered when a new sketch is 34 | uploaded, so there is no need to upload the same files again! 35 | Note: If open, you must close the "Serial Monitor" window to upload data to SPIFFS! 36 | 37 | The IDE will not copy the "data" folder with the sketch if you save the sketch under 38 | another name. It is necessary to manually make a copy and place it in the sketch 39 | folder. 40 | 41 | This sketch includes example images in the Data folder. 42 | 43 | Saving images, uploading and rendering on the TFT screen couldn't be much easier! 44 | 45 | The typical setup for a NodeMCU1.0 (ESP-12 Module) is : 46 | 47 | Display SDO/MISO to NodeMCU pin D6 <<<<<< This is not used by this sketch 48 | Display LED to NodeMCU pin 5V or 3.3V 49 | Display SCK to NodeMCU pin D5 50 | Display SDI/MOSI to NodeMCU pin D7 51 | Display DC/RS (or AO) to NodeMCU pin D3 52 | Display RESET to NodeMCU pin D4 <<<<<< Or connect to NodeMCU RST pin 53 | Display CS to NodeMCU pin D8 54 | Display GND to NodeMCU pin GND (0V) 55 | Display VCC to NodeMCU pin 5V or 3.3V 56 | 57 | Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin 58 | If 5V is not available at a pin you can use 3.3V but backlight brightness 59 | will be lower. 60 | 61 | If the TFT RESET signal is connected to the NodeMCU RST line then define the pin 62 | in the TFT library User_Config.h file as negative so the library ignores it, 63 | e.g. TFT_RST -1 64 | 65 | Created by Bodmer 24th Jan 2017 - Tested in Arduino IDE 1.8.0 esp8266 Core 2.3.0 66 | ==================================================================================*/ 67 | 68 | //==================================================================================== 69 | // Libraries 70 | //==================================================================================== 71 | // Call up the SPIFFS FLASH filing system this is part of the ESP Core 72 | #define FS_NO_GLOBALS 73 | #include 74 | 75 | // JPEG decoder library 76 | #include 77 | 78 | // SPI library, built into IDE 79 | #include 80 | 81 | // Call up the TFT libraries 82 | #include 83 | #include 84 | 85 | #define TFT_CS D8 // Chip select control pin 86 | #define TFT_DC D3 // Data Command control pin 87 | #define TFT_RST D4 // Reset pin (could connect to Arduino RESET pin) 88 | 89 | #define TFT_BLACK 0 90 | 91 | // Invoke TFT library with TFT signal pins 92 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); 93 | 94 | 95 | //==================================================================================== 96 | // Setup 97 | //==================================================================================== 98 | void setup() 99 | { 100 | Serial.begin(250000); // Used for messages and the C array generator 101 | 102 | delay(10); 103 | Serial.println("NodeMCU decoder test!"); 104 | 105 | tft.begin(); 106 | tft.setRotation(0); // 0 & 2 Portrait. 1 & 3 landscape 107 | tft.fillScreen(TFT_BLACK); 108 | 109 | if (!SPIFFS.begin()) { 110 | Serial.println("SPIFFS initialisation failed!"); 111 | while (1) yield(); // Stay here twiddling thumbs waiting 112 | } 113 | Serial.println("\r\nInitialisation done."); 114 | listFiles(); // Lists the files so you can see what is in the SPIFFS 115 | 116 | } 117 | 118 | //==================================================================================== 119 | // Loop 120 | //==================================================================================== 121 | void loop() 122 | { 123 | // Note the / before the SPIFFS file name must be present, this means the file is in 124 | // the root directory of the SPIFFS, e.g. "/Tiger.rjpg" for a file called "Tiger.jpg" 125 | 126 | tft.setRotation(0); // portrait 127 | tft.fillScreen(random(0xFFFF)); 128 | 129 | drawJpeg("/EagleEye.jpg", 0, 0); 130 | delay(2000); 131 | 132 | //tft.fillScreen(random(0xFFFF)); 133 | drawJpeg("/BaboonP.jpg", 0, 0); 134 | delay(2000); 135 | 136 | tft.setRotation(1); // landscape 137 | //tft.fillScreen(random(0xFFFF)); 138 | drawJpeg("/Mouse.jpg", 0, 0); 139 | delay(2000); 140 | 141 | //tft.fillScreen(random(0xFFFF)); 142 | drawJpeg("/BaboonL.jpg", 0, 0); 143 | delay(2000); 144 | 145 | createArray("/EagleEye.jpg"); 146 | delay(2000); 147 | while(1) yield(); // Stay here 148 | } 149 | //==================================================================================== 150 | 151 | -------------------------------------------------------------------------------- /examples/UTFT/UTFT_SD_Jpeg/Jpeg_utilities.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // Open a Jpeg image file and displays it at the given coordinates. 12 | //==================================================================================== 13 | 14 | void jpegDraw(const char* filename, int x, int y) { 15 | 16 | File jpegFile; 17 | 18 | // Try to open requested file on SD card 19 | if (!SD.open(filename, O_READ)) { 20 | Serial.println("Jpeg file not found on SD card."); 21 | return; 22 | } 23 | 24 | Serial.print(F("Decoding image '")); 25 | Serial.print(filename); 26 | Serial.println('\''); 27 | 28 | // initialise the decoder, check compatibility and gain access to image information 29 | boolean decoded = JpegDec.decodeSdFile(filename); 30 | 31 | if (decoded) { 32 | // print information about the image to the serial port 33 | jpegInfo(); 34 | 35 | // render the image onto the screen at given coordinates 36 | renderJPEG(x, y); 37 | } 38 | else { 39 | Serial.println(F("Jpeg file format not supported.")); 40 | } 41 | } 42 | 43 | 44 | //==================================================================================== 45 | // Print information about the decoded Jpeg image 46 | //==================================================================================== 47 | void jpegInfo() { 48 | Serial.println(F("===============")); 49 | Serial.println(F("JPEG image info")); 50 | Serial.println(F("===============")); 51 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 52 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 53 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 54 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 55 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 56 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 57 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 58 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 59 | Serial.println(F("===============")); 60 | } 61 | 62 | 63 | //==================================================================================== 64 | // Decode and render onto the TFT screen 65 | //==================================================================================== 66 | 67 | void renderJPEG(int xpos, int ypos) { 68 | 69 | // retrieve infomration about the image 70 | uint16_t *pImg; 71 | uint16_t mcu_w = JpegDec.MCUWidth; 72 | uint16_t mcu_h = JpegDec.MCUHeight; 73 | uint16_t max_x = JpegDec.width; 74 | uint16_t max_y = JpegDec.height; 75 | 76 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 77 | // Typically these MCUs are 16x16 pixel blocks 78 | // Determine the width and height of the right and bottom edge image blocks 79 | uint16_t min_w = minimum(mcu_w, max_x % mcu_w); 80 | uint16_t min_h = minimum(mcu_h, max_y % mcu_h); 81 | 82 | // save the current image block size 83 | uint16_t win_w = mcu_w; 84 | uint16_t win_h = mcu_h; 85 | 86 | // record the current time so we can measure how long it takes to draw an image 87 | uint32_t drawTime = millis(); 88 | 89 | // save the coordinate of the right and bottom edges to assist image cropping 90 | // to the screen size 91 | max_x += xpos; 92 | max_y += ypos; 93 | 94 | // read each MCU block until there are no more 95 | while ( JpegDec.read()) { 96 | 97 | // save a pointer to the image block 98 | pImg = JpegDec.pImage; 99 | 100 | // calculate where the image block should be drawn on the screen 101 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 102 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 103 | 104 | // check if the image block size needs to be changed for the right and bottom edges 105 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 106 | else win_w = min_w; 107 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 108 | else win_h = min_h; 109 | 110 | // calculate how many pixels must be drawn 111 | uint16_t mcu_pixels = win_w * win_h; 112 | 113 | // draw image MCU block only if it will fit on the screen 114 | if (( mcu_x + win_w ) <= myGLCD.getDisplayXSize() && ( mcu_y + win_h ) <= myGLCD.getDisplayYSize()) 115 | { 116 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 117 | digitalWrite(TFT_CS, LOW); // Set chip select low so we can take control of display 118 | myGLCD.setXY(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 119 | 120 | // Write all MCU pixels to the TFT window 121 | while (mcu_pixels--) { 122 | // Push each pixel to the TFT MCU area 123 | uint8_t col_h = (*pImg) >> 8; // High byte 124 | uint8_t col_l = (*pImg) & 0xFF; // Low byte 125 | pImg++; // Increment pointer 126 | myGLCD.LCD_Write_DATA(col_h, col_l); // Send a pixel colour to window 127 | } 128 | digitalWrite(TFT_CS, HIGH); // Set chip select high to release contol 129 | } 130 | 131 | // Stop drawing blocks if the bottom of the screen has been reached, 132 | // the abort function will close the file 133 | else if ( (mcu_y + win_h) >= myGLCD.getDisplayYSize()) JpegDec.abort(); 134 | } 135 | 136 | // calculate how long it took to draw the image 137 | drawTime = millis() - drawTime; 138 | 139 | // print the results to the serial port 140 | Serial.print(F( "Total render time was : ")); Serial.print(drawTime); Serial.println(F(" ms")); 141 | Serial.println(F("")); 142 | } 143 | 144 | //==================================================================================== 145 | // Open a Jpeg file and send it to the Serial port in a C array compatible format 146 | //==================================================================================== 147 | void createArray(const char *filename) { 148 | 149 | // Open the named file 150 | File jpgFile = SD.open( filename, O_READ); // get file handle reference for SD library 151 | 152 | if ( !jpgFile ) { 153 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 154 | return; 155 | } 156 | 157 | uint8_t data; 158 | byte line_len = 0; 159 | Serial.println(""); 160 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 161 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 162 | Serial.println(""); 163 | Serial.println("#if defined(__AVR__)"); 164 | Serial.println(" #include "); 165 | Serial.println("#endif"); 166 | Serial.println(""); 167 | Serial.print ("const uint8_t "); 168 | while (*filename != '.') Serial.print(*filename++); 169 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 170 | 171 | while ( jpgFile.available()) { 172 | 173 | data = jpgFile.read(); 174 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 175 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 176 | line_len++; 177 | if ( line_len >= 32) { 178 | line_len = 0; 179 | Serial.println(); 180 | } 181 | 182 | } 183 | 184 | Serial.println("};\r\n"); 185 | jpgFile.close(); 186 | } 187 | //==================================================================================== 188 | -------------------------------------------------------------------------------- /examples/UTFT/UTFT_Flash_Jpeg/UTFT_Flash_Jpeg.ino: -------------------------------------------------------------------------------- 1 | // This sketch draws a Jpeg file stored in an array onto the TFT screen using the UTFT library 2 | // by Henning Karlsen. 3 | // web: http://www.RinkyDinkElectronics.com/ 4 | // 5 | // This demo uses an Arduino Due and a 320x240 ILI9341 SPI based TFT screen. 6 | // The deom should also run on an Arduino Mega, but will be much slower 7 | /* 8 | By default the UTFT library does not configure the Gamma curve settings for the ILI9341 TFT, 9 | so photo images may not render well. To correct this ensure the set Gamma curve section 10 | in initlcd.h (library folder UTFT\tft_drivers\ili9341\s5p\initlcd.h) is NOT commented out. 11 | */ 12 | 13 | // The latest JPEGDecoder library can be found here: 14 | // https://github.com/Bodmer/JPEGDecoder 15 | 16 | // Information on JPEG compression can be found here: 17 | // https://en.wikipedia.org/wiki/JPEG 18 | 19 | #include 20 | 21 | #include // JPEG decoder library 22 | 23 | // Set the pins to the correct ones for your SPI TFT pins 24 | // ------------------------------------------------------------ 25 | #define TFT_SDA 7 // Serial data pin 26 | #define TFT_SCL 6 // Serial clock pin 27 | #define TFT_CS 10 // Chip Select for LCD 28 | #define TFT_RS 9 // Register select (also called DC) 29 | #define TFT_RST 8 // uncomment if you have ILI9340 30 | 31 | // Remember to change the model parameter to suit your display module! 32 | UTFT myGLCD(ILI9341_S5P,TFT_SDA, TFT_SCL, TFT_CS, TFT_RST, TFT_RS); 33 | 34 | // Include the sketch header file that contains the image stored as an array of bytes 35 | // More than one image array could be stored in each header file. 36 | #include "jpeg1.h" 37 | 38 | void setup() 39 | { 40 | Serial.begin(9600); 41 | myGLCD.InitLCD(PORTRAIT); // The test image is for a portrait orientation 42 | } 43 | 44 | void loop() 45 | { 46 | uint32_t clearTime = millis(); 47 | myGLCD.fillScr(255, 255, 255); 48 | // calculate how long it took to draw the image 49 | clearTime = millis() - clearTime; // Calculate the time it took 50 | 51 | // print the results to the serial port 52 | Serial.print(F( "Total clear time was : ")); Serial.print(clearTime); Serial.println(F(" ms")); 53 | Serial.println(F("")); 54 | 55 | // Draw a jpeg image stored in memory 56 | drawArrayJpeg(Baboon, sizeof(Baboon), 0, 0); 57 | 58 | delay(5000); 59 | } 60 | 61 | //#################################################################################################### 62 | // Draw a JPEG on the TFT pulled from a program memory array 63 | //#################################################################################################### 64 | void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int x, int y) { 65 | 66 | JpegDec.decodeArray(arrayname, array_size); 67 | 68 | jpegInfo(); // Print information from the JPEG file (could comment this line out) 69 | 70 | renderJPEG(x, y); 71 | 72 | Serial.println("#########################"); 73 | } 74 | 75 | //#################################################################################################### 76 | // Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit 77 | //#################################################################################################### 78 | // This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not 79 | // fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders. 80 | void renderJPEG(int xpos, int ypos) { 81 | 82 | // retrieve infomration about the image 83 | uint16_t *pImg; 84 | uint16_t mcu_w = JpegDec.MCUWidth; 85 | uint16_t mcu_h = JpegDec.MCUHeight; 86 | uint32_t max_x = JpegDec.width; 87 | uint32_t max_y = JpegDec.height; 88 | 89 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 90 | // Typically these MCUs are 16x16 pixel blocks 91 | // Determine the width and height of the right and bottom edge image blocks 92 | uint32_t min_w = min(mcu_w, max_x % mcu_w); 93 | uint32_t min_h = min(mcu_h, max_y % mcu_h); 94 | 95 | // save the current image block size 96 | uint32_t win_w = mcu_w; 97 | uint32_t win_h = mcu_h; 98 | 99 | // record the current time so we can measure how long it takes to draw an image 100 | uint32_t drawTime = millis(); 101 | 102 | // save the coordinate of the right and bottom edges to assist image cropping 103 | // to the screen size 104 | max_x += xpos; 105 | max_y += ypos; 106 | 107 | // read each MCU block until there are no more 108 | while (JpegDec.read()) { // While there is more data in the file 109 | 110 | // save a pointer to the image block 111 | pImg = JpegDec.pImage ; 112 | 113 | // calculate where the image block should be drawn on the screen 114 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU 115 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 116 | 117 | // check if the image block size needs to be changed for the right and bottom edges 118 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 119 | else win_w = min_w; 120 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 121 | else win_h = min_h; 122 | 123 | // calculate how many pixels must be drawn 124 | uint32_t mcu_pixels = win_w * win_h; 125 | 126 | // draw image MCU block only if it will fit on the screen 127 | if (( mcu_x + win_w ) <= myGLCD.getDisplayXSize() && ( mcu_y + win_h ) <= myGLCD.getDisplayYSize()) 128 | { 129 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 130 | digitalWrite(TFT_CS, LOW); // Set chip select low so we can take control of display 131 | myGLCD.setXY(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 132 | 133 | 134 | // Write all MCU pixels to the TFT window 135 | while (mcu_pixels--) { 136 | // Push each pixel to the TFT MCU area 137 | uint8_t col_h = (*pImg) >> 8; // High byte 138 | uint8_t col_l = (*pImg) & 0xFF; // Low byte 139 | pImg++; // Increment pointer 140 | myGLCD.LCD_Write_DATA(col_h, col_l); // Sent pixel colour to window 141 | } 142 | digitalWrite(TFT_CS, HIGH); // Set chip select high 143 | } 144 | else if ( (mcu_y + win_h) >= myGLCD.getDisplayYSize()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding 145 | } 146 | 147 | // calculate how long it took to draw the image 148 | drawTime = millis() - drawTime; // Calculate the time it took 149 | 150 | // print the results to the serial port 151 | Serial.print(F( "Total render time was : ")); Serial.print(drawTime); Serial.println(F(" ms")); 152 | Serial.println(F("")); 153 | } 154 | 155 | //==================================================================================== 156 | // Print information about the decoded Jpeg image 157 | //==================================================================================== 158 | 159 | void jpegInfo() { 160 | Serial.println(F("===============")); 161 | Serial.println(F("JPEG image info")); 162 | Serial.println(F("===============")); 163 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 164 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 165 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 166 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 167 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 168 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 169 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 170 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 171 | Serial.println(F("===============")); 172 | } 173 | 174 | -------------------------------------------------------------------------------- /examples/ILI9341_due/Due_SD_Jpeg/JPEG_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // Opens the image file and prime the Jpeg decoder 12 | //==================================================================================== 13 | void drawJpeg(const char *filename, int xpos, int ypos) { 14 | 15 | // Open the named file (the Jpeg decoder library will close it) 16 | File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 17 | 18 | if ( !jpegFile ) { 19 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 20 | return; 21 | } 22 | 23 | Serial.println("==========================="); 24 | Serial.print("Drawing file: "); Serial.println(filename); 25 | Serial.println("==========================="); 26 | 27 | // Use one of the following methods to initialise the decoder: 28 | //boolean decoded = JpegDec.decodeSdFile(jpegFile); // Pass the SD file handle to the decoder, 29 | boolean decoded = JpegDec.decodeSdFile(filename); // or pass the filename (String or character array) 30 | 31 | if (decoded) { 32 | // print information about the image to the serial port 33 | jpegInfo(); 34 | // render the image onto the screen at given coordinates 35 | jpegRender(xpos, ypos); 36 | } 37 | else { 38 | Serial.println("Jpeg file format not supported!"); 39 | } 40 | 41 | } 42 | 43 | //==================================================================================== 44 | // Decode and render the Jpeg image onto the TFT screen 45 | //==================================================================================== 46 | void jpegRender(int xpos, int ypos) { 47 | 48 | // retrieve information about the image 49 | uint16_t mcu_w = JpegDec.MCUWidth; 50 | uint16_t mcu_h = JpegDec.MCUHeight; 51 | uint32_t max_x = JpegDec.width; 52 | uint32_t max_y = JpegDec.height; 53 | 54 | uint16_t *pImg; // Pointer for the returned image block 55 | 56 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 57 | // Typically these MCUs are 16x16 pixel blocks 58 | // Determine the width and height of the right and bottom edge image blocks 59 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 60 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 61 | 62 | // save the current image block size 63 | uint32_t win_w = mcu_w; 64 | uint32_t win_h = mcu_h; 65 | 66 | // record the current time so we can measure how long it takes to draw an image 67 | uint32_t drawTime = millis(); 68 | 69 | // save the coordinate of the right and bottom edges to assist image cropping 70 | // to the screen size 71 | max_x += xpos; 72 | max_y += ypos; 73 | 74 | // read each MCU block until there are no more 75 | while ( JpegDec.read()) { 76 | 77 | // save a pointer to the image block 78 | pImg = JpegDec.pImage; // Pointer to block 79 | 80 | // calculate where the image block should be drawn on the screen 81 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 82 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 83 | 84 | // check if the image block size needs to be changed for the right and bottom edges 85 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 86 | else win_w = min_w; 87 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 88 | else win_h = min_h; 89 | 90 | // calculate how many pixels must be drawn 91 | uint32_t mcu_pixels = win_w * win_h; 92 | 93 | // draw image MCU block only if it will fit on the screen 94 | if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) 95 | { 96 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 97 | tft.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 98 | 99 | // Write all MCU pixels to the TFT window 100 | // while (mcu_pixels--) tft.pushColor(*pImg++); // Send to TFT 16 bits at a time 101 | tft.pushColors(pImg, 0, mcu_pixels); // Send the whole buffer, this is faster 102 | } 103 | 104 | // Stop drawing blocks if the bottom of the screen has been reached, 105 | // the abort function will close the file 106 | else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); 107 | 108 | } 109 | 110 | // calculate how long it took to draw the image 111 | drawTime = millis() - drawTime; 112 | 113 | // print the results to the serial port 114 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 115 | Serial.println("====================================="); 116 | 117 | } 118 | 119 | //==================================================================================== 120 | // Print information decoded from the Jpeg image 121 | //==================================================================================== 122 | void jpegInfo() { 123 | Serial.println(F("===============")); 124 | Serial.println(F("JPEG image info")); 125 | Serial.println(F("===============")); 126 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 127 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 128 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 129 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 130 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 131 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 132 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 133 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 134 | Serial.println(F("===============")); 135 | } 136 | 137 | //==================================================================================== 138 | // Open a Jpeg file and send it to the Serial port in a C array compatible format 139 | //==================================================================================== 140 | void createArray(const char *filename) { 141 | 142 | // Open the named file 143 | //fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 144 | File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 145 | 146 | if ( !jpgFile ) { 147 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 148 | return; 149 | } 150 | 151 | uint8_t data; 152 | byte line_len = 0; 153 | Serial.println(""); 154 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 155 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 156 | Serial.println(""); 157 | Serial.println("#if defined(__AVR__)"); 158 | Serial.println(" #include "); 159 | Serial.println("#endif"); 160 | Serial.println(""); 161 | Serial.print ("const uint8_t "); 162 | while (*filename != '.') Serial.print(*filename++); 163 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 164 | 165 | while ( jpgFile.available()) { 166 | 167 | data = jpgFile.read(); 168 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 169 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 170 | line_len++; 171 | if ( line_len >= 32) { 172 | line_len = 0; 173 | Serial.println(); 174 | } 175 | 176 | } 177 | 178 | Serial.println("};\r\n"); 179 | jpgFile.close(); 180 | } 181 | //==================================================================================== 182 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/NodeMCU_Jpeg/JPEG_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // Opens the image file and prime the Jpeg decoder 12 | //==================================================================================== 13 | void drawJpeg(const char *filename, int xpos, int ypos) { 14 | 15 | Serial.println("==========================="); 16 | Serial.print("Drawing file: "); Serial.println(filename); 17 | Serial.println("==========================="); 18 | 19 | // Open the named file (the Jpeg decoder library will close it after rendering image) 20 | fs::File jpegFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 21 | // File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 22 | 23 | if ( !jpegFile ) { 24 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 25 | return; 26 | } 27 | 28 | // Use one of the three following methods to initialise the decoder: 29 | //boolean decoded = JpegDec.decodeFsFile(jpegFile); // Pass a SPIFFS file handle to the decoder, 30 | //boolean decoded = JpegDec.decodeSdFile(jpegFile); // or pass the SD file handle to the decoder, 31 | boolean decoded = JpegDec.decodeFsFile(filename); // or pass the filename (leading / distinguishes SPIFFS files) 32 | // Note: the filename can be a String or character array type 33 | if (decoded) { 34 | // print information about the image to the serial port 35 | jpegInfo(); 36 | 37 | // render the image onto the screen at given coordinates 38 | jpegRender(xpos, ypos); 39 | } 40 | else { 41 | Serial.println("Jpeg file format not supported!"); 42 | } 43 | } 44 | 45 | //==================================================================================== 46 | // Decode and render the Jpeg image onto the TFT screen 47 | //==================================================================================== 48 | void jpegRender(int xpos, int ypos) { 49 | 50 | // retrieve infomration about the image 51 | uint16_t *pImg; 52 | uint16_t mcu_w = JpegDec.MCUWidth; 53 | uint16_t mcu_h = JpegDec.MCUHeight; 54 | uint32_t max_x = JpegDec.width; 55 | uint32_t max_y = JpegDec.height; 56 | 57 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 58 | // Typically these MCUs are 16x16 pixel blocks 59 | // Determine the width and height of the right and bottom edge image blocks 60 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 61 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 62 | 63 | // save the current image block size 64 | uint32_t win_w = mcu_w; 65 | uint32_t win_h = mcu_h; 66 | 67 | // record the current time so we can measure how long it takes to draw an image 68 | uint32_t drawTime = millis(); 69 | 70 | // save the coordinate of the right and bottom edges to assist image cropping 71 | // to the screen size 72 | max_x += xpos; 73 | max_y += ypos; 74 | 75 | // read each MCU block until there are no more 76 | while ( JpegDec.read()) { 77 | 78 | // save a pointer to the image block 79 | pImg = JpegDec.pImage; 80 | 81 | // calculate where the image block should be drawn on the screen 82 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 83 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 84 | 85 | // check if the image block size needs to be changed for the right edge 86 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 87 | else win_w = min_w; 88 | 89 | // check if the image block size needs to be changed for the bottom edge 90 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 91 | else win_h = min_h; 92 | 93 | // copy pixels into a contiguous block 94 | if (win_w != mcu_w) 95 | { 96 | for (int h = 1; h < win_h-1; h++) 97 | { 98 | memcpy(pImg + h * win_w, pImg + (h + 1) * mcu_w, win_w << 1); 99 | } 100 | } 101 | 102 | // draw image MCU block only if it will fit on the screen 103 | if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) 104 | { 105 | tft.drawRGBBitmap(mcu_x, mcu_y, pImg, win_w, win_h); 106 | } 107 | 108 | else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); 109 | 110 | } 111 | 112 | // calculate how long it took to draw the image 113 | drawTime = millis() - drawTime; // Calculate the time it took 114 | 115 | // print the results to the serial port 116 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 117 | Serial.println("====================================="); 118 | 119 | } 120 | 121 | //==================================================================================== 122 | // Print information decoded from the Jpeg image 123 | //==================================================================================== 124 | void jpegInfo() { 125 | 126 | Serial.println("==============="); 127 | Serial.println("JPEG image info"); 128 | Serial.println("==============="); 129 | Serial.print ("Width :"); Serial.println(JpegDec.width); 130 | Serial.print ("Height :"); Serial.println(JpegDec.height); 131 | Serial.print ("Components :"); Serial.println(JpegDec.comps); 132 | Serial.print ("MCU / row :"); Serial.println(JpegDec.MCUSPerRow); 133 | Serial.print ("MCU / col :"); Serial.println(JpegDec.MCUSPerCol); 134 | Serial.print ("Scan type :"); Serial.println(JpegDec.scanType); 135 | Serial.print ("MCU width :"); Serial.println(JpegDec.MCUWidth); 136 | Serial.print ("MCU height :"); Serial.println(JpegDec.MCUHeight); 137 | Serial.println("==============="); 138 | Serial.println(""); 139 | } 140 | 141 | //==================================================================================== 142 | // Open a Jpeg file and send it to the Serial port in a C array compatible format 143 | //==================================================================================== 144 | void createArray(const char *filename) { 145 | 146 | // Open the named file 147 | fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 148 | // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 149 | 150 | if ( !jpgFile ) { 151 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 152 | return; 153 | } 154 | 155 | uint8_t data; 156 | byte line_len = 0; 157 | Serial.println(""); 158 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 159 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 160 | Serial.println(""); 161 | Serial.println("#if defined(__AVR__)"); 162 | Serial.println(" #include "); 163 | Serial.println("#endif"); 164 | Serial.println(""); 165 | Serial.print ("const uint8_t "); 166 | while (*filename != '.') Serial.print(*filename++); 167 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 168 | 169 | while ( jpgFile.available()) { 170 | 171 | data = jpgFile.read(); 172 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 173 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 174 | line_len++; 175 | if ( line_len >= 32) { 176 | line_len = 0; 177 | Serial.println(); 178 | } 179 | 180 | } 181 | 182 | Serial.println("};\r\n"); 183 | jpgFile.close(); 184 | } 185 | //==================================================================================== 186 | -------------------------------------------------------------------------------- /examples/Other libraries/NodeMCU_Jpeg_ESP/JPEG_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // Opens the image file and prime the Jpeg decoder 12 | //==================================================================================== 13 | void drawJpeg(const char *filename, int xpos, int ypos) { 14 | 15 | Serial.println("==========================="); 16 | Serial.print("Drawing file: "); Serial.println(filename); 17 | Serial.println("==========================="); 18 | 19 | // Open the named file (the Jpeg decoder library will close it after rendering image) 20 | fs::File jpegFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 21 | // File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 22 | 23 | if ( !jpegFile ) { 24 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 25 | return; 26 | } 27 | 28 | // Use one of the three following methods to initialise the decoder: 29 | //boolean decoded = JpegDec.decodeFsFile(jpegFile); // Pass a SPIFFS file handle to the decoder, 30 | //boolean decoded = JpegDec.decodeSdFile(jpegFile); // or pass the SD file handle to the decoder, 31 | boolean decoded = JpegDec.decodeFsFile(filename); // or pass the filename (leading / distinguishes SPIFFS files) 32 | // Note: the filename can be a String or character array type 33 | if (decoded) { 34 | // print information about the image to the serial port 35 | jpegInfo(); 36 | 37 | // render the image onto the screen at given coordinates 38 | jpegRender(xpos, ypos); 39 | } 40 | else { 41 | Serial.println("Jpeg file format not supported!"); 42 | } 43 | } 44 | 45 | //==================================================================================== 46 | // Decode and render the Jpeg image onto the TFT screen 47 | //==================================================================================== 48 | void jpegRender(int xpos, int ypos) { 49 | 50 | // retrieve infomration about the image 51 | uint16_t *pImg; 52 | uint16_t mcu_w = JpegDec.MCUWidth; 53 | uint16_t mcu_h = JpegDec.MCUHeight; 54 | uint32_t max_x = JpegDec.width; 55 | uint32_t max_y = JpegDec.height; 56 | 57 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 58 | // Typically these MCUs are 16x16 pixel blocks 59 | // Determine the width and height of the right and bottom edge image blocks 60 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 61 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 62 | 63 | // save the current image block size 64 | uint32_t win_w = mcu_w; 65 | uint32_t win_h = mcu_h; 66 | 67 | // record the current time so we can measure how long it takes to draw an image 68 | uint32_t drawTime = millis(); 69 | 70 | // save the coordinate of the right and bottom edges to assist image cropping 71 | // to the screen size 72 | max_x += xpos; 73 | max_y += ypos; 74 | 75 | // read each MCU block until there are no more 76 | #ifdef USE_SPI_BUFFER 77 | while ( JpegDec.readSwappedBytes()) { // Swap byte order so the SPI buffer can be used 78 | #else 79 | while ( JpegDec.read()) { // Normal byte order read 80 | #endif 81 | // save a pointer to the image block 82 | pImg = JpegDec.pImage; 83 | 84 | // calculate where the image block should be drawn on the screen 85 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 86 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 87 | 88 | if ( mcu_y < tft.height() ) 89 | { 90 | // check if the image block size needs to be changed for the right edge 91 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 92 | else win_w = min_w; 93 | 94 | // check if the image block size needs to be changed for the bottom edge 95 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 96 | else win_h = min_h; 97 | 98 | // copy pixels into a smaller block 99 | if (win_w != mcu_w) 100 | { 101 | for (int h = 1; h < win_h; h++) 102 | { 103 | memcpy(pImg + h * win_w, pImg + h * mcu_w, win_w << 1); 104 | } 105 | } 106 | tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg); 107 | } 108 | else 109 | { 110 | JpegDec.abort(); 111 | } 112 | } 113 | 114 | // calculate how long it took to draw the image 115 | drawTime = millis() - drawTime; // Calculate the time it took 116 | 117 | // print the results to the serial port 118 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 119 | Serial.println("====================================="); 120 | 121 | } 122 | 123 | //==================================================================================== 124 | // Print information decoded from the Jpeg image 125 | //==================================================================================== 126 | void jpegInfo() { 127 | 128 | Serial.println("==============="); 129 | Serial.println("JPEG image info"); 130 | Serial.println("==============="); 131 | Serial.print ("Width :"); Serial.println(JpegDec.width); 132 | Serial.print ("Height :"); Serial.println(JpegDec.height); 133 | Serial.print ("Components :"); Serial.println(JpegDec.comps); 134 | Serial.print ("MCU / row :"); Serial.println(JpegDec.MCUSPerRow); 135 | Serial.print ("MCU / col :"); Serial.println(JpegDec.MCUSPerCol); 136 | Serial.print ("Scan type :"); Serial.println(JpegDec.scanType); 137 | Serial.print ("MCU width :"); Serial.println(JpegDec.MCUWidth); 138 | Serial.print ("MCU height :"); Serial.println(JpegDec.MCUHeight); 139 | Serial.println("==============="); 140 | Serial.println(""); 141 | } 142 | 143 | //==================================================================================== 144 | // Open a Jpeg file and send it to the Serial port in a C array compatible format 145 | //==================================================================================== 146 | void createArray(const char *filename) { 147 | 148 | // Open the named file 149 | fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 150 | // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 151 | 152 | if ( !jpgFile ) { 153 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 154 | return; 155 | } 156 | 157 | uint8_t data; 158 | byte line_len = 0; 159 | Serial.println(""); 160 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 161 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 162 | Serial.println(""); 163 | Serial.println("#if defined(__AVR__)"); 164 | Serial.println(" #include "); 165 | Serial.println("#endif"); 166 | Serial.println(""); 167 | Serial.print ("const uint8_t "); 168 | while (*filename != '.') Serial.print(*filename++); 169 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 170 | 171 | while ( jpgFile.available()) { 172 | 173 | data = jpgFile.read(); 174 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 175 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 176 | line_len++; 177 | if ( line_len >= 32) { 178 | line_len = 0; 179 | Serial.println(); 180 | } 181 | 182 | } 183 | 184 | Serial.println("};\r\n"); 185 | jpgFile.close(); 186 | } 187 | //==================================================================================== 188 | -------------------------------------------------------------------------------- /examples/Adafruit_GFX/Huzzah_Jpeg/JPEG_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // This function opens the Filing System Jpeg image file and primes the decoder 12 | //==================================================================================== 13 | void drawFSJpeg(const char *filename, int xpos, int ypos) { 14 | 15 | Serial.println("====================================="); 16 | Serial.print("Drawing file: "); Serial.println(filename); 17 | Serial.println("====================================="); 18 | 19 | // Open the file (the Jpeg decoder library will close it) 20 | fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 21 | // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 22 | 23 | if ( !jpgFile ) { 24 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 25 | return; 26 | } 27 | 28 | // To initialise the decoder and provide the file, we can use one of the three following methods: 29 | //boolean decoded = JpegDec.decodeFsFile(jpgFile); // We can pass the SPIFFS file handle to the decoder, 30 | //boolean decoded = JpegDec.decodeSdFile(jpgFile); // or we can pass the SD file handle to the decoder, 31 | boolean decoded = JpegDec.decodeFsFile(filename); // or we can pass the filename (leading / distinguishes SPIFFS files) 32 | // The filename can be a String or character array 33 | if (decoded) { 34 | // print information about the image to the serial port 35 | jpegInfo(); 36 | 37 | // render the image onto the screen at given coordinates 38 | jpegRender(xpos, ypos); 39 | } 40 | else { 41 | Serial.println("Jpeg file format not supported!"); 42 | } 43 | } 44 | 45 | //==================================================================================== 46 | // Decode and paint onto the TFT screen 47 | //==================================================================================== 48 | void jpegRender(int xpos, int ypos) { 49 | 50 | // retrieve infomration about the image 51 | uint16_t *pImg; 52 | uint16_t mcu_w = JpegDec.MCUWidth; 53 | uint16_t mcu_h = JpegDec.MCUHeight; 54 | uint32_t max_x = JpegDec.width; 55 | uint32_t max_y = JpegDec.height; 56 | 57 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 58 | // Typically these MCUs are 16x16 pixel blocks 59 | // Determine the width and height of the right and bottom edge image blocks 60 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 61 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 62 | 63 | // save the current image block size 64 | uint32_t win_w = mcu_w; 65 | uint32_t win_h = mcu_h; 66 | 67 | // record the current time so we can measure how long it takes to draw an image 68 | uint32_t drawTime = millis(); 69 | 70 | // save the coordinate of the right and bottom edges to assist image cropping 71 | // to the screen size 72 | max_x += xpos; 73 | max_y += ypos; 74 | 75 | // read each MCU block until there are no more 76 | while ( JpegDec.read()) { 77 | 78 | // save a pointer to the image block 79 | pImg = JpegDec.pImage; 80 | 81 | // calculate where the image block should be drawn on the screen 82 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 83 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 84 | 85 | // check if the image block size needs to be changed for the right edge 86 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 87 | else win_w = min_w; 88 | 89 | // check if the image block size needs to be changed for the bottom edge 90 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 91 | else win_h = min_h; 92 | 93 | // copy pixels into a contiguous block 94 | if (win_w != mcu_w) 95 | { 96 | for (int h = 1; h < win_h-1; h++) 97 | { 98 | memcpy(pImg + h * win_w, pImg + (h + 1) * mcu_w, win_w << 1); 99 | } 100 | } 101 | 102 | 103 | // draw image MCU block only if it will fit on the screen 104 | if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) 105 | { 106 | tft.drawRGBBitmap(mcu_x, mcu_y, pImg, win_w, win_h); 107 | } 108 | 109 | // Stop drawing blocks if the bottom of the screen has been reached, 110 | // the abort function will close the file 111 | else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); 112 | 113 | } 114 | 115 | // calculate how long it took to draw the image 116 | drawTime = millis() - drawTime; 117 | 118 | // print the results to the serial port 119 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 120 | Serial.println("====================================="); 121 | 122 | } 123 | 124 | //==================================================================================== 125 | // Send time taken to Serial port 126 | //==================================================================================== 127 | void jpegInfo() { 128 | Serial.println(F("===============")); 129 | Serial.println(F("JPEG image info")); 130 | Serial.println(F("===============")); 131 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 132 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 133 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 134 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 135 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 136 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 137 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 138 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 139 | Serial.println(F("===============")); 140 | } 141 | 142 | //==================================================================================== 143 | // Open a Jpeg file and dump it to the Serial port as a C array 144 | //==================================================================================== 145 | void createArray(const char *filename) { 146 | 147 | fs::File jpgFile; // File handle reference for SPIFFS 148 | // File jpgFile; // File handle reference For SD library 149 | 150 | if ( !( jpgFile = SPIFFS.open( filename, "r"))) { 151 | Serial.println(F("JPEG file not found")); 152 | return; 153 | } 154 | 155 | uint8_t data; 156 | byte line_len = 0; 157 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 158 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 159 | Serial.println(""); 160 | Serial.println("#if defined(__AVR__)"); 161 | Serial.println(" #include "); 162 | Serial.println("#endif"); 163 | Serial.println(""); 164 | Serial.print("const uint8_t "); 165 | while (*filename != '.') Serial.print(*filename++); 166 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 167 | 168 | while ( jpgFile.available()) { 169 | 170 | data = jpgFile.read(); 171 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 172 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 173 | line_len++; 174 | if ( line_len >= 32) { 175 | line_len = 0; 176 | Serial.println(); 177 | } 178 | 179 | } 180 | 181 | Serial.println("};\r\n"); 182 | // jpgFile.seek( 0, SeekEnd); 183 | jpgFile.close(); 184 | } 185 | //==================================================================================== 186 | -------------------------------------------------------------------------------- /examples/Other libraries/SPIFFS_Jpeg/JPEG_functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 15th Jan 2017 5 | Updated by Bodmer to support ESP32 with SPIFFS Jan 2018 6 | ==================================================================================*/ 7 | 8 | // Return the minimum of two values a and b 9 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 10 | 11 | //==================================================================================== 12 | // Opens the image file and prime the Jpeg decoder 13 | //==================================================================================== 14 | void drawJpeg(const char *filename, int xpos, int ypos) { 15 | 16 | Serial.println("==========================="); 17 | Serial.print("Drawing file: "); Serial.println(filename); 18 | Serial.println("==========================="); 19 | 20 | // Open the named file (the Jpeg decoder library will close it after rendering image) 21 | fs::File jpegFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 22 | // File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 23 | 24 | //ESP32 always seems to return 1 for jpegFile so this null trap does not work 25 | if ( !jpegFile ) { 26 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 27 | return; 28 | } 29 | 30 | // Use one of the three following methods to initialise the decoder, 31 | // the filename can be a String or character array type: 32 | 33 | //boolean decoded = JpegDec.decodeFsFile(jpegFile); // Pass a SPIFFS file handle to the decoder, 34 | //boolean decoded = JpegDec.decodeSdFile(jpegFile); // or pass the SD file handle to the decoder, 35 | boolean decoded = JpegDec.decodeFsFile(filename); // or pass the filename (leading / distinguishes SPIFFS files) 36 | 37 | if (decoded) { 38 | // print information about the image to the serial port 39 | jpegInfo(); 40 | 41 | // render the image onto the screen at given coordinates 42 | jpegRender(xpos, ypos); 43 | } 44 | else { 45 | Serial.println("Jpeg file format not supported!"); 46 | } 47 | } 48 | 49 | //==================================================================================== 50 | // Decode and render the Jpeg image onto the TFT screen 51 | //==================================================================================== 52 | void jpegRender(int xpos, int ypos) { 53 | 54 | // retrieve infomration about the image 55 | uint16_t *pImg; 56 | int16_t mcu_w = JpegDec.MCUWidth; 57 | int16_t mcu_h = JpegDec.MCUHeight; 58 | int32_t max_x = JpegDec.width; 59 | int32_t max_y = JpegDec.height; 60 | 61 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 62 | // Typically these MCUs are 16x16 pixel blocks 63 | // Determine the width and height of the right and bottom edge image blocks 64 | int32_t min_w = minimum(mcu_w, max_x % mcu_w); 65 | int32_t min_h = minimum(mcu_h, max_y % mcu_h); 66 | 67 | // save the current image block size 68 | int32_t win_w = mcu_w; 69 | int32_t win_h = mcu_h; 70 | 71 | // record the current time so we can measure how long it takes to draw an image 72 | uint32_t drawTime = millis(); 73 | 74 | // save the coordinate of the right and bottom edges to assist image cropping 75 | // to the screen size 76 | max_x += xpos; 77 | max_y += ypos; 78 | 79 | // read each MCU block until there are no more 80 | while ( JpegDec.readSwappedBytes()) { // Swapped byte order read 81 | 82 | // save a pointer to the image block 83 | pImg = JpegDec.pImage; 84 | 85 | // calculate where the image block should be drawn on the screen 86 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU 87 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 88 | 89 | // check if the image block size needs to be changed for the right edge 90 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 91 | else win_w = min_w; 92 | 93 | // check if the image block size needs to be changed for the bottom edge 94 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 95 | else win_h = min_h; 96 | 97 | // copy pixels into a contiguous block 98 | if (win_w != mcu_w) 99 | { 100 | for (int h = 1; h < win_h-1; h++) 101 | { 102 | memcpy(pImg + h * win_w, pImg + (h + 1) * mcu_w, win_w << 1); 103 | } 104 | } 105 | 106 | // draw image MCU block only if it will fit on the screen 107 | if ( mcu_x < tft.width() && mcu_y < tft.height()) 108 | { 109 | // Now push the image block to the screen 110 | tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg); 111 | } 112 | 113 | else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); 114 | 115 | } 116 | 117 | // calculate how long it took to draw the image 118 | drawTime = millis() - drawTime; // Calculate the time it took 119 | 120 | // print the results to the serial port 121 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 122 | Serial.println("====================================="); 123 | 124 | } 125 | 126 | //==================================================================================== 127 | // Print information decoded from the Jpeg image 128 | //==================================================================================== 129 | void jpegInfo() { 130 | 131 | Serial.println("==============="); 132 | Serial.println("JPEG image info"); 133 | Serial.println("==============="); 134 | Serial.print ("Width :"); Serial.println(JpegDec.width); 135 | Serial.print ("Height :"); Serial.println(JpegDec.height); 136 | Serial.print ("Components :"); Serial.println(JpegDec.comps); 137 | Serial.print ("MCU / row :"); Serial.println(JpegDec.MCUSPerRow); 138 | Serial.print ("MCU / col :"); Serial.println(JpegDec.MCUSPerCol); 139 | Serial.print ("Scan type :"); Serial.println(JpegDec.scanType); 140 | Serial.print ("MCU width :"); Serial.println(JpegDec.MCUWidth); 141 | Serial.print ("MCU height :"); Serial.println(JpegDec.MCUHeight); 142 | Serial.println("==============="); 143 | Serial.println(""); 144 | } 145 | 146 | //==================================================================================== 147 | // Open a Jpeg file and send it to the Serial port in a C array compatible format 148 | //==================================================================================== 149 | void createArray(const char *filename) { 150 | 151 | // Open the named file 152 | fs::File jpgFile = SPIFFS.open( filename, "r"); // File handle reference for SPIFFS 153 | // File jpgFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 154 | 155 | if ( !jpgFile ) { 156 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 157 | return; 158 | } 159 | 160 | uint8_t data; 161 | byte line_len = 0; 162 | Serial.println(""); 163 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 164 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 165 | Serial.println(""); 166 | Serial.println("#if defined(__AVR__)"); 167 | Serial.println(" #include "); 168 | Serial.println("#endif"); 169 | Serial.println(""); 170 | Serial.print ("const uint8_t "); 171 | while (*filename != '.') Serial.print(*filename++); 172 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 173 | 174 | while ( jpgFile.available()) { 175 | 176 | data = jpgFile.read(); 177 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 178 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 179 | line_len++; 180 | if ( line_len >= 32) { 181 | line_len = 0; 182 | Serial.println(); 183 | } 184 | 185 | } 186 | 187 | Serial.println("};\r\n"); 188 | jpgFile.close(); 189 | } 190 | //==================================================================================== 191 | -------------------------------------------------------------------------------- /examples/MCUFRIEND_kbv/jpeg_kbv/JPEG_Functions.ino: -------------------------------------------------------------------------------- 1 | /*==================================================================================== 2 | This sketch contains support functions to render the Jpeg images. 3 | 4 | Created by Bodmer 5th Feb 2017 5 | ==================================================================================*/ 6 | 7 | // Return the minimum of two values a and b 8 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 9 | 10 | //==================================================================================== 11 | // This function opens the array and primes the decoder 12 | //==================================================================================== 13 | void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) { 14 | 15 | boolean decoded = JpegDec.decodeArray(arrayname, array_size); 16 | 17 | if (decoded) { 18 | // print information about the image to the serial port 19 | jpegInfo(); 20 | 21 | // render the image onto the screen at given coordinates 22 | jpegRender(xpos, ypos); 23 | } 24 | else { 25 | Serial.println("Jpeg file format not supported!"); 26 | } 27 | } 28 | 29 | //==================================================================================== 30 | // This function opens the Filing System Jpeg image file and primes the decoder 31 | //==================================================================================== 32 | void drawFSJpeg(const char *filename, int xpos, int ypos) { 33 | 34 | Serial.println("====================================="); 35 | Serial.print("Drawing file: "); Serial.println(filename); 36 | Serial.println("====================================="); 37 | 38 | // Open the file (the Jpeg decoder library will close it) 39 | File jpgFile = SD.open( filename, FILE_READ); // file handle reference for SD library 40 | 41 | if ( !jpgFile ) { 42 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 43 | return; 44 | } 45 | 46 | // To initialise the decoder and provide the file, we can use one of the following methods: 47 | boolean decoded = JpegDec.decodeSdFile(jpgFile); // we can pass the SD file handle to the decoder, 48 | //boolean decoded = JpegDec.decodeFsFile(filename); // or we can pass the filename 49 | // The filename can be a String or character array 50 | if (decoded) { 51 | // print information about the image to the serial port 52 | jpegInfo(); 53 | 54 | // render the image onto the screen at given coordinates 55 | jpegRender(xpos, ypos); 56 | } 57 | else { 58 | Serial.println("Jpeg file format not supported!"); 59 | } 60 | } 61 | 62 | //==================================================================================== 63 | // Decode and paint onto the TFT screen 64 | //==================================================================================== 65 | void jpegRender(int xpos, int ypos) { 66 | 67 | // retrieve infomration about the image 68 | uint16_t *pImg; 69 | uint16_t mcu_w = JpegDec.MCUWidth; 70 | uint16_t mcu_h = JpegDec.MCUHeight; 71 | uint32_t max_x = JpegDec.width; 72 | uint32_t max_y = JpegDec.height; 73 | 74 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 75 | // Typically these MCUs are 16x16 pixel blocks 76 | // Determine the width and height of the right and bottom edge image blocks 77 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 78 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 79 | 80 | // save the current image block size 81 | uint32_t win_w = mcu_w; 82 | uint32_t win_h = mcu_h; 83 | 84 | // record the current time so we can measure how long it takes to draw an image 85 | uint32_t drawTime = millis(); 86 | 87 | // save the coordinate of the right and bottom edges to assist image cropping 88 | // to the screen size 89 | max_x += xpos; 90 | max_y += ypos; 91 | 92 | // read each MCU block until there are no more 93 | while ( JpegDec.read()) { 94 | 95 | // save a pointer to the image block 96 | pImg = JpegDec.pImage; 97 | 98 | // calculate where the image block should be drawn on the screen 99 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 100 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 101 | 102 | // check if the image block size needs to be changed for the right and bottom edges 103 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 104 | else win_w = min_w; 105 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 106 | else win_h = min_h; 107 | 108 | // calculate how many pixels must be drawn 109 | uint16_t mcu_pixels = win_w * win_h; 110 | 111 | // draw image MCU block only if it will fit on the screen 112 | if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height()) 113 | { 114 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 115 | tft.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 116 | 117 | // Write all MCU pixels to the TFT window 118 | //while (mcu_pixels--) tft.pushColor(*pImg++); // Send MCU buffer to TFT 16 bits at a time 119 | tft.pushColors(pImg, mcu_pixels, 1); 120 | } 121 | 122 | // Stop drawing blocks if the bottom of the screen has been reached, 123 | // the abort function will close the file 124 | else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort(); 125 | 126 | } 127 | 128 | // calculate how long it took to draw the image 129 | drawTime = millis() - drawTime; 130 | 131 | // print the results to the serial port 132 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 133 | Serial.println("====================================="); 134 | 135 | } 136 | 137 | //==================================================================================== 138 | // Send time taken to Serial port 139 | //==================================================================================== 140 | void jpegInfo() { 141 | Serial.println(F("===============")); 142 | Serial.println(F("JPEG image info")); 143 | Serial.println(F("===============")); 144 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 145 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 146 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 147 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 148 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 149 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 150 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 151 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 152 | Serial.println(F("===============")); 153 | } 154 | 155 | //==================================================================================== 156 | // Open a Jpeg file on an SD card and dump it to the Serial port as a C array 157 | //==================================================================================== 158 | void createArray(const char *filename) { 159 | 160 | File jpgFile; // File handle reference For SD library 161 | 162 | if ( !( jpgFile = SD.open( filename, FILE_READ))) { 163 | Serial.println(F("JPEG file not found")); 164 | return; 165 | } 166 | 167 | uint8_t data; 168 | byte line_len = 0; 169 | Serial.println("// Generated by a JPEGDecoder library example sketch:"); 170 | Serial.println("// https://github.com/Bodmer/JPEGDecoder"); 171 | Serial.println(""); 172 | Serial.println("#if defined(__AVR__)"); 173 | Serial.println(" #include "); 174 | Serial.println("#endif"); 175 | Serial.println(""); 176 | Serial.print("const uint8_t "); 177 | while (*filename != '.') Serial.print(*filename++); 178 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors 179 | 180 | while ( jpgFile.available()) { 181 | 182 | data = jpgFile.read(); 183 | Serial.print("0x"); if (abs(data) < 16) Serial.print("0"); 184 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 185 | line_len++; 186 | if ( line_len >= 32) { 187 | line_len = 0; 188 | Serial.println(); 189 | } 190 | 191 | } 192 | 193 | Serial.println("};\r\n"); 194 | jpgFile.close(); 195 | } 196 | //==================================================================================== 197 | 198 | -------------------------------------------------------------------------------- /examples/Arduino TFT/TFT_Jpeg/TFT_Jpeg.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Arduino TFT Jpeg example 4 | 5 | This example reads a Jpeg image file from a micro-SD card 6 | and draws it on the screen. 7 | 8 | In this sketch, the Arduino logo is read from a micro-SD card. 9 | There is a arduino.jpg file included with this sketch. 10 | - open the sketch folder (Ctrl-K or Cmd-K) 11 | - copy the "arduino.jpg" file to a micro-SD 12 | - put the SD into the SD slot of the Arduino TFT module. 13 | 14 | This example code is in the public domain. 15 | 16 | Original sketch "TFTBitmapLogo" created 19 April 2013 by Enrico Gueli 17 | 18 | Adapted by Bodmer 20 January 2017 to display a jpeg image 19 | rather than a bitmap 20 | 21 | Display details here: 22 | https://www.arduino.cc/en/Main/GTFT 23 | 24 | The decoding of jpeg images involves a lot of complex maths and 25 | requires a processor with at least 8 kbytes of RAM. This sketch has 26 | been tested with the Arduino Mega and Due boards. 27 | */ 28 | 29 | // include the necessary libraries 30 | #include 31 | #include 32 | #include // Arduino LCD library 33 | 34 | //#include // Hardware-specific library 35 | //TFT_HX8357 TFTscreen = TFT_HX8357(); // Invoke custom library 36 | 37 | #include // JPEG decoder library 38 | 39 | // pin definition for the Mega 40 | #define sd_cs 53 41 | #define lcd_cs 49 42 | #define dc 48 43 | #define rst 47 44 | 45 | #define TFT_WHITE 0xFFFF 46 | #define TFT_BLACK 0x0000 47 | #define TFT_RED 0xF800 48 | 49 | // TFT driver and graphics library 50 | TFT TFTscreen = TFT(lcd_cs, dc, rst); 51 | 52 | // this function determines the minimum of two numbers 53 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 54 | 55 | //==================================================================================== 56 | // setup 57 | //==================================================================================== 58 | void setup() { 59 | // initialize the GLCD and show a message 60 | // asking the user to open the serial line 61 | TFTscreen.begin(); 62 | TFTscreen.fillScreen(TFT_WHITE); // Alternative: TFTscreen.background(255, 255, 255); 63 | 64 | TFTscreen.setTextColor(TFT_RED); // Alternative: TFTscreen.stroke(0, 0, 255); 65 | TFTscreen.println(); 66 | TFTscreen.println(F("Arduino TFT Jpeg Example")); 67 | 68 | TFTscreen.setTextColor(TFT_BLACK); // Alternative: TFTscreen.stroke(0, 0, 0); 69 | TFTscreen.println(F("Open serial monitor")); 70 | TFTscreen.println(F("to run the sketch")); 71 | delay(10000); 72 | // initialize the serial port: it will be used to 73 | // print some diagnostic info 74 | Serial.begin(9600); 75 | while (!Serial) { 76 | // wait for serial port to connect. Needed for native USB port only 77 | } 78 | 79 | // clear the GLCD screen before starting 80 | // TFTscreen.background(255, 255, 255); 81 | TFTscreen.fillScreen(TFT_WHITE); 82 | 83 | // try to access the SD card. If that fails (e.g. 84 | // no card present), the setup process will stop. 85 | Serial.print(F("Initializing SD card...")); 86 | if (!SD.begin(sd_cs)) { 87 | Serial.println(F("failed!")); 88 | while (1); // SD initialisation failed so wait here 89 | } 90 | Serial.println(F("OK!")); 91 | 92 | // initialize and clear the GLCD screen 93 | TFTscreen.begin(); 94 | TFTscreen.fillScreen(TFT_WHITE); // Alternative: TFTscreen.background(255, 255, 255); 95 | 96 | // now that the SD card can be accessed, check the 97 | // image file exists. 98 | if (SD.exists("arduino.jpg")) { 99 | Serial.println("arduino.jpg found on SD card."); 100 | } else { 101 | Serial.println("arduino.jpg not found on SD card."); 102 | while (1); // Image file missing so stay here 103 | } 104 | 105 | } 106 | 107 | //==================================================================================== 108 | // Main loop 109 | //==================================================================================== 110 | void loop() { 111 | 112 | // open the image file 113 | File jpgFile = SD.open( "arduino.jpg", FILE_READ); 114 | 115 | // initialise the decoder to give access to image information 116 | JpegDec.decodeSdFile(jpgFile); 117 | 118 | // print information about the image to the serial port 119 | jpegInfo(); 120 | 121 | // render the image onto the screen at coordinate 0,0 122 | renderJPEG(0, 0); 123 | 124 | // wait a little bit before clearing the screen to random color and drawing again 125 | delay(4000); 126 | 127 | // clear screen 128 | TFTscreen.fillScreen(random(0xFFFF)); // Alternative: TFTscreen.background(255, 255, 255); 129 | } 130 | 131 | 132 | //==================================================================================== 133 | // Print information about the image 134 | //==================================================================================== 135 | void jpegInfo() { 136 | Serial.println(F("===============")); 137 | Serial.println(F("JPEG image info")); 138 | Serial.println(F("===============")); 139 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 140 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 141 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 142 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 143 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 144 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 145 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 146 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 147 | Serial.println(F("===============")); 148 | } 149 | 150 | 151 | //==================================================================================== 152 | // Decode and paint onto the TFT screen 153 | //==================================================================================== 154 | void renderJPEG(int xpos, int ypos) { 155 | 156 | // retrieve infomration about the image 157 | uint16_t *pImg; 158 | uint16_t mcu_w = JpegDec.MCUWidth; 159 | uint16_t mcu_h = JpegDec.MCUHeight; 160 | uint32_t max_x = JpegDec.width; 161 | uint32_t max_y = JpegDec.height; 162 | 163 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 164 | // Typically these MCUs are 16x16 pixel blocks 165 | // Determine the width and height of the right and bottom edge image blocks 166 | uint32_t min_w = minimum(mcu_w, max_x % mcu_w); 167 | uint32_t min_h = minimum(mcu_h, max_y % mcu_h); 168 | 169 | // save the current image block size 170 | uint32_t win_w = mcu_w; 171 | uint32_t win_h = mcu_h; 172 | 173 | // record the current time so we can measure how long it takes to draw an image 174 | uint32_t drawTime = millis(); 175 | 176 | // save the coordinate of the right and bottom edges to assist image cropping 177 | // to the screen size 178 | max_x += xpos; 179 | max_y += ypos; 180 | 181 | // read each MCU block until there are no more 182 | while ( JpegDec.read()) { 183 | 184 | // save a pointer to the image block 185 | pImg = JpegDec.pImage; 186 | 187 | // calculate where the image block should be drawn on the screen 188 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; 189 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 190 | 191 | // check if the image block size needs to be changed for the right and bottom edges 192 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 193 | else win_w = min_w; 194 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 195 | else win_h = min_h; 196 | 197 | // calculate how many pixels must be drawn 198 | uint32_t mcu_pixels = win_w * win_h; 199 | 200 | // draw image block if it will fit on the screen 201 | if ( ( mcu_x + win_w) <= TFTscreen.width() && ( mcu_y + win_h) <= TFTscreen.height()) { 202 | // open a window onto the screen to paint the pixels into 203 | //TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 204 | TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 205 | // push all the image block pixels to the screen 206 | while (mcu_pixels--) TFTscreen.pushColor(*pImg++); // Send to TFT 16 bits at a time 207 | } 208 | 209 | // stop drawing blocks if the bottom of the screen has been reached 210 | // the abort function will close the file 211 | else if ( ( mcu_y + win_h) >= TFTscreen.height()) JpegDec.abort(); 212 | 213 | } 214 | 215 | // calculate how long it took to draw the image 216 | drawTime = millis() - drawTime; // Calculate the time it took 217 | 218 | // print the results to the serial port 219 | Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); 220 | Serial.println("====================================="); 221 | 222 | } 223 | 224 | -------------------------------------------------------------------------------- /examples/Other libraries/Mega and Due/TFT_flash_jpg/TFT_flash_jpg.ino: -------------------------------------------------------------------------------- 1 | // Sketch to display images on a 480 x 320 HX8357 or ILI9481 2 | // 16 bit parallel TFT by Bodmer (aka rowboteer) 3 | // Version 0.10c 23/1/17 4 | 5 | // Renders images stored in an array in program (FLASH) 6 | // JPEG images are stored in header files (see jpeg1.h etc) 7 | 8 | // The sketch does not need the SD or sdFat libraries since it does not access an 9 | // SD Card. You can edit the "User_Config.h" file inside the JPEGDecoder library folder 10 | // to stop the decode loading the SD or sdFat library. 11 | // See comments in "User_Config.h". Editting the User_Config.h file is optional 12 | // and NOT essential but it will save some FLASH space. 13 | 14 | // Mega TFT library here: 15 | // https://github.com/Bodmer/TFT_HX8357 16 | 17 | // Due TFT library here: 18 | // https://github.com/Bodmer/TFT_HX8357_Due 19 | 20 | // This example draws a jpeg compressed image stored in memory onto the screen 21 | // the image is 480 x 320 pixels. 22 | 23 | // As an example Baboon40.jpg is compressed from ~460 kBytes (24 bit colour) to a mere 24 | // 24.4 kBytes (~19 times smaller), Mouse480.jpg is 6.45 kBytes (~70 times smaller) 25 | 26 | // As well as the HX8357 TFT library you will need the JPEG Decoder library. 27 | // A copy can be downloaded here, it is based on the library by Makoto Kurauchi. 28 | // The following copy has some bug fixes and extra/adapted member functions: 29 | // https://github.com/Bodmer/JPEGDecoder 30 | 31 | // As supplied this sketch will draw 4 images to screen in 4 different sizes 32 | // Note the whole JPEG has to be decoded to draw scaled images so drawing scaled 33 | // pictures is not significantly faster than drawing the 1:1 (unscaled) image 34 | 35 | //---------------------------------------------------------------------------------------------------- 36 | 37 | #include 38 | #include 39 | 40 | // Next the libraries are selected depending on whether it is an AVR (Mega) or otherwise a Due 41 | 42 | #if defined (ARDUINO_ARCH_AVR) 43 | // Mega libraries 44 | #include // Hardware-specific Mega library 45 | TFT_HX8357 tft = TFT_HX8357(); // Invoke custom Mega library 46 | #elif defined (ARDUINO_ARCH_SAM) 47 | // Due libraries 48 | #include // Hardware-specific Due library 49 | TFT_HX8357_Due tft = TFT_HX8357_Due(); // Invoke custom Due library 50 | #endif 51 | 52 | // JPEG decoder library 53 | #include 54 | 55 | // Chip Select Pin for SD card 56 | #define SD_CS 53 57 | 58 | // Include the sketch header file that contains the image stored as an array of bytes 59 | // More than one image array could be stored in each header file. 60 | #include "jpeg1.h" 61 | #include "jpeg2.h" 62 | #include "jpeg3.h" 63 | #include "jpeg4.h" 64 | 65 | // Count how many times the image is drawn for test purposes 66 | uint32_t icount = 0; 67 | //---------------------------------------------------------------------------------------------------- 68 | 69 | 70 | //#################################################################################################### 71 | // Setup 72 | //#################################################################################################### 73 | void setup() { 74 | Serial.begin(115200); 75 | tft.begin(); 76 | } 77 | 78 | //#################################################################################################### 79 | // Main loop 80 | //#################################################################################################### 81 | void loop() { 82 | 83 | tft.setRotation(2); // portrait 84 | tft.fillScreen(random(0xFFFF)); 85 | 86 | // The image is 300 x 300 pixels so we do some sums to position image in the middle of the screen! 87 | // Doing this by reading the image width and height from the jpeg info is left as an exercise! 88 | int x = (tft.width() - 300) / 2 - 1; 89 | int y = (tft.height() - 300) / 2 - 1; 90 | 91 | drawArrayJpeg(EagleEye, sizeof(EagleEye), x, y); // Draw a jpeg image stored in memory at x,y 92 | delay(2000); 93 | 94 | 95 | tft.setRotation(2); // portrait 96 | tft.fillScreen(random(0xFFFF)); 97 | drawArrayJpeg(Baboon40, sizeof(Baboon40), 0, 0); // Draw a jpeg image stored in memory 98 | delay(2000); 99 | 100 | 101 | tft.setRotation(2); // portrait 102 | tft.fillScreen(random(0xFFFF)); 103 | drawArrayJpeg(lena20k, sizeof(lena20k), 0, 0); // Draw a jpeg image stored in memory 104 | delay(2000); 105 | 106 | tft.setRotation(1); // landscape 107 | tft.fillScreen(random(0xFFFF)); 108 | 109 | // This image will be deliberately cropped as it is 480 x 320 thes extends off the screen when plotted 110 | // at coordinate 100,100 111 | drawArrayJpeg(Mouse480, sizeof(Mouse480), 100, 100); // Draw a jpeg image stored in memory, test cropping 112 | //drawArrayJpeg(Mouse480, sizeof(Mouse480), 0, 0); // Draw a jpeg image stored in memory 113 | delay(2000); 114 | } 115 | 116 | //#################################################################################################### 117 | // Draw a JPEG on the TFT pulled from a program memory array 118 | //#################################################################################################### 119 | void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) { 120 | 121 | int x = xpos; 122 | int y = ypos; 123 | 124 | JpegDec.decodeArray(arrayname, array_size); 125 | 126 | jpegInfo(); // Print information from the JPEG file (could comment this line out) 127 | 128 | renderJPEG(x, y); 129 | 130 | Serial.println("#########################"); 131 | } 132 | 133 | //#################################################################################################### 134 | // Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit 135 | //#################################################################################################### 136 | // This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not 137 | // fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders. 138 | void renderJPEG(int xpos, int ypos) { 139 | 140 | // retrieve infomration about the image 141 | uint16_t *pImg; 142 | uint16_t mcu_w = JpegDec.MCUWidth; 143 | uint16_t mcu_h = JpegDec.MCUHeight; 144 | uint32_t max_x = JpegDec.width; 145 | uint32_t max_y = JpegDec.height; 146 | 147 | // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) 148 | // Typically these MCUs are 16x16 pixel blocks 149 | // Determine the width and height of the right and bottom edge image blocks 150 | uint32_t min_w = min(mcu_w, max_x % mcu_w); 151 | uint32_t min_h = min(mcu_h, max_y % mcu_h); 152 | 153 | // save the current image block size 154 | uint32_t win_w = mcu_w; 155 | uint32_t win_h = mcu_h; 156 | 157 | // record the current time so we can measure how long it takes to draw an image 158 | uint32_t drawTime = millis(); 159 | 160 | // save the coordinate of the right and bottom edges to assist image cropping 161 | // to the screen size 162 | max_x += xpos; 163 | max_y += ypos; 164 | 165 | // read each MCU block until there are no more 166 | while (JpegDec.read()) { 167 | 168 | // save a pointer to the image block 169 | pImg = JpegDec.pImage ; 170 | 171 | // calculate where the image block should be drawn on the screen 172 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU 173 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 174 | 175 | // check if the image block size needs to be changed for the right and bottom edges 176 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 177 | else win_w = min_w; 178 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 179 | else win_h = min_h; 180 | 181 | // calculate how many pixels must be drawn 182 | uint32_t mcu_pixels = win_w * win_h; 183 | 184 | // draw image MCU block only if it will fit on the screen 185 | if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()) 186 | { 187 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 188 | tft.setWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 189 | 190 | // Write all MCU pixels to the TFT window 191 | while (mcu_pixels--) { 192 | // Push each pixel to the TFT MCU area 193 | tft.pushColor(*pImg++); 194 | } 195 | 196 | } 197 | else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding 198 | } 199 | 200 | // calculate how long it took to draw the image 201 | drawTime = millis() - drawTime; 202 | 203 | // print the results to the serial port 204 | Serial.print(F( "Total render time was : ")); Serial.print(drawTime); Serial.println(F(" ms")); 205 | Serial.println(F("")); 206 | } 207 | 208 | //#################################################################################################### 209 | // Print image information to the serial port (optional) 210 | //#################################################################################################### 211 | void jpegInfo() { 212 | Serial.println(F("===============")); 213 | Serial.println(F("JPEG image info")); 214 | Serial.println(F("===============")); 215 | Serial.print(F( "Width :")); Serial.println(JpegDec.width); 216 | Serial.print(F( "Height :")); Serial.println(JpegDec.height); 217 | Serial.print(F( "Components :")); Serial.println(JpegDec.comps); 218 | Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); 219 | Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); 220 | Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); 221 | Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); 222 | Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); 223 | Serial.println(F("===============")); 224 | } 225 | 226 | //#################################################################################################### 227 | // Show the execution time (optional) 228 | //#################################################################################################### 229 | // WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for 230 | // sketch sizes greater than ~70KBytes because 16 bit address pointers are used in some libraries. 231 | 232 | // The Due will work fine with the HX8357_Due library. 233 | 234 | void showTime(uint32_t msTime) { 235 | //tft.setCursor(0, 0); 236 | //tft.setTextFont(1); 237 | //tft.setTextSize(2); 238 | //tft.setTextColor(TFT_WHITE, TFT_BLACK); 239 | //tft.print(F(" JPEG drawn in ")); 240 | //tft.print(msTime); 241 | //tft.println(F(" ms ")); 242 | Serial.print(F(" JPEG drawn in ")); 243 | Serial.print(msTime); 244 | Serial.println(F(" ms ")); 245 | } 246 | 247 | -------------------------------------------------------------------------------- /src/JPEGDecoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | JPEGDecoder.cpp 3 | 4 | JPEG Decoder for Arduino 5 | https://github.com/MakotoKurauchi/JPEGDecoder 6 | Public domain, Makoto Kurauchi 7 | 8 | Latest version here: 9 | https://github.com/Bodmer/JPEGDecoder 10 | 11 | Bodmer (21/6/15): Adapted by Bodmer to display JPEGs on TFT (works with Mega and Due) but there 12 | is a memory leak somewhere, crashes after decoding 1 file :-) 13 | 14 | Bodmer (29/1/16): Now in a state with sufficient Mega and Due testing to release in the wild 15 | 16 | Bodmer (various): Various updates and latent bugs fixed 17 | 18 | Bodmer (14/1/17): Tried to merge ESP8266 and SPIFFS support from Frederic Plante's broken branch, 19 | worked on ESP8266, but broke the array handling :-( 20 | 21 | Bodmer (14/1/17): Scrapped all FP's updates, extended the built-in approach to using different 22 | data sources (currently array, SD files and/or SPIFFS files) 23 | 24 | Bodmer (14/1/17): Added ESP8266 support and SPIFFS as a source, added configuration option to 25 | swap bytes to support fast image transfer to TFT using ESP8266 SPI writePattern(). 26 | 27 | Bodmer (15/1/17): Now supports ad hoc use of SPIFFS, SD and arrays without manual configuration. 28 | 29 | Bodmer (19/1/17): Add support for filename being String type 30 | 31 | Bodmer (20/1/17): Correct last mcu block corruption (thanks stevstrong for tracking that bug down!) 32 | 33 | Bodmer (20/1/17): Prevent deleting the pImage pointer twice (causes an exception on ESP8266), 34 | tidy up code. 35 | 36 | Bodmer (24/1/17): Correct greyscale images, update examples 37 | 38 | Bodmer (26/2/22): Removed deprecated SPIFFS 39 | */ 40 | 41 | #include "JPEGDecoder.h" 42 | #include "picojpeg.h" 43 | 44 | JPEGDecoder JpegDec; 45 | 46 | JPEGDecoder::JPEGDecoder(){ 47 | mcu_x = 0 ; 48 | mcu_y = 0 ; 49 | is_available = 0; 50 | thisPtr = this; 51 | } 52 | 53 | 54 | JPEGDecoder::~JPEGDecoder(){ 55 | if (pImage) delete[] pImage; 56 | pImage = NULL; 57 | } 58 | 59 | 60 | uint8_t JPEGDecoder::pjpeg_callback(uint8_t* pBuf, uint8_t buf_size, uint8_t *pBytes_actually_read, void *pCallback_data) { 61 | JPEGDecoder *thisPtr = JpegDec.thisPtr ; 62 | thisPtr->pjpeg_need_bytes_callback(pBuf, buf_size, pBytes_actually_read, pCallback_data); 63 | return 0; 64 | } 65 | 66 | 67 | uint8_t JPEGDecoder::pjpeg_need_bytes_callback(uint8_t* pBuf, uint8_t buf_size, uint8_t *pBytes_actually_read, void *pCallback_data) { 68 | uint n; 69 | 70 | pCallback_data = pCallback_data; // Supress warning 71 | 72 | n = jpg_min(g_nInFileSize - g_nInFileOfs, buf_size); 73 | 74 | if (jpg_source == JPEG_ARRAY) { // We are handling an array 75 | for (uint i = 0; i < n; i++) { 76 | pBuf[i] = pgm_read_byte(jpg_data++); 77 | //Serial.println(pBuf[i],HEX); 78 | } 79 | } 80 | 81 | #ifdef LOAD_FLASH_FS 82 | if (jpg_source == JPEG_FS_FILE) g_pInFileFs.read(pBuf,n); // else we are handling a file 83 | #endif 84 | 85 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 86 | if (jpg_source == JPEG_SD_FILE) g_pInFileSd.read(pBuf,n); // else we are handling a file 87 | #endif 88 | 89 | *pBytes_actually_read = (uint8_t)(n); 90 | g_nInFileOfs += n; 91 | return 0; 92 | } 93 | 94 | int JPEGDecoder::decode_mcu(void) { 95 | 96 | status = pjpeg_decode_mcu(); 97 | 98 | if (status) { 99 | is_available = 0 ; 100 | 101 | if (status != PJPG_NO_MORE_BLOCKS) { 102 | #ifdef DEBUG 103 | Serial.print("pjpeg_decode_mcu() failed with status "); 104 | Serial.println(status); 105 | #endif 106 | 107 | return -1; 108 | } 109 | } 110 | return 1; 111 | } 112 | 113 | 114 | int JPEGDecoder::read(void) { 115 | int y, x; 116 | uint16_t *pDst_row; 117 | 118 | if(is_available == 0 || mcu_y >= image_info.m_MCUSPerCol) { 119 | abort(); 120 | return 0; 121 | } 122 | 123 | // Copy MCU's pixel blocks into the destination bitmap. 124 | pDst_row = pImage; 125 | for (y = 0; y < image_info.m_MCUHeight; y += 8) { 126 | 127 | const int by_limit = jpg_min(8, image_info.m_height - (mcu_y * image_info.m_MCUHeight + y)); 128 | 129 | for (x = 0; x < image_info.m_MCUWidth; x += 8) { 130 | uint16_t *pDst_block = pDst_row + x; 131 | 132 | // Compute source byte offset of the block in the decoder's MCU buffer. 133 | uint src_ofs = (x * 8U) + (y * 16U); 134 | const uint8_t *pSrcR = image_info.m_pMCUBufR + src_ofs; 135 | const uint8_t *pSrcG = image_info.m_pMCUBufG + src_ofs; 136 | const uint8_t *pSrcB = image_info.m_pMCUBufB + src_ofs; 137 | 138 | const int bx_limit = jpg_min(8, image_info.m_width - (mcu_x * image_info.m_MCUWidth + x)); 139 | 140 | if (image_info.m_scanType == PJPG_GRAYSCALE) { 141 | int bx, by; 142 | for (by = 0; by < by_limit; by++) { 143 | uint16_t *pDst = pDst_block; 144 | 145 | for (bx = 0; bx < bx_limit; bx++) { 146 | #ifdef SWAP_BYTES 147 | *pDst++ = (*pSrcR & 0xF8) | (*pSrcR & 0xE0) >> 5 | (*pSrcR & 0xF8) << 5 | (*pSrcR & 0x1C) << 11; 148 | #else 149 | *pDst++ = (*pSrcR & 0xF8) << 8 | (*pSrcR & 0xFC) <<3 | *pSrcR >> 3; 150 | #endif 151 | pSrcR++; 152 | } 153 | 154 | pSrcR += (8 - bx_limit); 155 | 156 | pDst_block += row_pitch; 157 | } 158 | } 159 | else { 160 | int bx, by; 161 | for (by = 0; by < by_limit; by++) { 162 | uint16_t *pDst = pDst_block; 163 | 164 | for (bx = 0; bx < bx_limit; bx++) { 165 | #ifdef SWAP_BYTES 166 | *pDst++ = (*pSrcR & 0xF8) | (*pSrcG & 0xE0) >> 5 | (*pSrcB & 0xF8) << 5 | (*pSrcG & 0x1C) << 11; 167 | #else 168 | *pDst++ = (*pSrcR & 0xF8) << 8 | (*pSrcG & 0xFC) <<3 | *pSrcB >> 3; 169 | #endif 170 | pSrcR++; pSrcG++; pSrcB++; 171 | } 172 | 173 | pSrcR += (8 - bx_limit); 174 | pSrcG += (8 - bx_limit); 175 | pSrcB += (8 - bx_limit); 176 | 177 | pDst_block += row_pitch; 178 | } 179 | } 180 | } 181 | pDst_row += (row_pitch * 8); 182 | } 183 | 184 | MCUx = mcu_x; 185 | MCUy = mcu_y; 186 | 187 | mcu_x++; 188 | if (mcu_x == image_info.m_MCUSPerRow) { 189 | mcu_x = 0; 190 | mcu_y++; 191 | } 192 | 193 | if(decode_mcu()==-1) is_available = 0 ; 194 | 195 | return 1; 196 | } 197 | 198 | int JPEGDecoder::readSwappedBytes(void) { 199 | int y, x; 200 | uint16_t *pDst_row; 201 | 202 | if(is_available == 0 || mcu_y >= image_info.m_MCUSPerCol) { 203 | abort(); 204 | return 0; 205 | } 206 | 207 | // Copy MCU's pixel blocks into the destination bitmap. 208 | pDst_row = pImage; 209 | for (y = 0; y < image_info.m_MCUHeight; y += 8) { 210 | 211 | const int by_limit = jpg_min(8, image_info.m_height - (mcu_y * image_info.m_MCUHeight + y)); 212 | 213 | for (x = 0; x < image_info.m_MCUWidth; x += 8) { 214 | uint16_t *pDst_block = pDst_row + x; 215 | 216 | // Compute source byte offset of the block in the decoder's MCU buffer. 217 | uint src_ofs = (x * 8U) + (y * 16U); 218 | const uint8_t *pSrcR = image_info.m_pMCUBufR + src_ofs; 219 | const uint8_t *pSrcG = image_info.m_pMCUBufG + src_ofs; 220 | const uint8_t *pSrcB = image_info.m_pMCUBufB + src_ofs; 221 | 222 | const int bx_limit = jpg_min(8, image_info.m_width - (mcu_x * image_info.m_MCUWidth + x)); 223 | 224 | if (image_info.m_scanType == PJPG_GRAYSCALE) { 225 | int bx, by; 226 | for (by = 0; by < by_limit; by++) { 227 | uint16_t *pDst = pDst_block; 228 | 229 | for (bx = 0; bx < bx_limit; bx++) { 230 | 231 | *pDst++ = (*pSrcR & 0xF8) | (*pSrcR & 0xE0) >> 5 | (*pSrcR & 0xF8) << 5 | (*pSrcR & 0x1C) << 11; 232 | 233 | pSrcR++; 234 | } 235 | } 236 | } 237 | else { 238 | int bx, by; 239 | for (by = 0; by < by_limit; by++) { 240 | uint16_t *pDst = pDst_block; 241 | 242 | for (bx = 0; bx < bx_limit; bx++) { 243 | 244 | *pDst++ = (*pSrcR & 0xF8) | (*pSrcG & 0xE0) >> 5 | (*pSrcB & 0xF8) << 5 | (*pSrcG & 0x1C) << 11; 245 | 246 | pSrcR++; pSrcG++; pSrcB++; 247 | } 248 | 249 | pSrcR += (8 - bx_limit); 250 | pSrcG += (8 - bx_limit); 251 | pSrcB += (8 - bx_limit); 252 | 253 | pDst_block += row_pitch; 254 | } 255 | } 256 | } 257 | pDst_row += (row_pitch * 8); 258 | } 259 | 260 | MCUx = mcu_x; 261 | MCUy = mcu_y; 262 | 263 | mcu_x++; 264 | if (mcu_x == image_info.m_MCUSPerRow) { 265 | mcu_x = 0; 266 | mcu_y++; 267 | } 268 | 269 | if(decode_mcu()==-1) is_available = 0 ; 270 | 271 | return 1; 272 | } 273 | 274 | 275 | // Generic file call for SD or Little_FS, uses leading / to distinguish Little_FS files 276 | int JPEGDecoder::decodeFile(const char *pFilename){ 277 | 278 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 279 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 280 | if (*pFilename == '/') 281 | #endif 282 | return decodeFsFile(pFilename); 283 | #endif 284 | 285 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 286 | return decodeSdFile(pFilename); 287 | #endif 288 | 289 | return -1; 290 | } 291 | 292 | int JPEGDecoder::decodeFile(const String& pFilename){ 293 | 294 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 295 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 296 | if (pFilename.charAt(0) == '/') 297 | #endif 298 | return decodeFsFile(pFilename); 299 | #endif 300 | 301 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 302 | return decodeSdFile(pFilename); 303 | #endif 304 | 305 | return -1; 306 | } 307 | 308 | 309 | #ifdef LOAD_FLASH_FS 310 | 311 | // Call specific to Little_FS 312 | int JPEGDecoder::decodeFsFile(const char *pFilename) { 313 | 314 | fs::File pInFile = LittleFS.open( pFilename, "r"); 315 | 316 | return decodeFsFile(pInFile); 317 | } 318 | 319 | int JPEGDecoder::decodeFsFile(const String& pFilename) { 320 | 321 | fs::File pInFile = LittleFS.open( pFilename, "r"); 322 | 323 | return decodeFsFile(pInFile); 324 | } 325 | 326 | int JPEGDecoder::decodeFsFile(fs::File jpgFile) { // This is for the Little_FS library 327 | 328 | g_pInFileFs = jpgFile; 329 | 330 | jpg_source = JPEG_FS_FILE; // Flag to indicate a Little_FS file 331 | 332 | if (!g_pInFileFs) { 333 | #ifdef DEBUG 334 | Serial.println("ERROR: Little_FS file not found!"); 335 | #endif 336 | 337 | return -1; 338 | } 339 | 340 | g_nInFileOfs = 0; 341 | 342 | g_nInFileSize = g_pInFileFs.size(); 343 | 344 | return decodeCommon(); 345 | 346 | } 347 | #endif 348 | 349 | 350 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 351 | 352 | // Call specific to SD filing system in case leading / is used 353 | int JPEGDecoder::decodeSdFile(const char *pFilename) { 354 | 355 | File pInFile = SD.open( pFilename, FILE_READ); 356 | 357 | return decodeSdFile(pInFile); 358 | } 359 | 360 | 361 | int JPEGDecoder::decodeSdFile(const String& pFilename) { 362 | #if !defined (ARDUINO_ARCH_SAM) 363 | 364 | File pInFile = SD.open( pFilename.c_str(), FILE_READ); 365 | 366 | return decodeSdFile(pInFile); 367 | #else 368 | return -1; 369 | #endif 370 | } 371 | 372 | 373 | int JPEGDecoder::decodeSdFile(File jpgFile) { // This is for the SD library 374 | 375 | g_pInFileSd = jpgFile; 376 | 377 | jpg_source = JPEG_SD_FILE; // Flag to indicate a SD file 378 | 379 | if (!g_pInFileSd) { 380 | #ifdef DEBUG 381 | Serial.println("ERROR: SD file not found!"); 382 | #endif 383 | 384 | return -1; 385 | } 386 | 387 | g_nInFileOfs = 0; 388 | 389 | g_nInFileSize = g_pInFileSd.size(); 390 | 391 | return decodeCommon(); 392 | 393 | } 394 | #endif 395 | 396 | 397 | int JPEGDecoder::decodeArray(const uint8_t array[], uint32_t array_size) { 398 | 399 | jpg_source = JPEG_ARRAY; // We are not processing a file, use arrays 400 | 401 | g_nInFileOfs = 0; 402 | 403 | jpg_data = (uint8_t *)array; 404 | 405 | g_nInFileSize = array_size; 406 | 407 | return decodeCommon(); 408 | } 409 | 410 | 411 | int JPEGDecoder::decodeCommon(void) { 412 | 413 | width = 0; 414 | height = 0; 415 | comps = 0; 416 | MCUSPerRow = 0; 417 | MCUSPerCol = 0; 418 | scanType = (pjpeg_scan_type_t)0; 419 | MCUWidth = 0; 420 | MCUHeight = 0; 421 | 422 | status = pjpeg_decode_init(&image_info, pjpeg_callback, NULL, 0); 423 | 424 | if (status) { 425 | #ifdef DEBUG 426 | Serial.print("pjpeg_decode_init() failed with status "); 427 | Serial.println(status); 428 | 429 | if (status == PJPG_UNSUPPORTED_MODE) { 430 | Serial.println("Progressive JPEG files are not supported."); 431 | } 432 | #endif 433 | 434 | return 0; 435 | } 436 | 437 | decoded_width = image_info.m_width; 438 | decoded_height = image_info.m_height; 439 | 440 | row_pitch = image_info.m_MCUWidth; 441 | pImage = new uint16_t[image_info.m_MCUWidth * image_info.m_MCUHeight]; 442 | 443 | memset(pImage , 0 , image_info.m_MCUWidth * image_info.m_MCUHeight * sizeof(*pImage)); 444 | 445 | row_blocks_per_mcu = image_info.m_MCUWidth >> 3; 446 | col_blocks_per_mcu = image_info.m_MCUHeight >> 3; 447 | 448 | is_available = 1 ; 449 | 450 | width = decoded_width; 451 | height = decoded_height; 452 | comps = 1; 453 | MCUSPerRow = image_info.m_MCUSPerRow; 454 | MCUSPerCol = image_info.m_MCUSPerCol; 455 | scanType = image_info.m_scanType; 456 | MCUWidth = image_info.m_MCUWidth; 457 | MCUHeight = image_info.m_MCUHeight; 458 | 459 | return decode_mcu(); 460 | } 461 | 462 | void JPEGDecoder::abort(void) { 463 | 464 | mcu_x = 0 ; 465 | mcu_y = 0 ; 466 | is_available = 0; 467 | if(pImage) delete[] pImage; 468 | pImage = NULL; 469 | 470 | #ifdef LOAD_FLASH_FS 471 | if (jpg_source == JPEG_FS_FILE) if (g_pInFileFs) g_pInFileFs.close(); 472 | #endif 473 | 474 | #if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY) 475 | if (jpg_source == JPEG_SD_FILE) if (g_pInFileSd) g_pInFileSd.close(); 476 | #endif 477 | } 478 | -------------------------------------------------------------------------------- /examples/Other libraries/Mega and Due/TFT_SDcard_jpg/TFT_SDcard_jpg.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Descendant of SerialCsvOut.ino 3 | Sample code of JPEG Decoder for Arduino 4 | Public domain, Makoto Kurauchi 5 | */ 6 | 7 | // Adapted to display images on a 480 x 320 HX8357 or ILI9481 8 | // 16 bit parallel TFT by Bodmer (aka rowboteer) 9 | // Version 0.05b 15/2/16 10 | 11 | // This sketch renders JPEG images stored on an SD Card. 12 | 13 | // Mega TFT library here: 14 | // https://github.com/Bodmer/TFT_HX8357 15 | 16 | // Due TFT library here: 17 | // https://github.com/Bodmer/TFT_HX8357_Due 18 | 19 | // As an example Baboon40.jpg is compressed from ~460 kBytes (24 bit colour) to a mere 20 | // 24.4 kBytes (~19 times smaller), Mouse480.jpg is 6.45 kBytes (~70 times smaller) 21 | 22 | // As well as the HX8357 TFT library you will need the JPEG Decoder library. 23 | // A copy can be downloaded here, it is based on the library by Makoto Kurauchi. 24 | // The following copy has some bug fixes and extra/adapted member functions: 25 | // https://github.com/Bodmer/JPEGDecoder 26 | 27 | // The Mega implementation uses the stock SD library built into the IDE 28 | // A preconfigured copy of the SdFat library to work with the Due is available here: 29 | // https://github.com/Bodmer/SdFat 30 | 31 | // A function called createArray() is provided to covert a jpeg file stored on SD Card 32 | // into a C array that can be pasted into any jpegX.h header file. The array is sent 33 | // to the Serial Monitor Window. 34 | 35 | // Images on SD Card must be put in the root folder (top level) to be found 36 | // Use the SdFat or SD library examples to verify your SD Card interface works! 37 | 38 | // Uncomment the #define LOAD_SDFAT_LIBRARY in User_Config.h in the JPEGDecoder src folder 39 | // if the Due is used with the SdFat library. SdFat allows bit bashing the SPI if needed. 40 | 41 | // The example images used to test this sketch can be found in the library 42 | // JPEGDecoder/extras folder 43 | //---------------------------------------------------------------------------------------------------- 44 | 45 | #include 46 | #include 47 | 48 | // Next the libraries are selected depending on whether it is an AVR (Mega) or otherwise a Due 49 | // >>>> Note: This works OK with IDE 1.6.7 but might produce errors with other IDE versions. <<<< 50 | // >>>> If you get errors here then edit or comment out the lines not needed. <<<< 51 | 52 | 53 | #if defined (ARDUINO_ARCH_AVR) 54 | // Mega libraries 55 | #include // Use the SD library for the Mega 56 | #include // Hardware-specific Mega library 57 | TFT_HX8357 tft = TFT_HX8357(); // Invoke custom Mega library 58 | #elif defined (ARDUINO_ARCH_SAM) 59 | // Due libraries 60 | #include // Use the SdFat library for the Due, see sketch header notes above 61 | SdFat SD; // Permit SD function call for the Due 62 | #include // Hardware-specific Due library 63 | TFT_HX8357_Due tft = TFT_HX8357_Due(); // Invoke custom Due library 64 | #endif 65 | 66 | // JPEG decoder library 67 | #include 68 | 69 | // Chip Select Pin for SD card 70 | byte SD_CS = 53; //Mega256 requirement 71 | 72 | // Count how many times the image is drawn for test purposes 73 | uint32_t icount = 0; 74 | //---------------------------------------------------------------------------------------------------- 75 | #define TFT_BLACK 0x0000 76 | #define TFT_BLUE 0x001F 77 | #define TFT_RED 0xF800 78 | #define TFT_GREEN 0x07E0 79 | #define TFT_CYAN 0x07FF 80 | #define TFT_MAGENTA 0xF81F 81 | #define TFT_YELLOW 0xFFE0 82 | #define TFT_WHITE 0xFFFF 83 | //---------------------------------------------------------------------------------------------------- 84 | 85 | 86 | //#################################################################################################### 87 | // Setup 88 | //#################################################################################################### 89 | void setup() { 90 | Serial.begin(115200); 91 | 92 | tft.begin(); 93 | tft.setRotation(1); // landscape 94 | tft.fillScreen(TFT_BLACK); 95 | 96 | Serial.print("Initialising SD card..."); 97 | 98 | if (!SD.begin(SD_CS)) { 99 | Serial.println("initialisation failed!"); 100 | return; 101 | } 102 | 103 | Serial.println("initialisation done."); 104 | } 105 | 106 | //#################################################################################################### 107 | // Main loop 108 | //#################################################################################################### 109 | void loop() { 110 | 111 | tft.setRotation(2); // portrait 112 | tft.fillScreen(random(0xFFFF)); 113 | 114 | // The image is 300 x 300 pixels so we do some sums to position image in the middle of the screen! 115 | // Doing this by reading the image width and height from the jpeg info is left as an exercise! 116 | int x = (tft.width() - 300) / 2 - 1; 117 | int y = (tft.height() - 300) / 2 - 1; 118 | 119 | drawSdJpeg("EagleEye.jpg", x, y); // This draws a jpeg pulled off the SD Card 120 | // createArray("EagleEye.jpg"); // This pulls a jpeg image off the SD Card and serial dumps an array 121 | delay(2000); 122 | 123 | tft.setRotation(2); // portrait 124 | tft.fillScreen(random(0xFFFF)); 125 | drawSdJpeg("Baboon40.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 126 | // createArray("Baboon40.jpg"); // This pulls a jpeg image off the SD Card and serial dumps an array 127 | delay(2000); 128 | 129 | tft.setRotation(2); // portrait 130 | tft.fillScreen(random(0xFFFF)); 131 | drawSdJpeg("lena20k.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 132 | //createArray("lena20k.jpg"); // This pulls a jpeg image off the SD Card and serial dumps an array 133 | delay(2000); 134 | 135 | tft.setRotation(1); // landscape 136 | tft.fillScreen(random(0xFFFF)); 137 | drawSdJpeg("Mouse480.jpg", 0, 0); // This draws a jpeg pulled off the SD Card 138 | 139 | 140 | createArray("Mouse480.jpg"); // This pulls a jpeg image off the SD Card and serial dumps in 141 | // the correct format for a C array. 142 | delay(2000); 143 | 144 | while(1); // Wait here 145 | } 146 | 147 | //#################################################################################################### 148 | // Draw a JPEG on the TFT pulled from SD Card 149 | //#################################################################################################### 150 | // xpos, ypos is top left corner of plotted image 151 | void drawSdJpeg(char *filename, int xpos, int ypos) { 152 | 153 | // Open the named file (the Jpeg decoder library will close it) 154 | File jpegFile = SD.open( filename, FILE_READ); // or, file handle reference for SD library 155 | 156 | if ( !jpegFile ) { 157 | Serial.print("ERROR: File \""); Serial.print(filename); Serial.println ("\" not found!"); 158 | return; 159 | } 160 | 161 | Serial.println("==========================="); 162 | Serial.print("Drawing file: "); Serial.println(filename); 163 | Serial.println("==========================="); 164 | 165 | // Use one of the following methods to initialise the decoder: 166 | boolean decoded = JpegDec.decodeSdFile(jpegFile); // Pass the SD file handle to the decoder, 167 | //boolean decoded = JpegDec.decodeSdFile(filename); // or pass the filename (String or character array) 168 | 169 | if (decoded) { 170 | // print information about the image to the serial port 171 | jpegInfo(); 172 | // render the image onto the screen at given coordinates 173 | jpegRender(xpos, ypos); 174 | } 175 | else { 176 | Serial.println("Jpeg file format not supported!"); 177 | } 178 | } 179 | 180 | //#################################################################################################### 181 | // Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit 182 | //#################################################################################################### 183 | // This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not 184 | // fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders. 185 | void jpegRender(int xpos, int ypos) { 186 | 187 | //jpegInfo(); // Print information from the JPEG file (could comment this line out) 188 | 189 | uint16_t *pImg; 190 | uint16_t mcu_w = JpegDec.MCUWidth; 191 | uint16_t mcu_h = JpegDec.MCUHeight; 192 | uint32_t max_x = JpegDec.width; 193 | uint32_t max_y = JpegDec.height; 194 | 195 | uint32_t min_w = min(mcu_w, max_x % mcu_w); 196 | uint32_t min_h = min(mcu_h, max_y % mcu_h); 197 | 198 | uint32_t win_w = mcu_w; 199 | uint32_t win_h = mcu_h; 200 | 201 | uint32_t drawTime = millis(); 202 | 203 | max_x += xpos; 204 | max_y += ypos; 205 | 206 | // Fetch data from the file, decode and display 207 | while (JpegDec.read()) { // While there is more data in the file 208 | pImg = JpegDec.pImage ; // Decode a MCU (Minimum Coding Unit, typically a 8x8 or 16x16 pixel block) 209 | 210 | int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU 211 | int mcu_y = JpegDec.MCUy * mcu_h + ypos; 212 | 213 | if (mcu_x + mcu_w <= max_x) win_w = mcu_w; 214 | else win_w = min_w; 215 | if (mcu_y + mcu_h <= max_y) win_h = mcu_h; 216 | else win_h = min_h; 217 | 218 | uint32_t mcu_pixels = win_w * win_h; 219 | 220 | if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height()) 221 | { 222 | // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1) 223 | tft.setWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); 224 | 225 | // Push all MCU pixels to the TFT window 226 | while (mcu_pixels--) { 227 | // Push each pixel to the TFT MCU area 228 | tft.pushColor(*pImg++); 229 | } 230 | 231 | // Push all MCU pixels to the TFT window, ~18% faster to pass an array pointer and length to the library 232 | // tft.pushColor16(pImg, mcu_pixels); // To be supported in HX8357 library at a future date 233 | 234 | } 235 | else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding 236 | } 237 | 238 | showTime(millis() - drawTime); // These lines are for sketch testing only 239 | //Serial.print(" Draw count:"); 240 | //Serial.println(icount++); 241 | } 242 | 243 | //#################################################################################################### 244 | // Print image information to the serial port (optional) 245 | //#################################################################################################### 246 | // JpegDec.decodeFile(...) or JpegDec.decodeArray(...) must be called before this info is available! 247 | void jpegInfo() { 248 | 249 | // Print information extracted from the JPEG file 250 | Serial.println("JPEG image info"); 251 | Serial.println("==============="); 252 | Serial.print("Width :"); 253 | Serial.println(JpegDec.width); 254 | Serial.print("Height :"); 255 | Serial.println(JpegDec.height); 256 | Serial.print("Components :"); 257 | Serial.println(JpegDec.comps); 258 | Serial.print("MCU / row :"); 259 | Serial.println(JpegDec.MCUSPerRow); 260 | Serial.print("MCU / col :"); 261 | Serial.println(JpegDec.MCUSPerCol); 262 | Serial.print("Scan type :"); 263 | Serial.println(JpegDec.scanType); 264 | Serial.print("MCU width :"); 265 | Serial.println(JpegDec.MCUWidth); 266 | Serial.print("MCU height :"); 267 | Serial.println(JpegDec.MCUHeight); 268 | Serial.println("==============="); 269 | Serial.println(""); 270 | } 271 | 272 | //#################################################################################################### 273 | // Show the execution time (optional) 274 | //#################################################################################################### 275 | // WARNING: for UNO/AVR legacy reasons printing text to the screen with the Mega might not work for 276 | // sketch sizes greater than ~70KBytes because 16 bit address pointers are used in some libraries. 277 | 278 | // The Due will work fine with the HX8357_Due library. 279 | 280 | void showTime(uint32_t msTime) { 281 | //tft.setCursor(0, 0); 282 | //tft.setTextFont(1); 283 | //tft.setTextSize(2); 284 | //tft.setTextColor(TFT_WHITE, TFT_BLACK); 285 | //tft.print(F(" JPEG drawn in ")); 286 | //tft.print(msTime); 287 | //tft.println(F(" ms ")); 288 | Serial.print(F(" JPEG drawn in ")); 289 | Serial.print(msTime); 290 | Serial.println(F(" ms ")); 291 | } 292 | 293 | //#################################################################################################### 294 | // Pull a jpeg file off the SD Card and send it as a "C" formatted as an array to the serial port 295 | //#################################################################################################### 296 | // The array can be cut and pasted from the Serial Monitor window into jpegX.h attached to this sketch 297 | void createArray(const char *filename) { 298 | File jpgFile; 299 | uint8_t sdbuffer[32]; // SD read pixel buffer (16 bits per pixel) 300 | 301 | // Check file exists and open it 302 | if ((jpgFile = SD.open(filename)) == NULL) { 303 | Serial.println(F("JPEG file not found")); 304 | return; 305 | } 306 | 307 | uint8_t data; 308 | byte line_len = 0; 309 | 310 | Serial.print("const uint8_t "); 311 | // Make the array the same as the file name with the .(file extension) removed 312 | while (*filename != '.') Serial.print(*filename++); 313 | 314 | Serial.println("[] PROGMEM = {"); // PROGMEM added for AVR processors, it is ignored by Due 315 | // Pull all data falues from file and print in the array format 316 | while (jpgFile.available()) { 317 | data = jpgFile.read(); 318 | Serial.print("0x"); // Add hexadecimal prefix 319 | if (abs(data) < 16) Serial.print("0"); // Add a leading zero to create a neater array 320 | Serial.print(data, HEX); Serial.print(",");// Add value and comma 321 | line_len++; 322 | // Add a newline every 32 bytes 323 | if (line_len >= 32) { 324 | line_len = 0; 325 | Serial.println(); 326 | } 327 | } 328 | Serial.println("};"); 329 | Serial.println(); 330 | // close the file: 331 | jpgFile.close(); 332 | } 333 | 334 | -------------------------------------------------------------------------------- /examples/Other libraries/Mega and Due/TFT_flash_jpg/jpeg2.h: -------------------------------------------------------------------------------- 1 | // We need this header file to use FLASH as storage with PROGMEM directive on the Mega 2 | #include 3 | 4 | // Here is the 320 x 480 jpeg image data 5 | const uint8_t Mouse480[] PROGMEM = { 6 | 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x00,0x48,0x00,0x48,0x00,0x00,0xFF,0xDB,0x00,0x43,0x00,0x28,0x1C,0x1E,0x23,0x1E,0x19,0x28, 7 | 0x23,0x21,0x23,0x2D,0x2B,0x28,0x30,0x3C,0x64,0x41,0x3C,0x37,0x37,0x3C,0x7B,0x58,0x5D,0x49,0x64,0x91,0x80,0x99,0x96,0x8F,0x80,0x8C,0x8A,0xA0,0xB4,0xE6,0xC3,0xA0, 8 | 0xAA,0xDA,0xAD,0x8A,0x8C,0xC8,0xFF,0xCB,0xDA,0xEE,0xF5,0xFF,0xFF,0xFF,0x9B,0xC1,0xFF,0xFF,0xFF,0xFA,0xFF,0xE6,0xFD,0xFF,0xF8,0xFF,0xDB,0x00,0x43,0x01,0x2B,0x2D, 9 | 0x2D,0x3C,0x35,0x3C,0x76,0x41,0x41,0x76,0xF8,0xA5,0x8C,0xA5,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8, 10 | 0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xFF,0xC0, 11 | 0x00,0x11,0x08,0x01,0x40,0x01,0xE0,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xFF,0xC4,0x00,0x1A,0x00,0x00,0x03,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00, 12 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0xFF,0xC4,0x00,0x2D,0x10,0x00,0x02,0x02,0x01,0x04,0x01,0x04,0x02,0x01,0x04,0x03,0x01,0x01,0x00, 13 | 0x00,0x00,0x00,0x01,0x02,0x11,0x21,0x03,0x12,0x31,0x41,0x51,0x04,0x13,0x22,0x61,0x32,0x71,0x81,0x05,0x23,0x42,0x91,0x14,0x33,0x52,0xA1,0xC1,0xFF,0xC4,0x00,0x16, 14 | 0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0xFF,0xC4,0x00,0x16,0x11,0x01,0x01,0x01,0x00,0x00,0x00,0x00, 15 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0xFF,0xDA,0x00,0x0C,0x03,0x01,0x00,0x02,0x11,0x03,0x11,0x00,0x3F,0x00,0xF5,0x1C,0x53,0x0F,0x6E,0x3E, 16 | 0x0C,0x56,0xF8,0x3E,0x6D,0x0E,0x1A,0xCE,0xE9,0xAC,0x04,0x6B,0xED,0xC7,0xC0,0x6C,0x8F,0x80,0x53,0x4F,0xB2,0x94,0x93,0x28,0x36,0xA0,0xDA,0x86,0x00,0x4E,0xD4,0x1B, 17 | 0x51,0x40,0x41,0x3B,0x50,0x6D,0x45,0x01,0x46,0x6E,0x0B,0xC0,0x9E,0x94,0x7C,0x1A,0x00,0x19,0x7B,0x51,0xF0,0x0F,0x4A,0x3E,0x0D,0x44,0xC0,0xE4,0xD5,0xD3,0x5E,0x0B, 18 | 0x86,0x8C,0x6B,0x82,0xA4,0xAE,0x66,0xA9,0x52,0x03,0x35,0xA5,0x15,0xD0,0xFD,0xB5,0xE0,0xB0,0x03,0x3F,0x6E,0x3E,0x07,0xB1,0x78,0x2C,0x00,0x8D,0x88,0x36,0x22,0xC4, 19 | 0x04,0x6D,0x43,0xDA,0x50,0x05,0x4E,0xD4,0x2D,0xA5,0x0D,0xAA,0xA0,0x88,0xA0,0xA2,0x84,0x02,0xA0,0xA1,0x80,0x13,0x41,0x43,0x00,0x15,0x0A,0x8A,0x00,0x26,0x82,0x86, 20 | 0x04,0x0A,0x85,0x45,0x08,0x05,0x41,0x43,0x02,0xAA,0x40,0x64,0x4E,0x6A,0x2B,0xEC,0x88,0x78,0xB0,0xA0,0xD2,0x83,0x75,0x29,0x72,0x37,0xF9,0x34,0x14,0xA8,0x54,0x30, 21 | 0x01,0x50,0x50,0xC0,0x05,0x42,0xA2,0x84,0x04,0xD0,0x51,0x40,0x04,0x50,0x51,0x40,0x06,0x6E,0x09,0xF2,0x85,0xED,0xAF,0x06,0x80,0x06,0x6F,0x4E,0x3E,0x09,0x7A,0x51, 22 | 0x78,0xA3,0x50,0x03,0x9D,0xFA,0x74,0x2F,0xF8,0xEB,0xA3,0xA4,0x40,0x76,0xD2,0x16,0xD8,0xF8,0xC9,0x4A,0x91,0x2E,0x37,0xC0,0x18,0x4E,0xD3,0x23,0x7C,0xD3,0xB4,0xED, 23 | 0x23,0xA9,0x41,0x3E,0x4C,0x67,0x0D,0xAF,0x8E,0x48,0x2B,0x4B,0xD4,0xEE,0xC4,0x95,0x78,0x66,0xCA,0x69,0xE3,0xB3,0x8B,0x63,0x52,0x76,0xB1,0xE4,0xA7,0x27,0xB7,0x1C, 24 | 0xA2,0xA3,0xB6,0xEC,0x67,0x9C,0xBD,0x63,0x8B,0xA9,0x2C,0x9D,0x5A,0x7A,0xF0,0x9F,0x12,0x28,0xDC,0x42,0xBB,0x1D,0x80,0x00,0x9B,0xA5,0x6C,0x87,0x27,0x2E,0x38,0x02, 25 | 0xDC,0x92,0x21,0xEA,0x66,0x92,0x15,0x08,0x95,0x43,0x6C,0x7B,0x9D,0x0A,0xE8,0x4F,0x81,0x43,0xF7,0x1D,0x95,0xBC,0xC4,0x59,0x04,0x74,0x29,0x27,0xD8,0xCE,0x58,0xC9, 26 | 0xDF,0x26,0xB1,0x99,0x46,0xA2,0x12,0x92,0x63,0x08,0x00,0x00,0x04,0x36,0xF8,0x10,0x00,0x08,0x62,0x00,0x00,0x00,0x01,0x0C,0x44,0x00,0x00,0x00,0x08,0x00,0x00,0x43, 27 | 0x10,0x00,0x01,0x8E,0xAE,0xB2,0x87,0xC5,0x65,0x85,0x56,0xA6,0xA6,0xD5,0x4B,0x92,0x74,0xE1,0x72,0xDD,0x2C,0xBF,0x04,0x41,0xA7,0x34,0xEC,0xEB,0x8A,0x49,0x5B,0xE4, 28 | 0x06,0x92,0x8C,0x4C,0x7F,0xC9,0x9A,0xB7,0x83,0x14,0xEE,0x4C,0x0A,0x00,0x00,0x10,0x0C,0x40,0x02,0x18,0x80,0x00,0x00,0x04,0x00,0x00,0x02,0x18,0x80,0x18,0x00,0x80, 29 | 0x00,0x04,0x07,0x75,0x20,0x59,0x04,0xED,0x0F,0x00,0x1C,0x70,0x4C,0x96,0xE4,0x55,0x24,0x26,0x9F,0x28,0x0C,0xE5,0xA6,0xEB,0xCA,0x32,0x70,0xF0,0x8E,0x8D,0xCC,0x55, 30 | 0xD8,0x1E,0x57,0xAB,0xD2,0x92,0x93,0x77,0x83,0x9E,0x3A,0x92,0x8B,0x54,0xCF,0x4B,0xD6,0xC7,0xE2,0xF3,0xFC,0x1E,0x63,0x48,0x0E,0xEF,0x4F,0xEB,0xA9,0xA8,0xCD,0xE0, 31 | 0xED,0x8E,0xB4,0x65,0xC3,0x4C,0xF0,0x92,0xA6,0x7A,0x1F,0xD3,0xA0,0xE5,0x29,0x49,0xDD,0x2E,0x00,0xEE,0x77,0x20,0x45,0xA4,0x14,0x41,0x2F,0x34,0x0C,0xAD,0xA4,0xC8, 32 | 0x28,0xA5,0xE4,0x86,0x36,0x98,0xF6,0x94,0x40,0x9A,0x65,0xD0,0x98,0x19,0xB4,0x1C,0x2B,0x29,0xA2,0x58,0x0E,0x32,0xCF,0xD9,0xB4,0x65,0x7F,0xB3,0x9D,0x70,0x52,0x93, 33 | 0x54,0x11,0xD0,0x04,0xC6,0x5B,0xA3,0x63,0x2A,0x18,0x81,0xB1,0x58,0x0C,0x40,0x0C,0x00,0x04,0x16,0x00,0x00,0x22,0x06,0x02,0xB0,0x00,0x00,0x00,0x01,0x05,0x99,0x6A, 34 | 0xEA,0xEC,0x4B,0xCB,0x01,0x6A,0xEB,0x28,0x61,0x72,0x73,0x76,0xDB,0xE5,0x8B,0x32,0x6D,0xB1,0xD3,0xB0,0xAD,0x74,0x23,0x9A,0xFB,0x3B,0x92,0x4B,0x07,0x36,0x84,0x29, 35 | 0xAF,0xB3,0xA2,0x4B,0x20,0x4D,0x72,0x66,0xF1,0x2A,0x46,0x92,0x7B,0x51,0x8B,0x95,0x48,0x0B,0x01,0x2C,0x8C,0x00,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x10,0x00,0x00, 36 | 0x80,0x00,0x00,0x43,0x10,0x00,0x80,0x00,0xED,0x4D,0x15,0x48,0x84,0x87,0xD9,0x06,0x8A,0x38,0x0A,0x27,0xAE,0x41,0x37,0xE6,0xC0,0x25,0x15,0x44,0xA6,0x93,0xA6,0x52, 37 | 0x97,0x94,0x27,0x4D,0x94,0x73,0xFA,0xBD,0x25,0x3D,0x37,0x2E,0xD1,0xE4,0xCA,0x3D,0x1E,0xE4,0xB3,0x06,0x8F,0x23,0x5A,0x29,0x37,0x92,0x0C,0x29,0xA7,0x83,0xD6,0xFE, 38 | 0x9D,0x9F,0x4C,0xBC,0xDE,0x4F,0x2A,0xCF,0x5F,0xFA,0x6D,0x3F,0x4D,0xF7,0x60,0x74,0xED,0x0A,0x2E,0x80,0xA2,0x1A,0x15,0x17,0x42,0x02,0x76,0xD7,0x24,0xB7,0xE0,0xA7, 39 | 0xF6,0x4F,0x2C,0x2A,0x68,0x1C,0x4A,0xE0,0x60,0x66,0xE2,0x44,0x91,0xB5,0x64,0x1C,0x40,0xE6,0xAB,0x07,0x68,0xD6,0x71,0xF0,0x67,0xF4,0xC0,0x4A,0x7E,0xDC,0xED,0xF0, 40 | 0xCD,0x94,0xE2,0xF8,0x66,0x0D,0x6E,0x8B,0x46,0x16,0xD4,0x6D,0x74,0x11,0xDE,0xD8,0xB7,0x5A,0xC1,0xC0,0xBD,0x54,0x96,0x03,0xFE,0x56,0x79,0xA2,0xA3,0xB9,0x4F,0xC8, 41 | 0xEC,0xE0,0x97,0xA8,0x69,0xD5,0x94,0xBD,0x4D,0x45,0xAE,0x48,0x3B,0x6C,0x56,0x71,0xC3,0xD4,0xDA,0xA9,0x3F,0xD3,0x0F,0xF9,0x29,0x3D,0xAD,0xE4,0x2B,0xB3,0x76,0x01, 42 | 0xBC,0x2A,0x39,0x23,0xEA,0x55,0xF3,0xC8,0x2F,0x50,0x93,0x69,0xBE,0xC2,0x3A,0xAF,0x16,0x0A,0x47,0x2C,0xB5,0xF6,0xB6,0x9B,0xC3,0xCA,0x2E,0x1A,0xA9,0xA6,0xEF,0x00, 43 | 0x6E,0xE5,0xF2,0x25,0xCF,0x2E,0x8C,0x5E,0xA2,0x73,0xE4,0x70,0x92,0xDC,0xEF,0xA0,0xAB,0x94,0xF6,0xA7,0x67,0x24,0xE4,0xE7,0x2B,0x67,0x44,0x96,0xF9,0x5F,0x46,0x7E, 44 | 0xDD,0x26,0xFA,0x02,0x62,0x8B,0xAC,0xA1,0xC6,0x1F,0x1B,0x08,0xAC,0xA0,0xAE,0x8D,0x04,0xD4,0x95,0x96,0xDE,0x4C,0xE2,0xF6,0xCE,0xBE,0x8B,0x5C,0x84,0x12,0xCA,0x31, 45 | 0x94,0x5F,0xF0,0x6F,0x2C,0xA2,0x1B,0x5B,0x1A,0x7C,0x81,0x31,0x78,0x28,0xCE,0x0B,0x34,0x5A,0x00,0x00,0x00,0x01,0x00,0x00,0x08,0x18,0x00,0x00,0x08,0x21,0x88,0x02, 46 | 0xC2,0x90,0x00,0x00,0x08,0x62,0x03,0xB2,0xCA,0x54,0xD1,0x12,0x8F,0xD5,0x02,0xAB,0xC9,0x15,0x6E,0x2E,0xB0,0x24,0xF2,0x35,0x2F,0x03,0xDC,0xBB,0x08,0x3F,0x92,0x5A, 47 | 0xF0,0x39,0x46,0x2F,0x29,0x91,0xB5,0xD5,0xA0,0x14,0xA4,0xD7,0x47,0x9F,0xEA,0xE3,0x4E,0xEB,0x93,0xD1,0x4D,0x3F,0xD9,0x8F,0xA9,0xD3,0x8C,0xA1,0x6D,0x64,0x0F,0x1D, 48 | 0xDD,0x9E,0xB7,0xF4,0xA7,0xFD,0xA9,0x23,0xCC,0x94,0x29,0xB3,0xBF,0xFA,0x5E,0xED,0xF2,0x5D,0x50,0xC1,0xE9,0xA0,0x62,0x19,0x42,0x64,0xB6,0x53,0x78,0x33,0xB0,0x09, 49 | 0x3A,0x64,0xB6,0x0C,0x9E,0x58,0x55,0x2C,0x94,0x90,0xA2,0x8B,0xE0,0x06,0x90,0x3A,0x16,0x58,0x6D,0x08,0x89,0x24,0xCC,0xA7,0x0A,0xC9,0xBB,0x89,0x12,0x88,0x1C,0xEB, 50 | 0x12,0x33,0xDB,0x53,0x94,0x1F,0x0C,0xD6,0x52,0x7C,0x51,0x13,0xAF,0x76,0x32,0xBE,0x79,0x03,0x97,0x5F,0x45,0xC7,0x55,0x7F,0xE5,0x9C,0xCF,0xF3,0x3D,0x5D,0x48,0x39, 51 | 0x45,0xAE,0xD1,0xC9,0xAB,0xA5,0xB6,0x9A,0xEF,0x20,0x63,0x94,0x91,0x15,0x2E,0x99,0xD3,0xB7,0x14,0x64,0xB9,0xC9,0x06,0x5F,0x24,0x6B,0x28,0xA9,0xC1,0x79,0x2B,0x6A, 52 | 0xD8,0xEB,0x94,0x52,0x8A,0x6A,0xD2,0x0A,0xC5,0xC1,0xC4,0x36,0xBB,0x5F,0x66,0xB2,0xCC,0x7E,0xEC,0x22,0x96,0xCF,0xB4,0xC5,0x12,0xE2,0xE4,0xA3,0xF4,0x5E,0x96,0x11, 53 | 0x7A,0x7C,0xD0,0x9C,0x76,0xCB,0x1E,0x42,0x27,0xCC,0x91,0x50,0x79,0x4F,0xC9,0x51,0x57,0x64,0xD5,0x45,0x57,0x90,0x37,0x8D,0xA6,0xCA,0x9A,0x6F,0x01,0x08,0xFC,0x53, 54 | 0x65,0xC7,0xE4,0x9C,0x97,0x9A,0x03,0x35,0x07,0x57,0xD0,0x25,0xD9,0xB4,0x60,0xDC,0xAA,0xB0,0x5C,0xA2,0x9A,0x49,0x2E,0x0A,0x31,0x93,0xA9,0x45,0xF9,0x29,0x26,0xF2, 55 | 0xB8,0x23,0x51,0x56,0xA2,0x5E,0x0B,0x4E,0x98,0x0D,0xE4,0x4E,0xE8,0xA6,0xAF,0x22,0x7F,0x88,0x18,0xB4,0xD6,0x4A,0x8C,0x93,0xC1,0x4D,0x6E,0x8B,0x30,0xFC,0x65,0x68, 56 | 0x0D,0xC4,0x0B,0x80,0x00,0x62,0x18,0x9B,0x00,0x00,0x00,0x01,0x00,0x00,0x31,0x0C,0x00,0x40,0x00,0x00,0x20,0x02,0x23,0xD2,0x69,0x32,0x76,0x2F,0x03,0x6C,0x96,0xD9, 57 | 0x15,0x2E,0x0D,0x66,0x2C,0x94,0xF3,0xF2,0x43,0x94,0x9F,0x81,0x29,0x4A,0x58,0x28,0xBD,0xA9,0xAC,0x31,0x53,0x8F,0x41,0x95,0xD0,0x7B,0x8B,0x89,0x00,0x52,0x64,0x6A, 58 | 0x41,0x4A,0x34,0x68,0xDC,0x64,0xB9,0x21,0x7C,0x70,0xF2,0x80,0xF3,0xFD,0x4E,0x96,0xCF,0xB5,0xD1,0x9F,0xA5,0xD6,0x7A,0x3A,0xE9,0xF4,0xF0,0xCF,0x47,0x5F,0x4A,0x3A, 59 | 0x91,0x6E,0x2F,0x3E,0x0F,0x2A,0x71,0x71,0x95,0x35,0x41,0x5E,0xEC,0x64,0x9A,0xB4,0x07,0x1F,0xA2,0xD5,0xDD,0xA4,0x97,0x68,0xEA,0x52,0x2A,0x06,0x27,0x81,0xDD,0xA2, 60 | 0x64,0x04,0x31,0xC5,0x0B,0xB2,0xD6,0x08,0xAA,0xBA,0x0E,0x58,0x24,0x52,0x45,0x02,0x45,0x36,0x90,0x89,0x93,0x08,0xAD,0xC9,0x99,0xC9,0x61,0x92,0xD8,0xB7,0x01,0x0D, 61 | 0x59,0x96,0xA2,0x5B,0xE2,0x6C,0xF0,0xAC,0x87,0x15,0x27,0x9E,0x42,0xB7,0xC2,0x69,0xF9,0x47,0x36,0xB4,0x2D,0xFE,0x8D,0xEF,0x15,0xE0,0x8E,0x48,0x8E,0x6D,0x48,0xA5, 62 | 0xA4,0xA5,0x46,0x1B,0x6D,0x33,0xAF,0x5D,0x7C,0x2B,0xA3,0x08,0x46,0xD9,0x06,0x1A,0x79,0x95,0x32,0xE2,0xF6,0x39,0x04,0x63,0x49,0xBF,0xB1,0x4B,0xF1,0x6C,0x29,0xC3, 63 | 0xE5,0x3C,0xF9,0x2B,0x51,0x6D,0x9B,0xA1,0x45,0x2C,0x3F,0x24,0x4D,0xB7,0xA8,0xC0,0xD2,0x0D,0x47,0x52,0xFA,0x68,0xAE,0x24,0x61,0x06,0xDC,0xAB,0xC1,0xAC,0xDB,0x4D, 64 | 0x34,0x11,0xA2,0x4F,0x76,0x3B,0x44,0x47,0xF1,0x6B,0xEC,0xAD,0x29,0x25,0x2B,0x64,0x39,0x53,0x6D,0x79,0x28,0xDF,0x77,0xC5,0x2F,0x05,0xE9,0x4B,0xFB,0x34,0xBC,0x9C, 65 | 0x91,0x9D,0x4F,0xF6,0x5E,0x8E,0xA6,0xD5,0x40,0x77,0x69,0xEA,0x5C,0x5B,0x45,0xA6,0x94,0x5F,0x9E,0x8C,0x74,0x12,0xF6,0x82,0x73,0x69,0xAA,0xE8,0xA0,0x9C,0x38,0xF2, 66 | 0x15,0x48,0xB8,0xFC,0x92,0xF2,0x4B,0xE4,0x0D,0x21,0x98,0x13,0x24,0xA8,0x51,0x9D,0x2D,0xA3,0xE8,0x0C,0x64,0xE9,0xFD,0x13,0x08,0xEE,0x7B,0x8B,0xD4,0xFC,0x78,0xC8, 67 | 0xA0,0xB0,0x03,0x01,0x89,0x80,0x98,0x50,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x40,0x0C,0x00,0x00,0x40,0x00,0x00,0x07,0xA0,0xFF,0x00,0x44,0xB0,0x72,0x5D,0x48,0x8B, 68 | 0x7F,0xB3,0x2A,0x76,0xD0,0xB0,0x4D,0xBE,0x19,0x6A,0x36,0x03,0x4E,0x49,0x60,0x96,0xEF,0x12,0x89,0x4D,0x38,0xFD,0x90,0xE7,0xD3,0x8B,0xB0,0x22,0x51,0xA7,0xF1,0x6C, 69 | 0xB8,0xB7,0xD8,0x26,0x9F,0xEC,0xA4,0xDD,0xD3,0x28,0xAA,0x8C,0x91,0xCB,0xEA,0xFD,0x35,0xAD,0xC8,0xEA,0xDB,0xE0,0x74,0x9A,0xA6,0x07,0x97,0xE9,0xA7,0xED,0x6A,0xD4, 70 | 0xB8,0x67,0xA4,0x96,0x4E,0x2F,0x55,0xA5,0xED,0xCA,0xD7,0x07,0x57,0xA7,0x9F,0xB9,0xA2,0xBB,0x6B,0x03,0x05,0xF0,0x26,0x53,0xA3,0x36,0xEC,0xA8,0x9C,0xD9,0x51,0x64, 71 | 0x8E,0x3C,0x91,0x5B,0x22,0xA8,0x51,0x28,0xA8,0x4C,0x96,0x8B,0x64,0xBE,0x00,0xC6,0x58,0xC0,0xA3,0xC9,0x53,0x56,0x8C,0xE3,0x2F,0x8B,0x4F,0x94,0x45,0x1A,0xB7,0x17, 72 | 0x5D,0x13,0xAA,0xEE,0x71,0xDB,0xDA,0x34,0xD4,0xF9,0xE8,0xEE,0xED,0x1C,0xD1,0xBD,0xF1,0xCF,0xE2,0x06,0xFA,0x6F,0x73,0x65,0x6D,0xA9,0x21,0x2F,0xFB,0x64,0xBC,0xA2, 73 | 0x95,0xE2,0xC2,0x32,0xD5,0x54,0xD5,0x9C,0xEA,0x2A,0x13,0x6A,0xFB,0x3A,0x75,0x1D,0xB3,0x29,0xAB,0xC8,0x10,0xA2,0xAD,0xA3,0x09,0xD4,0x62,0xCD,0xF5,0x25,0xB6,0x49, 74 | 0x99,0xC9,0xA9,0x26,0xAB,0x92,0x2A,0x34,0x7E,0x4B,0xF9,0xC0,0x35,0xFD,0xD6,0x3D,0x15,0xB6,0x71,0x6C,0xD1,0xAF,0xEE,0xDF,0x49,0x81,0x86,0xDA,0xB9,0x22,0xA7,0x6E, 75 | 0x2D,0x84,0xDD,0x6A,0x4A,0x3D,0x32,0xE2,0xAD,0xFD,0x50,0x46,0x37,0xB7,0x81,0xDF,0xC5,0x9A,0xCF,0x4D,0x29,0xA6,0xB8,0x32,0x9E,0x21,0x7E,0x58,0x52,0x8E,0x35,0x17, 76 | 0x84,0x3D,0xD9,0x6D,0x19,0x3F,0xC9,0xBB,0xE4,0xB8,0xAC,0x67,0xA2,0xA3,0xD0,0xD1,0x95,0xD4,0x45,0x3B,0x94,0xE9,0x3E,0xCC,0xBD,0x26,0xA7,0xCE,0x72,0x7D,0x23,0x6D, 77 | 0x27,0x72,0x7F,0xEC,0x0D,0xBF,0x15,0x44,0x59,0x0E,0x52,0x94,0xA9,0x14,0xA0,0xDF,0x2C,0x01,0xBF,0x92,0x65,0x6E,0x44,0xED,0x06,0x97,0x05,0x11,0x36,0xDB,0x6C,0x70, 78 | 0xCC,0x42,0x6B,0x09,0x0D,0x61,0x00,0x0B,0xB0,0x6C,0x02,0x18,0x86,0x4B,0x0A,0x00,0x3A,0x00,0x00,0x01,0x00,0xC4,0x00,0x00,0x21,0x88,0x00,0x43,0x11,0x07,0x6E,0xD4, 79 | 0xF3,0x63,0xA4,0xBF,0xC5,0x02,0xA1,0xD2,0xE8,0x8A,0x96,0xA3,0xE0,0xAA,0x55,0x86,0x52,0x42,0x71,0xFA,0x02,0x5B,0xF2,0x85,0xCE,0x47,0x4F,0xA2,0x5A,0x7D,0x80,0x35, 80 | 0x91,0xA7,0x4B,0x28,0x55,0x2F,0xE0,0xA4,0xAC,0x0A,0x8C,0x93,0xE0,0x62,0x51,0x5F,0xC9,0x40,0x65,0xAB,0x1D,0xF0,0x71,0x6A,0xCE,0x4D,0x3D,0xDA,0x13,0xAB,0xA4,0xCE, 81 | 0xEF,0xD1,0x32,0x82,0x92,0xA9,0x20,0x21,0xCD,0x32,0x45,0x28,0x3D,0x39,0x57,0x43,0x59,0x28,0x4C,0xA8,0xF2,0x15,0x80,0xE0,0x0D,0x62,0xCA,0xDC,0x64,0x99,0x59,0x28, 82 | 0xBB,0xB4,0x2B,0x11,0x16,0xD0,0x04,0x97,0x83,0x27,0xF9,0x3C,0x7E,0xCA,0x94,0x97,0x4C,0x95,0x6E,0x79,0xE0,0x81,0x45,0xD4,0x66,0xBA,0x1C,0x20,0x9D,0xB1,0xED,0x6D, 83 | 0x51,0x5A,0x69,0xA5,0x4C,0x80,0x8C,0x7E,0x69,0xF7,0x54,0x5B,0x56,0x90,0xEA,0xB2,0x46,0xEC,0xC9,0x78,0x2A,0x33,0x79,0x4F,0xCA,0x33,0xD4,0x74,0xB8,0xE8,0xD7,0x51, 84 | 0xA4,0xAD,0x2E,0x4C,0xD2,0xDC,0xB2,0x06,0x13,0x5B,0xA2,0x9A,0xF2,0x4C,0x63,0xF2,0xA3,0x6D,0x28,0xB5,0x19,0x45,0xF9,0xC0,0xE5,0x1A,0xD4,0xBA,0x0A,0x89,0x2A,0x84, 85 | 0xBF,0xD9,0x9A,0x96,0x2D,0x9A,0xCF,0xB5,0xD5,0x11,0x28,0x3D,0x88,0x0C,0x75,0x15,0xCA,0xFA,0x2F,0x46,0x5F,0xDB,0xB7,0xCA,0x09,0xAF,0xED,0x2F,0x36,0x65,0x95,0xC0, 86 | 0x46,0xCE,0x76,0xA2,0xFE,0xCC,0xB5,0x9F,0x09,0x79,0xB1,0x4B,0x08,0x13,0xDF,0x40,0x65,0x24,0xFA,0x34,0x6F,0xFF,0x00,0xA5,0x6C,0xB8,0x5A,0xE4,0x49,0x79,0x59,0x02, 87 | 0xB4,0xDE,0xCD,0x29,0x6D,0x7C,0xF2,0x75,0x68,0xC9,0x41,0x26,0xB3,0x83,0x95,0xAA,0xAB,0x5C,0x95,0x19,0xD3,0x51,0xBE,0xC0,0xED,0xD3,0xAB,0x6D,0x8E,0x4E,0xF8,0x66, 88 | 0x49,0xDC,0x13,0x5C,0x14,0x9A,0xAA,0x02,0xE2,0xAA,0x37,0x62,0x8A,0xB7,0x64,0xFC,0xBF,0x81,0xAC,0x70,0x50,0x49,0xDB,0x10,0x30,0x00,0x00,0x00,0x06,0x20,0x06,0x00, 89 | 0x02,0x00,0x80,0x43,0x10,0x50,0x00,0x00,0x01,0x60,0x20,0x0B,0x00,0x00,0x3D,0x04,0xFC,0x89,0xCE,0x3E,0x47,0x81,0x38,0xA7,0xD1,0x95,0x25,0x3F,0x00,0xE7,0x4F,0x22, 90 | 0xA8,0xF1,0x92,0x94,0x7F,0x90,0x17,0xB8,0x85,0xEE,0x45,0xF9,0x1C,0xA0,0xBC,0x12,0xAD,0x01,0x56,0x9F,0x19,0x1A,0xE7,0xC0,0xA3,0xFC,0x1A,0xAA,0x68,0x09,0xAB,0x0C, 91 | 0x8D,0xAF,0x03,0x45,0x42,0xC1,0x2C,0xBA,0x26,0x49,0x90,0x29,0x43,0x74,0x29,0x98,0x27,0x52,0xDA,0xCE,0x98,0xB2,0x35,0x34,0x63,0x27,0xB9,0x62,0x45,0x10,0xC8,0x63, 92 | 0x76,0xB0,0xC9,0x65,0x55,0xE9,0xF2,0x6B,0x76,0x61,0xA6,0x6B,0xF8,0xAC,0x01,0x4F,0x83,0x39,0xB6,0xBA,0x2E,0x32,0xB1,0xCA,0xB6,0xE4,0x83,0x96,0x76,0xE4,0xBC,0x33, 93 | 0x55,0x1F,0xED,0xC4,0xCA,0x32,0xAD,0x46,0x9F,0xE2,0xCD,0xE3,0xF8,0xA4,0x40,0xA2,0xBF,0xD9,0x4D,0x66,0xC4,0xD0,0x5E,0x4A,0x81,0xBC,0x5F,0x46,0x13,0x4E,0x33,0xDD, 94 | 0x78,0xB3,0x6D,0x46,0xD2,0xC7,0x01,0x08,0xA9,0x46,0x98,0x11,0xB7,0xFD,0x33,0x37,0x1C,0xFD,0xA3,0x57,0xBB,0x4D,0xBA,0xCA,0x1A,0xA7,0x94,0x07,0x3C,0x5B,0x72,0x6F, 95 | 0xC3,0x36,0x94,0x70,0x13,0x8A,0xAB,0x5D,0x96,0x93,0x94,0x62,0x07,0x36,0xA7,0xE0,0xBC,0x8A,0x51,0x7F,0x04,0x8D,0x35,0x57,0x0B,0xC3,0x0D,0x5B,0x5B,0x64,0x80,0xE5, 96 | 0x92,0xDA,0xB3,0xE4,0x4E,0x26,0xDA,0xD1,0xF8,0xA7,0xF6,0x4A,0x56,0xDF,0xD0,0x18,0xC6,0x36,0xDA,0x97,0x44,0x28,0xB7,0xA9,0x4B,0x18,0x36,0x7F,0x19,0xBB,0xEC,0x99, 97 | 0x2A,0x92,0x97,0xD0,0x52,0x83,0xA8,0xAF,0xA6,0x6B,0xA9,0x15,0x1A,0xC2,0xC9,0x8C,0x63,0x4C,0xE9,0x92,0x52,0x71,0x97,0x4D,0x04,0x65,0x3D,0x34,0xE9,0x98,0x6A,0x46, 98 | 0xA7,0x6B,0x84,0x75,0x24,0xD2,0xC9,0x1A,0x99,0x5B,0x50,0x17,0x09,0x45,0x68,0xC6,0x29,0x8E,0x0F,0x34,0x61,0x0C,0x4B,0x26,0xB0,0x69,0x20,0x3A,0x2D,0x25,0x44,0x8A, 99 | 0x39,0x19,0x40,0x08,0x00,0x00,0x41,0x76,0x00,0x00,0x30,0x01,0x08,0x60,0x02,0x13,0x1B,0x15,0x80,0x86,0x09,0x58,0xC0,0x40,0x00,0x40,0x80,0x62,0x03,0xD0,0xDB,0x8C, 100 | 0x12,0xD4,0x8B,0xA6,0x26,0x45,0x42,0x8B,0x5C,0x95,0x42,0x71,0x7E,0x43,0x2B,0xB0,0x2A,0xD1,0x33,0xDA,0xC7,0x61,0xF1,0x6B,0x90,0x22,0x2C,0xD6,0x35,0xE4,0xCE,0xDA, 101 | 0xC2,0x2A,0x36,0x06,0x80,0xC4,0xAC,0x69,0xB2,0xA2,0x5C,0xAB,0x92,0x65,0x3A,0x2D,0xD3,0xE8,0x9D,0xAA,0xEA,0x8A,0x26,0x33,0xB2,0x9A,0x6D,0x09,0xE8,0xAF,0xF1,0xC1, 102 | 0x1E,0xD6,0xA7,0xFE,0x88,0x1C,0xA2,0xFB,0x44,0x34,0x94,0x5B,0x2B,0xDB,0xD5,0x5D,0xD8,0xDC,0x24,0xE3,0x4D,0x14,0x4E,0x83,0xDD,0x0B,0x7E,0x4B,0xD4,0x58,0x4C,0x9D, 103 | 0x38,0xEC,0x54,0x53,0x56,0x80,0x22,0x93,0xC6,0xEC,0x8D,0xAA,0x12,0xC7,0x28,0x6E,0x48,0x8A,0x97,0x14,0xD6,0x57,0xF2,0x4A,0x83,0x8B,0x4D,0x32,0xDB,0xB4,0x25,0x10, 104 | 0x86,0xEC,0x87,0x69,0xE5,0x1A,0x3C,0xA6,0x99,0x09,0xDA,0x69,0x80,0xDD,0x35,0xC8,0x28,0xDA,0xC1,0x51,0x8C,0x64,0xAC,0xCB,0x5B,0x56,0x3A,0x4B,0xEC,0x0A,0xC4,0x6D, 105 | 0x49,0x91,0xBA,0x0A,0x5C,0xAA,0x67,0x9D,0xAF,0xEA,0x67,0x39,0x37,0x74,0x8C,0x3D,0xF9,0xF4,0xCA,0x3D,0x89,0x3D,0xBC,0x65,0x0F,0x7A,0x8E,0x9D,0x9E,0x66,0x9F,0xAC, 106 | 0x96,0x14,0x8E,0xD8,0xA5,0x34,0x9D,0xE1,0x81,0xA6,0x9A,0x73,0x4D,0xB0,0x97,0xCB,0x4D,0x7D,0x17,0x0C,0x45,0x89,0xD4,0x53,0x4F,0x86,0x06,0x7A,0x91,0xDD,0xA6,0x97, 107 | 0xD9,0x94,0x3E,0x12,0xD4,0xDC,0x8D,0x77,0x67,0x1E,0x49,0x94,0x1B,0x9B,0x7E,0x50,0x18,0x4E,0x2D,0xBB,0x26,0x71,0x6D,0x2A,0xE8,0xE8,0x8C,0x6D,0x2B,0x7D,0x10,0xBA, 108 | 0x44,0x54,0x46,0x34,0xD3,0x35,0x4D,0x7B,0x69,0x98,0xC7,0x30,0x92,0xFB,0xC1,0x49,0xFC,0x33,0xD0,0x46,0xB8,0xF6,0xDD,0xF2,0x73,0xA6,0x92,0xB9,0x1B,0xB7,0x95,0x4A, 109 | 0xF0,0x73,0x7A,0x9B,0x8F,0xA7,0x8C,0x97,0x92,0x89,0xD4,0x92,0xDC,0x9A,0x2E,0x2F,0x28,0xE5,0x86,0xB4,0x52,0xA9,0x23,0xA2,0x32,0x54,0x9C,0x73,0xF6,0x41,0xD4,0xA4, 110 | 0x92,0xFB,0x05,0xE4,0x88,0x2F,0x8A,0xB3,0x4E,0x8A,0x04,0x30,0xE8,0x12,0xEC,0x01,0x00,0x00,0x00,0x00,0x00,0x81,0xB1,0x37,0xE0,0x55,0xE4,0x05,0x96,0x3A,0x1F,0x00, 111 | 0x00,0x00,0x00,0x20,0x00,0x60,0x20,0x00,0x20,0xF4,0x89,0xAA,0xE4,0xA2,0x26,0xAD,0x72,0x45,0x27,0x37,0xD0,0x26,0xDF,0x44,0xA5,0x42,0x94,0xDA,0x5F,0x10,0x2D,0x90, 112 | 0xB7,0x37,0x84,0x2F,0x93,0xE4,0x29,0xAE,0xC0,0xB5,0x17,0xD9,0xA2,0x54,0x66,0x9B,0xF2,0x8A,0x52,0xF2,0x06,0x9C,0xA1,0x6D,0xA0,0x4C,0x76,0x54,0x21,0x76,0x3B,0x44, 113 | 0xDA,0x6C,0x0D,0x00,0x43,0x00,0x01,0x58,0x37,0x48,0xA2,0x65,0xF4,0x0B,0xEC,0x96,0xC9,0xDD,0xF6,0x40,0xF5,0x1D,0x70,0xE8,0x8D,0xD7,0xCA,0x26,0x6D,0xBE,0x82,0x2D, 114 | 0xB5,0x94,0x06,0x91,0xA2,0x99,0x92,0x61,0x29,0xD5,0x58,0x1A,0x73,0xC8,0xD4,0x48,0x86,0x4D,0x15,0x81,0x3A,0x92,0x5A,0x50,0x6C,0xF2,0xB5,0xF5,0xAE,0x57,0x23,0xB7, 115 | 0xD7,0x4E,0x94,0x57,0xF2,0x78,0xFA,0xFF,0x00,0x9F,0xEC,0xA2,0x67,0x2D,0xCF,0x1C,0x0B,0x80,0x82,0x6E,0x47,0x64,0xFD,0x14,0xD7,0xA7,0x5A,0xB5,0x6B,0xC0,0x1C,0x88, 116 | 0xF4,0x7D,0x0E,0xAE,0xE8,0xAD,0x37,0xE4,0xE0,0x8C,0x1B,0x6D,0x9D,0x5E,0x85,0x57,0xA8,0x8A,0xE8,0x0F,0x49,0x76,0x82,0x5F,0x21,0x3C,0xB6,0x82,0x1C,0xA4,0xC0,0x9A, 117 | 0x58,0x97,0x87,0x93,0x49,0xC7,0x6C,0xBE,0x99,0x35,0x4D,0xA4,0x5C,0x9D,0xA5,0x7C,0xA0,0x31,0x6A,0xAE,0xBA,0x32,0x71,0xDA,0xD3,0xE8,0xE8,0x69,0x6F,0x68,0x89,0x47, 118 | 0x04,0x1C,0xDA,0x4A,0xE5,0x20,0x7F,0x95,0x51,0xA4,0xA3,0xED,0xCA,0xD1,0x33,0xAD,0xD6,0x80,0xBB,0xA7,0x5F,0x46,0x1E,0xAB,0xE5,0xA0,0xEB,0xA3,0x65,0x15,0x4F,0xCB, 119 | 0x46,0x7B,0x37,0xDC,0x6C,0xA3,0xCA,0x78,0x35,0xF4,0xFA,0xCF,0x4E,0x75,0x8D,0xAF,0x92,0x35,0x23,0xB6,0x6D,0x7D,0x91,0x15,0x72,0x40,0x7B,0x30,0x76,0xAC,0xB5,0xC1, 120 | 0x96,0x93,0xFE,0xDA,0xC9,0x7B,0x97,0x0A,0xC0,0xAE,0x59,0x44,0xA6,0xEB,0x81,0x80,0x00,0x09,0xBA,0x01,0xB6,0x4D,0xDF,0x00,0x93,0x79,0x60,0x00,0x92,0x43,0x62,0x0B, 121 | 0x00,0x01,0x00,0x00,0x00,0x10,0x02,0x00,0xB0,0x00,0x10,0x01,0xE9,0xDA,0x22,0x72,0x4F,0x08,0xBC,0x22,0x25,0x44,0x54,0xA8,0x5F,0x25,0x46,0x15,0xC5,0x09,0x6D,0x43, 122 | 0xB2,0x01,0xDF,0x74,0x65,0x24,0xDC,0x8D,0x39,0x63,0xB4,0x97,0x45,0x10,0xA1,0xF6,0x52,0x8E,0x44,0xDB,0xE8,0x9A,0x93,0x7D,0x81,0xBA,0x03,0x35,0x16,0xB8,0xB2,0x92, 123 | 0x7D,0x95,0x0D,0xD1,0x2B,0x0C,0x1D,0x76,0x4A,0xAE,0x80,0xD6,0xC1,0xC9,0x24,0x4A,0xB0,0xA7,0xDA,0x01,0xB9,0x91,0x26,0xD8,0xF0,0x17,0x10,0x33,0xB6,0xB9,0x44,0x49, 124 | 0xAF,0x0C,0xD5,0xCF,0x1C,0x19,0xEF,0x4D,0xD3,0x40,0x34,0xD0,0x3C,0x0B,0xDB,0x4F,0x86,0xC7,0x4D,0x20,0x04,0xAF,0x82,0x96,0x55,0x49,0x0A,0x2E,0x8B,0x52,0x4D,0x74, 125 | 0xC0,0x95,0x1D,0xB9,0x8B,0xFE,0x0A,0x8E,0xB4,0x5E,0x1A,0xC9,0x9C,0xDA,0x4A,0xED,0xA3,0x38,0xCA,0xDE,0x7E,0x5F,0x60,0x65,0xFD,0x42,0x7F,0x28,0x9E,0x66,0xAE,0x5A, 126 | 0x3D,0x3F,0x57,0xA7,0xB9,0x27,0xD1,0xE6,0xEA,0x45,0xDF,0x0C,0xA2,0x60,0xE9,0xDF,0x67,0xA6,0xFD,0x6A,0x9F,0xA6,0x5A,0x49,0x5B,0x6A,0x9B,0x3C,0xA5,0x77,0xC1,0xD1, 127 | 0xA7,0xA5,0xA9,0x37,0x85,0x4B,0xC8,0x1D,0xDE,0x97,0xD1,0x2D,0x4D,0x37,0x29,0x3A,0xBE,0x0C,0x34,0x22,0xE1,0xAF,0x4B,0xA7,0x47,0x7E,0x8E,0xA3,0x86,0x8A,0x82,0x56, 128 | 0xD7,0x66,0x50,0xD3,0xA6,0xDB,0x59,0x60,0x6A,0xB3,0x25,0xFF,0x00,0xD0,0x96,0x33,0x10,0xDB,0x8B,0xEC,0x96,0x9C,0xA3,0x71,0x20,0x51,0x6D,0xB7,0xE5,0x96,0x9E,0x32, 129 | 0x65,0x19,0x2F,0x72,0x3D,0x79,0x2D,0xF3,0x2A,0xCD,0x14,0x38,0xBB,0x9E,0x4A,0x9A,0xCD,0x19,0xE9,0xBF,0x8D,0xB3,0x58,0xBD,0xCD,0x81,0x84,0xD2,0xDC,0xEF,0x8A,0x25, 130 | 0xC1,0x3D,0xB5,0xC1,0x73,0x8B,0xDC,0xDB,0x78,0x08,0x2F,0x92,0x88,0x13,0x2F,0xCA,0xBF,0xD1,0x0D,0x6D,0x78,0x35,0xE7,0x5A,0xBA,0xA2,0x1D,0x54,0xD0,0x1E,0x67,0xAB, 131 | 0x8D,0x6A,0x36,0xBB,0x64,0x68,0xC7,0x37,0xDF,0x07,0x66,0xBC,0x14,0x9B,0x75,0x83,0x28,0xC1,0x42,0x9A,0x03,0xA7,0x4F,0x0E,0xBC,0x23,0x68,0xA3,0x9E,0x12,0xF9,0x1D, 132 | 0x29,0xDA,0xE8,0x06,0x02,0xB5,0xE4,0x87,0x26,0xDD,0x20,0x2D,0xB1,0x25,0x9B,0x60,0xB0,0x0D,0x80,0xDB,0x26,0xC2,0xC0,0x00,0x04,0xE5,0x42,0x72,0x02,0x85,0x64,0x0E, 133 | 0xC0,0xAB,0x0E,0x45,0x63,0xB0,0x0A,0x0A,0x15,0x8E,0xC8,0x01,0x00,0x58,0x1E,0x94,0xA9,0x10,0xFF,0x00,0x46,0x8C,0x97,0x82,0x2A,0x36,0xBB,0x2B,0x6B,0x0B,0x25,0xDB, 134 | 0x20,0x6D,0xA8,0xF2,0xD1,0x0E,0x71,0xF0,0x0F,0x4F,0x36,0xC1,0x45,0x22,0x85,0xBD,0x78,0x1A,0xD5,0x4D,0xF2,0x91,0x2E,0x36,0xEA,0xCA,0x8E,0x92,0x02,0xD4,0xE3,0xE5, 135 | 0x87,0xBB,0xE0,0x14,0x12,0x0A,0x4B,0xC0,0x19,0xCB,0x55,0xDB,0xC0,0x46,0x79,0xE0,0x72,0x8A,0x7C,0x22,0x76,0x53,0x2A,0x36,0x53,0xAE,0x8A,0x53,0xBE,0x51,0x94,0x62, 136 | 0xFB,0x34,0x6A,0xCA,0x1B,0x7F,0x44,0xB6,0xAF,0x82,0x5A,0x97,0x93,0x39,0x39,0x27,0x96,0x41,0xAA,0x57,0xD0,0x9A,0x5E,0x0C,0x96,0xAC,0x97,0x56,0x0F,0x5B,0x20,0x6A, 137 | 0x92,0x5D,0x83,0xA7,0x8B,0x32,0x5A,0x89,0x94,0x9D,0xF0,0x80,0x6D,0x12,0xEF,0xAA,0x09,0xBC,0x70,0x63,0x57,0x2E,0x40,0xAF,0x9B,0xB4,0xD5,0xA3,0x48,0x61,0x13,0x1B, 138 | 0x8F,0x56,0x56,0xE5,0x2E,0xA9,0x91,0x4E,0x71,0x52,0x8D,0x1C,0xD2,0xF4,0xF9,0xB6,0xB0,0x6F,0xBA,0x4B,0xAC,0x15,0x26,0xE5,0x1C,0x3A,0xFA,0x2A,0x38,0xDF,0xA7,0x8E, 139 | 0x31,0xDE,0x51,0xB6,0x9E,0x9A,0x93,0xA5,0x84,0x87,0xEC,0x4B,0x75,0xB6,0xD9,0x6A,0x4E,0x18,0xAA,0x02,0xA3,0x17,0x18,0xBC,0x60,0x9D,0xEA,0xF2,0x8B,0x52,0xDF,0x82, 140 | 0x67,0x1A,0xC9,0x40,0xA5,0x9B,0x5C,0x0A,0xF6,0xCB,0xE9,0x8E,0x10,0x54,0x46,0xA4,0x9C,0x2F,0x8A,0x02,0x27,0x8D,0x5B,0xFB,0x34,0x87,0x32,0xFB,0x33,0x6B,0x76,0xD6, 141 | 0x27,0xA9,0xCA,0x5C,0x90,0x6A,0x95,0x60,0xB8,0x72,0xA8,0xC6,0x2D,0xBD,0xCF,0xE8,0xDA,0x12,0x4A,0x59,0xE1,0x22,0x89,0x9D,0x28,0xB5,0xF4,0x64,0xD3,0x8E,0xD9,0x2F, 142 | 0x06,0xB8,0x90,0xB5,0x6B,0x68,0x04,0x6A,0x55,0x25,0xFC,0x91,0xA8,0x97,0xBA,0xD7,0xD1,0x2A,0x5E,0xD4,0x9C,0x7C,0x86,0xAC,0xEB,0x35,0x6C,0x82,0x35,0x12,0x70,0x49, 143 | 0x72,0x73,0xEB,0x45,0xC7,0x06,0xBA,0x72,0xDD,0x37,0x7C,0x2C,0xB3,0x3D,0x67,0xBA,0xD9,0x44,0xEF,0x5F,0x16,0x8D,0xE2,0xD4,0x95,0xD9,0xCF,0xB6,0x3B,0x52,0xF0,0x54, 144 | 0x13,0x7D,0xE0,0x0D,0xB9,0xE0,0xA4,0xA8,0x49,0xF4,0x87,0x60,0x50,0x59,0x9B,0x95,0x06,0xE6,0xFE,0x80,0xA7,0x21,0x5D,0x93,0x61,0x60,0x50,0xAC,0x4D,0x92,0xD8,0x15, 145 | 0x61,0x64,0x58,0x58,0x1A,0x26,0x3B,0x33,0x4C,0x76,0x05,0x58,0x59,0x16,0x1B,0x88,0x2E,0xC4,0xE4,0x45,0x92,0xE4,0x07,0xB7,0x27,0x83,0x3B,0xC9,0x6D,0x36,0x25,0x05, 146 | 0x64,0x54,0xF2,0xCA,0xAA,0x1B,0xA1,0x36,0xA3,0x96,0x41,0x12,0xBE,0x88,0x69,0xAE,0x59,0x4E,0x76,0xF0,0x2A,0x6F,0x92,0x84,0xB0,0xAC,0xB4,0xA5,0x25,0xCD,0x11,0x4D, 147 | 0x2C,0x8D,0x36,0x05,0xA8,0x2F,0x2C,0x1C,0x2B,0xBB,0x1A,0x43,0xA6,0x04,0xDD,0x70,0x85,0xB9,0xDF,0xE2,0x8A,0x13,0x2A,0x29,0x4B,0xC8,0x36,0x88,0x4B,0x3C,0x8F,0x87, 148 | 0x55,0x60,0x57,0x24,0x4A,0x29,0xF2,0x52,0x77,0xFE,0x20,0xE3,0x68,0x0C,0x5C,0x52,0xE0,0xCE,0x5A,0x52,0x6E,0xEC,0xDF,0x6D,0x3E,0x45,0x2A,0x7D,0x81,0x8A,0xD3,0x6B, 149 | 0x96,0x34,0x92,0x34,0x49,0x57,0x90,0x70,0x8B,0xEA,0x80,0xCE,0x4E,0x5D,0x64,0x13,0x7F,0xE5,0x0A,0x2B,0xDA,0xAE,0x1B,0x07,0xEE,0xC7,0xB4,0xC0,0xA5,0x4D,0x60,0x1A, 150 | 0xAE,0x8C,0x9C,0x9F,0xF9,0x42,0xBE,0xCA,0x8D,0xBC,0xA9,0xFF,0x00,0x00,0x68,0xAD,0xA1,0x55,0xBC,0x8A,0xDD,0xFC,0xB0,0xBE,0x86,0xDC,0x2B,0x12,0x02,0xAE,0x97,0x22, 151 | 0x75,0x25,0x92,0x79,0xEE,0xC1,0x37,0x60,0x67,0x28,0xED,0x76,0xB8,0x2B,0x7F,0xC7,0x0E,0xCD,0x2F,0xCA,0xB3,0x2D,0x48,0x29,0x2C,0x2A,0x65,0x17,0x0D,0x44,0xB9,0xC1, 152 | 0x9E,0xAB,0x52,0xB3,0x08,0xC9,0xAB,0x84,0xFF,0x00,0x82,0x92,0x03,0x48,0xAA,0xAC,0xE0,0x51,0x8F,0xCF,0x22,0x85,0xD3,0x1E,0xEA,0xCB,0x01,0xA6,0xA1,0x16,0xBB,0x62, 153 | 0x93,0xB7,0x65,0x38,0xDE,0x44,0xD5,0x30,0x2F,0x4F,0x81,0x6A,0x53,0x9C,0x50,0xA2,0xE9,0x24,0xBF,0xD9,0x32,0xCC,0xAF,0xB0,0x22,0x7F,0x2D,0x46,0x42,0x5F,0x26,0xDB, 154 | 0xC2,0x09,0x27,0x17,0x60,0xAF,0xB5,0x86,0x04,0xC2,0x2E,0x9B,0x4B,0x93,0x2D,0x6C,0x51,0xD9,0x0A,0x8E,0x9E,0x32,0xCE,0x7D,0x68,0xDA,0xF9,0x01,0x94,0x53,0x9F,0x18, 155 | 0x46,0x89,0x25,0x80,0xD2,0x8F,0xC6,0xF8,0x4B,0xB3,0x2D,0x4D,0x4B,0x96,0xD8,0xAC,0x01,0xB6,0xF4,0xB8,0x64,0xB9,0x3E,0x88,0x4E,0xF2,0x35,0x6C,0x07,0x65,0x5B,0x26, 156 | 0xE8,0x2C,0x0B,0xBF,0xB1,0x59,0x36,0x16,0x05,0x58,0x85,0x90,0x00,0x00,0x13,0x02,0x90,0xC8,0x18,0x05,0x8A,0xC1,0xB2,0x5B,0x20,0xA6,0xF0,0x45,0x94,0xB2,0x43,0x03, 157 | 0xE8,0x1A,0xC0,0x50,0x30,0xB2,0x29,0x64,0x87,0x1B,0xE4,0xB7,0x6F,0x82,0x5A,0x02,0x29,0x2C,0x24,0x19,0x2A,0xFA,0x48,0x75,0x4B,0x20,0x46,0xDC,0xE4,0xA4,0x92,0x41, 158 | 0xC8,0x5A,0x01,0xA6,0x3C,0x0A,0xE8,0x00,0x2F,0xE8,0x97,0x2F,0xA1,0xB2,0x69,0x79,0xB2,0xA1,0xA6,0xBB,0x2B,0x7C,0x45,0x18,0xC7,0xB1,0x4B,0x6A,0xE0,0x07,0xB9,0x74, 159 | 0xC4,0xE4,0x85,0xBA,0x20,0xA5,0x17,0xD8,0x06,0x1F,0x04,0xB7,0xE5,0x17,0xBA,0x3D,0x11,0x29,0xD7,0x40,0x4B,0xD4,0x48,0x5E,0xE7,0xD8,0x56,0xE7,0x94,0x0E,0x31,0x51, 160 | 0xC8,0x07,0xB8,0xEB,0x9A,0x16,0xE7,0x79,0x64,0xBD,0x89,0xF0,0xCB,0x4A,0x1C,0xD3,0x0A,0xA5,0xA9,0x07,0xCA,0x6C,0x86,0xF3,0xF1,0x85,0x15,0x74,0xBE,0x3C,0x92,0xA5, 161 | 0xA9,0xFF,0x00,0x94,0x10,0xBF,0xB9,0xE1,0x31,0xAB,0xAF,0x92,0xA2,0xD6,0xEE,0xD5,0x15,0xD0,0x54,0xC6,0xFA,0xE0,0x78,0x7C,0xE1,0x89,0xC5,0xDE,0x30,0x16,0xCA,0x84, 162 | 0xE7,0x4F,0x22,0x7A,0xF0,0x7C,0x4B,0x25,0x34,0x9F,0x18,0x67,0x3E,0xA6,0x9D,0x3B,0x4A,0x98,0x1A,0x63,0x51,0xBB,0x8A,0x7F,0x64,0x45,0x38,0xB7,0x7C,0x13,0xA7,0x26, 163 | 0x9E,0x1F,0x06,0xD6,0xA5,0x56,0xF2,0x80,0xCE,0x09,0x6E,0x2D,0xC7,0x81,0xEC,0x4B,0x28,0x7D,0x05,0x4D,0x50,0xD2,0xBE,0x46,0xE2,0xE8,0x4F,0x8B,0x02,0x65,0x7C,0x22, 164 | 0x37,0x63,0xEC,0x72,0x79,0x26,0x9D,0xD9,0x04,0x4B,0x8C,0x97,0x06,0xB6,0xA4,0xC4,0xD7,0x42,0xE3,0x25,0x1A,0x24,0xDB,0xA4,0x67,0x28,0xEE,0x6A,0xCD,0x34,0xDD,0xA6, 165 | 0xFC,0x15,0x57,0xC0,0x46,0x13,0x69,0x45,0xA6,0xB0,0x72,0x4E,0x5B,0xA5,0x8E,0x0E,0xCD,0x78,0x52,0xA4,0xAC,0xE4,0x6A,0xC0,0x15,0x24,0x3B,0x12,0x45,0x00,0x24,0x31, 166 | 0x58,0x58,0x15,0x40,0x09,0x80,0x00,0x50,0xF6,0xFD,0x8D,0x20,0x25,0x8A,0x8A,0x68,0x90,0x04,0x53,0x58,0x12,0x1B,0x02,0x18,0x86,0xC4,0xC0,0x4B,0x90,0x6B,0x20,0x3E, 167 | 0x80,0xF7,0x84,0x3A,0xC1,0x3D,0x99,0x53,0x64,0xD3,0x6C,0xAE,0x43,0x80,0x15,0x50,0xA5,0x24,0x36,0xFC,0x90,0xD3,0x7F,0xA0,0x25,0xCA,0xFF,0x00,0x41,0x75,0x91,0xA8, 168 | 0xA6,0x27,0x1C,0xD0,0x0B,0x7D,0xB1,0xEE,0xCE,0x41,0xC6,0x83,0x1E,0x0A,0x1F,0x21,0x4E,0xF8,0x1D,0xB6,0x83,0x3D,0xBA,0x08,0x55,0xE5,0x83,0xDB,0xD0,0x35,0xE0,0x5D, 169 | 0xE5,0x81,0x4A,0x2B,0x90,0x70,0x5C,0xA0,0xB5,0x58,0x18,0x10,0xD3,0x0D,0xB6,0xB8,0x2F,0x81,0xD8,0x19,0xED,0xAE,0x41,0xB5,0xE2,0x87,0x3B,0xF2,0x4D,0x5F,0x20,0x27, 170 | 0x28,0xDF,0x16,0x27,0x75,0xF8,0xE0,0xD5,0x46,0xBA,0x06,0x97,0x6C,0x0C,0xA8,0xA8,0xC1,0x37,0x9C,0x06,0xF5,0x17,0x86,0x35,0x3B,0x02,0xF6,0xD7,0x12,0x0D,0xB7,0xF6, 171 | 0x2D,0xC9,0x72,0xCA,0x8C,0x90,0x0B,0x6C,0x5F,0x94,0x27,0x0C,0x62,0x45,0xB9,0x22,0x5E,0x51,0x47,0x26,0xA6,0xE8,0x3B,0xBC,0x1A,0xE9,0xEA,0xEF,0x8D,0x55,0xFD,0x86, 172 | 0xA6,0x9B,0x51,0x6D,0xB4,0x60,0xA4,0xE2,0xF9,0x03,0x59,0xE9,0x24,0xED,0x2C,0x92,0x9D,0x3F,0x0C,0xD5,0x4D,0xB4,0x85,0x34,0xA5,0x2F,0xB0,0x13,0xE0,0x78,0xDA,0x25, 173 | 0xE1,0x95,0xB9,0x78,0x0A,0x13,0xAF,0xD1,0x13,0xEE,0x86,0xD8,0xB6,0xB7,0x90,0x33,0x79,0x04,0xB3,0x43,0xA6,0xA6,0x5E,0xDE,0xC8,0xA9,0x68,0xCE,0x4B,0x06,0xEE,0x38, 174 | 0x22,0x50,0xC0,0x13,0xA5,0x8B,0x46,0xA9,0x78,0x33,0x4A,0x8D,0xA2,0xAA,0x25,0x65,0xCD,0xAF,0x76,0x72,0x49,0x3B,0x3B,0x35,0x93,0x7B,0x9D,0x1C,0xEE,0x2D,0xF4,0xCA, 175 | 0x32,0xA5,0x60,0x53,0x5F,0x44,0xBF,0xD1,0x03,0x15,0x80,0x80,0xAB,0x0B,0x26,0xC6,0x05,0x26,0x34,0xE8,0x48,0x00,0xD5,0x34,0xF0,0xC4,0xE1,0xE0,0xCD,0x33,0x48,0xC8, 176 | 0x09,0xAA,0x13,0x34,0x74,0xC9,0x71,0x02,0x18,0x81,0xE0,0x40,0x22,0xD7,0x18,0x24,0xA8,0xF8,0x03,0xDC,0x15,0x51,0x54,0x4B,0x32,0x01,0x4A,0x58,0xA0,0xAB,0x06,0xA8, 177 | 0x29,0x25,0x79,0x60,0xF8,0x1D,0x79,0x15,0x79,0x01,0x70,0xB0,0x22,0xEB,0x02,0xAC,0x01,0x0C,0x71,0x55,0xC8,0xEB,0x02,0x6F,0xA4,0x50,0x39,0x5F,0x08,0x54,0xD9,0x49, 178 | 0x52,0x1A,0x01,0x6D,0xC1,0x2E,0x28,0xB7,0x94,0x44,0x9F,0x48,0x22,0x78,0x2A,0xDD,0x12,0x92,0xB2,0xAD,0x74,0x01,0xFB,0x1E,0x3E,0xC2,0xD8,0x9A,0xFB,0x00,0x69,0x0B, 179 | 0x81,0x82,0x4B,0xB2,0x88,0x72,0x7E,0x41,0x3B,0x79,0x34,0xDA,0xBC,0x12,0xEB,0x8E,0x80,0xCE,0x54,0x90,0xA1,0x19,0xBC,0xD5,0x1A,0x36,0x93,0xC2,0x13,0x9F,0xD1,0x00, 180 | 0xA3,0x15,0xCE,0x59,0x69,0xAF,0x06,0x1E,0xE3,0x4F,0x82,0x94,0xE5,0x2C,0x70,0x06,0xFD,0x07,0xEC,0xCB,0x3E,0x47,0x58,0xCB,0x28,0x7A,0x89,0x35,0x47,0x3B,0x8F,0xC8, 181 | 0xD9,0xE9,0xA3,0x39,0xC5,0x2E,0x00,0x94,0xB3,0x96,0x6D,0x14,0xBC,0x99,0xC2,0x0F,0xC7,0xFB,0x2B,0xF1,0xC5,0x81,0x52,0x48,0x87,0x82,0x94,0x97,0x41,0x25,0x61,0x49, 182 | 0x71,0x65,0x44,0x86,0xE9,0xD2,0x04,0x45,0x12,0x54,0xEC,0xD7,0x4E,0x3B,0xA0,0xD8,0x45,0xA7,0x86,0x89,0x6F,0x6D,0xA5,0xC1,0x43,0x14,0xA1,0x51,0xB6,0x4E,0xE2,0xA4, 183 | 0xED,0x01,0x14,0xB0,0x53,0x95,0x44,0x9C,0xF8,0x1C,0xAD,0xC7,0x28,0x26,0xB0,0x9E,0xB4,0xD5,0xA7,0x1C,0x18,0xFB,0x92,0x6C,0x73,0x9D,0x4D,0xAB,0xB4,0x4A,0xCB,0x08, 184 | 0x52,0x93,0xBE,0x08,0xBB,0x66,0xB2,0x5E,0x4C,0xF6,0x81,0x2E,0x84,0x36,0xB2,0x27,0x80,0x10,0xD3,0x00,0x8E,0x40,0xB4,0x05,0x25,0x81,0x5E,0x40,0x54,0x34,0x0D,0xAA, 185 | 0x15,0x81,0x76,0x2D,0xC4,0xB0,0x00,0x96,0x49,0x28,0x4D,0x80,0x86,0x9B,0x10,0x01,0xEF,0xB7,0xD0,0xA8,0x10,0xEC,0x81,0x71,0x80,0x60,0x26,0x40,0xA4,0xFC,0x0B,0x8E, 186 | 0x41,0x8B,0xB0,0x0C,0xBF,0xD0,0xC5,0xBA,0xF0,0xB8,0x1A,0x28,0x6D,0x60,0x8A,0xA4,0x5D,0x90,0xF2,0x03,0x41,0x7E,0x04,0xD3,0x07,0x25,0x15,0x8E,0x40,0x2B,0xC8,0x9A, 187 | 0xB1,0x5B,0x6F,0x25,0x11,0x52,0x90,0x25,0x91,0xBC,0x22,0x6C,0xA2,0x9E,0x03,0x92,0x53,0xB2,0xAE,0x82,0x1A,0x4C,0x1B,0x48,0x87,0x27,0x60,0xF2,0x05,0x6E,0xC5,0x13, 188 | 0x4D,0x82,0x45,0x50,0x13,0xC0,0xBB,0x29,0xAC,0x12,0xCA,0x13,0x8D,0x92,0x93,0x8B,0x34,0x41,0xC8,0x13,0x74,0xEC,0x4A,0x6E,0xF8,0x34,0xA5,0xD9,0x32,0xA0,0x16,0xE7, 189 | 0x61,0x77,0x64,0x37,0x81,0xA4,0xDF,0x78,0x00,0x49,0xF9,0x29,0x42,0x37,0x72,0x7F,0xC0,0x37,0x4A,0x91,0x2A,0x37,0x96,0x06,0xCA,0x51,0xE2,0x31,0xA1,0x6D,0x21,0x27, 190 | 0x78,0x34,0x5C,0x01,0x2E,0x19,0x41,0xB7,0x26,0x94,0x3A,0x0B,0x59,0xED,0xA0,0x71,0x35,0xA2,0x24,0x81,0x59,0xED,0x1A,0x81,0x71,0x43,0x93,0xA0,0x56,0x7B,0x70,0x73, 191 | 0xEA,0xEA,0x38,0xE2,0xDA,0x35,0xD5,0xD4,0x70,0xE1,0x9C,0xBA,0x9A,0x9B,0xE9,0xD0,0x46,0x4E,0xA4,0xEF,0xB1,0x2E,0x46,0xC5,0xC0,0x17,0x29,0x7C,0x48,0xE9,0xB0,0x93, 192 | 0xB4,0x2F,0xF1,0x6B,0xC8,0x07,0x64,0xB4,0x3E,0x05,0x60,0x2A,0x1C,0x46,0xB2,0x3B,0x4B,0x80,0x1F,0x44,0xBC,0x05,0x8E,0x5C,0x01,0x3D,0x0D,0x02,0xAB,0xCF,0x05,0x4A, 193 | 0x1B,0x63,0x6B,0x28,0x05,0xC0,0x21,0xAC,0xA2,0x5E,0x38,0x02,0xAB,0xB1,0x55,0x89,0x26,0xC7,0x69,0x00,0x9C,0x71,0x68,0x86,0x6B,0x6B,0xA1,0x38,0xDA,0xB0,0x3D,0xAB, 194 | 0x1A,0xC0,0x20,0x66,0x41,0x63,0x13,0xE0,0x5B,0xBA,0x28,0x4D,0xF2,0x4B,0x45,0x36,0x00,0x4D,0x52,0xA1,0xA1,0x88,0x07,0x7D,0x05,0x09,0x60,0x68,0x06,0xF8,0x21,0xAB, 195 | 0x65,0x30,0xE1,0x01,0x3C,0x03,0x61,0xD0,0xBB,0xFB,0x01,0x3B,0x64,0xD7,0x93,0x5A,0xAF,0xD8,0xA8,0x8A,0x94,0x92,0x25,0xBF,0x05,0x55,0xB2,0x9A,0x48,0xA8,0xCD,0x46, 196 | 0xB2,0xC7,0x1C,0xC8,0xA9,0x24,0x4A,0xE0,0x02,0xF2,0x02,0xAC,0x8E,0xC0,0x1C,0xA8,0x9C,0xB1,0xD7,0x62,0xED,0x80,0x0E,0xE8,0x17,0xD8,0xCA,0x33,0x6E,0x56,0x29,0xB7, 197 | 0x45,0xC8,0x8A,0x02,0x37,0x53,0xFA,0x1A,0xD4,0xB7,0xFF,0x00,0xE0,0x38,0xAE,0x05,0x18,0xED,0xB9,0x73,0xE0,0x0D,0x2F,0x1F,0x61,0x1B,0x56,0xDB,0xC2,0x32,0xC8,0xB5, 198 | 0x27,0x2A,0xDB,0xD0,0x1D,0x31,0x9A,0x96,0x22,0x55,0xD1,0x84,0x24,0x92,0x49,0x72,0xC3,0xDC,0xBB,0xB2,0x8E,0xAD,0xCA,0xC3,0x71,0x8A,0x7C,0x0D,0x30,0x35,0x73,0xA4, 199 | 0x4A,0xD4,0x4E,0xCC,0xA5,0x2E,0x4C,0x77,0x64,0x0E,0xA7,0x34,0x44,0xF5,0x53,0x8F,0x27,0x23,0xD5,0x79,0x44,0xA6,0xDA,0xE4,0x0D,0x35,0x1E,0xE6,0x60,0xDD,0x1A,0x27, 200 | 0x82,0x24,0x88,0x33,0x6C,0x77,0x78,0x13,0xE4,0x40,0x52,0x6A,0xF2,0x3D,0x4E,0x57,0xE8,0xCE,0xF2,0x5D,0xEE,0x54,0xC0,0x9B,0xC0,0xB9,0x63,0x62,0x40,0x5B,0x58,0xC7, 201 | 0x44,0xDE,0x4D,0x20,0xFF,0x00,0xB5,0xA8,0x65,0x10,0x28,0xBA,0xB2,0x41,0x30,0x07,0x1A,0x35,0x8C,0x7E,0x0A,0xF8,0x25,0x2B,0x2A,0x72,0xC6,0x00,0x12,0x51,0xEA,0xC9, 202 | 0x95,0x5F,0x03,0x8E,0x16,0x49,0x9E,0x72,0xC0,0x84,0xED,0x93,0x65,0x4D,0xD5,0x35,0xD9,0x9B,0xCB,0x02,0xD3,0x36,0x82,0xBD,0x19,0xC9,0xF4,0x61,0x05,0x68,0xD6,0x33, 203 | 0xA8,0x4A,0x34,0x07,0xB1,0x76,0xC2,0xCC,0xF7,0x0F,0x71,0x05,0xD8,0xAD,0x72,0x45,0x87,0x2C,0x07,0x79,0x1A,0x24,0x37,0x24,0xE8,0x0B,0xBC,0xD0,0x9B,0xA6,0x46,0xEC, 204 | 0x85,0xD8,0x15,0x76,0x36,0xE9,0x11,0x16,0x3B,0x01,0xDE,0x46,0xDE,0x08,0xBA,0x64,0xB9,0x3B,0x28,0xD2,0xC7,0xD9,0x9A,0x90,0x6E,0x20,0xB6,0xC5,0x64,0xB9,0x0A,0x39, 205 | 0x02,0x93,0x49,0x8E,0xEC,0x86,0xB3,0x61,0x60,0x53,0xCB,0x0E,0x89,0xC8,0x00,0xC1,0xA2,0x6F,0x23,0x6E,0xCA,0x06,0xC1,0x88,0x5C,0x81,0x41,0x92,0x50,0xF7,0x00,0xD2, 206 | 0x06,0x90,0x37,0x82,0x1C,0xC0,0x6E,0x29,0x92,0x35,0x2B,0x56,0x99,0x2D,0x6E,0xE1,0xE4,0xA8,0x25,0xCD,0x99,0x6A,0x7E,0x68,0x35,0x25,0x8A,0x64,0x6E,0x6E,0x16,0xFA, 207 | 0x0A,0xD2,0x2F,0x6C,0xE3,0x27,0xC1,0x32,0xFC,0xF1,0xC5,0x86,0x9C,0xEA,0x1B,0x5E,0x55,0xE0,0x4E,0x5F,0x2E,0x02,0x36,0x72,0x49,0xAA,0x61,0xBA,0xCC,0x14,0x95,0x9A, 208 | 0x2C,0x01,0x4E,0x55,0xC9,0x17,0x16,0xDF,0x45,0x3A,0x68,0x99,0xAB,0xAA,0x03,0x29,0x41,0xDD,0xAE,0x03,0x29,0x34,0x90,0xD3,0x69,0xD3,0xE1,0x0E,0x53,0x4D,0xD5,0x11, 209 | 0x59,0x26,0xF8,0x63,0x6E,0xC7,0xB5,0x74,0x2A,0x02,0x5A,0x24,0xD3,0x82,0x5A,0xC8,0x11,0x5D,0x82,0x74,0xCB,0x96,0x9B,0x8C,0x13,0xF2,0x67,0x40,0x36,0xEC,0x09,0xAC, 210 | 0x95,0xD0,0x16,0x9D,0x69,0xB7,0xF6,0x24,0xC1,0xFF,0x00,0xD6,0xBF,0x64,0xBE,0x28,0x0B,0xB0,0x44,0xA6,0xA8,0x13,0xB6,0x51,0xB2,0xE2,0xC1,0x64,0x52,0x7B,0x20,0x97, 211 | 0x63,0x8D,0xA8,0x4A,0x40,0x29,0x4A,0xDD,0x0E,0x54,0xE2,0x8C,0x37,0x67,0x9C,0x94,0xA6,0xDB,0xA6,0x05,0x34,0x9E,0x09,0x9C,0x54,0x63,0x4B,0x92,0xEB,0xB1,0xD5,0xA2, 212 | 0x08,0xD3,0x87,0x6C,0x52,0x75,0x68,0xD2,0x4F,0x6A,0x32,0x92,0x4D,0xDA,0x03,0xFF,0xD9,}; 213 | 214 | --------------------------------------------------------------------------------