├── .gitattributes ├── .gitignore ├── README.md ├── examples ├── FLash_array │ ├── ESP32_Dual_Core_Flash_Jpg │ │ ├── ESP32_Dual_Core_Flash_Jpg.ino │ │ └── panda.h │ ├── Flash_Jpg │ │ ├── Flash_Jpg.ino │ │ └── panda.h │ └── Flash_Jpg_GFX │ │ ├── Flash_Jpg_GFX.ino │ │ └── panda.h ├── LittleFS │ ├── All_LittleFS │ │ ├── All_LittleFS.ino │ │ └── data │ │ │ ├── Baboon40.jpg │ │ │ ├── panda.jpg │ │ │ └── tiger.jpg │ ├── LittleFS_Jpg │ │ ├── LittleFS_Jpg.ino │ │ └── data │ │ │ └── panda.jpg │ └── LittleFS_Web_Jpg │ │ ├── List_LittleFS.h │ │ ├── LittleFS_Web_Jpg.ino │ │ └── Web_Fetch.h ├── SD Card │ └── SD_Jpg │ │ ├── SD_Jpg.ino │ │ └── data │ │ └── panda.jpg └── SPIFFS │ ├── All_SPIFFS │ ├── All_SPIFFS.ino │ └── Data │ │ ├── Baboon40.jpg │ │ ├── panda.jpg │ │ └── tiger.jpg │ ├── SPIFFS_Jpg │ ├── SPIFFS_Jpg.ino │ └── data │ │ └── panda.jpg │ └── SPIFFS_Web_Jpg │ ├── List_SPIFFS.h │ ├── SPIFFS_Web_Jpg.ino │ └── Web_Fetch.h ├── keywords.txt ├── library.json ├── library.properties ├── license.txt └── src ├── TJpg_Decoder.cpp ├── TJpg_Decoder.h ├── User_Config.h ├── tjpgd.c ├── tjpgd.h └── tjpgdcnf.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # ========================= 22 | # Operating System Files 23 | # ========================= 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino TJpg_Decoder library 2 | =========== 3 | 4 | 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 SPIFFS (ESP32, ESP8266) and LittleFS (ESP32, ESP8266, RP2040) Flash filing systems or alternatively "PROGMEM" arrays can be used. 5 | 6 | The library has been tested on the Arduino Due, ESP32 and ESP8266 (e.g. NodeMCU 1.0), STM32 and RP2040 processors. Other processors should work too if they have sufficient memory. Use with the ESP32 requires Arduino board package 2.0.0 or later. 7 | 8 | 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. 9 | 10 | When storing the jpeg in a memory array bear in mind that some Arduino boards have a maximum 32767 byte limit for the maximum size of an array (32 KBytes minus 1 byte). 11 | 12 | The decompression of Jpeg images needs more RAM than an UNO provides, thus this library is targetted at processors with more RAM. The decoder has a very small memory footprint, typically 3.5K Bytes of RAM (for workspace, Independent of Image Dimensions) and 3.5-8.5K Bytes of ROM for text and constants. 13 | 14 | 15 | On a Mega the number of images stored in FLASH must be limited because it they are large enough to push the executable code start over the 64K 16 bit address limit then the Mega will fail to boot even though the sketch compiles and uploads correctly. This is a limitation imposed by the Arduino environment not this library! 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. 16 | 17 | This library uses the TJpgDec decompressor engine detailed here: 18 | http://elm-chan.org/fsw/tjpgd/00index.html 19 | TJpgDec is a generic JPEG image decompressor module that highly optimized for small embedded systems. 20 | -------------------------------------------------------------------------------- /examples/FLash_array/ESP32_Dual_Core_Flash_Jpg/ESP32_Dual_Core_Flash_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example is for an ESP32, it renders a Jpeg file that is stored in an array within Flash (program) memory 5 | // see panda.h tab. The panda image file being ~13Kbytes. The Jpeg decoding is done by one processor core 0 and 6 | // the rendering to TFT by processor 1 (which is normally used to execute the Arduino sketches). 7 | 8 | // Single processor core Flash_Jpg sketch on ILI9341 at 40MHz SPI renders the panda Jpeg in 103ms 9 | // The Jpeg image takes 66ms to deocde and 37ms to render to TFT 10 | // This sketch uses both ESP32 processors in parallel so decoding and rendering only takes 66ms 11 | // Processor 1 runs the main sketch, processor 0 runs the Jpeg decoder 12 | 13 | // Include the array 14 | #include "panda.h" 15 | 16 | // Include the jpeg decoder library 17 | #include 18 | 19 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 20 | #include "SPI.h" 21 | #include // Hardware-specific library 22 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 23 | 24 | // Global variables available to BOTH processors 0 and 1 25 | TaskHandle_t Task1; 26 | const uint8_t* arrayName; // Name of FLASH array containing Jpeg 27 | bool doDecoding = false; // Mutex flag to start decoding 28 | bool mcuReady = false; // Mutex flag to indicate an MCU block is ready for rendering 29 | uint16_t mcuBuffer[16*16]; // Buffer to grab a snapshot of decoded MCU block 30 | int32_t mcu_x, mcu_y, mcu_w, mcu_h; // Snapshot of the place to render the MCU 31 | 32 | // This next function will be called by the TJpg_Decoder library during decoding of the jpeg file 33 | // A copy of the decoded MCU block is grabbed for rendering so decoding can then continue while 34 | // the MCU block is rendered on the TFT. Note: This function is called by processor 0 35 | bool mcu_decoded(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 36 | { 37 | // Stop further decoding as image is running off bottom of screen 38 | if ( y >= tft.height() ) return 0; 39 | 40 | while(mcuReady) yield(); // Wait here if rendering of last MCU block to TFT is still in progress 41 | 42 | memcpy(mcuBuffer, bitmap, 16*16*2); // Grab a copy of the MCU block image 43 | mcu_x = x; // Grab postion and size of MCU block 44 | mcu_y = y; 45 | mcu_w = w; 46 | mcu_h = h; 47 | mcuReady = true; // Flag to tell processor 1 that rendering of MCU can start 48 | 49 | // Return 1 to decode next Jpeg MCU block 50 | return 1; 51 | } 52 | 53 | // This is the task that runs on processor 0 (Arduino sketch runs on processor 1) 54 | // It decodes the Jpeg image 55 | void decodeJpg(void* p) { 56 | // This is an infinite loop, effectively the same as the normal sketch loop() 57 | // but this function and loop is running on processor 0 58 | for(;;) { 59 | // Decode the Jpeg image 60 | if (doDecoding) { // Only start decoding if main sketch sets this flag 61 | TJpgDec.drawJpg(0, 0, arrayName, sizeof(panda)); // Runs until complete image decoded 62 | doDecoding = false; // Set mutex false to indicate decoding has ended 63 | } 64 | // Must yield in this loop 65 | yield(); 66 | } 67 | } 68 | 69 | void setup() 70 | { 71 | //Create task decodeJpg to run on processor 0 to decode a Jpeg 72 | xTaskCreatePinnedToCore(decodeJpg, "decodeJpg", 10000, NULL, 0, NULL, 0); 73 | 74 | Serial.begin(115200); 75 | Serial.println("\n\n Testing TJpg_Decoder library"); 76 | 77 | // Initialise the TFT 78 | tft.begin(); 79 | tft.setTextColor(0xFFFF, 0x0000); 80 | tft.fillScreen(TFT_BLACK); 81 | 82 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 83 | TJpgDec.setJpgScale(1); 84 | 85 | // The byte order can be swapped (set true for TFT_eSPI) 86 | TJpgDec.setSwapBytes(true); 87 | 88 | // The decoder must be given the exact name of the mcu buffer function above 89 | TJpgDec.setCallback(mcu_decoded); 90 | } 91 | 92 | void loop() 93 | { 94 | tft.fillScreen(TFT_RED); 95 | 96 | // Get the width and height in pixels of the jpeg if you wish 97 | uint16_t w = 0, h = 0; 98 | TJpgDec.getJpgSize(&w, &h, panda, sizeof(panda)); 99 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 100 | 101 | // Time recorded for test purposes 102 | uint32_t t = millis(); 103 | 104 | // The order here is important, doDecoding must be set "true" last after other parameters have been defined 105 | arrayName = panda; // Name of FLASH array to be decoded 106 | mcuReady = false; // Flag which is set true when a MCU block is ready for display 107 | doDecoding = true; // Flag to tell task to decode the image 108 | 109 | // Only render MCU blocks if decoding is in progress OR an MCU is ready to render 110 | // Note: the OR mcuReady is required so the last block is rendered after decoding has ended 111 | while(doDecoding || mcuReady) { 112 | if (mcuReady) { 113 | tft.pushImage(mcu_x, mcu_y, mcu_w, mcu_h, mcuBuffer); 114 | mcuReady = false; 115 | } 116 | // Must yield in this loop 117 | yield(); 118 | } 119 | 120 | // How much time did rendering take 121 | t = millis() - t; 122 | Serial.print(t); Serial.println(" ms"); 123 | 124 | // Wait before drawing again 125 | delay(2000); 126 | } 127 | -------------------------------------------------------------------------------- /examples/FLash_array/Flash_Jpg/Flash_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example renders a Jpeg file that is stored in an array within Flash (program) memory 5 | // see panda.h tab. The panda image file being ~13Kbytes. 6 | 7 | // Include the array 8 | #include "panda.h" 9 | 10 | // Include the jpeg decoder library 11 | #include 12 | 13 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 14 | #include "SPI.h" 15 | #include // Hardware-specific library 16 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 17 | 18 | // This next function will be called during decoding of the jpeg file to 19 | // render each block to the TFT. If you use a different TFT library 20 | // you will need to adapt this function to suit. 21 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 22 | { 23 | // Stop further decoding as image is running off bottom of screen 24 | if ( y >= tft.height() ) return 0; 25 | 26 | // This function will clip the image block rendering automatically at the TFT boundaries 27 | tft.pushImage(x, y, w, h, bitmap); 28 | 29 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 30 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 31 | 32 | // Return 1 to decode next block 33 | return 1; 34 | } 35 | 36 | void setup() 37 | { 38 | 39 | Serial.begin(115200); 40 | Serial.println("\n\n Testing TJpg_Decoder library"); 41 | 42 | // Initialise the TFT 43 | tft.begin(); 44 | tft.setTextColor(0xFFFF, 0x0000); 45 | tft.fillScreen(TFT_BLACK); 46 | 47 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 48 | TJpgDec.setJpgScale(1); 49 | 50 | // The byte order can be swapped (set true for TFT_eSPI) 51 | TJpgDec.setSwapBytes(true); 52 | 53 | // The decoder must be given the exact name of the rendering function above 54 | TJpgDec.setCallback(tft_output); 55 | } 56 | 57 | void loop() 58 | { 59 | tft.fillScreen(TFT_RED); 60 | 61 | // Time recorded for test purposes 62 | uint32_t t = millis(); 63 | 64 | // Get the width and height in pixels of the jpeg if you wish 65 | uint16_t w = 0, h = 0; 66 | TJpgDec.getJpgSize(&w, &h, panda, sizeof(panda)); 67 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 68 | 69 | // Draw the image, top left at 0,0 70 | TJpgDec.drawJpg(0, 0, panda, sizeof(panda)); 71 | 72 | // How much time did rendering take (ESP8266 80MHz 262ms, 160MHz 149ms, ESP32 SPI 111ms, 8bit parallel 90ms 73 | t = millis() - t; 74 | Serial.print(t); Serial.println(" ms"); 75 | 76 | // Wait before drawing again 77 | delay(2000); 78 | } 79 | -------------------------------------------------------------------------------- /examples/FLash_array/Flash_Jpg/panda.h: -------------------------------------------------------------------------------- 1 | /* Create C arrays from jpeg images using this online tool: 2 | http://tomeko.net/online_tools/file_to_hex.php?lang=en 3 | 4 | If needed, first resize and crop to an appropriate width and height 5 | to suit your display with an image editing program such as IrfanView. 6 | 7 | You can also change the image "quality" to reduce the file size. 8 | 9 | Paste the array into a new tab, top and tail the array from the 10 | tool to look like the one below with: 11 | 12 | #include 13 | const uint8_t name[] PROGMEM = { 14 | 15 | to start and and end with: 16 | 17 | }; 18 | 19 | Change the name of the array 20 | 21 | 22 | */ 23 | 24 | #include 25 | const uint8_t panda[] PROGMEM = { 26 | 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0xB4, 27 | 0x00, 0xB4, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 28 | 0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14, 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12, 29 | 0x13, 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A, 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20, 30 | 0x22, 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C, 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27, 31 | 0x39, 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x09, 0x09, 32 | 0x09, 0x0C, 0x0B, 0x0C, 0x18, 0x0D, 0x0D, 0x18, 0x32, 0x21, 0x1C, 0x21, 0x32, 0x32, 0x32, 0x32, 33 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 34 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 35 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0xFF, 0xC0, 36 | 0x00, 0x11, 0x08, 0x01, 0x40, 0x00, 0xF0, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 37 | 0x01, 0xFF, 0xC4, 0x00, 0x1C, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x00, 0x08, 0xFF, 39 | 0xC4, 0x00, 0x3A, 0x10, 0x00, 0x02, 0x01, 0x03, 0x02, 0x04, 0x05, 0x02, 0x03, 0x07, 0x05, 0x00, 40 | 0x02, 0x03, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x12, 0x21, 0x05, 0x31, 0x41, 0x51, 41 | 0x06, 0x13, 0x22, 0x61, 0x71, 0x32, 0x81, 0x07, 0x91, 0xA1, 0x14, 0x23, 0x42, 0xB1, 0xC1, 0xD1, 42 | 0xF0, 0x15, 0x52, 0x62, 0xE1, 0xF1, 0x16, 0x33, 0x24, 0x72, 0x82, 0xFF, 0xC4, 0x00, 0x19, 0x01, 43 | 0x00, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xFF, 0xC4, 0x00, 0x21, 0x11, 0x01, 0x01, 0x00, 0x02, 0x03, 45 | 0x01, 0x01, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x03, 46 | 0x21, 0x31, 0x12, 0x41, 0x13, 0x04, 0x32, 0x51, 0x22, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 47 | 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0x8E, 0xC2, 0x24, 0x44, 0xCB, 0x0C, 0x7B, 0x0A, 0x9A, 48 | 0x5B, 0x80, 0xA7, 0x03, 0x95, 0x0E, 0x9A, 0xCA, 0x00, 0xA7, 0x48, 0xA7, 0x88, 0x40, 0xDC, 0x9C, 49 | 0x9F, 0x7A, 0xE4, 0x9D, 0x4E, 0x91, 0xCD, 0x28, 0x9C, 0xB2, 0xF2, 0xAF, 0x5B, 0x03, 0xE7, 0x64, 50 | 0xF7, 0xA8, 0xB2, 0x06, 0xC2, 0x8A, 0x81, 0x7D, 0x3A, 0xA9, 0x6C, 0xED, 0x3D, 0x0C, 0x9E, 0x55, 51 | 0x11, 0xE9, 0xE7, 0x55, 0x37, 0x0A, 0x0E, 0xEB, 0xCE, 0xA7, 0x95, 0x8B, 0x3E, 0xF5, 0x13, 0xAE, 52 | 0xD9, 0xCD, 0x3D, 0x34, 0x0F, 0x1A, 0xA8, 0xE9, 0xBF, 0x73, 0x49, 0x28, 0x27, 0x91, 0x38, 0xA5, 53 | 0x32, 0xA2, 0x1D, 0xDB, 0x1F, 0x35, 0x13, 0x5C, 0x07, 0x07, 0x1F, 0x4D, 0x2C, 0x19, 0x8E, 0xCD, 54 | 0x1B, 0x1C, 0x0F, 0xCA, 0x89, 0x8A, 0x15, 0x2A, 0x4B, 0x0A, 0xAE, 0x33, 0x16, 0x98, 0x20, 0xDB, 55 | 0x3D, 0x2A, 0xD0, 0x4A, 0x20, 0x83, 0x51, 0xFA, 0x71, 0x46, 0x4E, 0xD3, 0xBD, 0x29, 0xF8, 0xAD, 56 | 0xB6, 0x01, 0x68, 0xDB, 0x2B, 0xD5, 0x6B, 0x38, 0x6C, 0x99, 0x24, 0x2E, 0xA7, 0xD2, 0x4F, 0x2A, 57 | 0xBC, 0xBD, 0xBE, 0x02, 0x63, 0x83, 0xB1, 0xE9, 0x41, 0x99, 0x91, 0xB9, 0x0E, 0x74, 0x32, 0xCA, 58 | 0x1B, 0x18, 0x82, 0x14, 0xD2, 0x37, 0xA9, 0x83, 0x6F, 0x5E, 0xCE, 0xD8, 0x14, 0xE6, 0x09, 0x14, 59 | 0x45, 0x89, 0x1A, 0xB1, 0xB0, 0x26, 0x96, 0x6F, 0x2E, 0xA2, 0xB0, 0xF3, 0x2A, 0xC0, 0x35, 0x36, 60 | 0x0F, 0xB5, 0x45, 0x35, 0xF2, 0x36, 0x90, 0xA0, 0x26, 0x30, 0x79, 0xF3, 0xAA, 0xAB, 0xAB, 0xC2, 61 | 0x58, 0x86, 0xDB, 0x3C, 0x86, 0x28, 0x2F, 0xDA, 0x0E, 0x82, 0xA0, 0x9F, 0x62, 0x6B, 0xAB, 0x0E, 62 | 0x29, 0x27, 0x62, 0xB4, 0x9E, 0xF1, 0xF3, 0x8D, 0x5B, 0x67, 0x63, 0xDC, 0x52, 0x8E, 0x24, 0xD1, 63 | 0x85, 0x24, 0xEA, 0xD8, 0x9F, 0xBD, 0x53, 0x19, 0x89, 0xC0, 0x63, 0xF1, 0x4E, 0x2C, 0x74, 0x1C, 64 | 0x1D, 0xBA, 0x55, 0xA7, 0x40, 0xD9, 0x59, 0xF1, 0x94, 0x31, 0x69, 0x91, 0x71, 0x9D, 0x8B, 0x55, 65 | 0x90, 0x91, 0x65, 0x42, 0x63, 0x6D, 0xF3, 0x80, 0x33, 0x5C, 0xFB, 0xF6, 0x93, 0x18, 0x0D, 0x9E, 66 | 0x46, 0xAD, 0x6C, 0xB8, 0xA3, 0xAB, 0x8C, 0xB1, 0xC7, 0x53, 0xDF, 0xDA, 0x97, 0x2C, 0x66, 0x53, 67 | 0x46, 0x68, 0xA4, 0x8C, 0xAE, 0xA2, 0xC3, 0xAE, 0xF5, 0x5B, 0x72, 0x4E, 0xAC, 0x8A, 0xB1, 0xF3, 68 | 0xC5, 0xC5, 0xA0, 0x60, 0xDA, 0x54, 0x77, 0x34, 0x1C, 0x88, 0x08, 0xDE, 0xBC, 0xFC, 0xF8, 0xBE, 69 | 0x6B, 0x2B, 0x1E, 0x42, 0x49, 0x19, 0xA6, 0xE3, 0x23, 0x73, 0x52, 0x4E, 0xA1, 0x4E, 0xD5, 0x08, 70 | 0x26, 0xA5, 0xAD, 0x52, 0x58, 0xF1, 0x38, 0x3B, 0x57, 0x88, 0x2D, 0x4A, 0x14, 0xBB, 0x60, 0x0D, 71 | 0xCF, 0x41, 0x5A, 0x8F, 0x0D, 0xF8, 0x1F, 0x8B, 0xF8, 0x89, 0xD1, 0xA0, 0x80, 0xC5, 0x6A, 0xDC, 72 | 0xE7, 0x93, 0x61, 0xF6, 0xA6, 0x98, 0x77, 0xD0, 0x49, 0x6D, 0x66, 0xE0, 0xB5, 0x7B, 0x89, 0x16, 73 | 0x28, 0x91, 0x9E, 0x57, 0x38, 0x55, 0x51, 0xB9, 0x35, 0xD2, 0xBC, 0x2D, 0xF8, 0x4B, 0x3D, 0xE7, 74 | 0x97, 0x75, 0xC5, 0xDC, 0xC3, 0x09, 0x01, 0x95, 0x23, 0x23, 0x57, 0xDF, 0x20, 0x8A, 0xE8, 0x1E, 75 | 0x18, 0xF0, 0x0F, 0x0A, 0xF0, 0xE4, 0x6A, 0xFA, 0x45, 0xCD, 0xD6, 0x06, 0xA9, 0xA4, 0x51, 0xCF, 76 | 0xDB, 0xB5, 0x6B, 0x2B, 0xAB, 0x0E, 0x29, 0xFA, 0xAC, 0xC6, 0x40, 0xB6, 0x1C, 0x36, 0xD3, 0x85, 77 | 0xDA, 0xA5, 0xBD, 0x9D, 0xBC, 0x70, 0xC6, 0x83, 0x00, 0x22, 0x01, 0xFC, 0xA8, 0x93, 0x9A, 0xF1, 78 | 0xDF, 0xAD, 0x26, 0xE3, 0xAD, 0x5B, 0xC1, 0x7C, 0xFF, 0x00, 0x1B, 0x90, 0x06, 0x06, 0xD4, 0xC7, 79 | 0x96, 0x42, 0x7A, 0x28, 0xAF, 0x34, 0xCA, 0x87, 0x4F, 0x5A, 0x66, 0x0B, 0x1C, 0x85, 0x3F, 0x26, 80 | 0xB9, 0x25, 0x43, 0x2A, 0x91, 0x0E, 0xA3, 0x8C, 0xD1, 0xAB, 0x26, 0x84, 0x03, 0x34, 0x24, 0x2A, 81 | 0x14, 0xE4, 0x8A, 0x9C, 0xE1, 0x8E, 0x28, 0xCB, 0x76, 0x13, 0xC3, 0x48, 0x24, 0x96, 0xE9, 0x55, 82 | 0xD7, 0xF7, 0x86, 0x10, 0x71, 0x56, 0xED, 0x84, 0x8B, 0xFA, 0x55, 0x15, 0xE5, 0xB9, 0xBA, 0x62, 83 | 0x50, 0x64, 0x75, 0x14, 0xF4, 0xF8, 0xC0, 0x91, 0x4A, 0x67, 0xF5, 0x31, 0xA4, 0xB9, 0xBE, 0x48, 84 | 0x06, 0x90, 0x72, 0xDD, 0x85, 0x0B, 0x22, 0x4B, 0x6E, 0xC5, 0x08, 0xF8, 0xA8, 0x56, 0x06, 0x91, 85 | 0xC6, 0xA1, 0xB9, 0xA5, 0x5F, 0x1C, 0x3A, 0xEC, 0x77, 0x0C, 0x0F, 0x3C, 0xAD, 0x3B, 0xF2, 0xE9, 86 | 0x4F, 0xBF, 0xE2, 0x45, 0x25, 0x16, 0xDB, 0x90, 0x68, 0xB5, 0x8D, 0x6D, 0x6D, 0x34, 0xF2, 0x0A, 87 | 0x2A, 0x81, 0x95, 0xA7, 0xB8, 0x32, 0x13, 0xD7, 0x6A, 0xD7, 0xA9, 0xD3, 0x9A, 0xCF, 0xAC, 0x8F, 88 | 0x9A, 0x23, 0x26, 0x58, 0x1D, 0xFB, 0xD4, 0x21, 0x4A, 0x9E, 0x75, 0x64, 0xB0, 0x13, 0x1E, 0x4D, 89 | 0x09, 0xE5, 0xE6, 0x5C, 0x01, 0x49, 0x67, 0xE9, 0xA4, 0x49, 0x0A, 0x6A, 0x3B, 0xD0, 0x1C, 0x56, 90 | 0x66, 0x0F, 0xA1, 0x3A, 0x0E, 0xB5, 0x73, 0x14, 0x41, 0x53, 0x56, 0x2B, 0x39, 0xC6, 0x4E, 0x6E, 91 | 0x5D, 0x54, 0xE0, 0xA9, 0xDF, 0x03, 0x19, 0x1D, 0xEA, 0xBF, 0xE3, 0xE3, 0xDE, 0xCC, 0xAD, 0x92, 92 | 0x46, 0xCF, 0xA8, 0x9F, 0x83, 0x50, 0x16, 0xDF, 0x06, 0x9C, 0xDA, 0xCE, 0xC4, 0x93, 0xF3, 0x4D, 93 | 0x08, 0x71, 0x91, 0xBD, 0x75, 0x6C, 0x74, 0x70, 0x25, 0x97, 0x15, 0x2C, 0x59, 0xD5, 0xA0, 0x73, 94 | 0xDF, 0x9D, 0x24, 0x71, 0xEB, 0x2B, 0x83, 0xB9, 0xE6, 0x0D, 0x11, 0x14, 0x41, 0x89, 0x19, 0xDC, 95 | 0x75, 0x34, 0x40, 0xAB, 0x6C, 0xC6, 0x1C, 0x91, 0x91, 0xBE, 0x71, 0x4E, 0x11, 0xB4, 0x44, 0x10, 96 | 0x30, 0xB8, 0xAB, 0x0B, 0x22, 0x46, 0x53, 0x48, 0x21, 0x8E, 0x08, 0xCF, 0x4A, 0x36, 0xE7, 0x86, 97 | 0xBB, 0xDA, 0x1B, 0x91, 0x19, 0x0A, 0x5B, 0x48, 0x04, 0x1C, 0x93, 0xD6, 0x8F, 0x42, 0x83, 0x86, 98 | 0xDF, 0x3A, 0x90, 0xAC, 0xDB, 0x0F, 0xA7, 0x6A, 0xB4, 0x98, 0x16, 0x4F, 0x33, 0xCC, 0xD5, 0x9D, 99 | 0xCE, 0x45, 0x67, 0xED, 0xE2, 0x29, 0x74, 0x55, 0xC3, 0x0D, 0x39, 0xDB, 0xAF, 0xB7, 0xF3, 0x15, 100 | 0xBE, 0xF0, 0xEF, 0x84, 0xB8, 0x8F, 0x1E, 0x78, 0xE3, 0x48, 0xB1, 0x0E, 0xC5, 0xA4, 0xD5, 0xE9, 101 | 0x03, 0xE6, 0xB9, 0xF9, 0xB1, 0xDC, 0x6D, 0x31, 0x92, 0xEA, 0x62, 0x3A, 0xE4, 0xE0, 0x62, 0xB4, 102 | 0x1C, 0x1B, 0xC1, 0x1C, 0x6F, 0x8D, 0x2E, 0xAB, 0x6B, 0x37, 0x09, 0xD1, 0xDC, 0x69, 0x1F, 0x99, 103 | 0xE7, 0x5D, 0xC7, 0x81, 0x78, 0x23, 0x83, 0xF0, 0x58, 0xC6, 0x8B, 0x64, 0x92, 0x4E, 0x7A, 0xE4, 104 | 0x1A, 0x88, 0xAD, 0x2A, 0x22, 0xA2, 0xE9, 0x45, 0x0A, 0x3B, 0x01, 0x51, 0x9C, 0x1B, 0xF4, 0x7E, 105 | 0x63, 0x9E, 0xF8, 0x5F, 0xF0, 0xB7, 0x87, 0xF0, 0x93, 0x1D, 0xD7, 0x10, 0x63, 0x73, 0x74, 0x37, 106 | 0x03, 0x92, 0xA9, 0xF8, 0xEB, 0x5D, 0x09, 0x23, 0x48, 0x90, 0x2C, 0x68, 0x15, 0x7B, 0x01, 0x5E, 107 | 0x24, 0x83, 0x5E, 0xD5, 0x9A, 0xBE, 0x32, 0x63, 0xE0, 0xE8, 0xA6, 0x92, 0xBD, 0x9D, 0xEB, 0xC7, 108 | 0x14, 0xCC, 0xF1, 0x3D, 0x40, 0xA6, 0x12, 0x4E, 0x7F, 0x4A, 0x79, 0xC6, 0x29, 0x09, 0xC0, 0xE5, 109 | 0x4B, 0x46, 0x3E, 0x78, 0x84, 0x17, 0x3A, 0xF4, 0xEF, 0xDC, 0xD4, 0xE6, 0x37, 0x73, 0x92, 0x4D, 110 | 0x5E, 0x37, 0x0C, 0x88, 0xA6, 0x42, 0xE9, 0x3D, 0x85, 0x57, 0x5C, 0x29, 0x85, 0xB4, 0x91, 0x5C, 111 | 0xD8, 0xCD, 0x23, 0x70, 0x0A, 0x13, 0x4E, 0xDF, 0x9D, 0x39, 0xA4, 0x11, 0x8C, 0x9E, 0x54, 0x9A, 112 | 0xC9, 0x39, 0x3C, 0xAA, 0x19, 0x49, 0xE6, 0x0E, 0xDD, 0xA9, 0xFE, 0x42, 0xE3, 0xA2, 0xCB, 0x73, 113 | 0x95, 0xC6, 0x76, 0x34, 0x7D, 0x85, 0xB4, 0x6F, 0x06, 0xA3, 0xD4, 0x6E, 0x6B, 0x3D, 0x70, 0x59, 114 | 0x5B, 0x63, 0xB5, 0x1D, 0xC3, 0x6F, 0x5C, 0x42, 0x51, 0x8F, 0x2E, 0x54, 0x2F, 0x55, 0x6E, 0x3C, 115 | 0x76, 0x03, 0x8B, 0x85, 0x4B, 0x96, 0x02, 0x82, 0xB0, 0xFD, 0xED, 0xD8, 0x1D, 0x13, 0x7A, 0xB3, 116 | 0xBA, 0x87, 0xF6, 0x89, 0xDD, 0xC8, 0xF8, 0xCD, 0x09, 0x0E, 0x88, 0x26, 0x6C, 0x11, 0xAB, 0xAD, 117 | 0x6F, 0x27, 0x66, 0xE6, 0xBA, 0x9A, 0x89, 0x78, 0xA3, 0xE9, 0x83, 0x48, 0xE6, 0x6A, 0xBE, 0xD6, 118 | 0x22, 0x58, 0x60, 0x66, 0xA7, 0xBB, 0xB8, 0x12, 0x4C, 0x01, 0xED, 0x45, 0xD9, 0x22, 0x02, 0x01, 119 | 0x1B, 0x53, 0xD9, 0x2B, 0x9F, 0x19, 0xD2, 0x53, 0x09, 0x58, 0xB9, 0x74, 0xDE, 0xAB, 0xCC, 0x00, 120 | 0x31, 0x61, 0xB5, 0x5C, 0x5D, 0x48, 0xA9, 0x09, 0x20, 0xD5, 0x54, 0x72, 0x79, 0xB2, 0x60, 0xF2, 121 | 0xA9, 0xE5, 0xA9, 0xD1, 0xCC, 0xD4, 0x4B, 0x05, 0xD5, 0x81, 0xEE, 0x71, 0x54, 0x1C, 0x6E, 0xDC, 122 | 0xA5, 0xCF, 0x98, 0xAD, 0xF5, 0x0E, 0x43, 0xA5, 0x68, 0xEE, 0xA3, 0xD3, 0x18, 0x20, 0x61, 0xAA, 123 | 0xBF, 0x8B, 0xC6, 0x93, 0x70, 0xD5, 0x60, 0xA3, 0x5A, 0xF3, 0x23, 0x6A, 0xA7, 0x0F, 0x55, 0x99, 124 | 0x48, 0xF2, 0x5C, 0xAE, 0x74, 0xEA, 0xDB, 0x7D, 0xBF, 0xCE, 0x55, 0x24, 0x70, 0x33, 0x0C, 0x83, 125 | 0x8C, 0xF4, 0xC5, 0x79, 0x55, 0x9A, 0x40, 0xA0, 0x86, 0x3D, 0xB3, 0xFD, 0xEB, 0x49, 0xE1, 0xFF, 126 | 0x00, 0x0F, 0x4D, 0xC5, 0x6F, 0x22, 0x81, 0x11, 0xFD, 0x60, 0x91, 0x85, 0xC8, 0xFB, 0xE3, 0x95, 127 | 0x74, 0x8A, 0xA2, 0xDE, 0xC9, 0xE7, 0xD6, 0xAB, 0x1B, 0x33, 0xAA, 0xE7, 0x09, 0xCF, 0xFC, 0xDF, 128 | 0x35, 0xAD, 0xF0, 0x87, 0x81, 0x9F, 0x8D, 0xDC, 0x69, 0xB9, 0x72, 0x91, 0xE3, 0x07, 0x03, 0x07, 129 | 0x71, 0xB1, 0x1F, 0x15, 0xD5, 0x78, 0x2F, 0xE1, 0xE5, 0xB4, 0x10, 0xDB, 0xBB, 0xC0, 0x9E, 0x6C, 130 | 0x7C, 0x98, 0xAE, 0xE4, 0x76, 0x3D, 0x3B, 0xD6, 0xCA, 0xD3, 0x83, 0xDA, 0x58, 0xA0, 0x10, 0xC2, 131 | 0xA9, 0x83, 0x9C, 0x28, 0xC5, 0x2D, 0xCB, 0xFE, 0x1A, 0x46, 0x3F, 0x83, 0x7E, 0x1E, 0xF0, 0xFB, 132 | 0x28, 0x11, 0x24, 0x85, 0x24, 0xC0, 0xC3, 0x9C, 0x6C, 0xD8, 0xE4, 0x77, 0xAD, 0x0A, 0xF8, 0x5F, 133 | 0x86, 0x98, 0x7C, 0xA7, 0xB6, 0x8D, 0xA3, 0xE8, 0xA5, 0x79, 0x0F, 0xFC, 0xAB, 0xD0, 0xA0, 0x6C, 134 | 0x06, 0x29, 0x84, 0xE3, 0xAF, 0xCD, 0x4E, 0xD3, 0xC8, 0xCF, 0xAF, 0x81, 0x7C, 0x38, 0xB2, 0xBC, 135 | 0xDF, 0xE9, 0x50, 0x34, 0x8E, 0x49, 0x2E, 0x46, 0xF9, 0x35, 0x7B, 0x6F, 0x0C, 0x36, 0x70, 0xAC, 136 | 0x50, 0x44, 0xB1, 0xC6, 0xBC, 0x82, 0x8C, 0x52, 0x89, 0x29, 0x0C, 0x83, 0x34, 0xBB, 0x37, 0xCA, 137 | 0x7F, 0x34, 0xD7, 0xBC, 0xDE, 0xF4, 0x31, 0x71, 0xB9, 0xDA, 0xA9, 0x3C, 0x45, 0xE2, 0x5B, 0x4E, 138 | 0x05, 0xC3, 0xA6, 0x9E, 0x69, 0x54, 0x3A, 0x21, 0x60, 0xA4, 0xEE, 0x6B, 0x7D, 0xD6, 0xF8, 0x68, 139 | 0x24, 0xBA, 0x8A, 0x35, 0x2C, 0xCE, 0x00, 0x03, 0x27, 0x7A, 0x1F, 0xFD, 0x56, 0xD1, 0x94, 0xB0, 140 | 0x9D, 0x0A, 0x8D, 0xC9, 0xD5, 0xD2, 0xBE, 0x72, 0xE3, 0x5F, 0x8A, 0x97, 0xF3, 0x71, 0x1B, 0xD7, 141 | 0xB6, 0x25, 0x22, 0x9B, 0xD0, 0xAB, 0x9E, 0x4B, 0x8F, 0x6F, 0xBD, 0x67, 0x7F, 0xF9, 0xBF, 0x11, 142 | 0x8C, 0x3A, 0xC3, 0x33, 0x28, 0x92, 0x01, 0x13, 0x82, 0x7B, 0x0C, 0x6D, 0xDB, 0x6A, 0x7D, 0x52, 143 | 0xEF, 0x18, 0xFA, 0x9C, 0x78, 0x8F, 0x87, 0x00, 0x75, 0x5C, 0x46, 0xA4, 0x30, 0x4C, 0x67, 0xA9, 144 | 0xA2, 0xA2, 0xE2, 0x96, 0x93, 0x2E, 0xA4, 0x99, 0x19, 0x71, 0xA8, 0x90, 0x7A, 0x77, 0xAF, 0x8F, 145 | 0xA3, 0xF1, 0x57, 0x10, 0x8E, 0xE2, 0x39, 0x4C, 0xEC, 0xDE, 0x5B, 0x33, 0x2A, 0x9D, 0xC0, 0x26, 146 | 0xAD, 0xF8, 0x4F, 0x8E, 0xAF, 0xEC, 0xE3, 0x58, 0x9E, 0xE5, 0xBC, 0xA2, 0xC1, 0x9B, 0xDF, 0x1F, 147 | 0x4E, 0x7E, 0x39, 0xE2, 0x8F, 0xCD, 0x81, 0xBC, 0x6B, 0xEB, 0x05, 0xB8, 0x46, 0x50, 0xCA, 0x41, 148 | 0x06, 0xBC, 0x64, 0x07, 0x91, 0xFB, 0x57, 0x09, 0xE0, 0x9F, 0x89, 0xF2, 0xC3, 0x13, 0x3D, 0xC9, 149 | 0x24, 0x31, 0x0B, 0x1C, 0x61, 0xB7, 0xC7, 0xFC, 0x89, 0xEA, 0x7F, 0x95, 0x74, 0xBE, 0x13, 0xE2, 150 | 0x9B, 0x7B, 0xD8, 0x22, 0x46, 0x95, 0x1A, 0xE5, 0xFE, 0xA8, 0x94, 0xFD, 0x34, 0x97, 0x70, 0xF2, 151 | 0x4B, 0xE3, 0x01, 0x65, 0xC6, 0x92, 0x67, 0xF2, 0xE4, 0x6F, 0x51, 0x34, 0xCE, 0x2D, 0x75, 0x11, 152 | 0x00, 0x9C, 0x0C, 0x56, 0x22, 0xDD, 0xA5, 0x17, 0x0A, 0xC1, 0x8E, 0x47, 0xE9, 0x57, 0xF1, 0xDB, 153 | 0x49, 0x77, 0x6E, 0x1A, 0x52, 0x73, 0x8A, 0x9C, 0x97, 0x7A, 0x47, 0x7D, 0x68, 0xF5, 0xB8, 0x1E, 154 | 0x59, 0x20, 0xE7, 0x3C, 0xA9, 0xC9, 0x26, 0x41, 0x27, 0xEF, 0x50, 0x45, 0x1E, 0x8C, 0xA3, 0x74, 155 | 0x34, 0xDB, 0x86, 0x01, 0x59, 0x41, 0xC1, 0xA6, 0xAD, 0x87, 0xFE, 0xA9, 0x92, 0x62, 0x42, 0x71, 156 | 0x4E, 0xB5, 0xC4, 0x6E, 0x72, 0x6A, 0x38, 0xBE, 0x9D, 0xEA, 0x1B, 0x89, 0xCC, 0x3B, 0x81, 0x49, 157 | 0x7D, 0x74, 0x61, 0x35, 0x05, 0x5E, 0x4A, 0x16, 0x33, 0xA4, 0xF5, 0xDA, 0xAB, 0x2D, 0x89, 0xD4, 158 | 0xCC, 0x77, 0x2D, 0xCC, 0x9A, 0x69, 0xBA, 0x69, 0x07, 0xA8, 0x6D, 0x43, 0x06, 0x61, 0x2E, 0xD9, 159 | 0xC7, 0xB5, 0x3D, 0xC7, 0x71, 0x1E, 0x5E, 0xC4, 0xCB, 0x09, 0x69, 0x4B, 0x03, 0xE9, 0xCD, 0x19, 160 | 0x03, 0x68, 0x50, 0x33, 0xD2, 0x82, 0x32, 0x04, 0x5C, 0x62, 0xA4, 0x8F, 0x5B, 0x28, 0x6C, 0x6D, 161 | 0x4B, 0x75, 0x12, 0x94, 0xFB, 0x9B, 0x87, 0x76, 0xD2, 0x06, 0xD4, 0x96, 0xB1, 0x92, 0xEA, 0xD9, 162 | 0xC1, 0xA9, 0xFF, 0x00, 0x66, 0xFD, 0xD9, 0x24, 0xEF, 0xCE, 0xA3, 0x8D, 0xB4, 0xE4, 0x11, 0xCA, 163 | 0xA7, 0x7B, 0xA3, 0xB4, 0x97, 0x4F, 0x88, 0xF4, 0x31, 0xCB, 0x50, 0xF0, 0x05, 0x74, 0x78, 0xDC, 164 | 0x02, 0xAC, 0x39, 0x1A, 0x90, 0x8F, 0x35, 0x89, 0x22, 0xB4, 0x7E, 0x18, 0xF0, 0x95, 0xD7, 0x1E, 165 | 0x94, 0x88, 0x57, 0x44, 0x4B, 0xF5, 0x4A, 0xC3, 0x6A, 0xA7, 0x7B, 0xE8, 0x64, 0x67, 0xFC, 0x37, 166 | 0xE0, 0xFB, 0x8E, 0x2D, 0xC4, 0x9A, 0xDA, 0x05, 0x18, 0xCE, 0xE4, 0xAE, 0xCA, 0x33, 0xD4, 0xE3, 167 | 0xB5, 0x77, 0xEF, 0x0F, 0x78, 0x53, 0x86, 0xF8, 0x7E, 0x12, 0x2D, 0xA0, 0x55, 0x91, 0xB1, 0xAD, 168 | 0xBB, 0x9F, 0xE9, 0x46, 0x70, 0x4E, 0x07, 0x69, 0xC0, 0xEC, 0x92, 0xDE, 0xDD, 0x72, 0x40, 0xC1, 169 | 0x91, 0x80, 0xD4, 0x7E, 0xF5, 0x66, 0x6B, 0xA7, 0xBD, 0x76, 0x62, 0x6C, 0x06, 0xC2, 0x9A, 0xCF, 170 | 0x81, 0xCA, 0x98, 0xF2, 0x63, 0x6F, 0xEB, 0x50, 0xBC, 0x8C, 0x06, 0xD8, 0xF6, 0xC1, 0xA4, 0xB9, 171 | 0x1A, 0x63, 0xB3, 0x9D, 0xCE, 0xE4, 0x9C, 0x0F, 0x6A, 0x84, 0xB9, 0x3C, 0x85, 0x46, 0x72, 0x4E, 172 | 0x5F, 0x3F, 0x63, 0x51, 0xBB, 0x80, 0x32, 0x07, 0xC6, 0x6A, 0x37, 0x25, 0xA6, 0x29, 0x0B, 0xEE, 173 | 0x49, 0x3F, 0x6A, 0x4F, 0x30, 0xE7, 0x6A, 0x80, 0x16, 0x7C, 0x90, 0x30, 0x6B, 0xC4, 0x1D, 0x89, 174 | 0x3F, 0x71, 0x4B, 0x69, 0xF4, 0x74, 0xF2, 0xAC, 0x10, 0xB4, 0xB2, 0x36, 0x14, 0x0C, 0x93, 0x5F, 175 | 0x36, 0xFE, 0x27, 0x78, 0xB5, 0xB8, 0xD7, 0x1A, 0x30, 0xC2, 0xDF, 0xB9, 0x83, 0x29, 0x91, 0xD6, 176 | 0xBA, 0xAF, 0xE2, 0x8F, 0x19, 0x97, 0x85, 0xF8, 0x5D, 0xFC, 0xA9, 0x5A, 0x39, 0x24, 0x6D, 0x2A, 177 | 0xC3, 0xB7, 0x51, 0xEF, 0x5F, 0x35, 0x4C, 0xEC, 0xEE, 0x58, 0xEE, 0x49, 0xAB, 0x71, 0x63, 0xD6, 178 | 0xD1, 0xE5, 0xBA, 0xE8, 0x85, 0x8B, 0x01, 0xBD, 0x33, 0x3B, 0xF3, 0xA5, 0xCE, 0x57, 0x7A, 0x63, 179 | 0x1A, 0xBA, 0x05, 0x27, 0x34, 0xAA, 0xC4, 0x0D, 0xB9, 0xD4, 0x62, 0x9E, 0xA3, 0x3C, 0xCD, 0x60, 180 | 0x15, 0x14, 0xCD, 0x18, 0x04, 0x1C, 0x56, 0xCF, 0xC2, 0x3C, 0x7A, 0xF6, 0x1B, 0xD4, 0x44, 0x9D, 181 | 0x60, 0x88, 0x80, 0x65, 0x94, 0xF4, 0x51, 0xFC, 0xBF, 0x95, 0x61, 0x54, 0xE4, 0xE0, 0x55, 0x95, 182 | 0xA7, 0x9B, 0x03, 0x06, 0x52, 0x06, 0x39, 0x12, 0x73, 0xF9, 0x0A, 0x16, 0x6E, 0x1B, 0x1B, 0xAA, 183 | 0xDA, 0xEC, 0xB2, 0x7A, 0x70, 0x37, 0xAB, 0xFB, 0x2B, 0xA5, 0x36, 0xAA, 0xA4, 0xEE, 0x2B, 0x37, 184 | 0x00, 0x33, 0x39, 0x24, 0x11, 0xBF, 0x3A, 0xB7, 0x88, 0x84, 0x50, 0x0D, 0x46, 0xCB, 0xB4, 0xF7, 185 | 0xA1, 0xA6, 0x3D, 0x99, 0x87, 0xBD, 0x00, 0xC0, 0x92, 0x4B, 0x6F, 0xBD, 0x14, 0xD7, 0x20, 0x45, 186 | 0xBF, 0x2A, 0x08, 0x6B, 0x76, 0x62, 0xA7, 0x6A, 0x4C, 0xAE, 0x95, 0xE3, 0x85, 0x12, 0x22, 0x1C, 187 | 0x11, 0xB5, 0x47, 0x2A, 0x87, 0x19, 0xE9, 0x50, 0x4E, 0x92, 0x2B, 0xE3, 0x34, 0xE2, 0xC7, 0xCB, 188 | 0xC1, 0x04, 0x1A, 0x58, 0xE9, 0xF2, 0x68, 0x23, 0x60, 0x31, 0x51, 0x52, 0x45, 0x16, 0x58, 0x77, 189 | 0xA6, 0x88, 0xC8, 0x60, 0x4D, 0x11, 0x18, 0x23, 0xD5, 0xA7, 0x6A, 0xAD, 0xEA, 0x38, 0xF3, 0xF5, 190 | 0x14, 0xB0, 0x92, 0x41, 0x07, 0x6E, 0xB4, 0x42, 0xC9, 0x1A, 0x26, 0x41, 0xDF, 0x1C, 0xA9, 0x85, 191 | 0xF5, 0x36, 0x00, 0xA6, 0xBC, 0x2E, 0xD8, 0x2A, 0xA5, 0xBB, 0xE2, 0xA1, 0x74, 0x5D, 0x27, 0x5B, 192 | 0x90, 0xF8, 0x18, 0xC5, 0x3C, 0xE8, 0x2A, 0x4A, 0x8C, 0x1A, 0x1E, 0x3B, 0x79, 0x1C, 0x65, 0x46, 193 | 0x31, 0xDE, 0xB6, 0xDE, 0x03, 0xF0, 0x63, 0x71, 0xBB, 0x81, 0x7B, 0x7C, 0x24, 0x16, 0x91, 0xB6, 194 | 0xC0, 0xAE, 0x04, 0x87, 0xB6, 0x68, 0x49, 0x6D, 0xD4, 0x34, 0xEC, 0x0F, 0x85, 0xBC, 0x1D, 0x77, 195 | 0xC7, 0xAF, 0x90, 0x37, 0xEE, 0xED, 0x06, 0x19, 0xE5, 0x5C, 0x30, 0x23, 0xB6, 0x46, 0xD9, 0xAE, 196 | 0xDD, 0xC3, 0x38, 0x55, 0x97, 0x07, 0xB4, 0x16, 0xD6, 0x50, 0xAC, 0x51, 0xF3, 0x38, 0xEA, 0x7B, 197 | 0x9A, 0x9E, 0xDE, 0xD6, 0x0B, 0x38, 0x16, 0x1B, 0x78, 0x92, 0x28, 0x97, 0x92, 0xA2, 0x80, 0x07, 198 | 0xE5, 0x4E, 0x79, 0x02, 0xF5, 0xFC, 0xAB, 0xAB, 0x1C, 0x66, 0x3E, 0x9E, 0x43, 0xD9, 0x82, 0x8C, 199 | 0x93, 0x50, 0x3C, 0xA0, 0xE4, 0x6F, 0x9E, 0x82, 0xA2, 0x69, 0x59, 0x9B, 0x39, 0xDB, 0xE2, 0x93, 200 | 0x49, 0xC7, 0xD4, 0x77, 0xEB, 0x8A, 0x17, 0x2D, 0xA9, 0x31, 0x79, 0x99, 0xB2, 0x39, 0x63, 0xE6, 201 | 0xA2, 0x25, 0x8E, 0x70, 0x70, 0x29, 0x5D, 0x8A, 0x0F, 0x49, 0x03, 0xDA, 0xA3, 0x0C, 0xCE, 0x76, 202 | 0xFA, 0x73, 0xCA, 0xA7, 0x54, 0x91, 0xED, 0x05, 0xB9, 0xB6, 0x3D, 0xC5, 0x23, 0x2E, 0x8C, 0x65, 203 | 0xFF, 0x00, 0x31, 0x52, 0xEA, 0x25, 0x88, 0xC6, 0x3E, 0x69, 0xB8, 0x08, 0x0B, 0x36, 0xE7, 0xDE, 204 | 0x97, 0x43, 0xB3, 0x4E, 0x92, 0x06, 0x91, 0x8A, 0x67, 0xD2, 0xDA, 0x98, 0x02, 0x31, 0xF3, 0x4C, 205 | 0x92, 0x56, 0x3C, 0x86, 0x7B, 0x76, 0xA6, 0x23, 0x82, 0xE0, 0x36, 0xD8, 0x3C, 0xC1, 0xEB, 0x40, 206 | 0x5C, 0xA3, 0xF1, 0xBE, 0x60, 0xDC, 0x26, 0xCE, 0x35, 0x1B, 0x79, 0x99, 0xDC, 0x63, 0x15, 0xC1, 207 | 0xCE, 0x79, 0x57, 0xD0, 0x3F, 0x8E, 0x48, 0xCF, 0xE1, 0xFB, 0x47, 0x0C, 0x34, 0xA4, 0xBB, 0x02, 208 | 0x37, 0xCE, 0x3F, 0x4A, 0xF9, 0xF8, 0x83, 0x5D, 0x3C, 0x7F, 0xEA, 0xE7, 0xE4, 0xF5, 0x1B, 0x11, 209 | 0x8E, 0x54, 0xCD, 0xCF, 0x2A, 0x7B, 0x0C, 0x1A, 0x67, 0x4C, 0xF5, 0xAA, 0x24, 0x5D, 0xC6, 0x29, 210 | 0xEA, 0xB9, 0x14, 0xD5, 0xED, 0x8D, 0xFB, 0xD3, 0x84, 0x4D, 0xCC, 0x7E, 0x95, 0x98, 0xF5, 0x61, 211 | 0x19, 0xC6, 0x37, 0xF7, 0xA9, 0x83, 0x16, 0x23, 0x0C, 0x40, 0xA8, 0xE3, 0x94, 0xA8, 0x28, 0xE0, 212 | 0x32, 0x37, 0x3C, 0x8D, 0xFE, 0xC7, 0xA5, 0x49, 0xE4, 0xA1, 0xDD, 0x18, 0x9F, 0x93, 0x58, 0x5D, 213 | 0x36, 0xDF, 0x4A, 0xA0, 0x3C, 0xF6, 0xAF, 0x45, 0x28, 0x92, 0xE0, 0x29, 0xF7, 0xE5, 0x40, 0xDB, 214 | 0x89, 0x4C, 0x63, 0x9E, 0x33, 0x46, 0xD9, 0xDB, 0x32, 0xCC, 0x5C, 0xF4, 0x15, 0x1B, 0xC9, 0xAD, 215 | 0x42, 0x49, 0xDF, 0x62, 0x27, 0x88, 0xB6, 0x02, 0xF2, 0xA9, 0x60, 0x88, 0x2E, 0x7A, 0x1A, 0x46, 216 | 0x90, 0x2E, 0x32, 0x3A, 0xFE, 0x94, 0x89, 0x30, 0x66, 0x23, 0x18, 0xDB, 0x9D, 0x4F, 0x3D, 0x55, 217 | 0xF8, 0xFD, 0x7A, 0xE2, 0x35, 0x63, 0x8C, 0x55, 0x7C, 0xCA, 0xDD, 0x0E, 0xC2, 0x8E, 0x77, 0xEF, 218 | 0x4E, 0x31, 0x2B, 0xC0, 0x49, 0x14, 0x22, 0xD9, 0xDD, 0x45, 0x40, 0x72, 0x76, 0x23, 0x14, 0x50, 219 | 0x65, 0x09, 0xB1, 0xE9, 0xCA, 0xAB, 0xE7, 0x98, 0xAC, 0x8D, 0x8F, 0x8A, 0x9A, 0xDC, 0xB3, 0x26, 220 | 0x48, 0xDA, 0x9B, 0xEE, 0x5E, 0x9C, 0x79, 0x1C, 0xAC, 0xCA, 0xE5, 0xB1, 0xB5, 0x5D, 0x58, 0x94, 221 | 0x6B, 0x41, 0x87, 0x50, 0xD9, 0xC9, 0x06, 0xA9, 0x18, 0x86, 0x6D, 0x2A, 0x77, 0xED, 0x45, 0x5A, 222 | 0x5B, 0x4D, 0x73, 0x32, 0x5B, 0xC1, 0x1B, 0xBC, 0xAE, 0x42, 0x85, 0x5E, 0xB5, 0x1D, 0x6B, 0x2E, 223 | 0x83, 0xB6, 0x9B, 0x81, 0xF0, 0x57, 0xE3, 0xF7, 0xC2, 0x0B, 0x46, 0x8C, 0x04, 0x23, 0x59, 0x2D, 224 | 0xB8, 0x1D, 0xF1, 0xFF, 0x00, 0x95, 0xDA, 0xF8, 0x77, 0x0F, 0x83, 0x85, 0x58, 0x47, 0x6B, 0x6E, 225 | 0x08, 0x44, 0x1D, 0x4E, 0x49, 0xAA, 0xFF, 0x00, 0x0A, 0xF0, 0x7F, 0xF4, 0x4E, 0x01, 0x6F, 0x6E, 226 | 0xD1, 0xA2, 0x4D, 0xA7, 0x54, 0x9A, 0x7F, 0xDC, 0x7D, 0xF0, 0x3F, 0x95, 0x59, 0xC8, 0x4E, 0x09, 227 | 0xC9, 0xFB, 0x0A, 0xE8, 0xC6, 0x7C, 0xC5, 0x71, 0xC4, 0xB2, 0x33, 0x32, 0xEC, 0xDA, 0x7D, 0xE8, 228 | 0x72, 0x54, 0xB6, 0x47, 0xE7, 0x4C, 0x91, 0xB5, 0x1D, 0x23, 0xD5, 0xDF, 0x3B, 0x62, 0xA3, 0x2D, 229 | 0xA4, 0x85, 0x09, 0xB7, 0xCF, 0x5F, 0x9A, 0x16, 0xED, 0x69, 0x34, 0x94, 0xCB, 0x86, 0xC0, 0x27, 230 | 0x6E, 0x78, 0x15, 0x17, 0xED, 0x4A, 0x4E, 0xC5, 0x88, 0x1D, 0x01, 0xDE, 0x87, 0x96, 0x64, 0xC6, 231 | 0x92, 0xF8, 0x24, 0xEE, 0x46, 0xF4, 0x33, 0x0C, 0x1C, 0x89, 0x14, 0x47, 0x9E, 0x6C, 0x2A, 0x77, 232 | 0x23, 0xC8, 0x37, 0xCC, 0xF3, 0xA4, 0x5D, 0x27, 0x4F, 0x32, 0x41, 0x18, 0xCD, 0x4B, 0xF4, 0x26, 233 | 0xED, 0xF1, 0x8A, 0x0D, 0x14, 0x64, 0xB3, 0x13, 0x9C, 0x73, 0xC7, 0x4A, 0x35, 0x40, 0x05, 0x71, 234 | 0xBE, 0x79, 0x91, 0x46, 0x01, 0x00, 0xC3, 0x6B, 0x23, 0x1F, 0x1F, 0xD4, 0xD4, 0x1A, 0xD9, 0xC3, 235 | 0x1D, 0xB1, 0xD1, 0xBD, 0xEA, 0x77, 0x3A, 0xC1, 0xDC, 0x00, 0x7A, 0x50, 0x73, 0xB3, 0xE0, 0x29, 236 | 0x24, 0x2F, 0x6E, 0x54, 0x28, 0xC4, 0x37, 0x17, 0x21, 0x48, 0x45, 0x66, 0x20, 0x0D, 0xDF, 0x1B, 237 | 0x0A, 0x9A, 0x29, 0x0B, 0x05, 0x03, 0x73, 0xD8, 0x74, 0x1D, 0xEA, 0xBE, 0x40, 0x24, 0xB9, 0x50, 238 | 0x5F, 0x4A, 0x83, 0xF4, 0xAA, 0xFF, 0x00, 0x99, 0xA2, 0x6D, 0xB2, 0xCC, 0xC5, 0xCE, 0x09, 0x63, 239 | 0xA4, 0x73, 0xA1, 0x0C, 0xE6, 0x7F, 0x8D, 0x33, 0xC4, 0xFC, 0x32, 0xDE, 0x12, 0x8A, 0x59, 0x5C, 240 | 0xE1, 0x89, 0xDC, 0x1E, 0xD8, 0xAE, 0x0E, 0xED, 0x83, 0xB0, 0xAE, 0xC5, 0xF8, 0xB9, 0x03, 0x9B, 241 | 0xF8, 0x9B, 0x04, 0x8C, 0x1C, 0x03, 0xFE, 0x7C, 0xD7, 0x1E, 0x9D, 0x40, 0x6C, 0x81, 0x81, 0x5D, 242 | 0x58, 0x75, 0x1C, 0xB9, 0xFA, 0x89, 0xB9, 0xE4, 0x53, 0x47, 0x3D, 0xCD, 0x2A, 0x82, 0x4F, 0x61, 243 | 0x4A, 0x42, 0x86, 0xF4, 0xB6, 0x69, 0xC9, 0xA3, 0x40, 0x3A, 0xAA, 0x51, 0x23, 0x63, 0x03, 0x6C, 244 | 0x53, 0x30, 0x4F, 0x5C, 0x0A, 0x5C, 0xFA, 0x80, 0x1C, 0xAB, 0x6D, 0x92, 0x89, 0x86, 0xEA, 0xC0, 245 | 0x6F, 0x5E, 0x00, 0x83, 0x95, 0xCE, 0x2A, 0x3F, 0x2C, 0x9C, 0xED, 0x91, 0x52, 0x21, 0x65, 0x5D, 246 | 0x38, 0xCF, 0xBD, 0x10, 0x74, 0xE5, 0x2B, 0x10, 0x51, 0x9F, 0xB5, 0x1F, 0x14, 0x8B, 0xE5, 0x9C, 247 | 0x01, 0xB8, 0xAA, 0xC7, 0x8C, 0xBB, 0x02, 0x79, 0x54, 0xB6, 0xAD, 0xA0, 0x15, 0x07, 0x3B, 0xEF, 248 | 0x5C, 0x39, 0x72, 0x4F, 0xAD, 0x16, 0x16, 0x46, 0x26, 0x4D, 0x23, 0x9F, 0x2A, 0x2A, 0x35, 0x54, 249 | 0x4C, 0xB7, 0x3E, 0xB4, 0x3C, 0x63, 0xCC, 0xB9, 0xC1, 0x3B, 0x0A, 0x9A, 0xE1, 0x8A, 0xC3, 0x80, 250 | 0x29, 0xFA, 0xD6, 0xD6, 0xE3, 0xEC, 0x8D, 0x89, 0x36, 0xC8, 0xDA, 0xA7, 0x62, 0xA9, 0x68, 0x01, 251 | 0xE7, 0x8A, 0xA9, 0x8E, 0x42, 0x1C, 0xF7, 0x35, 0x34, 0xF2, 0xB0, 0x88, 0x83, 0x42, 0x7F, 0xD0, 252 | 0xCB, 0x2E, 0xF4, 0x12, 0x3B, 0x51, 0x3D, 0xC1, 0xD5, 0x9C, 0x67, 0x35, 0x6B, 0x25, 0xB2, 0xC3, 253 | 0x6F, 0x95, 0xDC, 0x11, 0x55, 0x96, 0xD7, 0x05, 0x64, 0xDB, 0x7E, 0x9B, 0xD1, 0x73, 0x4C, 0x64, 254 | 0x8F, 0x49, 0xC8, 0x15, 0x39, 0x3A, 0x4A, 0xFA, 0xAD, 0x89, 0x80, 0x95, 0xF5, 0x1F, 0xBD, 0x74, 255 | 0xBF, 0xC2, 0xCE, 0x18, 0xB7, 0xBC, 0x4E, 0x6B, 0xF7, 0x0D, 0xA2, 0x01, 0x84, 0x3B, 0x60, 0x93, 256 | 0xF6, 0xAE, 0x6E, 0xB1, 0xE6, 0x50, 0x07, 0x22, 0x77, 0xAF, 0xA3, 0xBC, 0x2F, 0xC3, 0xA3, 0xE1, 257 | 0x7C, 0x02, 0xDA, 0x24, 0x04, 0x12, 0x80, 0xB6, 0x40, 0xC8, 0x3D, 0xB6, 0x02, 0x9F, 0x87, 0x1D, 258 | 0xF6, 0x7C, 0x62, 0xD6, 0x49, 0x37, 0xC6, 0x32, 0x05, 0x07, 0x34, 0xD9, 0x3A, 0x22, 0x19, 0x6C, 259 | 0xF5, 0x3B, 0x0A, 0x9E, 0x57, 0x24, 0x9D, 0x8F, 0xB5, 0x09, 0x29, 0x55, 0x42, 0x09, 0x6E, 0xC3, 260 | 0x49, 0xFE, 0xB5, 0x5C, 0x96, 0xC6, 0x3C, 0xCE, 0xCA, 0xA0, 0x6A, 0x8F, 0x27, 0x99, 0x19, 0xFD, 261 | 0x31, 0x43, 0x5C, 0x92, 0x23, 0xC6, 0xE4, 0x91, 0xB6, 0x4E, 0x3F, 0x31, 0x48, 0xD3, 0x84, 0x01, 262 | 0x4B, 0x9C, 0x7B, 0x7F, 0x53, 0x41, 0xCF, 0x24, 0xF2, 0x49, 0xFB, 0xB3, 0xE9, 0xD5, 0xBE, 0x79, 263 | 0xE3, 0xB8, 0xFE, 0xD5, 0x3B, 0x54, 0x91, 0xE4, 0x09, 0x8C, 0x33, 0x61, 0x80, 0xF5, 0x22, 0xE7, 264 | 0x4D, 0x38, 0xBA, 0x2B, 0x0C, 0x28, 0x19, 0x18, 0x18, 0x4F, 0xEF, 0xCA, 0xA1, 0x88, 0x1C, 0xE4, 265 | 0xBB, 0x15, 0x1C, 0x97, 0x3B, 0xB7, 0xDE, 0xA4, 0x8D, 0x65, 0x42, 0x5D, 0x8F, 0xEF, 0x09, 0x2B, 266 | 0x91, 0xCB, 0xE3, 0xDE, 0x90, 0xE3, 0x61, 0x96, 0x34, 0x0C, 0x08, 0x3D, 0xC9, 0x61, 0xB7, 0xFD, 267 | 0xD4, 0xAB, 0x22, 0xB8, 0x62, 0x49, 0x04, 0xE3, 0x07, 0x1C, 0xFE, 0x05, 0x04, 0xDE, 0x76, 0x02, 268 | 0xAE, 0x08, 0xD8, 0x6A, 0x6D, 0x87, 0xBE, 0x28, 0xB0, 0x88, 0xD8, 0x38, 0xD5, 0xE9, 0xCE, 0x7D, 269 | 0xA9, 0xE1, 0x0A, 0xF2, 0x12, 0x30, 0xA3, 0x56, 0x39, 0xE3, 0x60, 0x28, 0x4B, 0x87, 0x12, 0xA2, 270 | 0x07, 0xC2, 0x93, 0x8C, 0x62, 0x88, 0x08, 0x06, 0x95, 0x1A, 0x98, 0x6E, 0x4E, 0xFB, 0x50, 0x8E, 271 | 0x52, 0x59, 0x18, 0x63, 0x51, 0x53, 0xB6, 0x3A, 0xD6, 0xA2, 0x45, 0x44, 0xD4, 0xD2, 0xB7, 0x25, 272 | 0x3B, 0xEA, 0xDC, 0x93, 0xDA, 0x9F, 0x13, 0x16, 0x0A, 0xE3, 0x2B, 0x83, 0x8C, 0x7F, 0x9F, 0x6A, 273 | 0x53, 0x6E, 0x02, 0x3E, 0xB7, 0xDB, 0x3B, 0x8F, 0x9A, 0x86, 0x45, 0x67, 0x68, 0x53, 0x50, 0x53, 274 | 0xB9, 0x63, 0x8A, 0x02, 0xE7, 0x1F, 0x8A, 0x96, 0x0E, 0xFC, 0x3A, 0x49, 0x55, 0xB3, 0xA5, 0x43, 275 | 0x6C, 0x39, 0x6F, 0x5C, 0x39, 0xE3, 0xD4, 0xA0, 0x81, 0x5F, 0x42, 0xFE, 0x25, 0x26, 0xBE, 0x0C, 276 | 0xF0, 0x28, 0x2C, 0xD2, 0x7A, 0x7D, 0x23, 0x24, 0x57, 0x22, 0xFF, 0x00, 0x4D, 0x1F, 0xB3, 0xC7, 277 | 0x18, 0x4C, 0x38, 0xF6, 0xDC, 0x0C, 0x55, 0xF1, 0xCA, 0x4C, 0x7B, 0x47, 0x2C, 0x6D, 0xAC, 0xAA, 278 | 0xDB, 0x93, 0x92, 0x00, 0xCF, 0x6A, 0x87, 0xC8, 0x65, 0x72, 0x31, 0xB9, 0xE8, 0x0D, 0x68, 0xE4, 279 | 0xB3, 0x56, 0x62, 0xA1, 0x88, 0x20, 0xF3, 0x22, 0xA2, 0x82, 0xC4, 0xA9, 0x77, 0xD3, 0xE9, 0x07, 280 | 0x72, 0xC3, 0x73, 0xF1, 0x4B, 0xFD, 0x4F, 0x38, 0x55, 0xAD, 0x6C, 0x3C, 0xA0, 0xC1, 0x4E, 0xE3, 281 | 0x9F, 0x73, 0x42, 0xB2, 0x3A, 0x1C, 0x2A, 0xFD, 0xC5, 0x5F, 0xDF, 0x46, 0x1F, 0xF7, 0xA8, 0x0E, 282 | 0xE7, 0x1A, 0x40, 0xE5, 0x55, 0x72, 0x9C, 0xA6, 0x06, 0x73, 0xD8, 0x56, 0xC3, 0x2B, 0x49, 0x9E, 283 | 0x3A, 0x0F, 0x6C, 0x24, 0x9A, 0x41, 0x18, 0x5C, 0xB1, 0xD8, 0x56, 0x92, 0xCB, 0xC1, 0xB7, 0xF7, 284 | 0x47, 0x0C, 0xA2, 0x3C, 0xF2, 0xC9, 0xDB, 0x1F, 0x22, 0xAB, 0xF8, 0x05, 0xA8, 0x92, 0xF0, 0x34, 285 | 0x83, 0x20, 0x1D, 0xB3, 0xDE, 0xBA, 0xCF, 0x0E, 0x74, 0xF2, 0xA2, 0xC0, 0xDF, 0x96, 0xDD, 0xA8, 286 | 0xE5, 0xC9, 0x65, 0xD4, 0x6C, 0x30, 0x96, 0x6E, 0xB3, 0x96, 0xCF, 0xE7, 0x03, 0x81, 0x45, 0xC3, 287 | 0x6B, 0xA0, 0x9F, 0x7A, 0xAE, 0xB1, 0x95, 0x61, 0x18, 0x62, 0x7D, 0xEA, 0xDA, 0x1B, 0x94, 0x75, 288 | 0xD8, 0xED, 0x5E, 0x6E, 0x5D, 0xE5, 0xB7, 0x21, 0x91, 0x5B, 0x85, 0x66, 0x62, 0x77, 0x34, 0x1F, 289 | 0x10, 0x94, 0xAB, 0xE0, 0x1F, 0xB5, 0x5A, 0x3B, 0x00, 0xB9, 0x02, 0xB3, 0xBC, 0x4A, 0x53, 0x93, 290 | 0xD4, 0xE6, 0xBA, 0xB8, 0xFF, 0x00, 0xD7, 0xB7, 0x46, 0x1D, 0x63, 0xB3, 0xE1, 0x70, 0xCD, 0x93, 291 | 0x53, 0x5C, 0x02, 0xD1, 0xEC, 0x6A, 0xB6, 0x09, 0x58, 0x01, 0x8A, 0x38, 0x3B, 0x31, 0xC9, 0xE5, 292 | 0x56, 0x97, 0x1F, 0x94, 0xAD, 0xDD, 0x32, 0xD9, 0x04, 0x72, 0x82, 0xC0, 0x62, 0x8F, 0x67, 0x53, 293 | 0x19, 0x3B, 0x54, 0x2F, 0x10, 0xF2, 0xF3, 0x9D, 0xEA, 0x04, 0x38, 0x62, 0x33, 0xD3, 0x15, 0x2D, 294 | 0xC2, 0xFA, 0xD5, 0xF8, 0x0B, 0x86, 0x37, 0x15, 0xF1, 0x2C, 0x63, 0x4C, 0x6F, 0x04, 0x23, 0x53, 295 | 0xAB, 0x28, 0xDF, 0xF4, 0xDA, 0xBB, 0x9C, 0xA4, 0x22, 0x04, 0x5C, 0x0C, 0x6D, 0x82, 0x6B, 0x0D, 296 | 0xF8, 0x59, 0xC2, 0x5A, 0xD3, 0x82, 0x3D, 0xF4, 0xB1, 0xC7, 0xAA, 0x66, 0x3A, 0x18, 0x2E, 0xF8, 297 | 0xF9, 0xAD, 0xAC, 0xC7, 0xA8, 0x3B, 0xD5, 0xB1, 0xEB, 0x15, 0xB1, 0x88, 0x1E, 0x62, 0xDC, 0x97, 298 | 0xE4, 0xFF, 0x00, 0x6A, 0x06, 0x49, 0x59, 0x09, 0x28, 0x32, 0xCD, 0xB6, 0xA1, 0xFF, 0x00, 0xB4, 299 | 0x4C, 0x8C, 0x75, 0x69, 0x50, 0x07, 0x7C, 0x9C, 0x50, 0x53, 0x4F, 0x2A, 0xC8, 0x0B, 0x3A, 0x15, 300 | 0xCE, 0x15, 0x7B, 0xFD, 0xF1, 0xB5, 0x25, 0xAB, 0xC8, 0x16, 0x58, 0xFC, 0xD6, 0xD0, 0x59, 0x25, 301 | 0x62, 0x70, 0xD8, 0xE4, 0xA3, 0xDE, 0xA2, 0x8F, 0x44, 0x4E, 0x51, 0x40, 0x5D, 0x07, 0x19, 0xEF, 302 | 0xF0, 0x3B, 0x74, 0xA7, 0x04, 0x26, 0x40, 0x9A, 0xC2, 0xA6, 0xE5, 0x97, 0xF8, 0xB3, 0xDF, 0x34, 303 | 0x44, 0x65, 0x62, 0x8B, 0x41, 0x8D, 0x70, 0x4E, 0x73, 0xED, 0xF1, 0x49, 0xE9, 0xDE, 0x0B, 0xE5, 304 | 0xA2, 0x28, 0x0E, 0x19, 0xB7, 0x55, 0x0B, 0xFF, 0x00, 0x7B, 0x51, 0x4B, 0xA9, 0x18, 0x05, 0x46, 305 | 0x6D, 0x23, 0x25, 0xFD, 0xEB, 0xC9, 0x16, 0x25, 0xD7, 0xA8, 0x1E, 0xF9, 0x14, 0xF4, 0xD6, 0xA0, 306 | 0x02, 0x08, 0xD5, 0xD4, 0x9A, 0x6D, 0x14, 0xDC, 0x6A, 0x65, 0x00, 0x93, 0xDB, 0x18, 0xA2, 0x63, 307 | 0x55, 0xDC, 0x32, 0xE7, 0x48, 0xE5, 0xDE, 0x98, 0x8C, 0x04, 0x8D, 0x82, 0x0A, 0x93, 0xCF, 0xA5, 308 | 0x7A, 0x35, 0x5F, 0xAB, 0x25, 0x89, 0xC8, 0xCF, 0xBD, 0x34, 0x02, 0xCC, 0x9A, 0x88, 0x00, 0x13, 309 | 0x9D, 0xF6, 0xA8, 0x52, 0xDC, 0x2A, 0xE4, 0x26, 0xF8, 0xC9, 0x22, 0x89, 0x92, 0x40, 0xB2, 0x00, 310 | 0xA7, 0x90, 0xC0, 0xA7, 0x30, 0xC4, 0x61, 0x31, 0x96, 0x23, 0xD5, 0x47, 0x41, 0xB0, 0x9A, 0x75, 311 | 0x62, 0x3C, 0xFA, 0xB9, 0x9C, 0xF2, 0xA8, 0x9A, 0xD4, 0x4B, 0x70, 0x5D, 0x72, 0x34, 0x73, 0x20, 312 | 0xF4, 0xFF, 0x00, 0x05, 0x14, 0x55, 0x63, 0x88, 0xB6, 0x7A, 0x13, 0xB9, 0xA8, 0x96, 0x5F, 0x2E, 313 | 0xD6, 0x59, 0x9B, 0xD2, 0x4A, 0xE3, 0x3E, 0xD4, 0x34, 0x6D, 0xB3, 0x1E, 0x25, 0xB7, 0x69, 0x6C, 314 | 0x32, 0xA0, 0x67, 0x58, 0x24, 0x9E, 0xD9, 0xE4, 0x2B, 0x01, 0xC4, 0x78, 0x42, 0x5B, 0x28, 0x78, 315 | 0x64, 0x46, 0x76, 0xDF, 0x4A, 0x37, 0x2F, 0x8A, 0xE9, 0x1C, 0x66, 0x45, 0x2B, 0x1E, 0xB6, 0x1E, 316 | 0x5E, 0xD9, 0xAC, 0x97, 0x16, 0xE1, 0x12, 0x5D, 0x5F, 0x48, 0xD1, 0x49, 0x98, 0xB6, 0xC1, 0x38, 317 | 0xC8, 0xEF, 0x8A, 0x96, 0x5B, 0x57, 0x0D, 0x39, 0xDD, 0xC4, 0x4D, 0x24, 0xE0, 0x13, 0x90, 0xC7, 318 | 0x1E, 0x91, 0xCE, 0xA4, 0x9F, 0x86, 0xBC, 0x71, 0x10, 0xAB, 0x81, 0x8D, 0xC7, 0x52, 0x6B, 0x43, 319 | 0x2F, 0x0B, 0x0B, 0x74, 0x89, 0x19, 0xCA, 0x46, 0x77, 0x27, 0x6D, 0x46, 0xA7, 0xBE, 0x80, 0x18, 320 | 0x55, 0x11, 0x46, 0x43, 0x05, 0x27, 0xF9, 0xD2, 0x9F, 0x6C, 0x9A, 0x70, 0xD3, 0x22, 0xE5, 0x93, 321 | 0xD0, 0xCB, 0x8D, 0x27, 0xA1, 0xAC, 0xCF, 0x19, 0xB5, 0x36, 0xEE, 0x85, 0x0E, 0xC3, 0xB1, 0xEB, 322 | 0x5D, 0x2E, 0x32, 0x21, 0xD1, 0x09, 0x40, 0x3A, 0xF2, 0xAC, 0x97, 0x1B, 0xE1, 0x53, 0x99, 0xE5, 323 | 0x66, 0x41, 0xE5, 0x39, 0xCA, 0xB0, 0xD8, 0x7E, 0xB5, 0xD1, 0xC5, 0xD3, 0x9B, 0x9B, 0xBA, 0xA5, 324 | 0xF0, 0xFC, 0xC1, 0x26, 0xD2, 0xC3, 0x99, 0xDF, 0x3D, 0x2B, 0xA4, 0xF0, 0xD7, 0xD1, 0x10, 0x25, 325 | 0xF9, 0xE3, 0x6A, 0xE6, 0x96, 0x56, 0xB3, 0x41, 0x7A, 0x10, 0x29, 0xCE, 0x79, 0x56, 0xF6, 0x09, 326 | 0x2E, 0x63, 0x31, 0x2E, 0x13, 0x43, 0x73, 0xCF, 0x31, 0x43, 0x39, 0x3E, 0xB6, 0x18, 0x5E, 0x98, 327 | 0xF9, 0x38, 0xB0, 0x40, 0x72, 0x77, 0xF6, 0x35, 0x04, 0x7C, 0x7C, 0xA4, 0x98, 0x04, 0xE2, 0xB3, 328 | 0xA5, 0xD8, 0xF3, 0xA4, 0x04, 0xD1, 0x9C, 0x18, 0xB9, 0x75, 0x1D, 0x16, 0xD3, 0x8D, 0x24, 0xB0, 329 | 0x90, 0xC7, 0x27, 0x14, 0x25, 0xF5, 0xCC, 0x67, 0x0C, 0xA7, 0x07, 0x1C, 0xAB, 0x19, 0x1D, 0xD4, 330 | 0xB1, 0x1C, 0xAB, 0x10, 0x6A, 0xD1, 0xA5, 0x92, 0x5B, 0x60, 0x5C, 0xEF, 0x8C, 0xE6, 0xB7, 0xF3, 331 | 0xD5, 0x5A, 0x65, 0xD6, 0x96, 0x51, 0x71, 0x04, 0x4D, 0xF0, 0x0F, 0xB5, 0x12, 0x78, 0xBC, 0x7F, 332 | 0xC2, 0x3E, 0x77, 0xAC, 0x88, 0x9A, 0x52, 0xFA, 0x40, 0xD6, 0x49, 0xD8, 0x60, 0xE4, 0x9F, 0xB7, 333 | 0x3A, 0x9B, 0xCE, 0x8E, 0x11, 0x87, 0x8C, 0x49, 0x27, 0xFB, 0x55, 0xCE, 0x07, 0xC9, 0xFE, 0xDF, 334 | 0x9D, 0x69, 0xC2, 0x8F, 0xCB, 0x4F, 0x27, 0x1B, 0x1E, 0x51, 0xC6, 0x3E, 0x68, 0x4B, 0x5E, 0x28, 335 | 0x65, 0xBC, 0x8E, 0x20, 0x59, 0x8C, 0x8C, 0x17, 0xD2, 0x35, 0x11, 0xF0, 0x33, 0x54, 0x1F, 0xEA, 336 | 0x33, 0x0F, 0x4C, 0x4B, 0x0C, 0x63, 0xFE, 0x31, 0x82, 0x7F, 0x33, 0x93, 0xFA, 0xD5, 0xEF, 0x83, 337 | 0x1E, 0xF2, 0xF3, 0xC5, 0xDC, 0x2E, 0xDB, 0xCE, 0x0C, 0x1A, 0xE1, 0x49, 0x59, 0x5D, 0x70, 0x46, 338 | 0x7A, 0x6A, 0xEB, 0x5A, 0x70, 0x4F, 0xD1, 0xF9, 0x7D, 0x59, 0xE1, 0xDB, 0x11, 0xC2, 0xFC, 0x39, 339 | 0x65, 0x68, 0x1B, 0x25, 0x63, 0x1A, 0x98, 0xE7, 0x73, 0xDE, 0x88, 0x96, 0x4D, 0xC1, 0x07, 0x38, 340 | 0xFD, 0x69, 0x67, 0x94, 0x22, 0xAA, 0xEC, 0x30, 0x00, 0x18, 0xA0, 0xA6, 0x90, 0xA2, 0x00, 0xBB, 341 | 0xC8, 0x4F, 0x22, 0x79, 0x51, 0xCA, 0xFE, 0x2F, 0x8C, 0x43, 0x72, 0xEC, 0xE1, 0x80, 0x19, 0x03, 342 | 0x63, 0xF3, 0x41, 0xC8, 0x51, 0x14, 0x8D, 0x4A, 0x30, 0xC3, 0x1A, 0x58, 0x80, 0x07, 0x6C, 0xD2, 343 | 0xCB, 0x30, 0x4C, 0x99, 0x25, 0x21, 0xB6, 0xD2, 0x49, 0xF4, 0xE4, 0xF6, 0xAA, 0xEB, 0xAB, 0xC7, 344 | 0x9A, 0x54, 0x45, 0x05, 0xB5, 0x1C, 0x61, 0x5B, 0x50, 0xC6, 0x77, 0xC9, 0x07, 0x35, 0x1C, 0xAA, 345 | 0xB2, 0x0E, 0x81, 0xCB, 0xCA, 0x5D, 0x53, 0x4A, 0x11, 0x90, 0x41, 0x1C, 0xBB, 0x62, 0xA6, 0x57, 346 | 0x88, 0xA7, 0x94, 0x43, 0x28, 0x24, 0x8C, 0x81, 0xFD, 0x7A, 0x55, 0x6B, 0xDC, 0x22, 0x12, 0x4C, 347 | 0xA0, 0x69, 0x19, 0x23, 0x5F, 0x21, 0xEF, 0x8A, 0x64, 0x1C, 0x5A, 0xDA, 0x79, 0x62, 0x89, 0x1B, 348 | 0x2E, 0x70, 0x35, 0x6A, 0xD8, 0x67, 0xBF, 0xF3, 0xA1, 0x0C, 0xD0, 0xC5, 0xA1, 0x10, 0x20, 0x93, 349 | 0xF8, 0xB0, 0x35, 0x1C, 0xE0, 0x75, 0xA9, 0x24, 0x72, 0x1C, 0x12, 0x47, 0xD4, 0x42, 0xFB, 0x0A, 350 | 0x07, 0xF6, 0x80, 0xC0, 0x95, 0x45, 0x60, 0x37, 0x53, 0xF7, 0xA5, 0x50, 0xC6, 0x41, 0x9D, 0xDB, 351 | 0x5E, 0xFD, 0x75, 0x53, 0xEC, 0x82, 0xC6, 0x7C, 0xDD, 0x21, 0x81, 0x5C, 0x8E, 0x5C, 0xCD, 0x17, 352 | 0x1E, 0x82, 0x70, 0xAB, 0x85, 0x53, 0xCC, 0xF5, 0xA0, 0xA0, 0x54, 0xCA, 0x9C, 0xB2, 0xFA, 0xC9, 353 | 0x6C, 0xF3, 0xA2, 0x1A, 0x70, 0x8E, 0xEA, 0x06, 0xDC, 0xF7, 0xEE, 0x69, 0xA0, 0x52, 0xC4, 0x4C, 354 | 0x8F, 0xAD, 0xB0, 0xBC, 0xD8, 0x8E, 0xC3, 0xA5, 0x34, 0x4A, 0x64, 0x98, 0xA8, 0xD5, 0xB8, 0xCF, 355 | 0x2E, 0x95, 0x3A, 0xE3, 0xCB, 0xDC, 0x7D, 0x58, 0x04, 0x52, 0x3E, 0x22, 0x84, 0x94, 0x1E, 0xB6, 356 | 0xF4, 0xD3, 0x17, 0x61, 0x66, 0xD5, 0x21, 0x7F, 0x57, 0xA0, 0x1A, 0x5B, 0x84, 0x56, 0xB3, 0xD0, 357 | 0x4E, 0x43, 0xF3, 0x3E, 0xD9, 0xA7, 0xAC, 0x40, 0xB2, 0xC7, 0x90, 0x11, 0x71, 0xA8, 0x53, 0x2E, 358 | 0x5D, 0x1C, 0x0C, 0x01, 0x85, 0xDC, 0x7D, 0xAB, 0x69, 0xB6, 0xAD, 0xBD, 0xB4, 0x46, 0x90, 0x45, 359 | 0xA1, 0x64, 0x45, 0x50, 0xDA, 0x4F, 0x7E, 0x54, 0x15, 0xDF, 0x0E, 0x48, 0xED, 0x58, 0x2E, 0x00, 360 | 0x00, 0x90, 0xCA, 0x77, 0x1D, 0xC5, 0x58, 0xCB, 0x21, 0x64, 0x25, 0x86, 0x72, 0x08, 0x26, 0x9A, 361 | 0xA3, 0xFF, 0x00, 0xC4, 0x80, 0xCA, 0x33, 0xE8, 0xDF, 0x3D, 0x69, 0x72, 0x92, 0x9E, 0x5D, 0x31, 362 | 0x3F, 0xE9, 0xCC, 0x59, 0x1D, 0x86, 0x96, 0x57, 0x27, 0x9F, 0x41, 0xCA, 0xAB, 0xEF, 0x62, 0x2A, 363 | 0x49, 0x05, 0x72, 0x72, 0x4E, 0x9E, 0x59, 0xAD, 0x2D, 0xE3, 0x68, 0x84, 0xB7, 0x96, 0x08, 0xD7, 364 | 0xBE, 0x17, 0xE9, 0x5A, 0xA9, 0x9A, 0x15, 0x08, 0xA5, 0xB6, 0x2C, 0xC4, 0xEC, 0x7A, 0x54, 0xBF, 365 | 0x55, 0xDF, 0x4A, 0x47, 0x55, 0x32, 0x63, 0x1E, 0xA5, 0x01, 0x88, 0xA8, 0xE6, 0x85, 0x6E, 0x94, 366 | 0xA1, 0x51, 0xA4, 0xF4, 0xAB, 0x29, 0xED, 0x8F, 0x99, 0x26, 0x93, 0x87, 0x4C, 0x6D, 0x9E, 0x62, 367 | 0xBD, 0x0F, 0x96, 0x14, 0x93, 0x19, 0x0C, 0x7F, 0x89, 0x79, 0x7E, 0x54, 0xF3, 0xA2, 0x5E, 0xE3, 368 | 0x21, 0x37, 0x0A, 0x7B, 0x7B, 0xF0, 0xC6, 0x30, 0xA1, 0x87, 0x3C, 0x72, 0xFB, 0xD1, 0xC6, 0xCD, 369 | 0x44, 0x82, 0x51, 0x96, 0x65, 0x1B, 0x11, 0xD3, 0xED, 0x57, 0xB7, 0xC8, 0x8D, 0x67, 0x23, 0x32, 370 | 0xB6, 0x42, 0x9D, 0xC0, 0xAC, 0xAD, 0xA5, 0xF3, 0x3D, 0xCB, 0x45, 0x36, 0x40, 0x0D, 0xE9, 0x0D, 371 | 0xD4, 0x63, 0xB5, 0x1B, 0xBF, 0x49, 0x3F, 0xE3, 0x03, 0x73, 0xC3, 0x5A, 0x37, 0x38, 0x07, 0x02, 372 | 0x84, 0x68, 0x08, 0xE6, 0x0D, 0x6E, 0xE7, 0xB1, 0x57, 0x6C, 0x11, 0x55, 0x77, 0x9C, 0x2C, 0x28, 373 | 0x24, 0x0A, 0xA7, 0xF4, 0x9A, 0x73, 0x32, 0xBE, 0x59, 0xD5, 0x8C, 0x55, 0xA3, 0x92, 0x96, 0xD8, 374 | 0xF6, 0xA2, 0xA3, 0xE1, 0x44, 0xB6, 0x71, 0x53, 0xDC, 0xD8, 0x9F, 0x24, 0x80, 0x29, 0x7F, 0xAE, 375 | 0x36, 0xE8, 0x71, 0x66, 0xF5, 0xB6, 0x18, 0x2F, 0xA4, 0x1E, 0x78, 0xEB, 0x51, 0x90, 0x6A, 0xCF, 376 | 0xF6, 0x13, 0x92, 0x31, 0x51, 0xCB, 0x66, 0xC8, 0x33, 0x8A, 0xA7, 0xF4, 0x85, 0x00, 0xA8, 0x6B, 377 | 0x79, 0xF8, 0x53, 0xC2, 0x66, 0xE2, 0x3E, 0x3B, 0xE1, 0xD2, 0x21, 0x5F, 0x2E, 0xDE, 0x41, 0x24, 378 | 0x9A, 0x87, 0x31, 0xDB, 0x60, 0x70, 0x79, 0x9F, 0xB5, 0x63, 0x56, 0x13, 0xCB, 0x1B, 0xD7, 0x78, 379 | 0xFC, 0x0C, 0xF0, 0xED, 0xCD, 0xBD, 0xA5, 0xC7, 0x1A, 0x96, 0x38, 0xD2, 0x19, 0x03, 0x24, 0x4F, 380 | 0xFC, 0x6E, 0x76, 0x1F, 0x60, 0x30, 0x7E, 0x73, 0xED, 0x47, 0x7D, 0x0C, 0xF5, 0xD4, 0xAE, 0x17, 381 | 0xF7, 0x8C, 0x58, 0x64, 0x03, 0xB1, 0xAA, 0x2B, 0xAB, 0x84, 0x67, 0x90, 0x11, 0xA5, 0x57, 0x91, 382 | 0x27, 0x3F, 0xF9, 0x57, 0x57, 0x5B, 0xB1, 0xDF, 0x6E, 0xE6, 0xA8, 0x6E, 0x1D, 0x23, 0x49, 0x1A, 383 | 0x17, 0x57, 0x73, 0x9D, 0x87, 0x33, 0xEF, 0xBF, 0x3F, 0x9A, 0x86, 0x73, 0x6E, 0x9C, 0x7A, 0x54, 384 | 0xDF, 0xF1, 0x45, 0x89, 0x50, 0x17, 0x8D, 0x57, 0xE9, 0x2A, 0xC3, 0x3B, 0x7B, 0x56, 0x23, 0x8E, 385 | 0x78, 0xBE, 0x2E, 0x1F, 0x13, 0xB6, 0x86, 0xCA, 0xEC, 0xBA, 0x46, 0xC7, 0xE0, 0x8E, 0x5F, 0x7A, 386 | 0xB4, 0xE3, 0xB7, 0x11, 0xBC, 0x13, 0x03, 0x11, 0x8B, 0x4E, 0x4E, 0xA5, 0x03, 0x5E, 0xAE, 0x7B, 387 | 0xFF, 0x00, 0x6A, 0xE3, 0x3C, 0x56, 0xF9, 0x6E, 0xF7, 0x33, 0x3B, 0x37, 0x3D, 0x2D, 0xD0, 0xF5, 388 | 0xE9, 0x5B, 0x8F, 0x8F, 0x7E, 0x86, 0x79, 0xEB, 0xC1, 0x97, 0x7E, 0x23, 0xE2, 0xB7, 0x57, 0x32, 389 | 0x4E, 0x2E, 0x5A, 0x1D, 0x7F, 0xC0, 0x87, 0x60, 0x3E, 0xF5, 0x7D, 0xE1, 0x7F, 0x13, 0x5D, 0xC3, 390 | 0x77, 0x65, 0x03, 0x7A, 0xF4, 0xB1, 0x02, 0x2F, 0x51, 0xF3, 0x09, 0xEB, 0xD8, 0x7E, 0x75, 0x8D, 391 | 0x86, 0xD6, 0x7B, 0x88, 0xE5, 0x99, 0x32, 0xEB, 0x18, 0x05, 0xC8, 0x42, 0x42, 0xFC, 0x90, 0x30, 392 | 0x29, 0xC9, 0x31, 0x0E, 0xBA, 0x58, 0xAB, 0xA9, 0xCE, 0x7B, 0x63, 0xB5, 0x5E, 0xE1, 0x34, 0x94, 393 | 0xCE, 0xED, 0xF4, 0xAF, 0x0C, 0xE2, 0xAA, 0xD0, 0x09, 0x5E, 0x4D, 0x50, 0xB7, 0x2C, 0x1C, 0xE3, 394 | 0xDB, 0x6E, 0xB9, 0xCE, 0xF5, 0x7F, 0x04, 0xDB, 0x19, 0x08, 0x1A, 0x94, 0x6F, 0xA7, 0xBF, 0x6A, 395 | 0xC1, 0xF8, 0x26, 0x74, 0xBA, 0xE1, 0x36, 0x3A, 0x62, 0x69, 0x32, 0x8A, 0xCC, 0xCB, 0xB9, 0xD5, 396 | 0xDC, 0x9C, 0x7D, 0xFE, 0xF5, 0xBE, 0xB7, 0x81, 0xED, 0x60, 0x91, 0xCB, 0x65, 0xB5, 0x0C, 0x00, 397 | 0x33, 0x8F, 0x61, 0xDE, 0xB9, 0xA4, 0xBB, 0xD3, 0xA3, 0x73, 0x42, 0xA3, 0xCA, 0x46, 0x19, 0x95, 398 | 0xB3, 0x8C, 0x82, 0x4F, 0x23, 0x4D, 0xD2, 0xA4, 0xBA, 0x83, 0xF4, 0x6E, 0x72, 0x76, 0xCD, 0x4B, 399 | 0x29, 0x21, 0x14, 0x9F, 0x40, 0x1B, 0xB0, 0x03, 0x24, 0xFB, 0x54, 0x41, 0x02, 0x29, 0xCF, 0xA5, 400 | 0x71, 0xA9, 0x8D, 0x52, 0x15, 0x31, 0xCA, 0x44, 0x8C, 0xDC, 0xFE, 0xA6, 0xCF, 0x42, 0x79, 0x53, 401 | 0xCC, 0xA4, 0x4C, 0x10, 0x6F, 0xE9, 0xFD, 0x68, 0x28, 0xEF, 0x92, 0x57, 0x11, 0xB2, 0x13, 0x1B, 402 | 0x36, 0x41, 0x3D, 0x87, 0xB5, 0x4B, 0x2D, 0xC2, 0xC5, 0x29, 0xDB, 0x0A, 0xC4, 0x10, 0x7D, 0xA8, 403 | 0x94, 0x51, 0x75, 0x52, 0x72, 0x3D, 0x4C, 0x72, 0x05, 0x56, 0xBB, 0xB4, 0xB7, 0x4F, 0x11, 0x03, 404 | 0x48, 0x4C, 0x80, 0x3F, 0xCF, 0x6A, 0x9A, 0x59, 0x10, 0xCD, 0xAC, 0xB6, 0x02, 0xAE, 0x17, 0x26, 405 | 0x80, 0xB7, 0x9D, 0x4D, 0xEC, 0xA7, 0x49, 0x62, 0xC4, 0x28, 0xC9, 0xED, 0xCE, 0x88, 0x09, 0x8E, 406 | 0x3D, 0x16, 0xA1, 0x4E, 0x49, 0x61, 0x90, 0x49, 0xE6, 0x68, 0x5B, 0xE7, 0xFD, 0xC3, 0x29, 0x60, 407 | 0xBA, 0x0E, 0x90, 0x49, 0xEC, 0x33, 0xB5, 0x17, 0x2C, 0xA0, 0x90, 0x0F, 0xA7, 0x0D, 0x85, 0x15, 408 | 0x9A, 0xE3, 0x33, 0x39, 0x92, 0x48, 0x14, 0xF2, 0x1A, 0x72, 0x3F, 0xE5, 0xD6, 0x85, 0x19, 0xEA, 409 | 0x19, 0xA7, 0x6C, 0xCC, 0x22, 0xDE, 0x33, 0x94, 0x03, 0x3C, 0xD8, 0x8E, 0x74, 0x3D, 0xD5, 0xB8, 410 | 0x2A, 0xE5, 0x89, 0xD5, 0x17, 0x22, 0x39, 0x11, 0xCB, 0x6A, 0x96, 0x10, 0x85, 0x98, 0x01, 0xB0, 411 | 0x8C, 0xE3, 0x7E, 0x6D, 0xEF, 0x50, 0xD8, 0x81, 0x24, 0x28, 0x2E, 0x1B, 0xF8, 0x89, 0xFC, 0xEA, 412 | 0x7A, 0x53, 0x61, 0x64, 0x41, 0x2A, 0xA4, 0x98, 0xD3, 0x2E, 0x31, 0xB9, 0xE7, 0x51, 0xA4, 0x4B, 413 | 0xA7, 0x20, 0xEF, 0xD9, 0x85, 0x3E, 0x46, 0x55, 0x99, 0x82, 0x8D, 0x2B, 0xBE, 0x9C, 0x9F, 0xA4, 414 | 0xF6, 0xA9, 0x62, 0x70, 0xD1, 0x90, 0xC1, 0x4B, 0x01, 0xBE, 0xD5, 0xB4, 0x1B, 0x35, 0x2D, 0x56, 415 | 0x44, 0x29, 0x21, 0x3E, 0xA1, 0x8C, 0x1A, 0xA1, 0x9B, 0x85, 0x44, 0xD6, 0xE7, 0x5A, 0x0F, 0x31, 416 | 0x18, 0x8D, 0x59, 0xFC, 0xBF, 0x4A, 0xD2, 0x06, 0x08, 0x41, 0x62, 0x00, 0xC6, 0x01, 0xA0, 0xCA, 417 | 0x23, 0x43, 0x2A, 0xBF, 0x42, 0x58, 0x1A, 0xA7, 0xE1, 0x3F, 0x58, 0xD9, 0x97, 0x12, 0x6D, 0x50, 418 | 0xCB, 0x17, 0x9C, 0x30, 0x39, 0x54, 0xD7, 0x2D, 0xEA, 0xC8, 0x14, 0xB6, 0xCD, 0x95, 0x15, 0xCF, 419 | 0x95, 0xDD, 0xD3, 0x9E, 0xFA, 0x86, 0x3B, 0x70, 0xA0, 0xEC, 0x2A, 0x39, 0xE1, 0x56, 0x18, 0xC0, 420 | 0xAB, 0x09, 0x63, 0x5C, 0x61, 0x4E, 0xF8, 0xA0, 0x01, 0x3E, 0x66, 0xFD, 0xEA, 0x37, 0x86, 0xCC, 421 | 0xB6, 0x1B, 0xD0, 0x35, 0xE1, 0xF8, 0x6C, 0x95, 0xE7, 0xDE, 0xA1, 0xBA, 0xB1, 0x0C, 0x39, 0x0A, 422 | 0xBC, 0x77, 0x40, 0xB9, 0x06, 0x9B, 0x69, 0x65, 0x27, 0x11, 0xBD, 0x82, 0xD2, 0x00, 0x0C, 0xB3, 423 | 0x48, 0xB1, 0xA6, 0x4E, 0xD9, 0x27, 0x1B, 0xD5, 0x7F, 0x9D, 0xB9, 0x4A, 0x1D, 0xDA, 0x27, 0xF0, 424 | 0xEF, 0xC0, 0x63, 0xC4, 0x7C, 0x7D, 0x64, 0xB9, 0x8C, 0x1E, 0x1F, 0x6A, 0x43, 0xCF, 0xAB, 0x38, 425 | 0x7E, 0xCA, 0x2B, 0xE8, 0xB5, 0xB7, 0x86, 0xD6, 0xD9, 0x61, 0xB7, 0x89, 0x63, 0x89, 0x46, 0x15, 426 | 0x23, 0x18, 0x03, 0xED, 0x41, 0x78, 0x73, 0x81, 0xC5, 0xE1, 0xEE, 0x07, 0x6F, 0xC3, 0xA2, 0x21, 427 | 0x8A, 0x0C, 0xC8, 0xE0, 0x63, 0x5B, 0x9E, 0x66, 0xAC, 0x26, 0x39, 0x1A, 0x06, 0xAC, 0x9D, 0xB6, 428 | 0x07, 0x6A, 0xEE, 0x98, 0xF4, 0xAC, 0xE9, 0x57, 0x77, 0xA0, 0x12, 0xAC, 0x32, 0x4F, 0x4C, 0x8D, 429 | 0xFF, 0x00, 0x3A, 0xAE, 0xBD, 0xE1, 0xD2, 0x4D, 0x13, 0x0F, 0x33, 0xF7, 0x7B, 0x80, 0x0B, 0x1D, 430 | 0x43, 0xE0, 0x8A, 0xB3, 0x68, 0x19, 0xA7, 0x5D, 0xB2, 0xBC, 0x88, 0x6C, 0xE7, 0xEE, 0x6A, 0x41, 431 | 0x67, 0xAC, 0xEE, 0xC7, 0x1D, 0x32, 0x73, 0x49, 0xF2, 0x7D, 0xB9, 0x37, 0x8A, 0x38, 0x58, 0xE1, 432 | 0xB6, 0x72, 0xCF, 0x1D, 0xE3, 0x2C, 0x86, 0x32, 0xAA, 0xA8, 0xA3, 0x51, 0x3F, 0xF2, 0x1F, 0x1D, 433 | 0x6B, 0x87, 0x3F, 0x0A, 0x9A, 0x6F, 0xDA, 0x27, 0x08, 0x55, 0x14, 0x93, 0x80, 0x39, 0xFC, 0x57, 434 | 0xD4, 0xBE, 0x30, 0xF0, 0xDC, 0x3C, 0x42, 0xC6, 0x40, 0x10, 0xE4, 0x0F, 0x4B, 0xF3, 0xC1, 0xFB, 435 | 0xD7, 0x09, 0xE3, 0x36, 0x77, 0x16, 0xB3, 0x1B, 0x70, 0x34, 0xB2, 0x39, 0x53, 0x8E, 0x95, 0x4C, 436 | 0x71, 0xD4, 0x25, 0x54, 0x0E, 0x2F, 0xC4, 0x97, 0x84, 0x2F, 0x02, 0x4B, 0xA9, 0xA1, 0xB0, 0x2C, 437 | 0x0B, 0xDB, 0xA9, 0xD0, 0xB9, 0x3C, 0xF5, 0x01, 0xF5, 0x72, 0xEB, 0x55, 0xB2, 0xD9, 0xC6, 0x2F, 438 | 0x9C, 0x40, 0xD9, 0x41, 0xB0, 0xCF, 0x7A, 0xB0, 0xBA, 0x17, 0x8D, 0xFF, 0x00, 0xDA, 0x15, 0xF4, 439 | 0x8C, 0x07, 0x70, 0x35, 0x7E, 0x75, 0x04, 0x11, 0x98, 0xD4, 0x96, 0xFA, 0xB9, 0xE6, 0x8F, 0x6D, 440 | 0x6B, 0xB9, 0xFE, 0x15, 0xDB, 0xE3, 0xC3, 0x48, 0x23, 0x04, 0xC7, 0x1B, 0x30, 0x59, 0x18, 0x63, 441 | 0x59, 0xEA, 0x7E, 0x39, 0x8E, 0x7D, 0x2B, 0x7C, 0xB8, 0xC0, 0x5C, 0x7A, 0x14, 0x8C, 0x1F, 0xF7, 442 | 0x1A, 0xE6, 0x9F, 0x86, 0x7C, 0x62, 0xD5, 0xEC, 0xA3, 0xE1, 0xB0, 0x92, 0x59, 0x21, 0x0D, 0x34, 443 | 0x9C, 0x86, 0xEE, 0x40, 0xE5, 0xD7, 0x7C, 0x7F, 0xEE, 0xDD, 0x16, 0xE6, 0xE2, 0x38, 0xE3, 0x80, 444 | 0x29, 0x18, 0xF3, 0x00, 0x19, 0xE7, 0x8A, 0x86, 0x53, 0x55, 0x4C, 0x6E, 0xE0, 0x97, 0x72, 0xCD, 445 | 0x32, 0x82, 0x35, 0x81, 0xE9, 0x02, 0x85, 0x9E, 0x37, 0x40, 0xCA, 0xD9, 0x21, 0xC1, 0x6F, 0x81, 446 | 0x8A, 0x1F, 0xF6, 0xA4, 0x5B, 0xC2, 0xC5, 0xB7, 0x1F, 0x58, 0x03, 0x71, 0xEC, 0x6B, 0xD7, 0x97, 447 | 0x03, 0xCB, 0x62, 0xEC, 0x01, 0xD3, 0xA4, 0xFC, 0x74, 0xA1, 0xB3, 0x22, 0xE1, 0xC5, 0x9E, 0x25, 448 | 0x2E, 0x43, 0x13, 0xAB, 0x63, 0xD3, 0xEF, 0xD7, 0xAD, 0x49, 0x71, 0x32, 0x34, 0xA9, 0x8C, 0x1D, 449 | 0x3C, 0xD7, 0xDB, 0x1F, 0xF9, 0x51, 0x24, 0xC2, 0x0B, 0x55, 0x90, 0xB6, 0xDB, 0xF2, 0xDF, 0xED, 450 | 0x55, 0xB0, 0xBC, 0x87, 0x8A, 0xC0, 0x58, 0x6A, 0x12, 0xA6, 0x90, 0x4F, 0x43, 0xFE, 0x1A, 0xCC, 451 | 0x9E, 0xEE, 0xE4, 0x08, 0xA2, 0xF3, 0x09, 0x0C, 0x65, 0x23, 0x03, 0xD8, 0x6D, 0xFA, 0xD3, 0xA1, 452 | 0x12, 0x41, 0x22, 0xB8, 0x3A, 0x86, 0xA3, 0xD2, 0x80, 0xBD, 0x94, 0x24, 0xD1, 0xA4, 0x87, 0x57, 453 | 0x96, 0xDA, 0xB2, 0x7B, 0x8C, 0x9A, 0x2E, 0xCA, 0xED, 0x25, 0x8E, 0xD9, 0x0B, 0x0C, 0x3B, 0x9C, 454 | 0x64, 0xF4, 0xDF, 0x9F, 0xE6, 0x28, 0x80, 0x8B, 0xBB, 0x8F, 0xDE, 0x32, 0x82, 0x17, 0x4F, 0xA8, 455 | 0x92, 0x79, 0x8C, 0x56, 0x7A, 0xE1, 0xB5, 0x1C, 0xB6, 0xDB, 0x60, 0x91, 0xDA, 0x8C, 0xE2, 0xB7, 456 | 0x8A, 0xB2, 0x98, 0xD0, 0x6A, 0xD6, 0x31, 0xBD, 0x57, 0x33, 0x34, 0x8A, 0xA0, 0x8D, 0xCE, 0x0F, 457 | 0xC8, 0x1F, 0xFB, 0x8A, 0xC0, 0x8E, 0x08, 0x5A, 0x39, 0x95, 0x75, 0xEC, 0xEA, 0x15, 0x46, 0x79, 458 | 0x0E, 0xB4, 0x44, 0xDA, 0x52, 0x38, 0x80, 0x03, 0x50, 0x38, 0xDB, 0xAD, 0x2D, 0xD9, 0x10, 0xC7, 459 | 0x91, 0xBB, 0x36, 0xC0, 0x8A, 0xF4, 0x69, 0xBB, 0x07, 0x23, 0x44, 0x7A, 0xBA, 0x6F, 0xBE, 0x29, 460 | 0x4F, 0x28, 0x49, 0x90, 0x10, 0x18, 0x0F, 0x4E, 0x76, 0xA8, 0x8B, 0x28, 0x72, 0x40, 0xF4, 0x92, 461 | 0x32, 0x2A, 0x65, 0xD6, 0x64, 0x7C, 0x26, 0x50, 0xE4, 0x0E, 0xB4, 0x34, 0xD9, 0x59, 0x34, 0x13, 462 | 0x91, 0x9C, 0x6F, 0x41, 0x85, 0x91, 0xFB, 0x82, 0xD8, 0xD5, 0x1B, 0x73, 0xA0, 0xD9, 0x44, 0x90, 463 | 0x93, 0x11, 0x19, 0x07, 0x7D, 0xF9, 0x8A, 0x94, 0x6B, 0x5D, 0xF3, 0xB0, 0x1A, 0x88, 0xAA, 0x6B, 464 | 0x99, 0x65, 0x85, 0xF5, 0xC4, 0x7E, 0x94, 0x20, 0x81, 0xC8, 0xFC, 0x8A, 0x6F, 0x49, 0x54, 0xF3, 465 | 0xC4, 0x49, 0xE5, 0x51, 0x2C, 0x45, 0x06, 0x73, 0x53, 0xDC, 0xCA, 0x17, 0x07, 0xF3, 0xA1, 0xFC, 466 | 0xDD, 0x4B, 0xE9, 0x18, 0xF9, 0xA9, 0x4D, 0x4B, 0xDA, 0x15, 0x33, 0xCA, 0xDE, 0x5E, 0x36, 0xCF, 467 | 0x7A, 0x81, 0x23, 0xD4, 0x4E, 0xF4, 0x85, 0x89, 0x14, 0xF8, 0x58, 0x0C, 0xE7, 0x9D, 0x57, 0x5B, 468 | 0x80, 0x8E, 0x48, 0xCF, 0x5E, 0x42, 0xBA, 0x17, 0xE1, 0x2F, 0x07, 0x5B, 0x8E, 0x27, 0x75, 0xC5, 469 | 0x64, 0x00, 0x8B, 0x65, 0x11, 0xC6, 0x08, 0xFE, 0x26, 0xE6, 0x7F, 0x2F, 0xE7, 0x58, 0x50, 0x8D, 470 | 0x3C, 0xAA, 0x91, 0xAB, 0x3B, 0xB1, 0xC0, 0x55, 0x19, 0x24, 0xFB, 0x57, 0x73, 0xF0, 0x37, 0x00, 471 | 0x97, 0xC3, 0xFE, 0x1D, 0x48, 0x6E, 0x36, 0xB9, 0x99, 0xCC, 0xD2, 0x2F, 0xFB, 0x49, 0x00, 0x05, 472 | 0xFB, 0x01, 0x47, 0x8E, 0x76, 0x38, 0xB4, 0xC4, 0xF4, 0x14, 0x99, 0xC0, 0xC9, 0xA8, 0xE4, 0x0C, 473 | 0x5B, 0x23, 0x6C, 0x75, 0xEF, 0x48, 0xA5, 0x9B, 0x20, 0xE3, 0x3B, 0x66, 0xAC, 0x73, 0xB4, 0xA9, 474 | 0x3A, 0xBB, 0x8A, 0x42, 0xE0, 0x6D, 0x8E, 0x54, 0x8F, 0x80, 0x33, 0x9C, 0x9A, 0x16, 0x50, 0xCC, 475 | 0x40, 0x27, 0x3B, 0x9D, 0xEB, 0x31, 0x2F, 0x1D, 0x64, 0x5D, 0x00, 0xEC, 0x46, 0xE6, 0xBE, 0x7E, 476 | 0xF1, 0xAC, 0x6D, 0x65, 0xE2, 0x7B, 0x9B, 0xA6, 0x81, 0x85, 0xAE, 0xBD, 0x0A, 0x4B, 0x0C, 0x33, 477 | 0x75, 0xE5, 0x5D, 0xE2, 0x52, 0xA0, 0x60, 0x92, 0x2B, 0x94, 0x7E, 0x28, 0x70, 0xD1, 0x3F, 0x96, 478 | 0x6D, 0x21, 0xCB, 0xBE, 0x0B, 0x60, 0xF6, 0x24, 0x93, 0xF3, 0xCA, 0x8E, 0x35, 0xAB, 0x10, 0x8B, 479 | 0x05, 0xCA, 0x8F, 0x37, 0x00, 0x97, 0x23, 0x4F, 0x6E, 0xDF, 0xD6, 0xAA, 0x78, 0x95, 0xB9, 0x59, 480 | 0x26, 0x44, 0x0B, 0xFB, 0xBD, 0xC0, 0x5E, 0x44, 0x63, 0x7D, 0xE9, 0x96, 0x53, 0x34, 0x65, 0xC8, 481 | 0x39, 0x56, 0xD8, 0x13, 0xFD, 0x7B, 0xD2, 0x48, 0x0A, 0xAB, 0x69, 0x62, 0x58, 0x73, 0x03, 0xF8, 482 | 0x81, 0xDA, 0x98, 0x8B, 0x0F, 0x07, 0xCD, 0x3C, 0x1C, 0x72, 0xCD, 0x6D, 0xE4, 0x68, 0xF5, 0x16, 483 | 0xF3, 0x18, 0x1E, 0xCA, 0x48, 0xFE, 0xDF, 0x7A, 0xED, 0x92, 0x5C, 0x3C, 0xAB, 0x68, 0x58, 0xB6, 484 | 0xA6, 0x44, 0x24, 0xF3, 0xC9, 0x06, 0xB8, 0xB7, 0x86, 0x66, 0x11, 0xF1, 0xEB, 0x6D, 0x63, 0x4A, 485 | 0x23, 0x2A, 0x8D, 0xB6, 0xF7, 0xCF, 0x7E, 0x55, 0xD9, 0x5A, 0x54, 0x40, 0x64, 0x66, 0xC2, 0x2C, 486 | 0x6B, 0x13, 0x20, 0xD8, 0xAE, 0xFB, 0x1D, 0xFD, 0xAA, 0x3C, 0x93, 0xB5, 0x70, 0xA2, 0xD1, 0x54, 487 | 0xDA, 0xDC, 0x5E, 0x13, 0xAF, 0x2F, 0x9D, 0x8F, 0x41, 0x53, 0xCE, 0xF1, 0xBC, 0x20, 0xB9, 0x00, 488 | 0x3A, 0x8C, 0x83, 0xD4, 0x74, 0xC5, 0x53, 0xAF, 0x10, 0x05, 0xA4, 0xB7, 0x3E, 0x9F, 0xA9, 0x40, 489 | 0x1C, 0x8E, 0x7F, 0xF3, 0xF5, 0xA2, 0x2E, 0x26, 0xCB, 0xC7, 0x14, 0xEA, 0x4A, 0x91, 0xA8, 0x01, 490 | 0xCC, 0x7F, 0x62, 0x0D, 0x43, 0xC5, 0x85, 0x5D, 0x49, 0x19, 0xB7, 0xF2, 0x35, 0x8C, 0x11, 0x94, 491 | 0x23, 0xAE, 0xDB, 0xD4, 0x16, 0x2E, 0x53, 0xF6, 0x5C, 0x9C, 0xB1, 0xC9, 0x19, 0xDE, 0xB3, 0xF7, 492 | 0x7C, 0x5F, 0x55, 0xCB, 0x5B, 0x31, 0x66, 0x08, 0xE4, 0xAB, 0x37, 0x31, 0xF1, 0xDB, 0xAD, 0x2D, 493 | 0xAD, 0xD4, 0xB1, 0xCD, 0x01, 0x2D, 0x90, 0xAF, 0xB3, 0x0E, 0x83, 0x99, 0xA6, 0x20, 0xCE, 0x29, 494 | 0x78, 0x4C, 0xD3, 0x46, 0x48, 0xF3, 0x1C, 0x60, 0x77, 0xC6, 0x33, 0x53, 0x46, 0xF1, 0x42, 0x91, 495 | 0x3A, 0x82, 0x16, 0x11, 0xBA, 0x81, 0xCD, 0x89, 0xE5, 0xFD, 0x7E, 0xD5, 0x4D, 0x77, 0x34, 0x37, 496 | 0xD7, 0xA6, 0xE9, 0x0B, 0x28, 0xD6, 0x72, 0xA7, 0xB7, 0x2C, 0xD4, 0xB2, 0x5E, 0x6B, 0xF2, 0x62, 497 | 0x53, 0x92, 0x84, 0xB8, 0xF7, 0xDB, 0x19, 0xFE, 0x74, 0x76, 0x09, 0x64, 0x6D, 0x52, 0xCE, 0xCE, 498 | 0x49, 0x2A, 0x39, 0x9F, 0x9D, 0xE9, 0xD1, 0x30, 0x96, 0x70, 0xB8, 0x23, 0x07, 0x3F, 0x03, 0x35, 499 | 0x5A, 0xF3, 0xB4, 0x97, 0x8C, 0xE3, 0x65, 0x67, 0xDC, 0x55, 0xA5, 0xB1, 0x1E, 0x50, 0x23, 0x79, 500 | 0x03, 0x0D, 0x59, 0xEA, 0x3F, 0xC3, 0x59, 0x8B, 0x3B, 0x97, 0x91, 0x1C, 0x01, 0xA2, 0x36, 0xD8, 501 | 0x7D, 0xF1, 0x44, 0x48, 0x35, 0x15, 0x45, 0x3A, 0x41, 0x5D, 0x4F, 0xF3, 0xEF, 0x4C, 0x94, 0xC4, 502 | 0xAC, 0x34, 0x8F, 0xDD, 0xB3, 0x6A, 0x07, 0xEF, 0xCA, 0x85, 0x49, 0x24, 0x5B, 0xC2, 0x49, 0xE7, 503 | 0x91, 0xF3, 0x8A, 0xD4, 0x63, 0xCB, 0x23, 0x46, 0x76, 0x19, 0xED, 0x93, 0xD6, 0xA0, 0x55, 0x32, 504 | 0x30, 0x0F, 0xB9, 0x23, 0x39, 0xA3, 0x65, 0x55, 0x8E, 0x74, 0x1A, 0x4E, 0xFC, 0xF3, 0xEF, 0x42, 505 | 0xAA, 0x95, 0x9D, 0xF7, 0xFA, 0x06, 0x73, 0x4A, 0x27, 0xAE, 0xA5, 0x91, 0x49, 0x1C, 0xC6, 0x01, 506 | 0x15, 0x4B, 0xC5, 0x7F, 0x77, 0x1C, 0xB2, 0xA8, 0xC1, 0x0D, 0xEA, 0x07, 0xEF, 0xFD, 0x4D, 0x5C, 507 | 0x89, 0x01, 0x20, 0xE7, 0x7C, 0x9C, 0x6F, 0xD6, 0xB2, 0xDC, 0x73, 0x89, 0x69, 0x46, 0x85, 0x88, 508 | 0x0C, 0x5B, 0x0D, 0xFC, 0xFF, 0x00, 0xA1, 0xAA, 0x63, 0x13, 0xCA, 0x85, 0x36, 0xC6, 0x62, 0x76, 509 | 0xDA, 0x98, 0xF0, 0x79, 0x7B, 0x74, 0xAB, 0xA5, 0x88, 0x44, 0x98, 0xC5, 0x03, 0x70, 0x15, 0x9B, 510 | 0x9E, 0xF4, 0x9F, 0x08, 0xAB, 0x8C, 0x79, 0xD8, 0x57, 0x92, 0x33, 0x9D, 0xAA, 0x59, 0x3D, 0x19, 511 | 0xC8, 0xA7, 0x41, 0xEA, 0x20, 0x77, 0xA6, 0x8C, 0xE9, 0xDF, 0x86, 0x5E, 0x19, 0x45, 0x83, 0xFD, 512 | 0x72, 0xE9, 0x55, 0xD9, 0xF2, 0xB6, 0xE1, 0x97, 0xE9, 0xC1, 0xC1, 0x6F, 0xE6, 0x2B, 0xA5, 0x50, 513 | 0xBC, 0x3A, 0xD9, 0x2C, 0xB8, 0x6D, 0xAD, 0xAC, 0x60, 0x04, 0x8A, 0x25, 0x41, 0x8F, 0x61, 0x44, 514 | 0x96, 0x02, 0xAD, 0x26, 0x8E, 0x42, 0x0E, 0x6A, 0x27, 0x04, 0x64, 0x80, 0x3B, 0xD2, 0xF9, 0xAB, 515 | 0x81, 0x93, 0x8C, 0xD4, 0x12, 0x5C, 0xAF, 0xA9, 0x49, 0x19, 0xCE, 0x05, 0x11, 0xD9, 0x92, 0x12, 516 | 0x4E, 0xED, 0x81, 0xB6, 0xF5, 0x0C, 0x92, 0xE8, 0x00, 0x96, 0x51, 0xB1, 0x03, 0xDC, 0xD3, 0x65, 517 | 0x94, 0x16, 0x20, 0xE0, 0x91, 0xD0, 0xD0, 0x57, 0x33, 0x2F, 0x31, 0xCC, 0x0D, 0xC1, 0x14, 0x18, 518 | 0x2D, 0xF7, 0x10, 0x0A, 0xD8, 0x62, 0xD8, 0xE8, 0x55, 0x73, 0x9E, 0x5F, 0xDA, 0xB3, 0xBE, 0x20, 519 | 0x96, 0x2B, 0xB8, 0xC0, 0x2A, 0x59, 0x31, 0x80, 0x71, 0xCF, 0x27, 0x07, 0xEF, 0xCA, 0x8E, 0xBB, 520 | 0xB9, 0x56, 0x95, 0x01, 0x25, 0x4E, 0xC0, 0x02, 0x71, 0xBE, 0x3D, 0xEA, 0x9E, 0xEA, 0xF6, 0x21, 521 | 0x23, 0x96, 0x46, 0x65, 0xC1, 0x00, 0x03, 0xD7, 0xDC, 0x74, 0xA4, 0xDE, 0x99, 0xC8, 0x7C, 0x41, 522 | 0x64, 0x9C, 0x2D, 0x83, 0x47, 0x29, 0x7D, 0x52, 0x10, 0x70, 0x36, 0xF7, 0xAA, 0x15, 0xE2, 0x06, 523 | 0x29, 0x09, 0x24, 0xE4, 0xAE, 0xD9, 0x3D, 0x6B, 0xA4, 0xF1, 0xBB, 0x3B, 0x6B, 0xBB, 0x56, 0x8A, 524 | 0x21, 0x86, 0x39, 0x62, 0xAC, 0x40, 0x3F, 0x03, 0xBD, 0x73, 0xEE, 0x21, 0xC2, 0x99, 0x34, 0x9D, 525 | 0x18, 0xD3, 0xB6, 0xC3, 0x9D, 0x1F, 0xE9, 0x3F, 0x5B, 0xE4, 0xFB, 0x5B, 0xE6, 0x8E, 0xE8, 0xBC, 526 | 0x4C, 0x36, 0x60, 0x41, 0x07, 0x38, 0x23, 0x96, 0x3F, 0x3A, 0xEA, 0x7C, 0x1F, 0x8D, 0x9E, 0x25, 527 | 0xC3, 0xA6, 0x69, 0xD3, 0xCC, 0xF2, 0x88, 0x42, 0x7A, 0xB0, 0x39, 0x19, 0xFE, 0x55, 0xC8, 0x56, 528 | 0x21, 0x0A, 0xFA, 0x49, 0xD4, 0x4D, 0x68, 0x6C, 0x3C, 0x44, 0xD6, 0x56, 0x9F, 0xB3, 0x63, 0x29, 529 | 0xE4, 0x34, 0x5B, 0x75, 0x2C, 0x72, 0x73, 0xF1, 0x49, 0x9E, 0x52, 0x8E, 0x3D, 0x3A, 0x65, 0xBD, 530 | 0xCF, 0x95, 0xC5, 0xE3, 0xB3, 0x91, 0x14, 0xA9, 0x64, 0x64, 0x90, 0x1C, 0x13, 0x9E, 0x87, 0xBF, 531 | 0x23, 0x57, 0x5C, 0x65, 0xDA, 0x39, 0x4E, 0x91, 0x91, 0xA7, 0x03, 0x49, 0xE5, 0xBF, 0xFD, 0xD6, 532 | 0x3A, 0xC3, 0x8C, 0x41, 0x78, 0xF6, 0x97, 0x11, 0x31, 0x73, 0x1C, 0x71, 0x64, 0xB0, 0xF5, 0x06, 533 | 0xFA, 0x4E, 0x47, 0xBE, 0x92, 0x6B, 0x41, 0xC6, 0x2F, 0xD1, 0xAD, 0x25, 0x99, 0x86, 0x18, 0x80, 534 | 0x32, 0x4F, 0xE7, 0x51, 0xBD, 0x29, 0xBD, 0xA8, 0x15, 0xDE, 0xE3, 0x8A, 0x30, 0x21, 0x48, 0x07, 535 | 0x4E, 0x4F, 0x6E, 0x7F, 0xDE, 0x88, 0x82, 0x42, 0x8A, 0xD1, 0x39, 0x38, 0xC1, 0x20, 0x83, 0xDA, 536 | 0xA9, 0xAD, 0x6E, 0xD8, 0xD9, 0xB4, 0x98, 0xC4, 0xCF, 0x20, 0x23, 0xDD, 0x7A, 0x54, 0xB6, 0xFC, 537 | 0x47, 0xCF, 0xBA, 0x62, 0xA4, 0xF9, 0x5B, 0xE8, 0xF7, 0x3D, 0x6B, 0x4A, 0x5E, 0xD6, 0x96, 0xAC, 538 | 0x10, 0xC8, 0x01, 0x3E, 0x86, 0x38, 0xCF, 0x6A, 0x59, 0xF2, 0x91, 0xC8, 0x54, 0x60, 0xB2, 0xE9, 539 | 0x56, 0xEE, 0x33, 0x51, 0x47, 0x22, 0xE4, 0x95, 0xD9, 0x86, 0xF8, 0x1D, 0x6B, 0xCC, 0x09, 0x8D, 540 | 0xB5, 0x6C, 0xD9, 0xCF, 0xF3, 0x34, 0xCC, 0x7A, 0xFE, 0xE8, 0x2E, 0xD9, 0xDC, 0x01, 0x56, 0x88, 541 | 0xEB, 0x1E, 0x4C, 0x7B, 0x9D, 0xF2, 0x7E, 0xDD, 0x3E, 0xF5, 0x57, 0x1C, 0x85, 0xA1, 0x8D, 0xF1, 542 | 0x91, 0x9D, 0x80, 0xE6, 0x6A, 0x48, 0xAE, 0x8C, 0x70, 0x98, 0xF1, 0x9D, 0x27, 0x4E, 0x73, 0xB9, 543 | 0xA1, 0xB1, 0x58, 0xAB, 0x03, 0x1C, 0x2C, 0x7D, 0x87, 0xB7, 0x3D, 0xE9, 0x58, 0x03, 0x7D, 0x9F, 544 | 0xE1, 0x04, 0xB0, 0xFB, 0xD4, 0x36, 0x92, 0x8F, 0x25, 0xCE, 0x30, 0xA8, 0xDE, 0x92, 0x7E, 0xF5, 545 | 0x3C, 0x6C, 0xA1, 0x7C, 0xD9, 0x06, 0xDA, 0x74, 0xD1, 0xF4, 0x52, 0xB4, 0x9A, 0x8E, 0x58, 0xEE, 546 | 0xAD, 0x95, 0xF8, 0xA1, 0x59, 0xCC, 0x72, 0x36, 0x40, 0xC9, 0x00, 0x1A, 0xF4, 0x92, 0x90, 0x23, 547 | 0x70, 0x01, 0x43, 0xCD, 0x47, 0x6E, 0x95, 0x1B, 0x48, 0xA1, 0xC9, 0x04, 0xB0, 0x65, 0xD8, 0x1A, 548 | 0x21, 0xB4, 0x17, 0x73, 0x8B, 0x78, 0xDE, 0x4E, 0x63, 0x19, 0xC7, 0xCD, 0x73, 0x1F, 0x10, 0x71, 549 | 0x63, 0x34, 0xF2, 0xEA, 0x6D, 0x6C, 0xC0, 0x1C, 0x8E, 0xBB, 0x7F, 0xE5, 0x6B, 0x3C, 0x5F, 0xC4, 550 | 0x85, 0xAF, 0x0B, 0x97, 0xCB, 0x24, 0x36, 0xD9, 0x03, 0xF2, 0x15, 0xCB, 0x6E, 0x2E, 0x0C, 0xA5, 551 | 0x58, 0x9C, 0xB1, 0x50, 0x0F, 0xB1, 0xAB, 0x61, 0x12, 0xB7, 0x6E, 0xC7, 0x79, 0x73, 0xA8, 0x90, 552 | 0x9C, 0xA8, 0x38, 0x61, 0x92, 0x52, 0x49, 0x53, 0x56, 0x76, 0xB6, 0x8B, 0x2C, 0x9A, 0x71, 0x93, 553 | 0x57, 0x70, 0x70, 0xF5, 0x8D, 0x75, 0x10, 0x06, 0xD4, 0x35, 0xB2, 0x31, 0xD7, 0xB6, 0xCC, 0x98, 554 | 0x24, 0x72, 0xA6, 0xDB, 0xAA, 0x8C, 0x33, 0xBE, 0x92, 0x37, 0x18, 0x5C, 0xD5, 0xF7, 0x14, 0x85, 555 | 0x4E, 0xE0, 0x56, 0x76, 0x6C, 0xC6, 0xC4, 0x50, 0xB8, 0xEA, 0xB7, 0x8E, 0x9D, 0xC3, 0xBF, 0x12, 556 | 0xF8, 0x75, 0xBF, 0x0F, 0x48, 0xF8, 0xA5, 0xDA, 0xC7, 0x2A, 0xAE, 0x03, 0x95, 0x20, 0x31, 0x1D, 557 | 0xBD, 0xEA, 0xE7, 0x86, 0xF8, 0xBB, 0x87, 0x71, 0x48, 0xC3, 0x5A, 0x5F, 0x24, 0x99, 0xFA, 0x57, 558 | 0x38, 0x38, 0xEE, 0x41, 0xDC, 0x57, 0x03, 0xE2, 0x56, 0xA6, 0xFE, 0xD9, 0x91, 0x5B, 0x4B, 0x83, 559 | 0x95, 0x27, 0xBD, 0x67, 0xAE, 0x38, 0xB7, 0x13, 0xE1, 0x57, 0x48, 0xD0, 0x48, 0xF6, 0xF3, 0x2A, 560 | 0xE3, 0x52, 0xEC, 0x69, 0xB1, 0xCE, 0x5E, 0xA1, 0xA5, 0x7D, 0x5A, 0x2F, 0xC4, 0xC1, 0x54, 0x65, 561 | 0x5B, 0xCC, 0xD0, 0x37, 0xE7, 0xCE, 0x87, 0xBD, 0x37, 0x31, 0x8D, 0x6A, 0xC0, 0xAE, 0x76, 0xC1, 562 | 0xCE, 0xDD, 0x73, 0x5F, 0x3A, 0x3F, 0xE2, 0xD7, 0x88, 0xFF, 0x00, 0x63, 0x8E, 0xDE, 0x26, 0x85, 563 | 0x19, 0x14, 0x2F, 0x9A, 0x13, 0xD4, 0x7B, 0x9F, 0x6E, 0xDE, 0xD5, 0xB3, 0xF0, 0x3F, 0x8D, 0x6F, 564 | 0x78, 0xDD, 0xB4, 0xF1, 0x5F, 0xC8, 0x45, 0xC0, 0x23, 0x33, 0xE7, 0x00, 0xE7, 0x27, 0xFA, 0x1A, 565 | 0x76, 0x74, 0x9F, 0xDB, 0xCC, 0x8E, 0xA8, 0x48, 0x27, 0x27, 0x99, 0xC7, 0xE5, 0x4F, 0x95, 0xF2, 566 | 0x0F, 0xA8, 0xEF, 0x8D, 0x81, 0xDC, 0xFC, 0xF4, 0xAA, 0x1E, 0x08, 0xE2, 0xE4, 0xE6, 0x62, 0xAC, 567 | 0xA0, 0x90, 0xBE, 0xC3, 0x7C, 0xE6, 0xAF, 0xBC, 0xE8, 0x1E, 0xD5, 0x5D, 0x25, 0x0A, 0xAC, 0x32, 568 | 0x18, 0x8D, 0xFA, 0x63, 0x7A, 0x14, 0x60, 0x33, 0x64, 0xC3, 0xD4, 0x49, 0x63, 0xC9, 0x89, 0xC6, 569 | 0x09, 0xAA, 0x1E, 0x2A, 0x91, 0xA2, 0xF9, 0x41, 0x00, 0x6F, 0xF8, 0x1E, 0x9F, 0x19, 0xCF, 0xDE, 570 | 0xAF, 0x2E, 0xEF, 0x92, 0x26, 0x93, 0x49, 0x76, 0x2B, 0x8D, 0x44, 0x83, 0x91, 0xF2, 0x07, 0x3A, 571 | 0xC5, 0xF1, 0x19, 0x1F, 0xCC, 0x69, 0xA5, 0x47, 0x95, 0x25, 0x6F, 0x4C, 0x84, 0xE3, 0x6E, 0xDB, 572 | 0x8A, 0x96, 0x47, 0x80, 0x2E, 0x2C, 0x56, 0x76, 0xF3, 0x1A, 0x45, 0x2A, 0x09, 0xF4, 0xC8, 0xC3, 573 | 0xD4, 0x3D, 0x89, 0xDC, 0x55, 0x6F, 0x11, 0x86, 0xDA, 0x3B, 0x26, 0x79, 0x0E, 0x83, 0xB8, 0x52, 574 | 0xE0, 0x80, 0x41, 0xEA, 0x3B, 0xD1, 0x17, 0x57, 0xBE, 0x54, 0x4A, 0x8F, 0x34, 0xBA, 0x41, 0xC2, 575 | 0x39, 0x5D, 0x46, 0x3F, 0x90, 0x46, 0x3F, 0x5A, 0xA7, 0xB9, 0xBC, 0x12, 0xB2, 0xAC, 0xAE, 0x5E, 576 | 0x3D, 0x3B, 0x80, 0x9B, 0x03, 0xFE, 0xE1, 0xDA, 0xA3, 0x65, 0x52, 0x59, 0x14, 0xB7, 0x10, 0x00, 577 | 0x04, 0xA6, 0x44, 0x70, 0x36, 0xCA, 0xED, 0x8A, 0x09, 0xC6, 0x06, 0xD8, 0x3E, 0xFD, 0xE8, 0xF6, 578 | 0x77, 0x49, 0x7C, 0xB4, 0x7C, 0xEB, 0x00, 0x8D, 0x51, 0xE9, 0x2D, 0xF0, 0x45, 0x0F, 0x34, 0x45, 579 | 0x17, 0x53, 0x2E, 0xDD, 0xFB, 0x56, 0xF0, 0xB6, 0x0E, 0xE1, 0x77, 0xEF, 0x65, 0x73, 0x14, 0xB1, 580 | 0x10, 0xCA, 0x30, 0x0A, 0x1E, 0xA7, 0x98, 0x1F, 0x99, 0xAD, 0x69, 0xE2, 0x22, 0xF3, 0x85, 0xCA, 581 | 0xB2, 0x6A, 0xF3, 0x5C, 0xE9, 0xD0, 0x3A, 0x0E, 0x98, 0xFD, 0x4D, 0x60, 0xED, 0xE3, 0x2E, 0x48, 582 | 0x43, 0xB7, 0xD4, 0x73, 0x5A, 0x2B, 0x49, 0xA3, 0x48, 0x94, 0xB4, 0x84, 0xCA, 0x72, 0x48, 0x07, 583 | 0x7C, 0x9F, 0xFD, 0xA4, 0xCE, 0xE9, 0xB1, 0x86, 0x49, 0x76, 0x50, 0x91, 0xA8, 0x99, 0x00, 0xD3, 584 | 0x91, 0xC8, 0x1C, 0x76, 0xF9, 0xA3, 0xE1, 0x54, 0x8E, 0xD2, 0x29, 0x0B, 0x10, 0x7C, 0xCC, 0x0F, 585 | 0x82, 0x2A, 0xB1, 0x54, 0x20, 0x91, 0x88, 0xC6, 0xAC, 0x9C, 0x9E, 0xA6, 0x9F, 0x1D, 0xC3, 0x79, 586 | 0x0C, 0x8A, 0x72, 0xA7, 0x04, 0xE7, 0xFA, 0x52, 0x4C, 0x9A, 0xC6, 0x99, 0x88, 0x5F, 0x26, 0x6C, 587 | 0xE1, 0x58, 0x10, 0x4F, 0xBF, 0x6A, 0x58, 0xE5, 0x2E, 0x15, 0x5C, 0x82, 0xA7, 0x2C, 0xA7, 0xFB, 588 | 0xFE, 0x75, 0x57, 0x15, 0xE3, 0x34, 0x08, 0xAD, 0xF4, 0xAB, 0x6B, 0x2B, 0x8E, 0xB9, 0xFF, 0x00, 589 | 0x05, 0x22, 0x5D, 0xBB, 0x4A, 0xC7, 0x38, 0x0D, 0xBF, 0xC5, 0x53, 0xFA, 0x48, 0x5D, 0x2C, 0xFC, 590 | 0xC6, 0x59, 0xC3, 0x30, 0xF4, 0xAE, 0xCA, 0x3B, 0x6D, 0xFF, 0x00, 0x74, 0xA8, 0xCC, 0xF7, 0x41, 591 | 0x40, 0xD8, 0x1C, 0xD0, 0x30, 0xCC, 0x75, 0x90, 0xDF, 0xC4, 0x7F, 0xF2, 0x8D, 0x82, 0x41, 0x1E, 592 | 0x87, 0x03, 0x53, 0xE0, 0xE6, 0x97, 0xEB, 0x67, 0xF1, 0x60, 0x24, 0x20, 0x98, 0xC1, 0xFA, 0x5B, 593 | 0x38, 0x1D, 0x69, 0xF7, 0x17, 0x47, 0xCB, 0x08, 0x0E, 0xC5, 0x77, 0x35, 0x5D, 0xE6, 0x14, 0x00, 594 | 0x03, 0xEA, 0xF6, 0xA9, 0x89, 0xC2, 0x82, 0xC7, 0xE9, 0x03, 0x7A, 0x79, 0x43, 0xA1, 0x29, 0x21, 595 | 0x6B, 0x67, 0x24, 0xE3, 0x6C, 0xFC, 0x50, 0xB7, 0x17, 0xC2, 0x18, 0x24, 0x70, 0x46, 0xB4, 0x43, 596 | 0x80, 0x7A, 0xD5, 0x37, 0x18, 0xE2, 0xEF, 0x69, 0x67, 0x2F, 0x92, 0x09, 0x64, 0x52, 0x70, 0x7F, 597 | 0xCF, 0xBF, 0xDA, 0xB1, 0xD7, 0xDE, 0x20, 0x96, 0xEB, 0x53, 0xEA, 0x20, 0x33, 0x2A, 0x90, 0x3E, 598 | 0x3F, 0xEF, 0x15, 0x6C, 0x26, 0xFB, 0x4E, 0xD4, 0x9E, 0x25, 0xE2, 0xAF, 0x78, 0xF3, 0x20, 0x24, 599 | 0x69, 0x70, 0x08, 0xEE, 0x37, 0xFE, 0xF5, 0x96, 0x38, 0x26, 0xA6, 0x92, 0x76, 0x72, 0xCF, 0xD5, 600 | 0x86, 0x08, 0xA8, 0x33, 0xD6, 0xAD, 0x0A, 0xFA, 0x47, 0x86, 0x5A, 0x47, 0x14, 0x61, 0x98, 0xFD, 601 | 0xEA, 0x79, 0xE7, 0x43, 0x9C, 0x72, 0xE9, 0x59, 0xBB, 0x5E, 0x2D, 0x24, 0x8A, 0x41, 0xE4, 0x39, 602 | 0x52, 0xDC, 0x71, 0x35, 0x8D, 0x72, 0x5B, 0x7E, 0xD5, 0x3C, 0x73, 0x9A, 0x29, 0x78, 0xA5, 0xDA, 603 | 0x45, 0x92, 0xC7, 0x3D, 0x80, 0xAC, 0xC4, 0xF7, 0x42, 0x42, 0x77, 0xA6, 0x71, 0x0E, 0x23, 0xE7, 604 | 0xC8, 0x40, 0x39, 0x3E, 0xD4, 0x06, 0xA6, 0xD4, 0x2B, 0x9F, 0x96, 0xE5, 0x9D, 0xD4, 0x01, 0xE9, 605 | 0x26, 0x83, 0x90, 0x81, 0xC9, 0x18, 0x00, 0xF4, 0x3D, 0xEA, 0xC1, 0xB8, 0x6F, 0x0C, 0xE2, 0x16, 606 | 0xFE, 0x5D, 0xF0, 0xFD, 0xA9, 0xE4, 0x01, 0x43, 0x2E, 0x57, 0xCB, 0x3F, 0xF0, 0x3C, 0xC9, 0x1C, 607 | 0xB3, 0xCB, 0xB6, 0x79, 0xD0, 0x11, 0x85, 0x68, 0xF3, 0x9D, 0xEA, 0xC2, 0xD6, 0xFE, 0x2B, 0x50, 608 | 0x02, 0x2E, 0x66, 0xFA, 0x43, 0xF4, 0x41, 0xED, 0xFA, 0xEF, 0x5B, 0x8F, 0x8F, 0xE7, 0xB6, 0x66, 609 | 0xB8, 0xA7, 0x80, 0xA5, 0xE1, 0xF7, 0x8A, 0xB1, 0xCB, 0x9B, 0x79, 0x06, 0x56, 0x49, 0x76, 0xD3, 610 | 0xF3, 0x8A, 0xB3, 0xB2, 0xB7, 0x87, 0x85, 0x58, 0x0B, 0x5E, 0x1A, 0x3F, 0x68, 0x76, 0x61, 0xE7, 611 | 0x48, 0x47, 0xD4, 0xC7, 0xE7, 0xA6, 0xD8, 0xAD, 0x21, 0xE2, 0x50, 0x5C, 0xDA, 0x98, 0xA6, 0x7F, 612 | 0x38, 0x6A, 0xC0, 0x1A, 0x7E, 0x9F, 0xF3, 0x9D, 0x55, 0x8E, 0x1F, 0x1A, 0x79, 0x8B, 0x68, 0xDB, 613 | 0xCD, 0x1E, 0x90, 0xA4, 0xEE, 0x3A, 0xFD, 0xB9, 0xD7, 0x47, 0xD5, 0x15, 0x97, 0x0C, 0xE3, 0x52, 614 | 0x59, 0x32, 0xB6, 0x57, 0xFF, 0x00, 0xAC, 0xAB, 0x63, 0xE9, 0x3B, 0xD5, 0xAC, 0x9C, 0x6D, 0xD2, 615 | 0xCF, 0x31, 0xCA, 0xA0, 0xB7, 0xA9, 0x43, 0x7C, 0x7E, 0x86, 0xB1, 0xAF, 0x17, 0x90, 0xA8, 0xB3, 616 | 0xC6, 0x43, 0x92, 0x40, 0x60, 0xB9, 0x5C, 0x64, 0x60, 0x0C, 0x6F, 0xB9, 0xCD, 0x11, 0x75, 0x1D, 617 | 0xDC, 0x30, 0xA6, 0x19, 0x7D, 0x08, 0x5B, 0x2B, 0xEA, 0x04, 0x8E, 0x5B, 0xFE, 0x7F, 0x6A, 0xDB, 618 | 0x3C, 0x1D, 0x79, 0xC6, 0x4D, 0xBB, 0x97, 0x79, 0x48, 0x95, 0x97, 0xD2, 0x4E, 0x76, 0x3F, 0xFB, 619 | 0xBD, 0x54, 0xB7, 0x12, 0x9A, 0xF2, 0x16, 0x95, 0x73, 0xE5, 0xAB, 0x1D, 0x71, 0xA9, 0x23, 0x7E, 620 | 0xBB, 0x54, 0x3C, 0x42, 0xDF, 0xF6, 0xDB, 0x51, 0x31, 0xCC, 0x60, 0xFA, 0x99, 0x47, 0x35, 0xC7, 621 | 0xF4, 0xDC, 0x7E, 0x55, 0x54, 0x78, 0xAC, 0x10, 0xC6, 0x77, 0xD4, 0xC1, 0x18, 0xC8, 0x41, 0x00, 622 | 0x9C, 0x03, 0xA4, 0x8C, 0xFD, 0x59, 0x38, 0x1D, 0xE8, 0x6B, 0x63, 0xBD, 0x2D, 0x7F, 0x6A, 0x89, 623 | 0x92, 0x41, 0xE7, 0xE8, 0x8B, 0x3B, 0x99, 0x4E, 0xC0, 0x7B, 0xF6, 0xF9, 0xA0, 0xAF, 0x42, 0xD9, 624 | 0x35, 0x9D, 0xDC, 0x25, 0xA5, 0x89, 0x9C, 0xAB, 0xA9, 0x3C, 0x88, 0xFF, 0x00, 0xA3, 0x9A, 0xCA, 625 | 0xDC, 0x71, 0x57, 0xD6, 0xF8, 0x97, 0xCE, 0x89, 0xF9, 0xC6, 0xE0, 0xAB, 0x29, 0xEF, 0x91, 0xB0, 626 | 0xFD, 0x47, 0xB5, 0x36, 0xDA, 0xF6, 0xE4, 0x44, 0x11, 0x0E, 0xFA, 0x71, 0x93, 0xBE, 0x07, 0xB7, 627 | 0xEB, 0x5A, 0xE2, 0x32, 0xAF, 0x2F, 0x78, 0x84, 0x2D, 0x6F, 0x8B, 0x75, 0x29, 0x01, 0x2D, 0x85, 628 | 0x65, 0xCE, 0x5B, 0xFE, 0x3D, 0xBA, 0xD0, 0xB6, 0xF2, 0x49, 0x32, 0x11, 0x2F, 0xAB, 0x0B, 0xF5, 629 | 0x1E, 0x74, 0xED, 0x46, 0xE8, 0x42, 0x98, 0xC4, 0x71, 0xAE, 0x3E, 0x9D, 0x8B, 0x75, 0x35, 0x30, 630 | 0x8C, 0x22, 0xE0, 0x73, 0x1D, 0xAA, 0x16, 0x9E, 0x92, 0xCD, 0x22, 0xB7, 0x5C, 0xB3, 0x1D, 0x52, 631 | 0x82, 0x14, 0x76, 0x5F, 0x71, 0xEE, 0x47, 0xF9, 0x9A, 0x26, 0xC3, 0xF7, 0x6E, 0x73, 0xC9, 0xB7, 632 | 0x26, 0x85, 0xC1, 0x66, 0x07, 0x19, 0x3D, 0xE8, 0xD8, 0x2D, 0x98, 0xAE, 0xA2, 0x77, 0x03, 0x00, 633 | 0x7B, 0x54, 0xF3, 0xF1, 0xB1, 0xA2, 0xA7, 0x93, 0x51, 0x00, 0x6E, 0x07, 0x6A, 0x7C, 0x51, 0xE9, 634 | 0x56, 0xC0, 0xE4, 0x69, 0x11, 0x42, 0x8C, 0x6D, 0xCA, 0x9E, 0x1D, 0x89, 0x03, 0xA0, 0xDF, 0x02, 635 | 0xA5, 0x1B, 0x7B, 0x4F, 0x0C, 0x2C, 0xE9, 0x93, 0xF4, 0x75, 0xA9, 0x95, 0x42, 0x92, 0x4E, 0x30, 636 | 0x36, 0x03, 0xDE, 0x99, 0xE7, 0x0D, 0x90, 0x73, 0xED, 0x51, 0xBC, 0xA3, 0x5E, 0xED, 0x8C, 0x77, 637 | 0xA3, 0xAB, 0x5B, 0x62, 0x41, 0x1A, 0x89, 0xC6, 0xC3, 0xAD, 0x13, 0xE6, 0x02, 0xAA, 0x8A, 0x76, 638 | 0x03, 0x24, 0x8A, 0xAD, 0x79, 0x82, 0x85, 0x50, 0x77, 0x63, 0x93, 0xF1, 0xBF, 0xF6, 0xA0, 0xAF, 639 | 0x78, 0xA2, 0x47, 0x6B, 0x22, 0x07, 0xC3, 0x4A, 0x8C, 0x43, 0x0E, 0x9D, 0xAA, 0x98, 0x71, 0xD0, 640 | 0xB9, 0x34, 0x16, 0xD7, 0x09, 0x34, 0xAC, 0x43, 0x75, 0xFD, 0x06, 0xD4, 0x3F, 0x1A, 0xE2, 0x49, 641 | 0x0D, 0xA6, 0x92, 0x4A, 0xB3, 0x30, 0x3C, 0xF1, 0xB5, 0x64, 0xE0, 0xE3, 0x1A, 0x23, 0xB8, 0x11, 642 | 0x3E, 0x1D, 0xC6, 0x01, 0xFF, 0x00, 0x68, 0xD4, 0xBF, 0xF7, 0x55, 0xBC, 0x4F, 0x8C, 0x4D, 0x77, 643 | 0xAD, 0x59, 0xB5, 0x6B, 0x0A, 0x48, 0xC7, 0xD3, 0xB0, 0xE5, 0xFA, 0xD7, 0x4E, 0x3C, 0x44, 0xB4, 644 | 0xBC, 0x47, 0x8C, 0xC9, 0x73, 0x74, 0xDA, 0x0E, 0x23, 0x62, 0xC0, 0x81, 0xD7, 0x24, 0xEF, 0xFA, 645 | 0xD5, 0x41, 0x73, 0xA4, 0xA9, 0xCF, 0x32, 0x7E, 0xF4, 0xDE, 0xB9, 0xE5, 0x4A, 0x40, 0xE7, 0xD0, 646 | 0x8A, 0xBC, 0x92, 0x14, 0xCC, 0x9A, 0x5E, 0x74, 0x9F, 0x7A, 0x51, 0x45, 0x9D, 0x42, 0x0E, 0x22, 647 | 0xC8, 0x31, 0x8F, 0x8A, 0x1E, 0x77, 0x96, 0x76, 0x24, 0x9D, 0xBB, 0x54, 0x28, 0x30, 0xF9, 0x39, 648 | 0xC5, 0x10, 0x1C, 0x27, 0x3A, 0xE2, 0xC4, 0x81, 0x61, 0x8B, 0x17, 0x1E, 0xA1, 0xBD, 0x11, 0x3A, 649 | 0x05, 0x03, 0x4F, 0xDE, 0x86, 0x9D, 0xF5, 0x3F, 0xA4, 0x52, 0x87, 0x24, 0x60, 0xF3, 0xEA, 0x6A, 650 | 0x9A, 0xD0, 0x2C, 0x22, 0x03, 0xC9, 0xDA, 0x84, 0x27, 0x2E, 0x74, 0x9A, 0x61, 0x99, 0xB4, 0x94, 651 | 0x0D, 0xB7, 0xB5, 0x4B, 0x02, 0x8C, 0x82, 0x79, 0xD3, 0x69, 0x8E, 0x8A, 0x43, 0x11, 0x05, 0xB3, 652 | 0xA7, 0xDB, 0x9D, 0x0F, 0x73, 0xC4, 0xE3, 0x89, 0x48, 0x89, 0xE4, 0xF3, 0x9C, 0xE1, 0x9B, 0x1B, 653 | 0x81, 0xD9, 0x7B, 0x51, 0x17, 0x5A, 0x52, 0x22, 0x73, 0x55, 0x76, 0xF2, 0x24, 0x7C, 0x42, 0x19, 654 | 0x0A, 0xB3, 0xE8, 0x70, 0xC0, 0x05, 0xCE, 0x7E, 0xD4, 0xD8, 0x8B, 0x5D, 0x0F, 0xFA, 0x85, 0xBF, 655 | 0x09, 0xB8, 0xBE, 0x9A, 0x24, 0x2C, 0x1C, 0x24, 0x66, 0x47, 0xFA, 0x70, 0x30, 0x5B, 0x00, 0x6F, 656 | 0xBE, 0x7F, 0x4A, 0xA6, 0x7F, 0x14, 0xC7, 0xA2, 0xEB, 0x11, 0x30, 0x58, 0x5D, 0x62, 0x0E, 0x7F, 657 | 0x8D, 0x89, 0x23, 0xF9, 0x02, 0x6B, 0x5B, 0x6B, 0xC4, 0x20, 0x9E, 0xD5, 0x2D, 0xA5, 0x65, 0xF3, 658 | 0x08, 0xD9, 0x00, 0xD9, 0x71, 0xDC, 0xF5, 0xF9, 0xAC, 0x6F, 0x1E, 0xF0, 0xE4, 0xAF, 0x91, 0x0E, 659 | 0x34, 0x06, 0x2E, 0x54, 0x00, 0x37, 0x3E, 0xD5, 0xAF, 0xCF, 0xE9, 0xA2, 0xA2, 0xFF, 0x00, 0x8A, 660 | 0xB5, 0xD4, 0xEF, 0x6E, 0x0F, 0x97, 0x0C, 0x61, 0x55, 0x98, 0x7F, 0x03, 0x9E, 0xA3, 0xE1, 0x8E, 661 | 0x3E, 0x33, 0x54, 0x32, 0xB3, 0x2C, 0x6E, 0x93, 0x12, 0x66, 0x8D, 0xBD, 0x27, 0xB7, 0x71, 0x47, 662 | 0xCB, 0xC1, 0x6E, 0xA3, 0x00, 0x79, 0x47, 0x7F, 0x6D, 0xFE, 0xF5, 0xE1, 0xC0, 0xAE, 0x88, 0xCE, 663 | 0x31, 0x91, 0xB6, 0x6B, 0x4C, 0xB1, 0x86, 0xF5, 0x46, 0xAA, 0xD2, 0xCA, 0x00, 0x19, 0x24, 0xF6, 664 | 0xAB, 0x7B, 0x2B, 0x47, 0xD4, 0xAC, 0xDF, 0x4D, 0x59, 0x5A, 0xF0, 0x47, 0x84, 0x93, 0xA3, 0x73, 665 | 0xCC, 0x91, 0x56, 0x0B, 0xC3, 0x9D, 0x70, 0x15, 0x7D, 0x3D, 0xFB, 0x54, 0xB9, 0x39, 0x77, 0xD4, 666 | 0x36, 0x3A, 0x43, 0x1C, 0x2B, 0x1A, 0xFA, 0x40, 0xC6, 0x29, 0x7C, 0x87, 0xCE, 0x68, 0x97, 0xF2, 667 | 0xE1, 0x52, 0x09, 0xE4, 0x39, 0x55, 0x7C, 0x9C, 0x61, 0x62, 0x7C, 0x08, 0xB6, 0xCF, 0x2C, 0xD4, 668 | 0x31, 0xC7, 0x2B, 0xE3, 0x5C, 0xA0, 0xE8, 0xAD, 0x46, 0xBD, 0x44, 0x72, 0x1B, 0xD5, 0x94, 0x36, 669 | 0xBA, 0xD3, 0x51, 0x20, 0x2F, 0x22, 0x4D, 0x53, 0x49, 0xC5, 0xA3, 0x60, 0xBE, 0x51, 0x20, 0x6C, 670 | 0x33, 0xDF, 0x3F, 0xF9, 0x56, 0xF6, 0x33, 0xBA, 0xDA, 0x81, 0x0B, 0x89, 0x1F, 0x03, 0x76, 0x6D, 671 | 0x38, 0xDB, 0x1B, 0x66, 0x9F, 0x0E, 0x1B, 0x95, 0xEC, 0x3E, 0xC6, 0x1B, 0x24, 0x58, 0xF5, 0x05, 672 | 0x66, 0xC8, 0xE6, 0x05, 0x08, 0xEA, 0xA9, 0x90, 0x00, 0x1B, 0xD1, 0x6C, 0xEC, 0x90, 0x67, 0x26, 673 | 0x49, 0x31, 0x9D, 0x39, 0xD7, 0xA7, 0xEC, 0x07, 0xEB, 0x55, 0x12, 0x4F, 0x3C, 0x93, 0x2C, 0x28, 674 | 0xAC, 0x5C, 0x9F, 0x52, 0xA8, 0xE5, 0xF7, 0xCE, 0xD5, 0xD1, 0xFC, 0x71, 0x6D, 0x96, 0x79, 0x04, 675 | 0x0C, 0x48, 0x65, 0xD4, 0x77, 0x24, 0x9E, 0x5F, 0xE6, 0x2A, 0xB5, 0xAE, 0x88, 0x69, 0x00, 0xFA, 676 | 0x17, 0xD5, 0x9C, 0x6E, 0x4D, 0x4B, 0x7F, 0x11, 0x84, 0xC6, 0x89, 0xEA, 0x92, 0x46, 0x3B, 0x8C, 677 | 0xE5, 0x88, 0xF9, 0xE6, 0x3A, 0x0E, 0xB4, 0x23, 0xC6, 0xD0, 0xAC, 0xAB, 0x29, 0xFD, 0xF0, 0x6D, 678 | 0x52, 0x36, 0x79, 0x1E, 0xDF, 0x6E, 0x54, 0xD3, 0x8E, 0x46, 0x24, 0xBC, 0x4B, 0x37, 0x48, 0x9B, 679 | 0x04, 0x03, 0x0C, 0x3D, 0xB1, 0x54, 0xD7, 0x37, 0x4D, 0x3C, 0xCC, 0xCE, 0x71, 0x94, 0xD3, 0x8F, 680 | 0xF6, 0x9A, 0x56, 0x6F, 0xDE, 0x3C, 0xDB, 0xEE, 0x7F, 0x4A, 0x12, 0x46, 0x2C, 0xC7, 0x3C, 0x89, 681 | 0xDA, 0x9A, 0x63, 0x20, 0x53, 0x3C, 0xC6, 0x40, 0x46, 0x77, 0x34, 0xCD, 0x58, 0x6C, 0xE2, 0x94, 682 | 0xF2, 0xC9, 0xA8, 0xCF, 0x2A, 0x60, 0x2E, 0x4E, 0x73, 0x4E, 0xC9, 0x3B, 0xD2, 0x32, 0x95, 0x62, 683 | 0x0F, 0x3C, 0x0A, 0x43, 0xB6, 0x00, 0x34, 0x58, 0x9B, 0xF3, 0xAF, 0x57, 0xB1, 0x5E, 0x34, 0x19, 684 | 0xD3, 0xEE, 0x60, 0x10, 0xAE, 0x47, 0x3E, 0xD4, 0x00, 0x66, 0x66, 0xC1, 0x34, 0x5D, 0xD5, 0xDF, 685 | 0x98, 0xE4, 0x9E, 0x40, 0xF5, 0xA0, 0xC3, 0x82, 0xFE, 0x9E, 0x79, 0xAE, 0x7E, 0x39, 0xB4, 0xD2, 686 | 0x84, 0xC1, 0xDE, 0x9A, 0xCA, 0x09, 0xC0, 0xA7, 0x33, 0x64, 0x67, 0xAD, 0x31, 0x0F, 0x3A, 0xA3, 687 | 0x1A, 0x54, 0x86, 0xD8, 0x51, 0x30, 0x7D, 0x43, 0x26, 0xA1, 0x66, 0xDF, 0xDE, 0x9F, 0x1E, 0x73, 688 | 0x90, 0x28, 0x5E, 0xC4, 0xFB, 0xF4, 0x3E, 0x49, 0x22, 0xA8, 0x85, 0xCC, 0xA8, 0x55, 0x03, 0x14, 689 | 0x8C, 0x7D, 0x46, 0x31, 0x86, 0x6F, 0xFF, 0x00, 0xAA, 0xD0, 0xCE, 0x41, 0x80, 0x93, 0xDA, 0xB3, 690 | 0xD2, 0x69, 0xF3, 0x08, 0xC7, 0x5A, 0x31, 0x85, 0x27, 0x14, 0x71, 0x70, 0x86, 0x04, 0x8E, 0x25, 691 | 0x5D, 0xC8, 0x39, 0x3B, 0x0E, 0x40, 0x9E, 0xBD, 0xFE, 0x7D, 0xF7, 0xAB, 0x51, 0xC7, 0x7F, 0x66, 692 | 0x68, 0x23, 0x95, 0xF5, 0x6A, 0x01, 0xDD, 0x98, 0xEE, 0xC4, 0xFF, 0x00, 0x9F, 0xCA, 0xB3, 0xE8, 693 | 0xC9, 0x13, 0x02, 0xD1, 0x2B, 0x8C, 0xEF, 0x9E, 0xD5, 0x11, 0x2D, 0x71, 0x74, 0xD3, 0x4A, 0x75, 694 | 0x31, 0x39, 0x3B, 0x51, 0xCA, 0x4B, 0xE8, 0xCE, 0x9A, 0xDB, 0x7E, 0x2A, 0x97, 0x7A, 0x83, 0x44, 695 | 0xA0, 0x8C, 0x67, 0xE6, 0x9B, 0x27, 0x13, 0xB7, 0x0A, 0x8C, 0xB1, 0x82, 0x0E, 0xE3, 0xE3, 0x15, 696 | 0x4B, 0x6D, 0xAA, 0x02, 0x62, 0x1E, 0x96, 0xE4, 0xF9, 0xEE, 0x79, 0xFF, 0x00, 0x4A, 0x87, 0x58, 697 | 0x91, 0x74, 0x0C, 0xF3, 0x04, 0x7E, 0x55, 0x1F, 0xE7, 0x0C, 0xB8, 0x9F, 0x89, 0xEA, 0x5C, 0x46, 698 | 0x17, 0x19, 0xC6, 0xC3, 0x71, 0x55, 0x32, 0xDC, 0x4E, 0x49, 0x61, 0x23, 0x03, 0xF3, 0x4F, 0x54, 699 | 0x2C, 0xA4, 0x8F, 0xA8, 0x0D, 0xEA, 0x39, 0x1B, 0xD3, 0xCB, 0x7A, 0xD3, 0x19, 0x04, 0x0D, 0xD4, 700 | 0xCF, 0x29, 0xD4, 0xC7, 0x2D, 0xD4, 0xD0, 0x24, 0xE4, 0xEE, 0x68, 0xA9, 0xC8, 0xCE, 0x48, 0xA1, 701 | 0xD4, 0x0D, 0x60, 0x9E, 0x59, 0xAA, 0x48, 0x5A, 0x9E, 0xD6, 0x17, 0x92, 0x55, 0x53, 0xB2, 0x93, 702 | 0xCF, 0x1F, 0xE6, 0x6B, 0x69, 0x02, 0x45, 0x66, 0x88, 0x55, 0x4C, 0x84, 0xAF, 0xA8, 0x10, 0x33, 703 | 0x9E, 0xC3, 0xB5, 0x50, 0xF0, 0xAB, 0x11, 0x3C, 0x9E, 0x63, 0x9C, 0x42, 0xBB, 0x92, 0x37, 0xC9, 704 | 0xED, 0x8A, 0xD1, 0xDA, 0xDA, 0x19, 0x35, 0x15, 0x90, 0xA1, 0x1B, 0x96, 0x73, 0x84, 0x03, 0xFC, 705 | 0xEC, 0x0D, 0x3E, 0x10, 0x21, 0xF3, 0xDF, 0xCE, 0xB1, 0x00, 0xB0, 0x08, 0x62, 0xC0, 0xC8, 0x51, 706 | 0x96, 0x63, 0xF2, 0x77, 0x34, 0x04, 0xFE, 0x5D, 0xA5, 0xA6, 0xA4, 0x50, 0x8D, 0x20, 0x1A, 0xB7, 707 | 0xF5, 0x11, 0xF3, 0x8A, 0x3E, 0xEE, 0x40, 0x53, 0xCB, 0x66, 0xF3, 0x34, 0x0F, 0x53, 0x3B, 0x1D, 708 | 0x87, 0x6F, 0xD6, 0xB3, 0x97, 0x85, 0xDF, 0xD7, 0x82, 0x85, 0xBD, 0x58, 0x3D, 0x07, 0x4F, 0x8E, 709 | 0xF4, 0xE7, 0x7A, 0xDE, 0x47, 0xB8, 0xB8, 0xD3, 0x6E, 0x9A, 0x51, 0x46, 0x1D, 0x8E, 0xFB, 0x7C, 710 | 0x74, 0xEB, 0x41, 0xF1, 0x2B, 0x85, 0xD1, 0x15, 0xBC, 0x23, 0x04, 0x31, 0xD4, 0xD9, 0xE7, 0x8F, 711 | 0xFD, 0x35, 0x67, 0x0B, 0x25, 0x95, 0x8B, 0x22, 0x69, 0x52, 0xED, 0xBB, 0x63, 0xD4, 0xDC, 0x85, 712 | 0x54, 0xC6, 0x8B, 0x2B, 0x49, 0x3B, 0x6C, 0xB1, 0x29, 0x25, 0xBA, 0x6F, 0xB5, 0x01, 0x01, 0x7D, 713 | 0xA6, 0x27, 0x1A, 0x00, 0xD0, 0xC0, 0x3E, 0x0F, 0xBF, 0x2F, 0xCA, 0x82, 0xC8, 0x53, 0x86, 0x03, 714 | 0x60, 0x40, 0xDB, 0x99, 0xA3, 0x78, 0xAE, 0x96, 0xBD, 0xF2, 0x90, 0x9F, 0xA1, 0x41, 0xFF, 0x00, 715 | 0x8E, 0x00, 0xCE, 0x7F, 0x5A, 0x07, 0x20, 0xCE, 0xC7, 0x6C, 0x61, 0x9B, 0x03, 0xA6, 0xC6, 0x88, 716 | 0x23, 0x70, 0x18, 0x1C, 0x0D, 0xF7, 0x3F, 0x02, 0x87, 0xA9, 0xD9, 0xF0, 0xEC, 0x7A, 0x30, 0x22, 717 | 0xA2, 0xEB, 0x40, 0x0A, 0xB9, 0x24, 0xE6, 0xBD, 0xF3, 0x5E, 0x5E, 0x74, 0xE0, 0x06, 0xE4, 0xF3, 718 | 0xAC, 0xC6, 0x63, 0xF2, 0xA5, 0xEB, 0x4B, 0x83, 0x9A, 0xF0, 0x15, 0x99, 0xD1, 0x2F, 0x74, 0xF9, 719 | 0x47, 0x18, 0xA0, 0x20, 0x7F, 0x51, 0x04, 0x7C, 0x54, 0xC5, 0x3D, 0x18, 0x27, 0x3E, 0xD5, 0xE5, 720 | 0x81, 0x73, 0xB0, 0xC1, 0xA8, 0x63, 0xD4, 0x21, 0xCC, 0xC0, 0x52, 0xC4, 0xDB, 0xFA, 0x86, 0x36, 721 | 0xAF, 0x3A, 0x69, 0x1C, 0xA9, 0xB8, 0xD8, 0x60, 0xD3, 0x7A, 0xC5, 0x97, 0xEA, 0x04, 0x51, 0x76, 722 | 0xCA, 0x0E, 0x36, 0xA0, 0x91, 0x49, 0x71, 0x56, 0x50, 0x00, 0xAC, 0x33, 0xCA, 0xB7, 0x83, 0x10, 723 | 0xDE, 0xFA, 0x50, 0x83, 0x54, 0x72, 0x47, 0x96, 0x24, 0x56, 0xA2, 0xEA, 0xDC, 0x4B, 0x0E, 0x73, 724 | 0x9A, 0xA1, 0x96, 0x23, 0x1B, 0x91, 0x4D, 0x04, 0x03, 0x29, 0xE4, 0x76, 0xA7, 0x44, 0xCF, 0x0B, 725 | 0x87, 0x89, 0xB4, 0xBA, 0x90, 0x55, 0x87, 0x30, 0x7D, 0xA9, 0xD2, 0x0D, 0xF7, 0x14, 0x84, 0x8C, 726 | 0x72, 0xAC, 0x06, 0x87, 0x64, 0x56, 0x21, 0xB7, 0xC8, 0xDE, 0xBD, 0x1C, 0x98, 0x3B, 0x73, 0xAF, 727 | 0x30, 0xC8, 0xF7, 0xA8, 0xC2, 0x91, 0xC8, 0x50, 0xA2, 0x2D, 0x25, 0x3A, 0x81, 0x1C, 0xB3, 0x5E, 728 | 0x70, 0x34, 0x93, 0x9A, 0x81, 0x33, 0xAB, 0x14, 0xE9, 0x58, 0x85, 0xDE, 0xA7, 0xFA, 0x60, 0x33, 729 | 0xF3, 0xC0, 0xAF, 0x59, 0xC0, 0xD7, 0x37, 0x0B, 0x0A, 0x80, 0x59, 0xB3, 0x80, 0x4E, 0x07, 0xE7, 730 | 0x4B, 0x26, 0xF5, 0x61, 0xC1, 0xAD, 0x07, 0xED, 0x2B, 0x23, 0x49, 0xA1, 0xD4, 0xE5, 0x40, 0xDC, 731 | 0xE3, 0xB8, 0xC5, 0x52, 0x13, 0xF5, 0xA0, 0xB1, 0xB3, 0x9A, 0xD2, 0x24, 0x8B, 0xCB, 0x2B, 0x18, 732 | 0xDC, 0xE0, 0xFD, 0x4D, 0xED, 0x83, 0xBD, 0x1C, 0x8C, 0xB6, 0xC8, 0xAA, 0xD7, 0x31, 0xC6, 0xA3, 733 | 0x7E, 0xB9, 0xC7, 0xE5, 0x45, 0x5B, 0x5B, 0x81, 0x18, 0x94, 0x2E, 0x09, 0x5D, 0x9B, 0xBF, 0xD8, 734 | 0x0F, 0xEB, 0x55, 0xD7, 0x83, 0xCC, 0x5D, 0x10, 0x85, 0x04, 0xEC, 0xAD, 0x8D, 0xCE, 0xFC, 0xBE, 735 | 0x2A, 0xB2, 0x6A, 0x1A, 0x22, 0xBD, 0xE2, 0x11, 0xDD, 0x01, 0x15, 0xA8, 0x90, 0xE4, 0x92, 0xC5, 736 | 0x90, 0x28, 0x0C, 0x7F, 0xDA, 0x07, 0xE5, 0xBF, 0xE5, 0x55, 0x97, 0xB0, 0x47, 0xFB, 0x5C, 0x10, 737 | 0x8B, 0x88, 0xE6, 0x0B, 0xA5, 0xE6, 0x11, 0x03, 0xFB, 0xB3, 0xCC, 0xA6, 0x79, 0x36, 0x00, 0xDF, 738 | 0x1D, 0xE8, 0xAB, 0x99, 0xA0, 0xB3, 0xB6, 0x01, 0x5C, 0xF9, 0xAD, 0xF5, 0x8C, 0x06, 0x08, 0xBD, 739 | 0x77, 0xEA, 0xC4, 0xF6, 0xE5, 0x8E, 0x75, 0x5F, 0x6F, 0x19, 0x16, 0xD2, 0xB9, 0x02, 0x31, 0xA4, 740 | 0x48, 0xE7, 0x39, 0x31, 0xA7, 0x21, 0x9E, 0xC4, 0x92, 0x0F, 0xDE, 0xB1, 0x91, 0x5A, 0x46, 0x2E, 741 | 0x6F, 0xC2, 0xCC, 0x74, 0x40, 0xAA, 0x49, 0x19, 0x1B, 0x0C, 0x12, 0x06, 0xE7, 0x9E, 0x7A, 0x77, 742 | 0xAA, 0xF3, 0x31, 0x11, 0xB5, 0xBC, 0x44, 0x98, 0xF5, 0x21, 0xC6, 0x79, 0xEC, 0x7F, 0xBD, 0x4A, 743 | 0x2E, 0x84, 0x90, 0xCF, 0x3A, 0x07, 0xF2, 0xD4, 0x1C, 0x29, 0xE6, 0x73, 0x81, 0x92, 0x7B, 0xEF, 744 | 0x40, 0xC0, 0xCA, 0x67, 0x69, 0x59, 0xBE, 0x95, 0x24, 0x90, 0x3E, 0xD4, 0x18, 0x07, 0x9A, 0x03, 745 | 0xCA, 0xD8, 0xF5, 0x31, 0xFF, 0x00, 0x3F, 0xA5, 0x0E, 0x5B, 0xD4, 0x48, 0xEB, 0x52, 0x85, 0xD4, 746 | 0xE5, 0x77, 0xD8, 0x1E, 0x55, 0x19, 0x0B, 0xB6, 0x01, 0xE7, 0xB8, 0x35, 0x80, 0xD6, 0xDF, 0x71, 747 | 0xCA, 0xBD, 0x8A, 0x93, 0x4E, 0xA3, 0x8C, 0xF4, 0xAF, 0x05, 0x20, 0xE2, 0xB0, 0x12, 0x35, 0x2C, 748 | 0xC0, 0x54, 0x9A, 0x0E, 0x09, 0xFD, 0x29, 0xF1, 0xAE, 0x14, 0xF7, 0x06, 0x97, 0x48, 0xD3, 0x9C, 749 | 0x9C, 0x9A, 0xC2, 0x1D, 0xB7, 0x26, 0x95, 0x46, 0x76, 0xAF, 0x2A, 0x9D, 0xEA, 0x68, 0x90, 0x93, 750 | 0x42, 0xD6, 0x6E, 0x9C, 0x0C, 0xE3, 0x1B, 0xD4, 0x69, 0x95, 0x6E, 0xC2, 0x9E, 0xEC, 0x4B, 0x6F, 751 | 0x4D, 0x63, 0xB6, 0x47, 0x3A, 0x92, 0x67, 0xCC, 0x3D, 0x02, 0x84, 0xD4, 0x73, 0x81, 0x53, 0x96, 752 | 0x2C, 0xBB, 0xD4, 0x0C, 0x42, 0x9D, 0xE8, 0x63, 0xB6, 0x15, 0x1E, 0x00, 0x04, 0xE2, 0xA6, 0x59, 753 | 0x37, 0x02, 0x82, 0x47, 0xCB, 0x60, 0x51, 0x8A, 0xBB, 0x03, 0x4C, 0x23, 0x0C, 0xFA, 0x62, 0xC1, 754 | 0x38, 0xC5, 0x53, 0x5C, 0x3A, 0xBB, 0x12, 0x79, 0xD1, 0x37, 0x52, 0x11, 0x19, 0x00, 0xF4, 0xAA, 755 | 0xD7, 0xCE, 0x9C, 0x93, 0xF6, 0xA6, 0x6D, 0x99, 0x21, 0x53, 0x50, 0x6D, 0xA8, 0xE2, 0xBC, 0x79, 756 | 0xE4, 0x52, 0x64, 0x93, 0xCE, 0x85, 0x13, 0xF1, 0x8A, 0xF1, 0x20, 0x53, 0x59, 0xB1, 0xF3, 0x48, 757 | 0xBB, 0xEE, 0x4E, 0xD4, 0xA2, 0x99, 0x06, 0xD9, 0x15, 0x05, 0xC3, 0x74, 0x15, 0x29, 0x7C, 0x03, 758 | 0xBE, 0xF4, 0x1C, 0xEF, 0x93, 0x41, 0xAF, 0x8F, 0x5B, 0xC2, 0xD7, 0x37, 0x0B, 0x10, 0x56, 0x24, 759 | 0x9E, 0x82, 0xB7, 0x56, 0x36, 0xFF, 0x00, 0xB0, 0xC5, 0x1A, 0x24, 0x2E, 0x57, 0x4E, 0x08, 0x00, 760 | 0x0C, 0x9F, 0x9F, 0xEB, 0x8A, 0xCF, 0xF8, 0x66, 0xDE, 0x26, 0x95, 0xA7, 0x92, 0x55, 0x42, 0x9D, 761 | 0x59, 0x76, 0xFC, 0xFA, 0x74, 0xAB, 0xFB, 0xFB, 0xBF, 0x2A, 0x37, 0x53, 0x72, 0x8E, 0x54, 0x6A, 762 | 0xD2, 0xD2, 0x17, 0xFE, 0x9B, 0x7E, 0x62, 0xAB, 0x8B, 0x48, 0x1A, 0xE7, 0x88, 0x2D, 0x9A, 0x17, 763 | 0xB9, 0xCC, 0x25, 0xD8, 0x0C, 0x91, 0xAF, 0xF9, 0x55, 0x73, 0x5F, 0xCF, 0x28, 0x6F, 0x21, 0x00, 764 | 0x0E, 0x74, 0xF9, 0xAE, 0x9E, 0xB3, 0xBE, 0xD8, 0xE8, 0xB4, 0x0C, 0xF7, 0xCB, 0x31, 0xD4, 0xAA, 765 | 0x00, 0x0D, 0x80, 0xC4, 0x8C, 0xE2, 0x83, 0xBA, 0xBB, 0x8A, 0x48, 0x88, 0x88, 0x3C, 0xAE, 0xB8, 766 | 0xCB, 0x31, 0xDB, 0xFE, 0xFB, 0x53, 0x6C, 0xDA, 0x11, 0x3C, 0xF1, 0x41, 0x33, 0xA0, 0x65, 0xB9, 767 | 0x94, 0x9D, 0x21, 0x94, 0xE5, 0x73, 0xED, 0xB7, 0xAA, 0x87, 0xBF, 0x9E, 0x4F, 0x2E, 0x51, 0x3B, 768 | 0xEA, 0x62, 0xC4, 0xB8, 0xEA, 0x1B, 0xFC, 0xDB, 0xF4, 0xA8, 0x0C, 0x73, 0x45, 0x68, 0x97, 0x25, 769 | 0x02, 0x34, 0x99, 0x2A, 0x71, 0xD3, 0x3F, 0xC3, 0xDB, 0xE6, 0x99, 0x77, 0x0E, 0x88, 0x22, 0xB7, 770 | 0x19, 0x6B, 0x8D, 0x8C, 0xBB, 0xF5, 0x39, 0xC0, 0xCE, 0x6B, 0x31, 0xE6, 0x15, 0x82, 0xDA, 0x18, 771 | 0x4C, 0xC1, 0xDE, 0x58, 0x56, 0x4C, 0x20, 0xCE, 0x9D, 0x44, 0x6D, 0xCF, 0x9E, 0x33, 0xFA, 0x52, 772 | 0x5A, 0x45, 0x0B, 0x4B, 0x24, 0x12, 0x10, 0xA7, 0xCB, 0x73, 0xEA, 0xE5, 0x90, 0x09, 0xC6, 0xDE, 773 | 0xE0, 0x54, 0xB2, 0x2C, 0x2D, 0x0A, 0x4A, 0xB2, 0x66, 0x48, 0xFD, 0x0C, 0xA5, 0x71, 0xA7, 0x00, 774 | 0x69, 0x24, 0xF5, 0xCE, 0xE0, 0x0F, 0xF8, 0xD0, 0x31, 0xDC, 0x33, 0x5F, 0xF9, 0x8C, 0xA1, 0xB4, 775 | 0x93, 0xE9, 0x27, 0x62, 0x3A, 0x8C, 0xD0, 0x60, 0xB0, 0xC8, 0x23, 0xBB, 0x56, 0x20, 0x15, 0xDC, 776 | 0x1F, 0x8E, 0x55, 0xEB, 0x88, 0x56, 0x19, 0xA6, 0x88, 0x38, 0x6D, 0x0D, 0xE9, 0x2B, 0xC9, 0x87, 777 | 0x71, 0x9E, 0x9D, 0x6A, 0x36, 0x5D, 0x2E, 0x71, 0x9C, 0x03, 0xB6, 0x6A, 0x70, 0xEB, 0x34, 0x25, 778 | 0x1C, 0xE1, 0x90, 0x7A, 0x5B, 0x19, 0xC8, 0xEC, 0x68, 0x82, 0x10, 0x37, 0x19, 0x18, 0xC8, 0xA9, 779 | 0x52, 0x32, 0x02, 0x30, 0x20, 0x83, 0xB1, 0x1D, 0x8D, 0x46, 0xDE, 0xA7, 0x07, 0x90, 0x34, 0xF5, 780 | 0x91, 0xA3, 0x57, 0x41, 0xC8, 0x1C, 0xFD, 0xEB, 0x31, 0xC0, 0xFA, 0xDA, 0x22, 0x71, 0xBE, 0xC4, 781 | 0xD3, 0x19, 0xC8, 0x00, 0x11, 0x5E, 0x67, 0x0D, 0x2F, 0x98, 0x07, 0x30, 0x32, 0x29, 0x0A, 0x9C, 782 | 0x81, 0x8A, 0x0C, 0xF2, 0x2F, 0xAA, 0x8A, 0x8A, 0x3C, 0x51, 0x96, 0x7C, 0x25, 0x65, 0x55, 0x91, 783 | 0xEE, 0xA0, 0x89, 0x08, 0x07, 0x53, 0x37, 0xF4, 0xAB, 0x62, 0xBE, 0x1D, 0xB4, 0x83, 0x05, 0xAE, 784 | 0xEF, 0xAE, 0x31, 0xFC, 0x18, 0x89, 0x17, 0xEE, 0x72, 0x4D, 0x47, 0x2E, 0x59, 0xBD, 0x42, 0xDC, 785 | 0xE4, 0x59, 0xDC, 0x2A, 0xA8, 0x24, 0x54, 0x31, 0x30, 0xD5, 0x83, 0x52, 0xCC, 0xC1, 0xD3, 0x6E, 786 | 0x54, 0x20, 0xD8, 0xF3, 0xA6, 0x93, 0xA2, 0x89, 0x70, 0xB9, 0xC8, 0xE9, 0x41, 0xC8, 0xBA, 0xB2, 787 | 0x3A, 0xD3, 0xCC, 0xB8, 0xD8, 0x9D, 0xA9, 0x81, 0x8B, 0x36, 0xD5, 0xBC, 0x9D, 0xB2, 0x48, 0x17, 788 | 0x49, 0xC9, 0xA3, 0xD7, 0x05, 0x40, 0x14, 0x0A, 0x92, 0x36, 0xCD, 0x13, 0x19, 0x23, 0x14, 0x37, 789 | 0xB1, 0x9D, 0xA0, 0xBB, 0xC8, 0xEF, 0x8A, 0xAE, 0x69, 0x36, 0xC7, 0x5A, 0xB7, 0xBC, 0x40, 0x62, 790 | 0xCD, 0x51, 0x49, 0xB6, 0x70, 0x69, 0xDB, 0x46, 0xB1, 0xA6, 0x6B, 0xC5, 0x35, 0x9F, 0xA6, 0x69, 791 | 0x34, 0xEA, 0xEB, 0x42, 0x8A, 0x4D, 0x41, 0xBF, 0xEE, 0x9E, 0x0E, 0x3E, 0x6A, 0x10, 0x98, 0xA9, 792 | 0x54, 0x1C, 0xD2, 0x89, 0x49, 0xF4, 0xEF, 0x42, 0x48, 0x35, 0x12, 0x40, 0xAB, 0xCB, 0x1E, 0x09, 793 | 0x73, 0xC4, 0x91, 0x8C, 0x05, 0x35, 0x2E, 0x3D, 0x25, 0xB7, 0x3F, 0x6F, 0xB5, 0x5A, 0xF0, 0xFF, 794 | 0x00, 0x0D, 0x2D, 0xB4, 0x5E, 0x6D, 0xFC, 0x0D, 0xE6, 0x0C, 0xEC, 0x0E, 0x46, 0xDF, 0x14, 0xD8, 795 | 0xE3, 0x6B, 0x50, 0xFC, 0x16, 0xD6, 0x5B, 0x3B, 0x35, 0x69, 0x63, 0x68, 0x96, 0x43, 0x9F, 0x30, 796 | 0xAE, 0xAC, 0x8F, 0xFF, 0x00, 0x53, 0x44, 0x5D, 0xDA, 0x35, 0xD6, 0xAD, 0x09, 0x2B, 0xA2, 0x9C, 797 | 0x92, 0x55, 0x54, 0x7C, 0xF2, 0x18, 0x1C, 0x85, 0x1F, 0x32, 0x5A, 0xC8, 0xFE, 0x4C, 0x31, 0x30, 798 | 0x50, 0x07, 0xD6, 0xDC, 0x8F, 0x5C, 0x63, 0xFA, 0x8A, 0xAA, 0xBB, 0x49, 0xCA, 0x30, 0x91, 0x15, 799 | 0xA3, 0x43, 0x92, 0xBB, 0xE9, 0x56, 0xF7, 0xFF, 0x00, 0x71, 0xFE, 0x54, 0xDE, 0x1A, 0x33, 0xD3, 800 | 0xCA, 0xB3, 0x33, 0x2B, 0xC6, 0x15, 0x7A, 0x1D, 0x23, 0x03, 0xF2, 0x1B, 0xD4, 0x51, 0xC8, 0x90, 801 | 0xC5, 0xBC, 0x5A, 0x54, 0x1C, 0xE4, 0x81, 0xCB, 0xE0, 0xED, 0x47, 0xDD, 0xB3, 0x26, 0xA0, 0x63, 802 | 0x0B, 0x9F, 0xE1, 0x23, 0x7C, 0x75, 0xCF, 0xB9, 0xDE, 0xAB, 0x40, 0x55, 0xC8, 0x9D, 0x04, 0x85, 803 | 0x77, 0xD0, 0xA4, 0x32, 0x0F, 0x92, 0x3E, 0x6B, 0x41, 0x49, 0x2C, 0xD2, 0x5C, 0xBA, 0xDC, 0xCE, 804 | 0x87, 0xCB, 0x24, 0x94, 0x19, 0xD8, 0x8A, 0x10, 0xB8, 0x8F, 0x5B, 0x11, 0xEB, 0x91, 0x83, 0x0C, 805 | 0xFD, 0xFF, 0x00, 0x3E, 0x62, 0x9D, 0x3C, 0xED, 0x71, 0x28, 0x5C, 0x92, 0xE3, 0x9E, 0x93, 0xB6, 806 | 0x3B, 0x0E, 0xD4, 0x0E, 0x5A, 0x69, 0x49, 0xC7, 0xA7, 0x90, 0x34, 0xC0, 0x9C, 0x4C, 0x11, 0x99, 807 | 0x95, 0x41, 0x0D, 0x1E, 0x86, 0x53, 0xC8, 0x9C, 0xE4, 0xFF, 0x00, 0x2F, 0xD2, 0xA3, 0x75, 0xF2, 808 | 0x8C, 0x6E, 0x06, 0xAD, 0xF7, 0x39, 0xD8, 0x8F, 0xE9, 0x49, 0x26, 0x72, 0x11, 0x88, 0x21, 0x18, 809 | 0xEE, 0xBB, 0xE7, 0x34, 0x44, 0x58, 0x7D, 0xB0, 0xA7, 0x19, 0x21, 0x24, 0x38, 0xC8, 0xF6, 0xAC, 810 | 0x01, 0x9B, 0xCA, 0x90, 0x15, 0xD0, 0xF1, 0xC8, 0xB9, 0x27, 0x7C, 0xE7, 0xED, 0xD2, 0x90, 0x11, 811 | 0x0C, 0x72, 0x00, 0x41, 0x67, 0x00, 0x1F, 0x61, 0xCF, 0xFA, 0x52, 0xB4, 0x9A, 0x25, 0x8C, 0xE0, 812 | 0x86, 0x56, 0xDC, 0x37, 0x3C, 0x76, 0xA8, 0xEE, 0x1F, 0x12, 0xCA, 0xB9, 0xC8, 0x2F, 0xCF, 0xBE, 813 | 0x39, 0x56, 0xD3, 0x1B, 0xD4, 0x02, 0x29, 0x85, 0x89, 0x62, 0x49, 0xE6, 0x73, 0x5E, 0x0F, 0xB1, 814 | 0xCF, 0x3C, 0x57, 0x80, 0xD4, 0x7B, 0x9A, 0xCC, 0x70, 0xCE, 0x79, 0x6C, 0x28, 0xA8, 0xE3, 0x2C, 815 | 0x72, 0x29, 0x61, 0x88, 0x6C, 0x08, 0xFC, 0xA8, 0xC0, 0x81, 0x46, 0x05, 0x27, 0xAD, 0x4C, 0x5C, 816 | 0x85, 0x03, 0x34, 0xF5, 0x52, 0x7A, 0x52, 0x69, 0x3D, 0xB6, 0xA9, 0x01, 0xC0, 0xCE, 0x29, 0xB4, 817 | 0x47, 0xFF, 0xD9, }; 818 | -------------------------------------------------------------------------------- /examples/FLash_array/Flash_Jpg_GFX/Flash_Jpg_GFX.ino: -------------------------------------------------------------------------------- 1 | // Adafruit_GFX compatible example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example renders a Jpeg file that is stored in an array within Flash (program) memory 5 | // see panda.h tab. The panda image file being ~13Kbytes. 6 | 7 | // Include the array 8 | #include "panda.h" 9 | 10 | // Include the jpeg decoder library 11 | #include 12 | 13 | //ESP32 example setup 14 | //* 15 | #define TFT_CS 27 16 | #define TFT_DC 26 17 | #define TFT_RST 5 18 | //#define SD_CS 4 19 | //*/ 20 | 21 | //ESP8266 example setup 22 | /* 23 | #define TFT_CS D3 24 | #define TFT_DC D8 25 | #define TFT_RST D4 26 | //#define SD_CS 4 27 | //*/ 28 | 29 | #define TFT_BLACK 0x0000 30 | #define TFT_RED 0xF800 31 | 32 | // Include the TFT library 33 | #include "SPI.h" 34 | #include 35 | Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST); 36 | 37 | // This next function will be called during decoding of the jpeg file to 38 | // render each block to the TFT. If you use a different TFT library 39 | // you will need to adapt this function to suit. 40 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 41 | { 42 | // Stop further decoding as image is running off bottom of screen 43 | if ( y >= tft.height() ) return 0; 44 | 45 | // In ILI9341 library this function clips the image block at TFT boundaries 46 | tft.drawRGBBitmap(x, y, bitmap, w, h); 47 | 48 | // Return 1 to decode next block 49 | return 1; 50 | } 51 | 52 | void setup() 53 | { 54 | Serial.begin(115200); 55 | Serial.println("\n\n Testing TJpg_Decoder library"); 56 | 57 | // Initialise the TFT 58 | tft.begin(); 59 | tft.fillScreen(TFT_BLACK); 60 | 61 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 62 | TJpgDec.setJpgScale(1); 63 | 64 | // The decoder must be given the exact name of the rendering function above 65 | TJpgDec.setCallback(tft_output); 66 | } 67 | 68 | void loop() 69 | { 70 | tft.fillScreen(TFT_RED); 71 | 72 | // Time recorded for test purposes 73 | uint32_t t = millis(); 74 | 75 | // Get the width and height in pixels of the jpeg if you wish 76 | uint16_t w = 0, h = 0; 77 | TJpgDec.getJpgSize(&w, &h, panda, sizeof(panda)); 78 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 79 | 80 | // Draw the image, top left at 0,0 81 | TJpgDec.drawJpg(0, 0, panda, sizeof(panda)); 82 | 83 | // How much time did rendering take (ESP8266 80MHz 473ms, 160MHz 266ms, ESP32 SPI 116ms) 84 | t = millis() - t; 85 | Serial.print(t); Serial.println(" ms"); 86 | 87 | // Wait before drawing again 88 | delay(2000); 89 | } 90 | -------------------------------------------------------------------------------- /examples/LittleFS/All_LittleFS/All_LittleFS.ino: -------------------------------------------------------------------------------- 1 | 2 | // Example for library: 3 | // https://github.com/Bodmer/TJpg_Decoder 4 | 5 | // This example if for processors with LittleFS capability (e.g. RP2040, 6 | // ESP32, ESP8266). It renders a Jpeg file that is stored in a LittleFS 7 | // file. 8 | 9 | // The test image is in the sketch "data" folder (press Ctrl+K to see it). 10 | // You must upload the image to LittleFS using the Arduino IDE Tools Data 11 | // Upload menu option (you may need to install extra tools for that). 12 | 13 | // Include the jpeg decoder library 14 | #include 15 | 16 | // Include LittleFS 17 | #include 18 | #include "LittleFS.h" // ESP32 only 19 | 20 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 21 | #include "SPI.h" 22 | #include // Hardware-specific library 23 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 24 | 25 | // Support funtion prototypes 26 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap); 27 | void loadFile(const char *name); 28 | 29 | //==================================================================================== 30 | // Setup 31 | //==================================================================================== 32 | void setup() 33 | { 34 | Serial.begin(115200); 35 | Serial.println("\n\n Testing TJpg_Decoder library"); 36 | 37 | // Initialise LittleFS 38 | if (!LittleFS.begin()) { 39 | Serial.println("LittleFS initialisation failed!"); 40 | while (1) yield(); // Stay here twiddling thumbs waiting 41 | } 42 | Serial.println("\r\nInitialisation done."); 43 | 44 | // Initialise the TFT 45 | tft.begin(); 46 | tft.setTextColor(0xFFFF, 0x0000); 47 | tft.fillScreen(TFT_BLACK); 48 | 49 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 50 | TJpgDec.setJpgScale(1); 51 | 52 | // The byte order can be swapped (set true for TFT_eSPI) 53 | TJpgDec.setSwapBytes(true); 54 | 55 | // The decoder must be given the exact name of the rendering function above 56 | TJpgDec.setCallback(tft_output); 57 | } 58 | 59 | //==================================================================================== 60 | // Loop 61 | //==================================================================================== 62 | void loop() 63 | { 64 | File root = LittleFS.open("/", "r"); 65 | while (File file = root.openNextFile()) { 66 | String strname = file.name(); 67 | strname = "/" + strname; 68 | Serial.println(file.name()); 69 | // If it is not a directory and filename ends in .jpg then load it 70 | if (!file.isDirectory() && strname.endsWith(".jpg")) { 71 | loadFile(strname.c_str()); 72 | } 73 | } 74 | } 75 | 76 | //==================================================================================== 77 | // tft_output 78 | //==================================================================================== 79 | // This next function will be called during decoding of the jpeg file to 80 | // render each block to the TFT. If you use a different TFT library 81 | // you will need to adapt this function to suit. 82 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 83 | { 84 | // Stop further decoding as image is running off bottom of screen 85 | if ( y >= tft.height() ) return 0; 86 | 87 | // This function will clip the image block rendering automatically at the TFT boundaries 88 | tft.pushImage(x, y, w, h, bitmap); 89 | 90 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 91 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 92 | 93 | // Return 1 to decode next block 94 | return 1; 95 | } 96 | 97 | //==================================================================================== 98 | // load_file 99 | //==================================================================================== 100 | 101 | void loadFile(const char *name) 102 | { 103 | tft.fillScreen(TFT_RED); 104 | 105 | // Time recorded for test purposes 106 | uint32_t t = millis(); 107 | 108 | // Get the width and height in pixels of the jpeg if you wish 109 | uint16_t w = 0, h = 0, scale; 110 | TJpgDec.getFsJpgSize(&w, &h, name, LittleFS); // Note name preceded with "/" 111 | tft.setRotation(w > h ? 1 : 0); 112 | 113 | for (scale = 1; scale <= 8; scale <<= 1) { 114 | if (w <= tft.width() * scale && h <= tft.height() * scale) break; 115 | } 116 | TJpgDec.setJpgScale(scale); 117 | 118 | // Draw the image, top left at 0,0 119 | TJpgDec.drawFsJpg(0, 0, name, LittleFS); 120 | 121 | // How much time did rendering take 122 | t = millis() - t; 123 | 124 | char buf[80]; 125 | sprintf(buf, "%s %dx%d 1:%d %u ms", name, w, h, scale, t); 126 | tft.setCursor(0, tft.height() - 8); 127 | tft.print(buf); 128 | Serial.println(buf); 129 | delay(2000); 130 | } 131 | -------------------------------------------------------------------------------- /examples/LittleFS/All_LittleFS/data/Baboon40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/LittleFS/All_LittleFS/data/Baboon40.jpg -------------------------------------------------------------------------------- /examples/LittleFS/All_LittleFS/data/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/LittleFS/All_LittleFS/data/panda.jpg -------------------------------------------------------------------------------- /examples/LittleFS/All_LittleFS/data/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/LittleFS/All_LittleFS/data/tiger.jpg -------------------------------------------------------------------------------- /examples/LittleFS/LittleFS_Jpg/LittleFS_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example if for processors with LittleFS capability (e.g. RP2040, 5 | // ESP32, ESP8266). It renders a Jpeg file that is stored in a LittleFS 6 | // file. 7 | 8 | // The test image is in the sketch "data" folder (press Ctrl+K to see it). 9 | // You must upload the image to LittleFS using the Arduino IDE Tools Data 10 | // Upload menu option (you may need to install extra tools for that). 11 | 12 | // Include the jpeg decoder library 13 | #include 14 | 15 | // Include LittleFS 16 | #include 17 | #include "LittleFS.h" 18 | 19 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 20 | #include "SPI.h" 21 | #include // Hardware-specific library 22 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 23 | 24 | 25 | // This next function will be called during decoding of the jpeg file to 26 | // render each block to the TFT. If you use a different TFT library 27 | // you will need to adapt this function to suit. 28 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 29 | { 30 | // Stop further decoding as image is running off bottom of screen 31 | if ( y >= tft.height() ) return 0; 32 | 33 | // This function will clip the image block rendering automatically at the TFT boundaries 34 | tft.pushImage(x, y, w, h, bitmap); 35 | 36 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 37 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 38 | 39 | // Return 1 to decode next block 40 | return 1; 41 | } 42 | 43 | 44 | void setup() 45 | { 46 | Serial.begin(115200); 47 | Serial.println("\n\n Testing TJpg_Decoder library"); 48 | 49 | // Initialise LittleFS 50 | if (!LittleFS.begin()) { 51 | Serial.println("LittleFS initialisation failed!"); 52 | while (1) yield(); // Stay here twiddling thumbs waiting 53 | } 54 | Serial.println("\r\nInitialisation done."); 55 | 56 | // Initialise the TFT 57 | tft.begin(); 58 | tft.setTextColor(0xFFFF, 0x0000); 59 | tft.fillScreen(TFT_BLACK); 60 | tft.setSwapBytes(true); // We need to swap the colour bytes (endianess) 61 | 62 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 63 | TJpgDec.setJpgScale(1); 64 | 65 | // The decoder must be given the exact name of the rendering function above 66 | TJpgDec.setCallback(tft_output); 67 | } 68 | 69 | void loop() 70 | { 71 | tft.fillScreen(TFT_RED); 72 | 73 | // Time recorded for test purposes 74 | uint32_t t = millis(); 75 | 76 | // Get the width and height in pixels of the jpeg if you wish 77 | uint16_t w = 0, h = 0; 78 | TJpgDec.getFsJpgSize(&w, &h, "/panda.jpg", LittleFS); // Note name preceded with "/" 79 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 80 | 81 | // Draw the image, top left at 0,0 82 | TJpgDec.drawFsJpg(0, 0, "/panda.jpg", LittleFS); 83 | 84 | // How much time did rendering take (ESP8266 80MHz 271ms, 160MHz 157ms, ESP32 SPI 120ms, 8bit parallel 105ms 85 | t = millis() - t; 86 | Serial.print(t); Serial.println(" ms"); 87 | 88 | // Wait before drawing again 89 | delay(2000); 90 | } 91 | -------------------------------------------------------------------------------- /examples/LittleFS/LittleFS_Jpg/data/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/LittleFS/LittleFS_Jpg/data/panda.jpg -------------------------------------------------------------------------------- /examples/LittleFS/LittleFS_Web_Jpg/List_LittleFS.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | ** Function name: listLittleFS 3 | ** Description: Listing LittleFS files 4 | ***************************************************************************************/ 5 | void listLittleFS(void) { 6 | Serial.println(F("\r\nListing LittleFS files:")); 7 | static const char line[] PROGMEM = "================================================="; 8 | 9 | Serial.println(FPSTR(line)); 10 | Serial.println(F(" File name Size")); 11 | Serial.println(FPSTR(line)); 12 | 13 | fs::File root = LittleFS.open("/", "r"); 14 | if (!root) { 15 | Serial.println(F("Failed to open directory")); 16 | return; 17 | } 18 | if (!root.isDirectory()) { 19 | Serial.println(F("Not a directory")); 20 | return; 21 | } 22 | 23 | fs::File file = root.openNextFile(); 24 | while (file) { 25 | 26 | if (file.isDirectory()) { 27 | Serial.print("DIR : "); 28 | String fileName = file.name(); 29 | Serial.print(fileName); 30 | } else { 31 | String fileName = file.name(); 32 | Serial.print(" " + fileName); 33 | // File path can be 31 characters maximum in LittleFS 34 | int spaces = 33 - fileName.length(); // Tabulate nicely 35 | if (spaces < 1) spaces = 1; 36 | while (spaces--) Serial.print(" "); 37 | String fileSize = (String) file.size(); 38 | spaces = 10 - fileSize.length(); // Tabulate nicely 39 | if (spaces < 1) spaces = 1; 40 | while (spaces--) Serial.print(" "); 41 | Serial.println(fileSize + " bytes"); 42 | } 43 | 44 | file = root.openNextFile(); 45 | } 46 | 47 | Serial.println(FPSTR(line)); 48 | Serial.println(); 49 | delay(1000); 50 | } 51 | -------------------------------------------------------------------------------- /examples/LittleFS/LittleFS_Web_Jpg/LittleFS_Web_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example is for an ESP8266 or ESP32, it fetches a Jpeg file 5 | // from the web and saves it in a LittleFS file. You must have LittleFS 6 | // space allocated in the IDE. 7 | 8 | // Chenge next 2 lines to suit your WiFi network 9 | #define WIFI_SSID "Your_SSID" 10 | #define PASSWORD "Your password" 11 | 12 | 13 | // Include the jpeg decoder library 14 | #include 15 | 16 | // Include LittleFS 17 | #include 18 | #include "LittleFS.h" 19 | 20 | // Include WiFi and http client 21 | #ifdef ARDUINO_ARCH_ESP8266 22 | #include 23 | #include 24 | #include 25 | #include 26 | #else 27 | #include 28 | #include 29 | #endif 30 | 31 | // Load tabs attached to this sketch 32 | #include "List_LittleFS.h" 33 | #include "Web_Fetch.h" 34 | 35 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 36 | #include "SPI.h" 37 | #include // Hardware-specific library 38 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 39 | 40 | // This next function will be called during decoding of the jpeg file to 41 | // render each block to the TFT. If you use a different TFT library 42 | // you will need to adapt this function to suit. 43 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 44 | { 45 | // Stop further decoding as image is running off bottom of screen 46 | if ( y >= tft.height() ) return 0; 47 | 48 | // This function will clip the image block rendering automatically at the TFT boundaries 49 | tft.pushImage(x, y, w, h, bitmap); 50 | 51 | // Return 1 to decode next block 52 | return 1; 53 | } 54 | 55 | void setup() 56 | { 57 | Serial.begin(115200); 58 | Serial.println("\n\n Testing TJpg_Decoder library"); 59 | 60 | // Initialise LittleFS 61 | if (!LittleFS.begin()) { 62 | Serial.println("LittleFS initialisation failed!"); 63 | while (1) yield(); // Stay here twiddling thumbs waiting 64 | } 65 | Serial.println("\r\nInitialisation done."); 66 | 67 | // Initialise the TFT 68 | tft.begin(); 69 | tft.fillScreen(TFT_BLACK); 70 | 71 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 72 | TJpgDec.setJpgScale(1); 73 | 74 | // The byte order can be swapped (set true for TFT_eSPI) 75 | TJpgDec.setSwapBytes(true); 76 | 77 | // The decoder must be given the exact name of the rendering function above 78 | TJpgDec.setCallback(tft_output); 79 | 80 | WiFi.begin(WIFI_SSID, PASSWORD); 81 | 82 | while (WiFi.status() != WL_CONNECTED) { 83 | delay(1000); 84 | Serial.print("."); 85 | } 86 | Serial.println(); 87 | 88 | // This is for demoe purposes only so that file is fetched each time this is run 89 | if (LittleFS.exists("/M81.jpg") == true) { 90 | Serial.println("For test only, removing file"); 91 | LittleFS.remove("/M81.jpg"); 92 | //LittleFS.remove("/F35.jpg"); 93 | } 94 | } 95 | 96 | void loop() 97 | { 98 | // List files stored in LittleFS 99 | listLittleFS(); 100 | 101 | // Time recorded for test purposes 102 | uint32_t t = millis(); 103 | 104 | // Fetch the jpg file from the specified URL, examples only, from imgur 105 | bool loaded_ok = getFile("https://i.imgur.com/C77RWcq.jpg", "/M81.jpg"); // Note name preceded with "/" 106 | //bool loaded_ok = getFile("https://i.imgur.com/OnW2qOO.jpg", "/F35.jpg"); 107 | 108 | t = millis() - t; 109 | if (loaded_ok) { Serial.print(t); Serial.println(" ms to download"); } 110 | 111 | // List files stored in LittleFS, should have the file now 112 | listLittleFS(); 113 | 114 | t = millis(); 115 | 116 | // Now draw the LittleFS file 117 | TJpgDec.drawFsJpg(0, 0, "/M81.jpg", LittleFS); 118 | //TJpgDec.drawFsJpg(0, 0, "/F35.jpg", LittleFS); 119 | 120 | t = millis() - t; 121 | Serial.print(t); Serial.println(" ms to draw to TFT"); 122 | 123 | // Wait forever 124 | while(1) yield(); 125 | } 126 | -------------------------------------------------------------------------------- /examples/LittleFS/LittleFS_Web_Jpg/Web_Fetch.h: -------------------------------------------------------------------------------- 1 | // Fetch a file from the URL given and save it in LittleFS 2 | // Return 1 if a web fetch was needed or 0 if file already exists 3 | bool getFile(String url, String filename) { 4 | 5 | // If it exists then no need to fetch it 6 | if (LittleFS.exists(filename) == true) { 7 | Serial.println("Found " + filename); 8 | return 0; 9 | } 10 | 11 | Serial.println("Downloading " + filename + " from " + url); 12 | 13 | // Check WiFi connection 14 | if ((WiFi.status() == WL_CONNECTED)) { 15 | 16 | Serial.print("[HTTP] begin...\n"); 17 | 18 | #ifdef ARDUINO_ARCH_ESP8266 19 | std::unique_ptrclient(new BearSSL::WiFiClientSecure); 20 | client -> setInsecure(); 21 | HTTPClient http; 22 | http.begin(*client, url); 23 | #else 24 | HTTPClient http; 25 | // Configure server and url 26 | http.begin(url); 27 | #endif 28 | 29 | Serial.print("[HTTP] GET...\n"); 30 | // Start connection and send HTTP header 31 | int httpCode = http.GET(); 32 | if (httpCode == 200) { 33 | fs::File f = LittleFS.open(filename, "w+"); 34 | if (!f) { 35 | Serial.println("file open failed"); 36 | return 0; 37 | } 38 | // HTTP header has been send and Server response header has been handled 39 | Serial.printf("[HTTP] GET... code: %d\n", httpCode); 40 | 41 | // File found at server 42 | if (httpCode == HTTP_CODE_OK) { 43 | 44 | // Get length of document (is -1 when Server sends no Content-Length header) 45 | int total = http.getSize(); 46 | int len = total; 47 | 48 | // Create buffer for read 49 | uint8_t buff[128] = { 0 }; 50 | 51 | // Get tcp stream 52 | WiFiClient * stream = http.getStreamPtr(); 53 | 54 | // Read all data from server 55 | while (http.connected() && (len > 0 || len == -1)) { 56 | // Get available data size 57 | size_t size = stream->available(); 58 | 59 | if (size) { 60 | // Read up to 128 bytes 61 | int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); 62 | 63 | // Write it to file 64 | f.write(buff, c); 65 | 66 | // Calculate remaining bytes 67 | if (len > 0) { 68 | len -= c; 69 | } 70 | } 71 | yield(); 72 | } 73 | Serial.println(); 74 | Serial.print("[HTTP] connection closed or file end.\n"); 75 | } 76 | f.close(); 77 | } 78 | else { 79 | Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 80 | } 81 | http.end(); 82 | } 83 | return 1; // File was fetched from web 84 | } 85 | -------------------------------------------------------------------------------- /examples/SD Card/SD_Jpg/SD_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example if for an ESP8266 or ESP32, it renders a Jpeg file 5 | // that is stored in a SD card file. The test image is in the sketch 6 | // "data" folder (press Ctrl+K to see it). You must save the image 7 | // to the SD card using you PC. 8 | 9 | // Include the jpeg decoder library 10 | #include 11 | 12 | // Include SD 13 | #define FS_NO_GLOBALS 14 | #include 15 | #ifdef ESP32 16 | #include "SPIFFS.h" // ESP32 only 17 | #endif 18 | 19 | #define SD_CS 4 20 | 21 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 22 | #include "SPI.h" 23 | #include // Hardware-specific library 24 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 25 | 26 | 27 | // This next function will be called during decoding of the jpeg file to 28 | // render each block to the TFT. If you use a different TFT library 29 | // you will need to adapt this function to suit. 30 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 31 | { 32 | // Stop further decoding as image is running off bottom of screen 33 | if ( y >= tft.height() ) return 0; 34 | 35 | // This function will clip the image block rendering automatically at the TFT boundaries 36 | tft.pushImage(x, y, w, h, bitmap); 37 | 38 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 39 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 40 | 41 | // Return 1 to decode next block 42 | return 1; 43 | } 44 | 45 | 46 | void setup() 47 | { 48 | Serial.begin(115200); 49 | Serial.println("\n\n Testing TJpg_Decoder library"); 50 | 51 | // Initialise SD before TFT 52 | if (!SD.begin(SD_CS)) { 53 | Serial.println(F("SD.begin failed!")); 54 | while (1) delay(0); 55 | } 56 | Serial.println("\r\nInitialisation done."); 57 | 58 | // Initialise the TFT 59 | tft.begin(); 60 | tft.setTextColor(0xFFFF, 0x0000); 61 | tft.fillScreen(TFT_BLACK); 62 | tft.setSwapBytes(true); // We need to swap the colour bytes (endianess) 63 | 64 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 65 | TJpgDec.setJpgScale(1); 66 | 67 | // The decoder must be given the exact name of the rendering function above 68 | TJpgDec.setCallback(tft_output); 69 | } 70 | 71 | void loop() 72 | { 73 | tft.fillScreen(TFT_RED); 74 | 75 | // Time recorded for test purposes 76 | uint32_t t = millis(); 77 | 78 | // Get the width and height in pixels of the jpeg if you wish 79 | uint16_t w = 0, h = 0; 80 | TJpgDec.getSdJpgSize(&w, &h, "/panda.jpg"); 81 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 82 | 83 | // Draw the image, top left at 0,0 84 | TJpgDec.drawSdJpg(0, 0, "/panda.jpg"); 85 | 86 | // How much time did rendering take 87 | t = millis() - t; 88 | Serial.print(t); Serial.println(" ms"); 89 | 90 | // Wait before drawing again 91 | delay(2000); 92 | } 93 | -------------------------------------------------------------------------------- /examples/SD Card/SD_Jpg/data/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/SD Card/SD_Jpg/data/panda.jpg -------------------------------------------------------------------------------- /examples/SPIFFS/All_SPIFFS/All_SPIFFS.ino: -------------------------------------------------------------------------------- 1 | 2 | // Example for library: 3 | // https://github.com/Bodmer/TJpg_Decoder 4 | 5 | // This example is for an ESP8266 or ESP32, it renders all Jpeg files 6 | // found in SPIFFS. The test images are in the sketch "data" folder 7 | // (press Ctrl+K to see it). You can add more images of your own to 8 | // the Data folder. 9 | 10 | // You must upload the images to SPIFFS using the ESP8266 or ESP32 11 | // Arduino IDE Sketch Data Upload menu option. 12 | 13 | // Include the jpeg decoder library 14 | #include 15 | 16 | // Include SPIFFS 17 | #define FS_NO_GLOBALS 18 | #include 19 | #ifdef ESP32 20 | #include "SPIFFS.h" // ESP32 only 21 | #endif 22 | 23 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 24 | #include "SPI.h" 25 | #include // Hardware-specific library 26 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 27 | 28 | // Support funtion prototypes 29 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap); 30 | void loadFile(const char *name); 31 | 32 | //==================================================================================== 33 | // Setup 34 | //==================================================================================== 35 | void setup() 36 | { 37 | Serial.begin(115200); 38 | Serial.println("\n\n Testing TJpg_Decoder library"); 39 | 40 | // Initialise SPIFFS 41 | if (!SPIFFS.begin()) { 42 | Serial.println("SPIFFS initialisation failed!"); 43 | while (1) yield(); // Stay here twiddling thumbs waiting 44 | } 45 | Serial.println("\r\nInitialisation done."); 46 | 47 | // Initialise the TFT 48 | tft.begin(); 49 | tft.setTextColor(0xFFFF, 0x0000); 50 | tft.fillScreen(TFT_BLACK); 51 | 52 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 53 | TJpgDec.setJpgScale(1); 54 | 55 | // The byte order can be swapped (set true for TFT_eSPI) 56 | TJpgDec.setSwapBytes(true); 57 | 58 | // The decoder must be given the exact name of the rendering function above 59 | TJpgDec.setCallback(tft_output); 60 | } 61 | 62 | //==================================================================================== 63 | // Loop 64 | //==================================================================================== 65 | #if defined(ESP32) 66 | void loop() 67 | { 68 | File root = SPIFFS.open("/"); 69 | while (File file = root.openNextFile()) { 70 | String strname = file.name(); 71 | strname = "/" + strname; 72 | // If it is not a directory and filename ends in .jpg then load it 73 | if (!file.isDirectory() && strname.endsWith(".jpg")) { 74 | loadFile(strname.c_str()); 75 | } 76 | } 77 | } 78 | #else // ESP8266 has different SPIFFS methods 79 | void loop() 80 | { 81 | fs::Dir directory = SPIFFS.openDir("/"); 82 | while (directory.next()) { 83 | String strname = directory.fileName(); 84 | strname = "/" + strname; 85 | // If filename ends in .jpg then load it 86 | if (strname.endsWith(".jpg")) { 87 | loadFile(strname.c_str()); 88 | } 89 | } 90 | } 91 | #endif 92 | 93 | //==================================================================================== 94 | // tft_output 95 | //==================================================================================== 96 | // This next function will be called during decoding of the jpeg file to 97 | // render each block to the TFT. If you use a different TFT library 98 | // you will need to adapt this function to suit. 99 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 100 | { 101 | // Stop further decoding as image is running off bottom of screen 102 | if ( y >= tft.height() ) return 0; 103 | 104 | // This function will clip the image block rendering automatically at the TFT boundaries 105 | tft.pushImage(x, y, w, h, bitmap); 106 | 107 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 108 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 109 | 110 | // Return 1 to decode next block 111 | return 1; 112 | } 113 | 114 | //==================================================================================== 115 | // load_file 116 | //==================================================================================== 117 | 118 | void loadFile(const char *name) 119 | { 120 | tft.fillScreen(TFT_RED); 121 | 122 | // Time recorded for test purposes 123 | uint32_t t = millis(); 124 | 125 | // Get the width and height in pixels of the jpeg if you wish 126 | uint16_t w = 0, h = 0, scale; 127 | TJpgDec.getFsJpgSize(&w, &h, name); // Note name preceded with "/" 128 | tft.setRotation(w > h ? 1 : 0); 129 | 130 | for (scale = 1; scale <= 8; scale <<= 1) { 131 | if (w <= tft.width() * scale && h <= tft.height() * scale) break; 132 | } 133 | TJpgDec.setJpgScale(scale); 134 | 135 | // Draw the image, top left at 0,0 136 | TJpgDec.drawFsJpg(0, 0, name); 137 | 138 | // How much time did rendering take 139 | t = millis() - t; 140 | 141 | char buf[80]; 142 | sprintf(buf, "%s %dx%d 1:%d %u ms", name, w, h, scale, t); 143 | tft.setCursor(0, tft.height() - 8); 144 | tft.print(buf); 145 | Serial.println(buf); 146 | delay(2000); 147 | } 148 | -------------------------------------------------------------------------------- /examples/SPIFFS/All_SPIFFS/Data/Baboon40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/SPIFFS/All_SPIFFS/Data/Baboon40.jpg -------------------------------------------------------------------------------- /examples/SPIFFS/All_SPIFFS/Data/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/SPIFFS/All_SPIFFS/Data/panda.jpg -------------------------------------------------------------------------------- /examples/SPIFFS/All_SPIFFS/Data/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/SPIFFS/All_SPIFFS/Data/tiger.jpg -------------------------------------------------------------------------------- /examples/SPIFFS/SPIFFS_Jpg/SPIFFS_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example if for an ESP8266 or ESP32, it renders a Jpeg file 5 | // that is stored in a SPIFFS file. The test image is in the sketch 6 | // "data" folder (press Ctrl+K to see it). You must upload the image 7 | // to SPIFFS using the ESP8266 or ESP32 Arduino IDE upload menu option. 8 | 9 | // Include the jpeg decoder library 10 | #include 11 | 12 | // Include SPIFFS 13 | #define FS_NO_GLOBALS 14 | #include 15 | #ifdef ESP32 16 | #include "SPIFFS.h" // ESP32 only 17 | #endif 18 | 19 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 20 | #include "SPI.h" 21 | #include // Hardware-specific library 22 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 23 | 24 | 25 | // This next function will be called during decoding of the jpeg file to 26 | // render each block to the TFT. If you use a different TFT library 27 | // you will need to adapt this function to suit. 28 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 29 | { 30 | // Stop further decoding as image is running off bottom of screen 31 | if ( y >= tft.height() ) return 0; 32 | 33 | // This function will clip the image block rendering automatically at the TFT boundaries 34 | tft.pushImage(x, y, w, h, bitmap); 35 | 36 | // This might work instead if you adapt the sketch to use the Adafruit_GFX library 37 | // tft.drawRGBBitmap(x, y, bitmap, w, h); 38 | 39 | // Return 1 to decode next block 40 | return 1; 41 | } 42 | 43 | 44 | void setup() 45 | { 46 | Serial.begin(115200); 47 | Serial.println("\n\n Testing TJpg_Decoder library"); 48 | 49 | // Initialise SPIFFS 50 | if (!SPIFFS.begin()) { 51 | Serial.println("SPIFFS initialisation failed!"); 52 | while (1) yield(); // Stay here twiddling thumbs waiting 53 | } 54 | Serial.println("\r\nInitialisation done."); 55 | 56 | // Initialise the TFT 57 | tft.begin(); 58 | tft.setTextColor(0xFFFF, 0x0000); 59 | tft.fillScreen(TFT_BLACK); 60 | tft.setSwapBytes(true); // We need to swap the colour bytes (endianess) 61 | 62 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 63 | TJpgDec.setJpgScale(1); 64 | 65 | // The decoder must be given the exact name of the rendering function above 66 | TJpgDec.setCallback(tft_output); 67 | } 68 | 69 | void loop() 70 | { 71 | tft.fillScreen(TFT_RED); 72 | 73 | // Time recorded for test purposes 74 | uint32_t t = millis(); 75 | 76 | // Get the width and height in pixels of the jpeg if you wish 77 | uint16_t w = 0, h = 0; 78 | TJpgDec.getFsJpgSize(&w, &h, "/panda.jpg"); // Note name preceded with "/" 79 | Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h); 80 | 81 | // Draw the image, top left at 0,0 82 | TJpgDec.drawFsJpg(0, 0, "/panda.jpg"); 83 | 84 | // How much time did rendering take (ESP8266 80MHz 271ms, 160MHz 157ms, ESP32 SPI 120ms, 8bit parallel 105ms 85 | t = millis() - t; 86 | Serial.print(t); Serial.println(" ms"); 87 | 88 | // Wait before drawing again 89 | delay(2000); 90 | } 91 | -------------------------------------------------------------------------------- /examples/SPIFFS/SPIFFS_Jpg/data/panda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bodmer/TJpg_Decoder/71bfc2607b6963ee3334ff6f601345c5d2b7a8da/examples/SPIFFS/SPIFFS_Jpg/data/panda.jpg -------------------------------------------------------------------------------- /examples/SPIFFS/SPIFFS_Web_Jpg/List_SPIFFS.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | ** Function name: listSPIFFS 3 | ** Description: Listing SPIFFS files 4 | ***************************************************************************************/ 5 | #ifdef ARDUINO_ARCH_ESP8266 6 | void listSPIFFS(void) { 7 | Serial.println(F("\r\nListing SPIFFS files:")); 8 | 9 | fs::Dir dir = SPIFFS.openDir("/"); // Root directory 10 | 11 | static const char line[] PROGMEM = "================================================="; 12 | Serial.println(FPSTR(line)); 13 | Serial.println(F(" File name Size")); 14 | Serial.println(FPSTR(line)); 15 | 16 | while (dir.next()) { 17 | String fileName = dir.fileName(); 18 | Serial.print(fileName); 19 | int spaces = 33 - fileName.length(); // Tabulate nicely 20 | if (spaces < 1) spaces = 1; 21 | while (spaces--) Serial.print(" "); 22 | 23 | fs::File f = dir.openFile("r"); 24 | String fileSize = (String) f.size(); 25 | spaces = 10 - fileSize.length(); // Tabulate nicely 26 | if (spaces < 1) spaces = 1; 27 | while (spaces--) Serial.print(" "); 28 | Serial.println(fileSize + " bytes"); 29 | } 30 | 31 | Serial.println(FPSTR(line)); 32 | Serial.println(); 33 | delay(1000); 34 | } 35 | 36 | //==================================================================================== 37 | 38 | #elif defined ESP32 39 | 40 | void listSPIFFS(void) { 41 | Serial.println(F("\r\nListing SPIFFS files:")); 42 | static const char line[] PROGMEM = "================================================="; 43 | 44 | Serial.println(FPSTR(line)); 45 | Serial.println(F(" File name Size")); 46 | Serial.println(FPSTR(line)); 47 | 48 | fs::File root = SPIFFS.open("/"); 49 | if (!root) { 50 | Serial.println(F("Failed to open directory")); 51 | return; 52 | } 53 | if (!root.isDirectory()) { 54 | Serial.println(F("Not a directory")); 55 | return; 56 | } 57 | 58 | fs::File file = root.openNextFile(); 59 | while (file) { 60 | 61 | if (file.isDirectory()) { 62 | Serial.print("DIR : "); 63 | String fileName = file.name(); 64 | Serial.print(fileName); 65 | } else { 66 | String fileName = file.name(); 67 | Serial.print(" " + fileName); 68 | // File path can be 31 characters maximum in SPIFFS 69 | int spaces = 33 - fileName.length(); // Tabulate nicely 70 | if (spaces < 1) spaces = 1; 71 | while (spaces--) Serial.print(" "); 72 | String fileSize = (String) file.size(); 73 | spaces = 10 - fileSize.length(); // Tabulate nicely 74 | if (spaces < 1) spaces = 1; 75 | while (spaces--) Serial.print(" "); 76 | Serial.println(fileSize + " bytes"); 77 | } 78 | 79 | file = root.openNextFile(); 80 | } 81 | 82 | Serial.println(FPSTR(line)); 83 | Serial.println(); 84 | delay(1000); 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /examples/SPIFFS/SPIFFS_Web_Jpg/SPIFFS_Web_Jpg.ino: -------------------------------------------------------------------------------- 1 | // Example for library: 2 | // https://github.com/Bodmer/TJpg_Decoder 3 | 4 | // This example is for an ESP8266 or ESP32, it fetches a Jpeg file 5 | // from the web and saves it in a SPIFFS file. You must have SPIFFS 6 | // space allocated in the IDE. 7 | 8 | // Chenge next 2 lines to suit your WiFi network 9 | #define WIFI_SSID "Your_SSID" 10 | #define PASSWORD "Your password" 11 | 12 | 13 | // Include the jpeg decoder library 14 | #include 15 | 16 | // Include SPIFFS 17 | #define FS_NO_GLOBALS 18 | #include 19 | 20 | // Include WiFi and http client 21 | #ifdef ARDUINO_ARCH_ESP8266 22 | #include 23 | #include 24 | #include 25 | #include 26 | #else 27 | #include "SPIFFS.h" // Required for ESP32 only 28 | #include 29 | #include 30 | #endif 31 | 32 | // Load tabs attached to this sketch 33 | #include "List_SPIFFS.h" 34 | #include "Web_Fetch.h" 35 | 36 | // Include the TFT library https://github.com/Bodmer/TFT_eSPI 37 | #include "SPI.h" 38 | #include // Hardware-specific library 39 | TFT_eSPI tft = TFT_eSPI(); // Invoke custom library 40 | 41 | // This next function will be called during decoding of the jpeg file to 42 | // render each block to the TFT. If you use a different TFT library 43 | // you will need to adapt this function to suit. 44 | bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) 45 | { 46 | // Stop further decoding as image is running off bottom of screen 47 | if ( y >= tft.height() ) return 0; 48 | 49 | // This function will clip the image block rendering automatically at the TFT boundaries 50 | tft.pushImage(x, y, w, h, bitmap); 51 | 52 | // Return 1 to decode next block 53 | return 1; 54 | } 55 | 56 | void setup() 57 | { 58 | Serial.begin(115200); 59 | Serial.println("\n\n Testing TJpg_Decoder library"); 60 | 61 | // Initialise SPIFFS 62 | if (!SPIFFS.begin()) { 63 | Serial.println("SPIFFS initialisation failed!"); 64 | while (1) yield(); // Stay here twiddling thumbs waiting 65 | } 66 | Serial.println("\r\nInitialisation done."); 67 | 68 | // Initialise the TFT 69 | tft.begin(); 70 | tft.fillScreen(TFT_BLACK); 71 | 72 | // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 73 | TJpgDec.setJpgScale(1); 74 | 75 | // The byte order can be swapped (set true for TFT_eSPI) 76 | TJpgDec.setSwapBytes(true); 77 | 78 | // The decoder must be given the exact name of the rendering function above 79 | TJpgDec.setCallback(tft_output); 80 | 81 | WiFi.begin(WIFI_SSID, PASSWORD); 82 | 83 | while (WiFi.status() != WL_CONNECTED) { 84 | delay(1000); 85 | Serial.print("."); 86 | } 87 | Serial.println(); 88 | 89 | // This is for demoe purposes only so that file is fetched each time this is run 90 | if (SPIFFS.exists("/M81.jpg") == true) { 91 | Serial.println("For test only, removing file"); 92 | SPIFFS.remove("/M81.jpg"); 93 | //SPIFFS.remove("/F35.jpg"); 94 | } 95 | } 96 | 97 | void loop() 98 | { 99 | // List files stored in SPIFFS 100 | listSPIFFS(); 101 | 102 | // Time recorded for test purposes 103 | uint32_t t = millis(); 104 | 105 | // Fetch the jpg file from the specified URL, examples only, from imgur 106 | bool loaded_ok = getFile("https://i.imgur.com/C77RWcq.jpg", "/M81.jpg"); // Note name preceded with "/" 107 | //bool loaded_ok = getFile("https://i.imgur.com/OnW2qOO.jpg", "/F35.jpg"); 108 | 109 | t = millis() - t; 110 | if (loaded_ok) { Serial.print(t); Serial.println(" ms to download"); } 111 | 112 | // List files stored in SPIFFS, should have the file now 113 | listSPIFFS(); 114 | 115 | t = millis(); 116 | 117 | // Now draw the SPIFFS file 118 | TJpgDec.drawFsJpg(0, 0, "/M81.jpg"); 119 | //TJpgDec.drawFsJpg(0, 0, "/F35.jpg"); 120 | 121 | t = millis() - t; 122 | Serial.print(t); Serial.println(" ms to draw to TFT"); 123 | 124 | // Wait forever 125 | while(1) yield(); 126 | } 127 | -------------------------------------------------------------------------------- /examples/SPIFFS/SPIFFS_Web_Jpg/Web_Fetch.h: -------------------------------------------------------------------------------- 1 | // Fetch a file from the URL given and save it in SPIFFS 2 | // Return 1 if a web fetch was needed or 0 if file already exists 3 | bool getFile(String url, String filename) { 4 | 5 | // If it exists then no need to fetch it 6 | if (SPIFFS.exists(filename) == true) { 7 | Serial.println("Found " + filename); 8 | return 0; 9 | } 10 | 11 | Serial.println("Downloading " + filename + " from " + url); 12 | 13 | // Check WiFi connection 14 | if ((WiFi.status() == WL_CONNECTED)) { 15 | 16 | Serial.print("[HTTP] begin...\n"); 17 | 18 | #ifdef ARDUINO_ARCH_ESP8266 19 | std::unique_ptrclient(new BearSSL::WiFiClientSecure); 20 | client -> setInsecure(); 21 | HTTPClient http; 22 | http.begin(*client, url); 23 | #else 24 | HTTPClient http; 25 | // Configure server and url 26 | http.begin(url); 27 | #endif 28 | 29 | Serial.print("[HTTP] GET...\n"); 30 | // Start connection and send HTTP header 31 | int httpCode = http.GET(); 32 | if (httpCode > 0) { 33 | fs::File f = SPIFFS.open(filename, "w+"); 34 | if (!f) { 35 | Serial.println("file open failed"); 36 | return 0; 37 | } 38 | // HTTP header has been send and Server response header has been handled 39 | Serial.printf("[HTTP] GET... code: %d\n", httpCode); 40 | 41 | // File found at server 42 | if (httpCode == HTTP_CODE_OK) { 43 | 44 | // Get length of document (is -1 when Server sends no Content-Length header) 45 | int total = http.getSize(); 46 | int len = total; 47 | 48 | // Create buffer for read 49 | uint8_t buff[128] = { 0 }; 50 | 51 | // Get tcp stream 52 | WiFiClient * stream = http.getStreamPtr(); 53 | 54 | // Read all data from server 55 | while (http.connected() && (len > 0 || len == -1)) { 56 | // Get available data size 57 | size_t size = stream->available(); 58 | 59 | if (size) { 60 | // Read up to 128 bytes 61 | int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); 62 | 63 | // Write it to file 64 | f.write(buff, c); 65 | 66 | // Calculate remaining bytes 67 | if (len > 0) { 68 | len -= c; 69 | } 70 | } 71 | yield(); 72 | } 73 | Serial.println(); 74 | Serial.print("[HTTP] connection closed or file end.\n"); 75 | } 76 | f.close(); 77 | } 78 | else { 79 | Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); 80 | } 81 | http.end(); 82 | } 83 | return 1; // File was fetched from web 84 | } 85 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | ####################################### 5 | # Datatypes (KEYWORD1) 6 | ####################################### 7 | 8 | TJpg_Decoder KEYWORD1 9 | 10 | ####################################### 11 | # Methods and Functions (KEYWORD2) 12 | ####################################### 13 | TJpgDec KEYWORD2 14 | TJpg_Decoder KEYWORD2 15 | 16 | drawJpg KEYWORD2 17 | drawSdJpg KEYWORD2 18 | drawFsJpg KEYWORD2 19 | 20 | getJpgSize KEYWORD2 21 | getSdJpgSize KEYWORD2 22 | getFsJpgSize KEYWORD2 23 | 24 | setJpgScale KEYWORD2 25 | setCallback KEYWORD2 26 | 27 | //tft_output KEYWORD2 -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TJpg_Decoder", 3 | "version": "1.1.0", 4 | "keywords": "jpeg, jpg, tft, display, RP2040, STM32, ESP8266, ESP32", 5 | "description": "A JPEG decoder library based on Tiny JPEG Decompressor", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/Bodmer/TJpg_Decoder" 10 | }, 11 | "authors": 12 | [ 13 | { 14 | "name": "Bodmer", 15 | "email": "bodmer@anola.net", 16 | "maintainer": true 17 | } 18 | ], 19 | "frameworks": "arduino", 20 | "platforms": "raspberrypi, espressif8266, espressif32, ststm32", 21 | "headers": "TJpg_Decoder.h" 22 | } 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=TJpg_Decoder 2 | version=1.1.0 3 | author=Bodmer 4 | maintainer=Bodmer 5 | sentence=A JPEG decoder based on tjpgd 6 | paragraph=Renders jpeg images to TFT displays. 7 | category=Display 8 | url=https://github.com/Bodmer/TJpg_Decoder 9 | architectures=* 10 | includes=TJpg_Decoder.h 11 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | This library incorporate the Tiny JPEG Decompressor code files: 2 | "tjpgd.h" and "tjpgd.c". The licence for these files is: 3 | 4 | /*----------------------------------------------------------------------------/ 5 | / TJpgDec - Tiny JPEG Decompressor R0.01c (C)ChaN, 2019 6 | /-----------------------------------------------------------------------------/ 7 | / The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. 8 | / This is a free software that opened for education, research and commercial 9 | / developments under license policy of following terms. 10 | / 11 | / Copyright (C) 2019, ChaN, all right reserved. 12 | / 13 | / * The TJpgDec module is a free software and there is NO WARRANTY. 14 | / * No restriction on use. You can use, modify and redistribute it for 15 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 16 | / * Redistributions of source code must retain the above copyright notice. 17 | / 18 | / 19 | /-----------------------------------------------------------------------------/ 20 | 21 | This Arduino library "TJpd_Decoder" has been created by Bodmer, for all the 22 | additional code the FreeBSD licence applies and is compatible with the GNU GPL: 23 | 24 | vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvStartvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 25 | Software License Agreement (FreeBSD License) 26 | 27 | Copyright (c) 2019 Bodmer (https://github.com/Bodmer) 28 | 29 | All rights reserved. 30 | 31 | Redistribution and use in source and binary forms, with or without 32 | modification, are permitted provided that the following conditions are met: 33 | 34 | 1. Redistributions of source code must retain the above copyright notice, this 35 | list of conditions and the following disclaimer. 36 | 2. Redistributions in binary form must reproduce the above copyright notice, 37 | this list of conditions and the following disclaimer in the documentation 38 | and/or other materials provided with the distribution. 39 | 40 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 41 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 42 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 44 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 45 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 47 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 49 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | 51 | The views and conclusions contained in the software and documentation are those 52 | of the authors and should not be interpreted as representing official policies, 53 | either expressed or implied, of the FreeBSD Project. 54 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^End^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 55 | -------------------------------------------------------------------------------- /src/TJpg_Decoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TJpg_Decoder.cpp 3 | 4 | Created by Bodmer 18/10/19 5 | 6 | Latest version here: 7 | https://github.com/Bodmer/TJpg_Decoder 8 | */ 9 | 10 | #include "TJpg_Decoder.h" 11 | 12 | // Create a class instance to be used by the sketch (defined as extern in header) 13 | TJpg_Decoder TJpgDec; 14 | 15 | /*************************************************************************************** 16 | ** Function name: TJpg_Decoder 17 | ** Description: Constructor 18 | ***************************************************************************************/ 19 | TJpg_Decoder::TJpg_Decoder(){ 20 | // Setup a pointer to this class for static functions 21 | thisPtr = this; 22 | } 23 | 24 | /*************************************************************************************** 25 | ** Function name: ~TJpg_Decoder 26 | ** Description: Destructor 27 | ***************************************************************************************/ 28 | TJpg_Decoder::~TJpg_Decoder(){ 29 | // Bye 30 | } 31 | 32 | /*************************************************************************************** 33 | ** Function name: setJpgScale 34 | ** Description: Set the reduction scale factor (1, 2, 4 or 8) 35 | ***************************************************************************************/ 36 | void TJpg_Decoder::setSwapBytes(bool swapBytes){ 37 | _swap = swapBytes; 38 | } 39 | 40 | /*************************************************************************************** 41 | ** Function name: setJpgScale 42 | ** Description: Set the reduction scale factor (1, 2, 4 or 8) 43 | ***************************************************************************************/ 44 | void TJpg_Decoder::setJpgScale(uint8_t scaleFactor) 45 | { 46 | switch (scaleFactor) 47 | { 48 | case 1: 49 | jpgScale = 0; 50 | break; 51 | case 2: 52 | jpgScale = 1; 53 | break; 54 | case 4: 55 | jpgScale = 2; 56 | break; 57 | case 8: 58 | jpgScale = 3; 59 | break; 60 | default: 61 | jpgScale = 0; 62 | } 63 | } 64 | 65 | /*************************************************************************************** 66 | ** Function name: setCallback 67 | ** Description: Set the sketch callback function to render decoded blocks 68 | ***************************************************************************************/ 69 | void TJpg_Decoder::setCallback(SketchCallback sketchCallback) 70 | { 71 | tft_output = sketchCallback; 72 | } 73 | 74 | /*************************************************************************************** 75 | ** Function name: jd_input (declared static) 76 | ** Description: Called by tjpgd.c to get more data 77 | ***************************************************************************************/ 78 | unsigned int TJpg_Decoder::jd_input(JDEC* jdec, uint8_t* buf, unsigned int len) 79 | { 80 | TJpg_Decoder *thisPtr = TJpgDec.thisPtr; 81 | jdec = jdec; // Supress warning 82 | 83 | // Handle an array input 84 | if (thisPtr->jpg_source == TJPG_ARRAY) { 85 | // Avoid running off end of array 86 | if (thisPtr->array_index + len > thisPtr->array_size) { 87 | len = thisPtr->array_size - thisPtr->array_index; 88 | } 89 | 90 | // If buf is valid then copy len bytes to buffer 91 | if (buf) memcpy_P(buf, (const uint8_t *)(thisPtr->array_data + thisPtr->array_index), len); 92 | 93 | // Move pointer 94 | thisPtr->array_index += len; 95 | } 96 | 97 | #ifdef TJPGD_LOAD_FFS 98 | // Handle SPIFFS input 99 | else if (thisPtr->jpg_source == TJPG_FS_FILE) { 100 | // Check how many bytes are available 101 | uint32_t bytesLeft = thisPtr->jpgFile.available(); 102 | if (bytesLeft < len) len = bytesLeft; 103 | 104 | if (buf) { 105 | // Read into buffer, pointer moved as well 106 | thisPtr->jpgFile.read(buf, len); 107 | } 108 | else { 109 | // Buffer is null, so skip data by moving pointer 110 | thisPtr->jpgFile.seek(thisPtr->jpgFile.position() + len); 111 | } 112 | } 113 | #endif 114 | 115 | #if defined (TJPGD_LOAD_SD_LIBRARY) 116 | // Handle SD library input 117 | else if (thisPtr->jpg_source == TJPG_SD_FILE) { 118 | // Check how many bytes are available 119 | uint32_t bytesLeft = thisPtr->jpgSdFile.available(); 120 | if (bytesLeft < len) len = bytesLeft; 121 | 122 | if (buf) { 123 | // Read into buffer, pointer moved as well 124 | thisPtr->jpgSdFile.read(buf, len); 125 | } 126 | else { 127 | // Buffer is null, so skip data by moving pointer 128 | thisPtr->jpgSdFile.seek(thisPtr->jpgSdFile.position() + len); 129 | } 130 | } 131 | #endif 132 | 133 | return len; 134 | } 135 | 136 | /*************************************************************************************** 137 | ** Function name: jd_output (declared static) 138 | ** Description: Called by tjpgd.c with an image block for rendering 139 | ***************************************************************************************/ 140 | // Pass image block back to the sketch for rendering, may be a complete or partial MCU 141 | int TJpg_Decoder::jd_output(JDEC* jdec, void* bitmap, JRECT* jrect) 142 | { 143 | // This is a static function so create a pointer to access other members of the class 144 | TJpg_Decoder *thisPtr = TJpgDec.thisPtr; 145 | 146 | jdec = jdec; // Supress warning as ID is not used 147 | 148 | // Retrieve rendering parameters and add any offset 149 | int16_t x = jrect->left + thisPtr->jpeg_x; 150 | int16_t y = jrect->top + thisPtr->jpeg_y; 151 | uint16_t w = jrect->right + 1 - jrect->left; 152 | uint16_t h = jrect->bottom + 1 - jrect->top; 153 | 154 | // Pass the image block and rendering parameters in a callback to the sketch 155 | return thisPtr->tft_output(x, y, w, h, (uint16_t*)bitmap); 156 | } 157 | 158 | 159 | #if defined (TJPGD_LOAD_SD_LIBRARY) || defined (TJPGD_LOAD_FFS) 160 | 161 | /*************************************************************************************** 162 | ** Function name: drawJpg 163 | ** Description: Draw a named jpg file at x,y (name in char array) 164 | ***************************************************************************************/ 165 | // Generic file call for SD or SPIFFS, uses leading / to distinguish SPIFFS files 166 | JRESULT TJpg_Decoder::drawJpg(int32_t x, int32_t y, const char *pFilename){ 167 | 168 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 169 | #if defined (TJPGD_LOAD_SD_LIBRARY) 170 | if (*pFilename == '/') 171 | #endif 172 | return drawFsJpg(x, y, pFilename); 173 | #endif 174 | 175 | #if defined (TJPGD_LOAD_SD_LIBRARY) 176 | return drawSdJpg(x, y, pFilename); 177 | #endif 178 | 179 | return JDR_INP; 180 | } 181 | 182 | /*************************************************************************************** 183 | ** Function name: drawJpg 184 | ** Description: Draw a named jpg file at x,y (name in String) 185 | ***************************************************************************************/ 186 | // Generic file call for SD or SPIFFS, uses leading / to distinguish SPIFFS files 187 | JRESULT TJpg_Decoder::drawJpg(int32_t x, int32_t y, const String& pFilename){ 188 | 189 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 190 | #if defined (TJPGD_LOAD_SD_LIBRARY) 191 | if (pFilename.charAt(0) == '/') 192 | #endif 193 | return drawFsJpg(x, y, pFilename); 194 | #endif 195 | 196 | #if defined (TJPGD_LOAD_SD_LIBRARY) 197 | return drawSdJpg(x, y, pFilename); 198 | #endif 199 | 200 | return JDR_INP; 201 | } 202 | 203 | /*************************************************************************************** 204 | ** Function name: getJpgSize 205 | ** Description: Get width and height of a jpg file (name in char array) 206 | ***************************************************************************************/ 207 | // Generic file call for SD or SPIFFS, uses leading / to distinguish SPIFFS files 208 | JRESULT TJpg_Decoder::getJpgSize(uint16_t *w, uint16_t *h, const char *pFilename){ 209 | 210 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 211 | #if defined (TJPGD_LOAD_SD_LIBRARY) 212 | if (*pFilename == '/') 213 | #endif 214 | return getFsJpgSize(w, h, pFilename); 215 | #endif 216 | 217 | #if defined (TJPGD_LOAD_SD_LIBRARY) 218 | return getSdJpgSize(w, h, pFilename); 219 | #endif 220 | 221 | return JDR_INP; 222 | } 223 | 224 | /*************************************************************************************** 225 | ** Function name: getJpgSize 226 | ** Description: Get width and height of a jpg file (name in String) 227 | ***************************************************************************************/ 228 | // Generic file call for SD or SPIFFS, uses leading / to distinguish SPIFFS files 229 | JRESULT TJpg_Decoder::getJpgSize(uint16_t *w, uint16_t *h, const String& pFilename){ 230 | 231 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 232 | #if defined (TJPGD_LOAD_SD_LIBRARY) 233 | if (pFilename.charAt(0) == '/') 234 | #endif 235 | return getFsJpgSize(w, h, pFilename); 236 | #endif 237 | 238 | #if defined (TJPGD_LOAD_SD_LIBRARY) 239 | return getSdJpgSize(w, h, pFilename); 240 | #endif 241 | 242 | return JDR_INP; 243 | } 244 | 245 | #endif 246 | 247 | #ifdef TJPGD_LOAD_FFS 248 | 249 | /*************************************************************************************** 250 | ** Function name: drawFsJpg 251 | ** Description: Draw a named jpg file at x,y (name in char array) 252 | ***************************************************************************************/ 253 | // Call specific to SPIFFS 254 | JRESULT TJpg_Decoder::drawFsJpg(int32_t x, int32_t y, const char *pFilename, fs::FS &fs) { 255 | // Check if file exists 256 | if ( !fs.exists(pFilename) ) 257 | { 258 | Serial.println(F("Jpeg file not found")); 259 | return JDR_INP; 260 | } 261 | 262 | return drawFsJpg(x, y, fs.open( pFilename, "r")); 263 | } 264 | 265 | /*************************************************************************************** 266 | ** Function name: drawFsJpg 267 | ** Description: Draw a named jpg file at x,y (name in String) 268 | ***************************************************************************************/ 269 | JRESULT TJpg_Decoder::drawFsJpg(int32_t x, int32_t y, const String& pFilename, fs::FS &fs) { 270 | // Check if file exists 271 | if ( !fs.exists(pFilename) ) 272 | { 273 | Serial.println(F("Jpeg file not found")); 274 | return JDR_INP; 275 | } 276 | return drawFsJpg(x, y, fs.open( pFilename, "r")); 277 | } 278 | 279 | /*************************************************************************************** 280 | ** Function name: drawFsJpg 281 | ** Description: Draw a jpg with opened file handle at x,y 282 | ***************************************************************************************/ 283 | JRESULT TJpg_Decoder::drawFsJpg(int32_t x, int32_t y, fs::File inFile) { 284 | JDEC jdec; 285 | JRESULT jresult = JDR_OK; 286 | 287 | jpg_source = TJPG_FS_FILE; 288 | jpeg_x = x; 289 | jpeg_y = y; 290 | 291 | jdec.swap = _swap; 292 | 293 | jpgFile = inFile; 294 | 295 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, (unsigned int)0); 296 | 297 | // Extract image and render 298 | if (jresult == JDR_OK) { 299 | jresult = jd_decomp(&jdec, jd_output, jpgScale); 300 | } 301 | 302 | // Close file 303 | if (jpgFile) jpgFile.close(); 304 | 305 | return jresult; 306 | 307 | } 308 | 309 | /*************************************************************************************** 310 | ** Function name: getFsJpgSize 311 | ** Description: Get width and height of a jpg saved in SPIFFS or LittleFS 312 | ***************************************************************************************/ 313 | // Call specific to SPIFFS 314 | JRESULT TJpg_Decoder::getFsJpgSize(uint16_t *w, uint16_t *h, const char *pFilename, fs::FS &fs) { 315 | // Check if file exists 316 | if ( !fs.exists(pFilename) ) 317 | { 318 | Serial.println(F("Jpeg file not found")); 319 | return JDR_INP; 320 | } 321 | 322 | return getFsJpgSize(w, h, fs.open( pFilename, "r")); 323 | } 324 | 325 | /*************************************************************************************** 326 | ** Function name: getFsJpgSize 327 | ** Description: Get width and height of a jpg saved in SPIFFS or LittleFS 328 | ***************************************************************************************/ 329 | JRESULT TJpg_Decoder::getFsJpgSize(uint16_t *w, uint16_t *h, const String& pFilename, fs::FS &fs) { 330 | // Check if file exists 331 | if ( !fs.exists(pFilename) ) 332 | { 333 | Serial.println(F("Jpeg file not found")); 334 | return JDR_INP; 335 | } 336 | 337 | return getFsJpgSize(w, h, fs.open( pFilename, "r")); 338 | } 339 | 340 | /*************************************************************************************** 341 | ** Function name: getFsJpgSize 342 | ** Description: Get width and height of a jpg saved in SPIFFS 343 | ***************************************************************************************/ 344 | JRESULT TJpg_Decoder::getFsJpgSize(uint16_t *w, uint16_t *h, fs::File inFile) { 345 | JDEC jdec; 346 | JRESULT jresult = JDR_OK; 347 | 348 | *w = 0; 349 | *h = 0; 350 | 351 | jpg_source = TJPG_FS_FILE; 352 | 353 | jpgFile = inFile; 354 | 355 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, 0); 356 | 357 | if (jresult == JDR_OK) { 358 | *w = jdec.width; 359 | *h = jdec.height; 360 | } 361 | 362 | // Close file 363 | if (jpgFile) jpgFile.close(); 364 | 365 | return jresult; 366 | } 367 | 368 | #endif 369 | 370 | 371 | #if defined (TJPGD_LOAD_SD_LIBRARY) 372 | 373 | /*************************************************************************************** 374 | ** Function name: drawSdJpg 375 | ** Description: Draw a named jpg SD file at x,y (name in char array) 376 | ***************************************************************************************/ 377 | // Call specific to SD 378 | JRESULT TJpg_Decoder::drawSdJpg(int32_t x, int32_t y, const char *pFilename) { 379 | 380 | // Check if file exists 381 | if ( !SD.exists(pFilename) ) 382 | { 383 | Serial.println(F("Jpeg file not found")); 384 | return JDR_INP; 385 | } 386 | 387 | return drawSdJpg(x, y, SD.open( pFilename, FILE_READ)); 388 | } 389 | 390 | /*************************************************************************************** 391 | ** Function name: drawSdJpg 392 | ** Description: Draw a named jpg SD file at x,y (name in String) 393 | ***************************************************************************************/ 394 | JRESULT TJpg_Decoder::drawSdJpg(int32_t x, int32_t y, const String& pFilename) { 395 | 396 | // Check if file exists 397 | if ( !SD.exists(pFilename) ) 398 | { 399 | Serial.println(F("Jpeg file not found")); 400 | return JDR_INP; 401 | } 402 | 403 | return drawSdJpg(x, y, SD.open( pFilename, FILE_READ)); 404 | } 405 | 406 | /*************************************************************************************** 407 | ** Function name: drawSdJpg 408 | ** Description: Draw a jpg with opened SD file handle at x,y 409 | ***************************************************************************************/ 410 | JRESULT TJpg_Decoder::drawSdJpg(int32_t x, int32_t y, File inFile) { 411 | JDEC jdec; 412 | JRESULT jresult = JDR_OK; 413 | 414 | jpg_source = TJPG_SD_FILE; 415 | jpeg_x = x; 416 | jpeg_y = y; 417 | 418 | jdec.swap = _swap; 419 | 420 | jpgSdFile = inFile; 421 | 422 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, 0); 423 | 424 | // Extract image and render 425 | if (jresult == JDR_OK) { 426 | jresult = jd_decomp(&jdec, jd_output, jpgScale); 427 | } 428 | 429 | // Close file 430 | if (jpgSdFile) jpgSdFile.close(); 431 | 432 | return jresult; 433 | 434 | } 435 | 436 | /*************************************************************************************** 437 | ** Function name: getSdJpgSize 438 | ** Description: Get width and height of a jpg saved in SPIFFS 439 | ***************************************************************************************/ 440 | // Call specific to SD 441 | JRESULT TJpg_Decoder::getSdJpgSize(uint16_t *w, uint16_t *h, const char *pFilename) { 442 | 443 | // Check if file exists 444 | if ( !SD.exists(pFilename) ) 445 | { 446 | Serial.println(F("Jpeg file not found")); 447 | return JDR_INP; 448 | } 449 | 450 | return getSdJpgSize(w, h, SD.open( pFilename, FILE_READ)); 451 | } 452 | 453 | /*************************************************************************************** 454 | ** Function name: getSdJpgSize 455 | ** Description: Get width and height of a jpg saved in SPIFFS 456 | ***************************************************************************************/ 457 | JRESULT TJpg_Decoder::getSdJpgSize(uint16_t *w, uint16_t *h, const String& pFilename) { 458 | 459 | // Check if file exists 460 | if ( !SD.exists(pFilename) ) 461 | { 462 | Serial.println(F("Jpeg file not found")); 463 | return JDR_INP; 464 | } 465 | 466 | return getSdJpgSize(w, h, SD.open( pFilename, FILE_READ)); 467 | } 468 | 469 | /*************************************************************************************** 470 | ** Function name: getSdJpgSize 471 | ** Description: Get width and height of a jpg saved in SPIFFS 472 | ***************************************************************************************/ 473 | JRESULT TJpg_Decoder::getSdJpgSize(uint16_t *w, uint16_t *h, File inFile) { 474 | JDEC jdec; 475 | JRESULT jresult = JDR_OK; 476 | 477 | *w = 0; 478 | *h = 0; 479 | 480 | jpg_source = TJPG_SD_FILE; 481 | 482 | jpgSdFile = inFile; 483 | 484 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, 0); 485 | 486 | if (jresult == JDR_OK) { 487 | *w = jdec.width; 488 | *h = jdec.height; 489 | } 490 | 491 | // Close file 492 | if (jpgSdFile) jpgSdFile.close(); 493 | 494 | return jresult; 495 | } 496 | 497 | #endif 498 | 499 | /*************************************************************************************** 500 | ** Function name: drawJpg 501 | ** Description: Draw a jpg saved in a FLASH memory array 502 | ***************************************************************************************/ 503 | JRESULT TJpg_Decoder::drawJpg(int32_t x, int32_t y, const uint8_t jpeg_data[], uint32_t data_size) { 504 | JDEC jdec; 505 | JRESULT jresult = JDR_OK; 506 | 507 | jpg_source = TJPG_ARRAY; 508 | array_index = 0; 509 | array_data = jpeg_data; 510 | array_size = data_size; 511 | 512 | jpeg_x = x; 513 | jpeg_y = y; 514 | 515 | jdec.swap = _swap; 516 | 517 | // Analyse input data 518 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, 0); 519 | 520 | // Extract image and render 521 | if (jresult == JDR_OK) { 522 | jresult = jd_decomp(&jdec, jd_output, jpgScale); 523 | } 524 | 525 | return jresult; 526 | } 527 | 528 | /*************************************************************************************** 529 | ** Function name: getJpgSize 530 | ** Description: Get width and height of a jpg saved in a FLASH memory array 531 | ***************************************************************************************/ 532 | JRESULT TJpg_Decoder::getJpgSize(uint16_t *w, uint16_t *h, const uint8_t jpeg_data[], uint32_t data_size) { 533 | JDEC jdec; 534 | JRESULT jresult = JDR_OK; 535 | 536 | *w = 0; 537 | *h = 0; 538 | 539 | jpg_source = TJPG_ARRAY; 540 | array_index = 0; 541 | array_data = jpeg_data; 542 | array_size = data_size; 543 | 544 | // Analyse input data 545 | jresult = jd_prepare(&jdec, jd_input, workspace, TJPGD_WORKSPACE_SIZE, 0); 546 | 547 | if (jresult == JDR_OK) { 548 | *w = jdec.width; 549 | *h = jdec.height; 550 | } 551 | 552 | return jresult; 553 | } 554 | -------------------------------------------------------------------------------- /src/TJpg_Decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | TJpg_Decoder.h 3 | 4 | JPEG Decoder for Arduino using TJpgDec: 5 | http://elm-chan.org/fsw/tjpgd/00index.html 6 | 7 | Incorporated into an Arduino library by Bodmer 18/10/19 8 | 9 | Latest version here: 10 | https://github.com/Bodmer/TJpg_Decoder 11 | */ 12 | 13 | #ifndef TJpg_Decoder_H 14 | #define TJpg_Decoder_H 15 | 16 | #include "User_Config.h" 17 | #include "Arduino.h" 18 | #include "tjpgd.h" 19 | 20 | #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) 21 | #include 22 | #include 23 | #include 24 | #ifdef ESP32 25 | #include "SPIFFS.h" // ESP32 only 26 | #endif 27 | #define TJPGD_LOAD_FFS 28 | #elif defined (ARDUINO_ARCH_RP2040) && defined (TJPGD_LOAD_FFS) 29 | #include 30 | #include 31 | #define SPIFFS LittleFS 32 | #define TJPGD_LOAD_FFS 33 | #endif 34 | 35 | #if defined (TJPGD_LOAD_SD_LIBRARY) 36 | #include 37 | #endif 38 | 39 | enum { 40 | TJPG_ARRAY = 0, 41 | TJPG_FS_FILE, 42 | TJPG_SD_FILE 43 | }; 44 | 45 | //------------------------------------------------------------------------------ 46 | 47 | typedef bool (*SketchCallback)(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *data); 48 | 49 | class TJpg_Decoder { 50 | 51 | private: 52 | #if defined (TJPGD_LOAD_SD_LIBRARY) 53 | File jpgSdFile; 54 | #endif 55 | 56 | #ifdef TJPGD_LOAD_FFS 57 | fs::File jpgFile; 58 | #endif 59 | 60 | public: 61 | 62 | TJpg_Decoder(); 63 | ~TJpg_Decoder(); 64 | 65 | static int jd_output(JDEC* jdec, void* bitmap, JRECT* jrect); 66 | static unsigned int jd_input(JDEC* jdec, uint8_t* buf, unsigned int len); 67 | 68 | void setJpgScale(uint8_t scale); 69 | void setCallback(SketchCallback sketchCallback); 70 | 71 | 72 | #if defined (TJPGD_LOAD_SD_LIBRARY) || defined (TJPGD_LOAD_FFS) 73 | JRESULT drawJpg (int32_t x, int32_t y, const char *pFilename); 74 | JRESULT drawJpg (int32_t x, int32_t y, const String& pFilename); 75 | 76 | JRESULT getJpgSize(uint16_t *w, uint16_t *h, const char *pFilename); 77 | JRESULT getJpgSize(uint16_t *w, uint16_t *h, const String& pFilename); 78 | #endif 79 | 80 | #if defined (TJPGD_LOAD_SD_LIBRARY) 81 | JRESULT drawSdJpg (int32_t x, int32_t y, const char *pFilename); 82 | JRESULT drawSdJpg (int32_t x, int32_t y, const String& pFilename); 83 | JRESULT drawSdJpg (int32_t x, int32_t y, File inFile); 84 | 85 | JRESULT getSdJpgSize(uint16_t *w, uint16_t *h, const char *pFilename); 86 | JRESULT getSdJpgSize(uint16_t *w, uint16_t *h, const String& pFilename); 87 | JRESULT getSdJpgSize(uint16_t *w, uint16_t *h, File inFile); 88 | #endif 89 | 90 | #ifdef TJPGD_LOAD_FFS 91 | JRESULT drawFsJpg (int32_t x, int32_t y, const char *pFilename, fs::FS &fs = SPIFFS); 92 | JRESULT drawFsJpg (int32_t x, int32_t y, const String& pFilename, fs::FS &fs = SPIFFS); 93 | JRESULT drawFsJpg (int32_t x, int32_t y, fs::File inFile); 94 | 95 | JRESULT getFsJpgSize(uint16_t *w, uint16_t *h, const char *pFilename, fs::FS &fs = SPIFFS); 96 | JRESULT getFsJpgSize(uint16_t *w, uint16_t *h, const String& pFilename, fs::FS &fs = SPIFFS); 97 | JRESULT getFsJpgSize(uint16_t *w, uint16_t *h, fs::File inFile); 98 | #endif 99 | 100 | JRESULT drawJpg(int32_t x, int32_t y, const uint8_t array[], uint32_t array_size); 101 | JRESULT getJpgSize(uint16_t *w, uint16_t *h, const uint8_t array[], uint32_t array_size); 102 | 103 | void setSwapBytes(bool swap); 104 | 105 | bool _swap = false; 106 | 107 | const uint8_t* array_data = nullptr; 108 | uint32_t array_index = 0; 109 | uint32_t array_size = 0; 110 | 111 | // Must align workspace to a 32 bit boundary 112 | uint8_t workspace[TJPGD_WORKSPACE_SIZE] __attribute__((aligned(4))); 113 | 114 | uint8_t jpg_source = 0; 115 | 116 | int16_t jpeg_x = 0; 117 | int16_t jpeg_y = 0; 118 | 119 | uint8_t jpgScale = 0; 120 | 121 | SketchCallback tft_output = nullptr; 122 | 123 | TJpg_Decoder *thisPtr = nullptr; 124 | }; 125 | 126 | extern TJpg_Decoder TJpgDec; 127 | 128 | #endif // TJpg_Decoder_H 129 | -------------------------------------------------------------------------------- /src/User_Config.h: -------------------------------------------------------------------------------- 1 | #if defined (ESP32) || defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_RP2040) 2 | #define TJPGD_LOAD_FFS 3 | #endif 4 | 5 | #define TJPGD_LOAD_SD_LIBRARY 6 | -------------------------------------------------------------------------------- /src/tjpgd.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor R0.03 (C)ChaN, 2021 3 | /-----------------------------------------------------------------------------/ 4 | / The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. 5 | / This is a free software that opened for education, research and commercial 6 | / developments under license policy of following terms. 7 | / 8 | / Copyright (C) 2021, ChaN, all right reserved. 9 | / 10 | / * The TJpgDec module is a free software and there is NO WARRANTY. 11 | / * No restriction on use. You can use, modify and redistribute it for 12 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 13 | / * Redistributions of source code must retain the above copyright notice. 14 | / 15 | /-----------------------------------------------------------------------------/ 16 | / Oct 04, 2011 R0.01 First release. 17 | / Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. 18 | / Sep 03, 2012 R0.01b Added JD_TBLCLIP option. 19 | / Mar 16, 2019 R0.01c Supprted stdint.h. 20 | / Jul 01, 2020 R0.01d Fixed wrong integer type usage. 21 | / May 08, 2021 R0.02 Supprted grayscale image. Separated configuration options. 22 | / Jun 11, 2021 R0.02a Some performance improvement. 23 | / Jul 01, 2021 R0.03 Added JD_FASTDECODE option. 24 | / Some performance improvement. 25 | /----------------------------------------------------------------------------*/ 26 | 27 | #include "tjpgd.h" 28 | 29 | 30 | #if JD_FASTDECODE == 2 31 | #define HUFF_BIT 10 /* Bit length to apply fast huffman decode */ 32 | #define HUFF_LEN (1 << HUFF_BIT) 33 | #define HUFF_MASK (HUFF_LEN - 1) 34 | #endif 35 | 36 | 37 | /*-----------------------------------------------*/ 38 | /* Zigzag-order to raster-order conversion table */ 39 | /*-----------------------------------------------*/ 40 | 41 | static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ 42 | 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 43 | 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 44 | 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 45 | 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 46 | }; 47 | 48 | 49 | 50 | /*-------------------------------------------------*/ 51 | /* Input scale factor of Arai algorithm */ 52 | /* (scaled up 16 bits for fixed point operations) */ 53 | /*-------------------------------------------------*/ 54 | 55 | static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ 56 | (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), 57 | (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), 58 | (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), 59 | (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), 60 | (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), 61 | (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), 62 | (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), 63 | (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) 64 | }; 65 | 66 | 67 | 68 | /*---------------------------------------------*/ 69 | /* Conversion table for fast clipping process */ 70 | /*---------------------------------------------*/ 71 | 72 | #if JD_TBLCLIP 73 | 74 | #define BYTECLIP(v) Clip8[(unsigned int)(v) & 0x3FF] 75 | 76 | static const uint8_t Clip8[1024] = { 77 | /* 0..255 */ 78 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 79 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 80 | 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 81 | 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 82 | 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 83 | 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 84 | 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 85 | 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 86 | /* 256..511 */ 87 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 88 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 89 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 91 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 93 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 94 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 95 | /* -512..-257 */ 96 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 | /* -256..-1 */ 105 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 113 | }; 114 | 115 | #else /* JD_TBLCLIP */ 116 | 117 | static uint8_t BYTECLIP (int val) 118 | { 119 | if (val < 0) return 0; 120 | else if (val > 255) return 255; 121 | return (uint8_t)val; 122 | } 123 | 124 | #endif 125 | 126 | 127 | 128 | /*-----------------------------------------------------------------------*/ 129 | /* Allocate a memory block from memory pool */ 130 | /*-----------------------------------------------------------------------*/ 131 | 132 | static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ 133 | JDEC* jd, /* Pointer to the decompressor object */ 134 | size_t ndata /* Number of bytes to allocate */ 135 | ) 136 | { 137 | char *rp = 0; 138 | 139 | 140 | ndata = (ndata + 3) & ~3; /* Align block size to the word boundary */ 141 | 142 | if (jd->sz_pool >= ndata) { 143 | jd->sz_pool -= ndata; 144 | rp = (char*)jd->pool; /* Get start of available memory pool */ 145 | jd->pool = (void*)(rp + ndata); /* Allocate requierd bytes */ 146 | } 147 | 148 | return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ 149 | } 150 | 151 | 152 | 153 | 154 | /*-----------------------------------------------------------------------*/ 155 | /* Create de-quantization and prescaling tables with a DQT segment */ 156 | /*-----------------------------------------------------------------------*/ 157 | 158 | static JRESULT create_qt_tbl ( /* 0:OK, !0:Failed */ 159 | JDEC* jd, /* Pointer to the decompressor object */ 160 | const uint8_t* data, /* Pointer to the quantizer tables */ 161 | size_t ndata /* Size of input data */ 162 | ) 163 | { 164 | unsigned int i, zi; 165 | uint8_t d; 166 | int32_t *pb; 167 | 168 | 169 | while (ndata) { /* Process all tables in the segment */ 170 | if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ 171 | ndata -= 65; 172 | d = *data++; /* Get table property */ 173 | if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ 174 | i = d & 3; /* Get table ID */ 175 | pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ 176 | if (!pb) return JDR_MEM1; /* Err: not enough memory */ 177 | jd->qttbl[i] = pb; /* Register the table */ 178 | for (i = 0; i < 64; i++) { /* Load the table */ 179 | zi = Zig[i]; /* Zigzag-order to raster-order conversion */ 180 | pb[zi] = (int32_t)((uint32_t)*data++ * Ipsf[zi]); /* Apply scale factor of Arai algorithm to the de-quantizers */ 181 | } 182 | } 183 | 184 | return JDR_OK; 185 | } 186 | 187 | 188 | 189 | 190 | /*-----------------------------------------------------------------------*/ 191 | /* Create huffman code tables with a DHT segment */ 192 | /*-----------------------------------------------------------------------*/ 193 | 194 | static JRESULT create_huffman_tbl ( /* 0:OK, !0:Failed */ 195 | JDEC* jd, /* Pointer to the decompressor object */ 196 | const uint8_t* data, /* Pointer to the packed huffman tables */ 197 | size_t ndata /* Size of input data */ 198 | ) 199 | { 200 | unsigned int i, j, b, cls, num; 201 | size_t np; 202 | uint8_t d, *pb, *pd; 203 | uint16_t hc, *ph; 204 | 205 | 206 | while (ndata) { /* Process all tables in the segment */ 207 | if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ 208 | ndata -= 17; 209 | d = *data++; /* Get table number and class */ 210 | if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ 211 | cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ 212 | pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ 213 | if (!pb) return JDR_MEM1; /* Err: not enough memory */ 214 | jd->huffbits[num][cls] = pb; 215 | for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ 216 | np += (pb[i] = *data++); /* Get sum of code words for each code */ 217 | } 218 | ph = alloc_pool(jd, np * sizeof (uint16_t));/* Allocate a memory block for the code word table */ 219 | if (!ph) return JDR_MEM1; /* Err: not enough memory */ 220 | jd->huffcode[num][cls] = ph; 221 | hc = 0; 222 | for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ 223 | b = pb[i]; 224 | while (b--) ph[j++] = hc++; 225 | hc <<= 1; 226 | } 227 | 228 | if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ 229 | ndata -= np; 230 | pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ 231 | if (!pd) return JDR_MEM1; /* Err: not enough memory */ 232 | jd->huffdata[num][cls] = pd; 233 | for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code word */ 234 | d = *data++; 235 | if (!cls && d > 11) return JDR_FMT1; 236 | pd[i] = d; 237 | } 238 | #if JD_FASTDECODE == 2 239 | { /* Create fast huffman decode table */ 240 | unsigned int span, td, ti; 241 | uint16_t *tbl_ac = 0; 242 | uint8_t *tbl_dc = 0; 243 | 244 | if (cls) { 245 | tbl_ac = alloc_pool(jd, HUFF_LEN * sizeof (uint16_t)); /* LUT for AC elements */ 246 | if (!tbl_ac) return JDR_MEM1; /* Err: not enough memory */ 247 | jd->hufflut_ac[num] = tbl_ac; 248 | memset(tbl_ac, 0xFF, HUFF_LEN * sizeof (uint16_t)); /* Default value (0xFFFF: may be long code) */ 249 | } else { 250 | tbl_dc = alloc_pool(jd, HUFF_LEN * sizeof (uint8_t)); /* LUT for AC elements */ 251 | if (!tbl_dc) return JDR_MEM1; /* Err: not enough memory */ 252 | jd->hufflut_dc[num] = tbl_dc; 253 | memset(tbl_dc, 0xFF, HUFF_LEN * sizeof (uint8_t)); /* Default value (0xFF: may be long code) */ 254 | } 255 | for (i = b = 0; b < HUFF_BIT; b++) { /* Create LUT */ 256 | for (j = pb[b]; j; j--) { 257 | ti = ph[i] << (HUFF_BIT - 1 - b) & HUFF_MASK; /* Index of input pattern for the code */ 258 | if (cls) { 259 | td = pd[i++] | ((b + 1) << 8); /* b15..b8: code length, b7..b0: zero run and data length */ 260 | for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_ac[ti++] = (uint16_t)td) ; 261 | } else { 262 | td = pd[i++] | ((b + 1) << 4); /* b7..b4: code length, b3..b0: data length */ 263 | for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_dc[ti++] = (uint8_t)td) ; 264 | } 265 | } 266 | } 267 | jd->longofs[num][cls] = i; /* Code table offset for long code */ 268 | } 269 | #endif 270 | } 271 | 272 | return JDR_OK; 273 | } 274 | 275 | 276 | 277 | 278 | /*-----------------------------------------------------------------------*/ 279 | /* Extract a huffman decoded data from input stream */ 280 | /*-----------------------------------------------------------------------*/ 281 | 282 | static int huffext ( /* >=0: decoded data, <0: error code */ 283 | JDEC* jd, /* Pointer to the decompressor object */ 284 | unsigned int id, /* Table ID (0:Y, 1:C) */ 285 | unsigned int cls /* Table class (0:DC, 1:AC) */ 286 | ) 287 | { 288 | size_t dc = jd->dctr; 289 | uint8_t *dp = jd->dptr; 290 | unsigned int d, flg = 0; 291 | 292 | #if JD_FASTDECODE == 0 293 | uint8_t bm, nd, bl; 294 | const uint8_t *hb = jd->huffbits[id][cls]; /* Bit distribution table */ 295 | const uint16_t *hc = jd->huffcode[id][cls]; /* Code word table */ 296 | const uint8_t *hd = jd->huffdata[id][cls]; /* Data table */ 297 | 298 | 299 | bm = jd->dbit; /* Bit mask to extract */ 300 | d = 0; bl = 16; /* Max code length */ 301 | do { 302 | if (!bm) { /* Next byte? */ 303 | if (!dc) { /* No input data is available, re-fill input buffer */ 304 | dp = jd->inbuf; /* Top of input buffer */ 305 | dc = jd->infunc(jd, dp, JD_SZBUF); 306 | if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ 307 | } else { 308 | dp++; /* Next data ptr */ 309 | } 310 | dc--; /* Decrement number of available bytes */ 311 | if (flg) { /* In flag sequence? */ 312 | flg = 0; /* Exit flag sequence */ 313 | if (*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ 314 | *dp = 0xFF; /* The flag is a data 0xFF */ 315 | } else { 316 | if (*dp == 0xFF) { /* Is start of flag sequence? */ 317 | flg = 1; continue; /* Enter flag sequence, get trailing byte */ 318 | } 319 | } 320 | bm = 0x80; /* Read from MSB */ 321 | } 322 | d <<= 1; /* Get a bit */ 323 | if (*dp & bm) d++; 324 | bm >>= 1; 325 | 326 | for (nd = *hb++; nd; nd--) { /* Search the code word in this bit length */ 327 | if (d == *hc++) { /* Matched? */ 328 | jd->dbit = bm; jd->dctr = dc; jd->dptr = dp; 329 | return *hd; /* Return the decoded data */ 330 | } 331 | hd++; 332 | } 333 | bl--; 334 | } while (bl); 335 | 336 | #else 337 | const uint8_t *hb, *hd; 338 | const uint16_t *hc; 339 | unsigned int nc, bl, wbit = jd->dbit % 32; 340 | uint32_t w = jd->wreg & ((1UL << wbit) - 1); 341 | 342 | 343 | while (wbit < 16) { /* Prepare 16 bits into the working register */ 344 | if (jd->marker) { 345 | d = 0xFF; /* Input stream has stalled for a marker. Generate stuff bits */ 346 | } else { 347 | if (!dc) { /* Buffer empty, re-fill input buffer */ 348 | dp = jd->inbuf; /* Top of input buffer */ 349 | dc = jd->infunc(jd, dp, JD_SZBUF); 350 | if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ 351 | } 352 | d = *dp++; dc--; 353 | if (flg) { /* In flag sequence? */ 354 | flg = 0; /* Exit flag sequence */ 355 | if (d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ 356 | d = 0xFF; 357 | } else { 358 | if (d == 0xFF) { /* Is start of flag sequence? */ 359 | flg = 1; continue; /* Enter flag sequence, get trailing byte */ 360 | } 361 | } 362 | } 363 | w = w << 8 | d; /* Shift 8 bits in the working register */ 364 | wbit += 8; 365 | } 366 | jd->dctr = dc; jd->dptr = dp; 367 | jd->wreg = w; 368 | 369 | #if JD_FASTDECODE == 2 370 | /* Table serch for the short codes */ 371 | d = (unsigned int)(w >> (wbit - HUFF_BIT)); /* Short code as table index */ 372 | if (cls) { /* AC element */ 373 | d = jd->hufflut_ac[id][d]; /* Table decode */ 374 | if (d != 0xFFFF) { /* It is done if hit in short code */ 375 | jd->dbit = wbit - (d >> 8); /* Snip the code length */ 376 | return d & 0xFF; /* b7..0: zero run and following data bits */ 377 | } 378 | } else { /* DC element */ 379 | d = jd->hufflut_dc[id][d]; /* Table decode */ 380 | if (d != 0xFF) { /* It is done if hit in short code */ 381 | jd->dbit = wbit - (d >> 4); /* Snip the code length */ 382 | return d & 0xF; /* b3..0: following data bits */ 383 | } 384 | } 385 | 386 | /* Incremental serch for the codes longer than HUFF_BIT */ 387 | hb = jd->huffbits[id][cls] + HUFF_BIT; /* Bit distribution table */ 388 | hc = jd->huffcode[id][cls] + jd->longofs[id][cls]; /* Code word table */ 389 | hd = jd->huffdata[id][cls] + jd->longofs[id][cls]; /* Data table */ 390 | bl = HUFF_BIT + 1; 391 | #else 392 | /* Incremental serch for all codes */ 393 | hb = jd->huffbits[id][cls]; /* Bit distribution table */ 394 | hc = jd->huffcode[id][cls]; /* Code word table */ 395 | hd = jd->huffdata[id][cls]; /* Data table */ 396 | bl = 1; 397 | #endif 398 | for ( ; bl <= 16; bl++) { /* Incremental search */ 399 | nc = *hb++; 400 | if (nc) { 401 | d = w >> (wbit - bl); 402 | do { /* Search the code word in this bit length */ 403 | if (d == *hc++) { /* Matched? */ 404 | jd->dbit = wbit - bl; /* Snip the huffman code */ 405 | return *hd; /* Return the decoded data */ 406 | } 407 | hd++; 408 | } while (--nc); 409 | } 410 | } 411 | #endif 412 | 413 | return 0 - (int)JDR_FMT1; /* Err: code not found (may be collapted data) */ 414 | } 415 | 416 | 417 | 418 | 419 | /*-----------------------------------------------------------------------*/ 420 | /* Extract N bits from input stream */ 421 | /*-----------------------------------------------------------------------*/ 422 | 423 | static int bitext ( /* >=0: extracted data, <0: error code */ 424 | JDEC* jd, /* Pointer to the decompressor object */ 425 | unsigned int nbit /* Number of bits to extract (1 to 16) */ 426 | ) 427 | { 428 | size_t dc = jd->dctr; 429 | uint8_t *dp = jd->dptr; 430 | unsigned int d, flg = 0; 431 | 432 | #if JD_FASTDECODE == 0 433 | uint8_t mbit = jd->dbit; 434 | 435 | d = 0; 436 | do { 437 | if (!mbit) { /* Next byte? */ 438 | if (!dc) { /* No input data is available, re-fill input buffer */ 439 | dp = jd->inbuf; /* Top of input buffer */ 440 | dc = jd->infunc(jd, dp, JD_SZBUF); 441 | if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ 442 | } else { 443 | dp++; /* Next data ptr */ 444 | } 445 | dc--; /* Decrement number of available bytes */ 446 | if (flg) { /* In flag sequence? */ 447 | flg = 0; /* Exit flag sequence */ 448 | if (*dp != 0) return 0 - (int)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ 449 | *dp = 0xFF; /* The flag is a data 0xFF */ 450 | } else { 451 | if (*dp == 0xFF) { /* Is start of flag sequence? */ 452 | flg = 1; continue; /* Enter flag sequence */ 453 | } 454 | } 455 | mbit = 0x80; /* Read from MSB */ 456 | } 457 | d <<= 1; /* Get a bit */ 458 | if (*dp & mbit) d |= 1; 459 | mbit >>= 1; 460 | nbit--; 461 | } while (nbit); 462 | 463 | jd->dbit = mbit; jd->dctr = dc; jd->dptr = dp; 464 | return (int)d; 465 | 466 | #else 467 | unsigned int wbit = jd->dbit % 32; 468 | uint32_t w = jd->wreg & ((1UL << wbit) - 1); 469 | 470 | 471 | while (wbit < nbit) { /* Prepare nbit bits into the working register */ 472 | if (jd->marker) { 473 | d = 0xFF; /* Input stream stalled, generate stuff bits */ 474 | } else { 475 | if (!dc) { /* Buffer empty, re-fill input buffer */ 476 | dp = jd->inbuf; /* Top of input buffer */ 477 | dc = jd->infunc(jd, dp, JD_SZBUF); 478 | if (!dc) return 0 - (int)JDR_INP; /* Err: read error or wrong stream termination */ 479 | } 480 | d = *dp++; dc--; 481 | if (flg) { /* In flag sequence? */ 482 | flg = 0; /* Exit flag sequence */ 483 | if (d != 0) jd->marker = d; /* Not an escape of 0xFF but a marker */ 484 | d = 0xFF; 485 | } else { 486 | if (d == 0xFF) { /* Is start of flag sequence? */ 487 | flg = 1; continue; /* Enter flag sequence, get trailing byte */ 488 | } 489 | } 490 | } 491 | w = w << 8 | d; /* Get 8 bits into the working register */ 492 | wbit += 8; 493 | } 494 | jd->wreg = w; jd->dbit = wbit - nbit; 495 | jd->dctr = dc; jd->dptr = dp; 496 | 497 | return (int)(w >> ((wbit - nbit) % 32)); 498 | #endif 499 | } 500 | 501 | 502 | 503 | 504 | /*-----------------------------------------------------------------------*/ 505 | /* Process restart interval */ 506 | /*-----------------------------------------------------------------------*/ 507 | 508 | static JRESULT restart ( 509 | JDEC* jd, /* Pointer to the decompressor object */ 510 | uint16_t rstn /* Expected restert sequense number */ 511 | ) 512 | { 513 | unsigned int i; 514 | uint8_t *dp = jd->dptr; 515 | size_t dc = jd->dctr; 516 | 517 | #if JD_FASTDECODE == 0 518 | uint16_t d = 0; 519 | 520 | /* Get two bytes from the input stream */ 521 | for (i = 0; i < 2; i++) { 522 | if (!dc) { /* No input data is available, re-fill input buffer */ 523 | dp = jd->inbuf; 524 | dc = jd->infunc(jd, dp, JD_SZBUF); 525 | if (!dc) return JDR_INP; 526 | } else { 527 | dp++; 528 | } 529 | dc--; 530 | d = d << 8 | *dp; /* Get a byte */ 531 | } 532 | jd->dptr = dp; jd->dctr = dc; jd->dbit = 0; 533 | 534 | /* Check the marker */ 535 | if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { 536 | return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ 537 | } 538 | 539 | #else 540 | uint16_t marker; 541 | 542 | 543 | if (jd->marker) { /* Generate a maker if it has been detected */ 544 | marker = 0xFF00 | jd->marker; 545 | jd->marker = 0; 546 | } else { 547 | marker = 0; 548 | for (i = 0; i < 2; i++) { /* Get a restart marker */ 549 | if (!dc) { /* No input data is available, re-fill input buffer */ 550 | dp = jd->inbuf; 551 | dc = jd->infunc(jd, dp, JD_SZBUF); 552 | if (!dc) return JDR_INP; 553 | } 554 | marker = (marker << 8) | *dp++; /* Get a byte */ 555 | dc--; 556 | } 557 | jd->dptr = dp; jd->dctr = dc; 558 | } 559 | 560 | /* Check the marker */ 561 | if ((marker & 0xFFD8) != 0xFFD0 || (marker & 7) != (rstn & 7)) { 562 | return JDR_FMT1; /* Err: expected RSTn marker was not detected (may be collapted data) */ 563 | } 564 | 565 | jd->dbit = 0; /* Discard stuff bits */ 566 | #endif 567 | 568 | jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Reset DC offset */ 569 | return JDR_OK; 570 | } 571 | 572 | 573 | 574 | 575 | /*-----------------------------------------------------------------------*/ 576 | /* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ 577 | /*-----------------------------------------------------------------------*/ 578 | 579 | static void block_idct ( 580 | int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ 581 | jd_yuv_t* dst /* Pointer to the destination to store the block as byte array */ 582 | ) 583 | { 584 | const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); 585 | int32_t v0, v1, v2, v3, v4, v5, v6, v7; 586 | int32_t t10, t11, t12, t13; 587 | int i; 588 | 589 | /* Process columns */ 590 | for (i = 0; i < 8; i++) { 591 | v0 = src[8 * 0]; /* Get even elements */ 592 | v1 = src[8 * 2]; 593 | v2 = src[8 * 4]; 594 | v3 = src[8 * 6]; 595 | 596 | t10 = v0 + v2; /* Process the even elements */ 597 | t12 = v0 - v2; 598 | t11 = (v1 - v3) * M13 >> 12; 599 | v3 += v1; 600 | t11 -= v3; 601 | v0 = t10 + v3; 602 | v3 = t10 - v3; 603 | v1 = t11 + t12; 604 | v2 = t12 - t11; 605 | 606 | v4 = src[8 * 7]; /* Get odd elements */ 607 | v5 = src[8 * 1]; 608 | v6 = src[8 * 5]; 609 | v7 = src[8 * 3]; 610 | 611 | t10 = v5 - v4; /* Process the odd elements */ 612 | t11 = v5 + v4; 613 | t12 = v6 - v7; 614 | v7 += v6; 615 | v5 = (t11 - v7) * M13 >> 12; 616 | v7 += t11; 617 | t13 = (t10 + t12) * M5 >> 12; 618 | v4 = t13 - (t10 * M2 >> 12); 619 | v6 = t13 - (t12 * M4 >> 12) - v7; 620 | v5 -= v6; 621 | v4 -= v5; 622 | 623 | src[8 * 0] = v0 + v7; /* Write-back transformed values */ 624 | src[8 * 7] = v0 - v7; 625 | src[8 * 1] = v1 + v6; 626 | src[8 * 6] = v1 - v6; 627 | src[8 * 2] = v2 + v5; 628 | src[8 * 5] = v2 - v5; 629 | src[8 * 3] = v3 + v4; 630 | src[8 * 4] = v3 - v4; 631 | 632 | src++; /* Next column */ 633 | } 634 | 635 | /* Process rows */ 636 | src -= 8; 637 | for (i = 0; i < 8; i++) { 638 | v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ 639 | v1 = src[2]; 640 | v2 = src[4]; 641 | v3 = src[6]; 642 | 643 | t10 = v0 + v2; /* Process the even elements */ 644 | t12 = v0 - v2; 645 | t11 = (v1 - v3) * M13 >> 12; 646 | v3 += v1; 647 | t11 -= v3; 648 | v0 = t10 + v3; 649 | v3 = t10 - v3; 650 | v1 = t11 + t12; 651 | v2 = t12 - t11; 652 | 653 | v4 = src[7]; /* Get odd elements */ 654 | v5 = src[1]; 655 | v6 = src[5]; 656 | v7 = src[3]; 657 | 658 | t10 = v5 - v4; /* Process the odd elements */ 659 | t11 = v5 + v4; 660 | t12 = v6 - v7; 661 | v7 += v6; 662 | v5 = (t11 - v7) * M13 >> 12; 663 | v7 += t11; 664 | t13 = (t10 + t12) * M5 >> 12; 665 | v4 = t13 - (t10 * M2 >> 12); 666 | v6 = t13 - (t12 * M4 >> 12) - v7; 667 | v5 -= v6; 668 | v4 -= v5; 669 | 670 | /* Descale the transformed values 8 bits and output a row */ 671 | #if JD_FASTDECODE >= 1 672 | dst[0] = (int16_t)((v0 + v7) >> 8); 673 | dst[7] = (int16_t)((v0 - v7) >> 8); 674 | dst[1] = (int16_t)((v1 + v6) >> 8); 675 | dst[6] = (int16_t)((v1 - v6) >> 8); 676 | dst[2] = (int16_t)((v2 + v5) >> 8); 677 | dst[5] = (int16_t)((v2 - v5) >> 8); 678 | dst[3] = (int16_t)((v3 + v4) >> 8); 679 | dst[4] = (int16_t)((v3 - v4) >> 8); 680 | #else 681 | dst[0] = BYTECLIP((v0 + v7) >> 8); 682 | dst[7] = BYTECLIP((v0 - v7) >> 8); 683 | dst[1] = BYTECLIP((v1 + v6) >> 8); 684 | dst[6] = BYTECLIP((v1 - v6) >> 8); 685 | dst[2] = BYTECLIP((v2 + v5) >> 8); 686 | dst[5] = BYTECLIP((v2 - v5) >> 8); 687 | dst[3] = BYTECLIP((v3 + v4) >> 8); 688 | dst[4] = BYTECLIP((v3 - v4) >> 8); 689 | #endif 690 | 691 | dst += 8; src += 8; /* Next row */ 692 | } 693 | } 694 | 695 | 696 | 697 | 698 | /*-----------------------------------------------------------------------*/ 699 | /* Load all blocks in an MCU into working buffer */ 700 | /*-----------------------------------------------------------------------*/ 701 | 702 | static JRESULT mcu_load ( 703 | JDEC* jd /* Pointer to the decompressor object */ 704 | ) 705 | { 706 | int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ 707 | int d, e; 708 | unsigned int blk, nby, i, bc, z, id, cmp; 709 | jd_yuv_t *bp; 710 | const int32_t *dqf; 711 | 712 | 713 | nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ 714 | bp = jd->mcubuf; /* Pointer to the first block of MCU */ 715 | 716 | for (blk = 0; blk < nby + 2; blk++) { /* Get nby Y blocks and two C blocks */ 717 | cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ 718 | 719 | if (cmp && jd->ncomp != 3) { /* Clear C blocks if not exist (monochrome image) */ 720 | for (i = 0; i < 64; bp[i++] = 128) ; 721 | 722 | } else { /* Load Y/C blocks from input stream */ 723 | id = cmp ? 1 : 0; /* Huffman table ID of this component */ 724 | 725 | /* Extract a DC element from input stream */ 726 | d = huffext(jd, id, 0); /* Extract a huffman coded data (bit length) */ 727 | if (d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input */ 728 | bc = (unsigned int)d; 729 | d = jd->dcv[cmp]; /* DC value of previous block */ 730 | if (bc) { /* If there is any difference from previous block */ 731 | e = bitext(jd, bc); /* Extract data bits */ 732 | if (e < 0) return (JRESULT)(0 - e); /* Err: input */ 733 | bc = 1 << (bc - 1); /* MSB position */ 734 | if (!(e & bc)) e -= (bc << 1) - 1; /* Restore negative value if needed */ 735 | d += e; /* Get current value */ 736 | jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ 737 | } 738 | dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ 739 | tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ 740 | 741 | /* Extract following 63 AC elements from input stream */ 742 | memset(&tmp[1], 0, 63 * sizeof (int32_t)); /* Initialize all AC elements */ 743 | z = 1; /* Top of the AC elements (in zigzag-order) */ 744 | do { 745 | d = huffext(jd, id, 1); /* Extract a huffman coded value (zero runs and bit length) */ 746 | if (d == 0) break; /* EOB? */ 747 | if (d < 0) return (JRESULT)(0 - d); /* Err: invalid code or input error */ 748 | bc = (unsigned int)d; 749 | z += bc >> 4; /* Skip leading zero run */ 750 | if (z >= 64) return JDR_FMT1; /* Too long zero run */ 751 | if (bc &= 0x0F) { /* Bit length? */ 752 | d = bitext(jd, bc); /* Extract data bits */ 753 | if (d < 0) return (JRESULT)(0 - d); /* Err: input device */ 754 | bc = 1 << (bc - 1); /* MSB position */ 755 | if (!(d & bc)) d -= (bc << 1) - 1; /* Restore negative value if needed */ 756 | i = Zig[z]; /* Get raster-order index */ 757 | tmp[i] = d * dqf[i] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ 758 | } 759 | } while (++z < 64); /* Next AC element */ 760 | 761 | if (JD_FORMAT != 2 || !cmp) { /* C components may not be processed if in grayscale output */ 762 | if (z == 1 || (JD_USE_SCALE && jd->scale == 3)) { /* If no AC element or scale ratio is 1/8, IDCT can be ommited and the block is filled with DC value */ 763 | d = (jd_yuv_t)((*tmp / 256) + 128); 764 | if (JD_FASTDECODE >= 1) { 765 | for (i = 0; i < 64; bp[i++] = d) ; 766 | } else { 767 | memset(bp, d, 64); 768 | } 769 | } else { 770 | block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ 771 | } 772 | } 773 | } 774 | 775 | bp += 64; /* Next block */ 776 | } 777 | 778 | return JDR_OK; /* All blocks have been loaded successfully */ 779 | } 780 | 781 | 782 | 783 | 784 | /*-----------------------------------------------------------------------*/ 785 | /* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ 786 | /*-----------------------------------------------------------------------*/ 787 | 788 | static JRESULT mcu_output ( 789 | JDEC* jd, /* Pointer to the decompressor object */ 790 | int (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ 791 | unsigned int x, /* MCU location in the image */ 792 | unsigned int y /* MCU location in the image */ 793 | ) 794 | { 795 | const int CVACC = (sizeof (int) > 2) ? 1024 : 128; /* Adaptive accuracy for both 16-/32-bit systems */ 796 | unsigned int ix, iy, mx, my, rx, ry; 797 | int yy, cb, cr; 798 | jd_yuv_t *py, *pc; 799 | uint8_t *pix; 800 | JRECT rect; 801 | 802 | 803 | mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ 804 | rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end of image) */ 805 | ry = (y + my <= jd->height) ? my : jd->height - y; 806 | if (JD_USE_SCALE) { 807 | rx >>= jd->scale; ry >>= jd->scale; 808 | if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ 809 | x >>= jd->scale; y >>= jd->scale; 810 | } 811 | rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ 812 | rect.top = y; rect.bottom = y + ry - 1; 813 | 814 | 815 | if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ 816 | pix = (uint8_t*)jd->workbuf; 817 | 818 | if (JD_FORMAT != 2) { /* RGB output (build an RGB MCU from Y/C component) */ 819 | for (iy = 0; iy < my; iy++) { 820 | pc = py = jd->mcubuf; 821 | if (my == 16) { /* Double block height? */ 822 | pc += 64 * 4 + (iy >> 1) * 8; 823 | if (iy >= 8) py += 64; 824 | } else { /* Single block height */ 825 | pc += mx * 8 + iy * 8; 826 | } 827 | py += iy * 8; 828 | for (ix = 0; ix < mx; ix++) { 829 | cb = pc[0] - 128; /* Get Cb/Cr component and remove offset */ 830 | cr = pc[64] - 128; 831 | if (mx == 16) { /* Double block width? */ 832 | if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ 833 | pc += ix & 1; /* Step forward chroma pointer every two pixels */ 834 | } else { /* Single block width */ 835 | pc++; /* Step forward chroma pointer every pixel */ 836 | } 837 | yy = *py++; /* Get Y component */ 838 | *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr) / CVACC); 839 | *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC); 840 | *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb) / CVACC); 841 | } 842 | } 843 | } else { /* Monochrome output (build a grayscale MCU from Y comopnent) */ 844 | for (iy = 0; iy < my; iy++) { 845 | py = jd->mcubuf + iy * 8; 846 | if (my == 16) { /* Double block height? */ 847 | if (iy >= 8) py += 64; 848 | } 849 | for (ix = 0; ix < mx; ix++) { 850 | if (mx == 16) { /* Double block width? */ 851 | if (ix == 8) py += 64 - 8; /* Jump to next block if double block height */ 852 | } 853 | if (JD_FASTDECODE >= 1) { 854 | *pix++ = BYTECLIP(*py++); /* Get and store a Y value as grayscale */ 855 | } else { 856 | *pix++ = *py++; /* Get and store a Y value as grayscale */ 857 | } 858 | } 859 | } 860 | } 861 | 862 | /* Descale the MCU rectangular if needed */ 863 | if (JD_USE_SCALE && jd->scale) { 864 | unsigned int x, y, r, g, b, s, w, a; 865 | uint8_t *op; 866 | 867 | /* Get averaged RGB value of each square correcponds to a pixel */ 868 | s = jd->scale * 2; /* Number of shifts for averaging */ 869 | w = 1 << jd->scale; /* Width of square */ 870 | a = (mx - w) * (JD_FORMAT != 2 ? 3 : 1); /* Bytes to skip for next line in the square */ 871 | op = (uint8_t*)jd->workbuf; 872 | for (iy = 0; iy < my; iy += w) { 873 | for (ix = 0; ix < mx; ix += w) { 874 | pix = (uint8_t*)jd->workbuf + (iy * mx + ix) * (JD_FORMAT != 2 ? 3 : 1); 875 | r = g = b = 0; 876 | for (y = 0; y < w; y++) { /* Accumulate RGB value in the square */ 877 | for (x = 0; x < w; x++) { 878 | r += *pix++; /* Accumulate R or Y (monochrome output) */ 879 | if (JD_FORMAT != 2) { /* RGB output? */ 880 | g += *pix++; /* Accumulate G */ 881 | b += *pix++; /* Accumulate B */ 882 | } 883 | } 884 | pix += a; 885 | } /* Put the averaged pixel value */ 886 | *op++ = (uint8_t)(r >> s); /* Put R or Y (monochrome output) */ 887 | if (JD_FORMAT != 2) { /* RGB output? */ 888 | *op++ = (uint8_t)(g >> s); /* Put G */ 889 | *op++ = (uint8_t)(b >> s); /* Put B */ 890 | } 891 | } 892 | } 893 | } 894 | 895 | } else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ 896 | 897 | /* Build a 1/8 descaled RGB MCU from discrete comopnents */ 898 | pix = (uint8_t*)jd->workbuf; 899 | pc = jd->mcubuf + mx * my; 900 | cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ 901 | cr = pc[64] - 128; 902 | for (iy = 0; iy < my; iy += 8) { 903 | py = jd->mcubuf; 904 | if (iy == 8) py += 64 * 2; 905 | for (ix = 0; ix < mx; ix += 8) { 906 | yy = *py; /* Get Y component */ 907 | py += 64; 908 | if (JD_FORMAT != 2) { 909 | *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr / CVACC)); 910 | *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC); 911 | *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb / CVACC)); 912 | } else { 913 | *pix++ = yy; 914 | } 915 | } 916 | } 917 | } 918 | 919 | /* Squeeze up pixel table if a part of MCU is to be truncated */ 920 | mx >>= jd->scale; 921 | if (rx < mx) { /* Is the MCU spans rigit edge? */ 922 | uint8_t *s, *d; 923 | unsigned int x, y; 924 | 925 | s = d = (uint8_t*)jd->workbuf; 926 | for (y = 0; y < ry; y++) { 927 | for (x = 0; x < rx; x++) { /* Copy effective pixels */ 928 | *d++ = *s++; 929 | if (JD_FORMAT != 2) { 930 | *d++ = *s++; 931 | *d++ = *s++; 932 | } 933 | } 934 | s += (mx - rx) * (JD_FORMAT != 2 ? 3 : 1); /* Skip truncated pixels */ 935 | } 936 | } 937 | 938 | /* Convert RGB888 to RGB565 if needed */ 939 | if (JD_FORMAT == 1) { 940 | uint8_t *s = (uint8_t*)jd->workbuf; 941 | uint16_t w, *d = (uint16_t*)s; 942 | unsigned int n = rx * ry; 943 | 944 | if (jd->swap) 945 | { 946 | do { 947 | w = (*s++ & 0xF8) << 8; // RRRRR----------- 948 | w |= (*s++ & 0xFC) << 3; // -----GGGGGG----- 949 | w |= *s++ >> 3; // -----------BBBBB 950 | *d++ = (w << 8) | (w >> 8); // Swap bytes 951 | } while (--n); 952 | } 953 | else 954 | { 955 | do { 956 | w = ( *s++ & 0xF8) << 8; // RRRRR----------- 957 | w |= (*s++ & 0xFC) << 3; // -----GGGGGG----- 958 | w |= *s++ >> 3; // -----------BBBBB 959 | *d++ = w; 960 | } while (--n); 961 | } 962 | } 963 | 964 | /* Output the rectangular */ 965 | return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; 966 | } 967 | 968 | 969 | 970 | 971 | /*-----------------------------------------------------------------------*/ 972 | /* Analyze the JPEG image and Initialize decompressor object */ 973 | /*-----------------------------------------------------------------------*/ 974 | 975 | #define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) 976 | 977 | 978 | JRESULT jd_prepare ( 979 | JDEC* jd, /* Blank decompressor object */ 980 | size_t (*infunc)(JDEC*, uint8_t*, size_t), /* JPEG strem input function */ 981 | void* pool, /* Working buffer for the decompression session */ 982 | size_t sz_pool, /* Size of working buffer */ 983 | void* dev /* I/O device identifier for the session */ 984 | ) 985 | { 986 | uint8_t *seg, b; 987 | uint16_t marker; 988 | unsigned int n, i, ofs; 989 | size_t len; 990 | JRESULT rc; 991 | 992 | uint8_t tmp = jd->swap; // Copy the swap flag 993 | memset(jd, 0, sizeof (JDEC)); /* Clear decompression object (this might be a problem if machine's null pointer is not all bits zero) */ 994 | jd->pool = pool; /* Work memroy */ 995 | jd->sz_pool = sz_pool; /* Size of given work memory */ 996 | jd->infunc = infunc; /* Stream input function */ 997 | jd->device = dev; /* I/O device identifier */ 998 | jd->swap = tmp; // Restore the swap flag 999 | 1000 | jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ 1001 | if (!seg) return JDR_MEM1; 1002 | 1003 | ofs = marker = 0; /* Find SOI marker */ 1004 | do { 1005 | if (jd->infunc(jd, seg, 1) != 1) return JDR_INP; /* Err: SOI was not detected */ 1006 | ofs++; 1007 | marker = marker << 8 | seg[0]; 1008 | } while (marker != 0xFFD8); 1009 | 1010 | for (;;) { /* Parse JPEG segments */ 1011 | /* Get a JPEG marker */ 1012 | if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; 1013 | marker = LDB_WORD(seg); /* Marker */ 1014 | len = LDB_WORD(seg + 2); /* Length field */ 1015 | if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; 1016 | len -= 2; /* Segent content size */ 1017 | ofs += 4 + len; /* Number of bytes loaded */ 1018 | 1019 | switch (marker & 0xFF) { 1020 | case 0xC0: /* SOF0 (baseline JPEG) */ 1021 | if (len > JD_SZBUF) return JDR_MEM2; 1022 | if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ 1023 | 1024 | jd->width = LDB_WORD(&seg[3]); /* Image width in unit of pixel */ 1025 | jd->height = LDB_WORD(&seg[1]); /* Image height in unit of pixel */ 1026 | jd->ncomp = seg[5]; /* Number of color components */ 1027 | if (jd->ncomp != 3 && jd->ncomp != 1) return JDR_FMT3; /* Err: Supports only Grayscale and Y/Cb/Cr */ 1028 | 1029 | /* Check each image component */ 1030 | for (i = 0; i < jd->ncomp; i++) { 1031 | b = seg[7 + 3 * i]; /* Get sampling factor */ 1032 | if (i == 0) { /* Y component */ 1033 | if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ 1034 | return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ 1035 | } 1036 | jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ 1037 | } else { /* Cb/Cr component */ 1038 | if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cb/Cr must be 1 */ 1039 | } 1040 | jd->qtid[i] = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ 1041 | if (jd->qtid[i] > 3) return JDR_FMT3; /* Err: Invalid ID */ 1042 | } 1043 | break; 1044 | 1045 | case 0xDD: /* DRI - Define Restart Interval */ 1046 | if (len > JD_SZBUF) return JDR_MEM2; 1047 | if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ 1048 | 1049 | jd->nrst = LDB_WORD(seg); /* Get restart interval (MCUs) */ 1050 | break; 1051 | 1052 | case 0xC4: /* DHT - Define Huffman Tables */ 1053 | if (len > JD_SZBUF) return JDR_MEM2; 1054 | if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ 1055 | 1056 | rc = create_huffman_tbl(jd, seg, len); /* Create huffman tables */ 1057 | if (rc) return rc; 1058 | break; 1059 | 1060 | case 0xDB: /* DQT - Define Quaitizer Tables */ 1061 | if (len > JD_SZBUF) return JDR_MEM2; 1062 | if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ 1063 | 1064 | rc = create_qt_tbl(jd, seg, len); /* Create de-quantizer tables */ 1065 | if (rc) return rc; 1066 | break; 1067 | 1068 | case 0xDA: /* SOS - Start of Scan */ 1069 | if (len > JD_SZBUF) return JDR_MEM2; 1070 | if (jd->infunc(jd, seg, len) != len) return JDR_INP; /* Load segment data */ 1071 | 1072 | if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ 1073 | if (seg[0] != jd->ncomp) return JDR_FMT3; /* Err: Wrong color components */ 1074 | 1075 | /* Check if all tables corresponding to each components have been loaded */ 1076 | for (i = 0; i < jd->ncomp; i++) { 1077 | b = seg[2 + 2 * i]; /* Get huffman table ID */ 1078 | if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ 1079 | n = i ? 1 : 0; /* Component class */ 1080 | if (!jd->huffbits[n][0] || !jd->huffbits[n][1]) { /* Check huffman table for this component */ 1081 | return JDR_FMT1; /* Err: Nnot loaded */ 1082 | } 1083 | if (!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ 1084 | return JDR_FMT1; /* Err: Not loaded */ 1085 | } 1086 | } 1087 | 1088 | /* Allocate working buffer for MCU and pixel output */ 1089 | n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ 1090 | if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ 1091 | len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ 1092 | if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ 1093 | jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ 1094 | if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ 1095 | jd->mcubuf = alloc_pool(jd, (n + 2) * 64 * sizeof (jd_yuv_t)); /* Allocate MCU working buffer */ 1096 | if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ 1097 | 1098 | /* Align stream read offset to JD_SZBUF */ 1099 | if (ofs %= JD_SZBUF) { 1100 | jd->dctr = jd->infunc(jd, seg + ofs, (size_t)(JD_SZBUF - ofs)); 1101 | } 1102 | jd->dptr = seg + ofs - (JD_FASTDECODE ? 0 : 1); 1103 | 1104 | return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ 1105 | 1106 | case 0xC1: /* SOF1 */ 1107 | case 0xC2: /* SOF2 */ 1108 | case 0xC3: /* SOF3 */ 1109 | case 0xC5: /* SOF5 */ 1110 | case 0xC6: /* SOF6 */ 1111 | case 0xC7: /* SOF7 */ 1112 | case 0xC9: /* SOF9 */ 1113 | case 0xCA: /* SOF10 */ 1114 | case 0xCB: /* SOF11 */ 1115 | case 0xCD: /* SOF13 */ 1116 | case 0xCE: /* SOF14 */ 1117 | case 0xCF: /* SOF15 */ 1118 | case 0xD9: /* EOI */ 1119 | return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ 1120 | 1121 | default: /* Unknown segment (comment, exif or etc..) */ 1122 | /* Skip segment data (null pointer specifies to remove data from the stream) */ 1123 | if (jd->infunc(jd, 0, len) != len) return JDR_INP; 1124 | } 1125 | } 1126 | } 1127 | 1128 | 1129 | 1130 | 1131 | /*-----------------------------------------------------------------------*/ 1132 | /* Start to decompress the JPEG picture */ 1133 | /*-----------------------------------------------------------------------*/ 1134 | 1135 | JRESULT jd_decomp ( 1136 | JDEC* jd, /* Initialized decompression object */ 1137 | int (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ 1138 | uint8_t scale /* Output de-scaling factor (0 to 3) */ 1139 | ) 1140 | { 1141 | unsigned int x, y, mx, my; 1142 | uint16_t rst, rsc; 1143 | JRESULT rc; 1144 | 1145 | 1146 | if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; 1147 | jd->scale = scale; 1148 | 1149 | mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ 1150 | 1151 | jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ 1152 | rst = rsc = 0; 1153 | 1154 | rc = JDR_OK; 1155 | for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ 1156 | for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ 1157 | if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ 1158 | rc = restart(jd, rsc++); 1159 | if (rc != JDR_OK) return rc; 1160 | rst = 1; 1161 | } 1162 | rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */ 1163 | if (rc != JDR_OK) return rc; 1164 | rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (YCbCr to RGB, scaling and output) */ 1165 | if (rc != JDR_OK) return rc; 1166 | } 1167 | } 1168 | 1169 | return rc; 1170 | } 1171 | -------------------------------------------------------------------------------- /src/tjpgd.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor R0.03 include file (C)ChaN, 2021 3 | /----------------------------------------------------------------------------*/ 4 | #ifndef DEF_TJPGDEC 5 | #define DEF_TJPGDEC 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include "tjpgdcnf.h" 12 | #include 13 | 14 | #if defined(_WIN32) /* VC++ or some compiler without stdint.h */ 15 | typedef unsigned char uint8_t; 16 | typedef unsigned short uint16_t; 17 | typedef short int16_t; 18 | typedef unsigned long uint32_t; 19 | typedef long int32_t; 20 | #else /* Embedded platform */ 21 | #include 22 | #endif 23 | 24 | #if JD_FASTDECODE >= 1 25 | typedef int16_t jd_yuv_t; 26 | #else 27 | typedef uint8_t jd_yuv_t; 28 | #endif 29 | 30 | 31 | /* Error code */ 32 | typedef enum { 33 | JDR_OK = 0, /* 0: Succeeded */ 34 | JDR_INTR, /* 1: Interrupted by output function */ 35 | JDR_INP, /* 2: Device error or wrong termination of input stream */ 36 | JDR_MEM1, /* 3: Insufficient memory pool for the image */ 37 | JDR_MEM2, /* 4: Insufficient stream input buffer */ 38 | JDR_PAR, /* 5: Parameter error */ 39 | JDR_FMT1, /* 6: Data format error (may be broken data) */ 40 | JDR_FMT2, /* 7: Right format but not supported */ 41 | JDR_FMT3 /* 8: Not supported JPEG standard */ 42 | } JRESULT; 43 | 44 | 45 | 46 | /* Rectangular region in the output image */ 47 | typedef struct { 48 | uint16_t left; /* Left end */ 49 | uint16_t right; /* Right end */ 50 | uint16_t top; /* Top end */ 51 | uint16_t bottom; /* Bottom end */ 52 | } JRECT; 53 | 54 | 55 | 56 | /* Decompressor object structure */ 57 | typedef struct JDEC JDEC; 58 | struct JDEC { 59 | size_t dctr; /* Number of bytes available in the input buffer */ 60 | uint8_t* dptr; /* Current data read ptr */ 61 | uint8_t* inbuf; /* Bit stream input buffer */ 62 | uint8_t dbit; /* Number of bits availavble in wreg or reading bit mask */ 63 | uint8_t scale; /* Output scaling ratio */ 64 | uint8_t msx, msy; /* MCU size in unit of block (width, height) */ 65 | uint8_t qtid[3]; /* Quantization table ID of each component, Y, Cb, Cr */ 66 | uint8_t ncomp; /* Number of color components 1:grayscale, 3:color */ 67 | int16_t dcv[3]; /* Previous DC element of each component */ 68 | uint16_t nrst; /* Restart inverval */ 69 | uint16_t width, height; /* Size of the input image (pixel) */ 70 | uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ 71 | uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ 72 | uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ 73 | int32_t* qttbl[4]; /* Dequantizer tables [id] */ 74 | #if JD_FASTDECODE >= 1 75 | uint32_t wreg; /* Working shift register */ 76 | uint8_t marker; /* Detected marker (0:None) */ 77 | #if JD_FASTDECODE == 2 78 | uint8_t longofs[2][2]; /* Table offset of long code [id][dcac] */ 79 | uint16_t* hufflut_ac[2]; /* Fast huffman decode tables for AC short code [id] */ 80 | uint8_t* hufflut_dc[2]; /* Fast huffman decode tables for DC short code [id] */ 81 | #endif 82 | #endif 83 | void* workbuf; /* Working buffer for IDCT and RGB output */ 84 | jd_yuv_t* mcubuf; /* Working buffer for the MCU */ 85 | void* pool; /* Pointer to available memory pool */ 86 | size_t sz_pool; /* Size of momory pool (bytes available) */ 87 | size_t (*infunc)(JDEC*, uint8_t*, size_t); /* Pointer to jpeg stream input function */ 88 | void* device; /* Pointer to I/O device identifiler for the session */ 89 | uint8_t swap; /* Added by Bodmer to control byte swapping */ 90 | }; 91 | 92 | 93 | 94 | /* TJpgDec API functions */ 95 | JRESULT jd_prepare (JDEC* jd, size_t (*infunc)(JDEC*,uint8_t*,size_t), void* pool, size_t sz_pool, void* dev); 96 | JRESULT jd_decomp (JDEC* jd, int (*outfunc)(JDEC*,void*,JRECT*), uint8_t scale); 97 | 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif 102 | 103 | #endif /* _TJPGDEC */ 104 | -------------------------------------------------------------------------------- /src/tjpgdcnf.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------*/ 2 | /* TJpgDec System Configurations R0.03 */ 3 | /*----------------------------------------------*/ 4 | 5 | #define JD_SZBUF 512 6 | /* Specifies size of stream input buffer */ 7 | 8 | #define JD_FORMAT 1 9 | /* Specifies output pixel format. 10 | / 0: RGB888 (24-bit/pix) 11 | / 1: RGB565 (16-bit/pix) 12 | / 2: Grayscale (8-bit/pix) 13 | */ 14 | 15 | #define JD_USE_SCALE 1 16 | /* Switches output descaling feature. 17 | / 0: Disable 18 | / 1: Enable 19 | */ 20 | 21 | #define JD_TBLCLIP 0 22 | /* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size. 23 | / 0: Disable 24 | / 1: Enable 25 | */ 26 | 27 | #define JD_FASTDECODE 1 28 | /* Optimization level 29 | / 0: Basic optimization. Suitable for 8/16-bit MCUs. 30 | / Workspace of 3100 bytes needed. 31 | / 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. 32 | / Workspace of 3480 bytes needed. 33 | / 2: + Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM). 34 | / Workspace of 9644 bytes needed. 35 | */ 36 | 37 | // Do not change this, it is the minimum size in bytes of the workspace needed by the decoder 38 | #if JD_FASTDECODE == 0 39 | #define TJPGD_WORKSPACE_SIZE 3100 40 | #elif JD_FASTDECODE == 1 41 | #define TJPGD_WORKSPACE_SIZE 3500 42 | #elif JD_FASTDECODE == 2 43 | #define TJPGD_WORKSPACE_SIZE (3500 + 6144) 44 | #endif --------------------------------------------------------------------------------