From fc316d89aa90cf7bf0b1558dc57ddf45413121df Mon Sep 17 00:00:00 2001 From: Thomas Ballmann Date: Sat, 28 Mar 2020 12:02:11 +0100 Subject: [PATCH] switch to a new jpeg encoder #7 --- platformio.ini | 3 +- src/imageJPEG.cpp | 206 +++++++++++++++++++++++++++++++++------------- 2 files changed, 151 insertions(+), 58 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5fe819e..1346eff 100644 --- a/platformio.ini +++ b/platformio.ini @@ -31,7 +31,8 @@ lib_deps = ESP Async WebServer@~1.2.3 ArduinoJson@~6.14.1 https://github.com/kikuchan/pngle.git - TJpg_Decoder@~0.0.3 + #TJpg_Decoder@~0.0.3 + JPEGDecoder@~1.8.0 # Semantic Versioning Rules # http://docs.platformio.org/page/userguide/lib/cmd_install.html#description diff --git a/src/imageJPEG.cpp b/src/imageJPEG.cpp index 777e5e7..2cabb5b 100644 --- a/src/imageJPEG.cpp +++ b/src/imageJPEG.cpp @@ -1,9 +1,12 @@ #include #include -#include +//#include +#include // JPEG decoder library #include "imageJPEG.h" #include "display.h" +#define DEBUG = 1 + File tmpFileBuffer; bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap); @@ -15,17 +18,19 @@ static int16_t curRowDeltaJ[MAX_WIDTH + 1]; unsigned int pixelCount = 0; +#define minimum(a, b) (((a) < (b)) ? (a) : (b)) + void setupImageJPEG() { Serial.println("setupJPEG"); // The jpeg image can be scaled by a factor of 1, 2, 4, or 8 - TJpgDec.setJpgScale(1); + //TJpgDec.setJpgScale(1); // The decoder must be given the exact name of the rendering function above - TJpgDec.setCallback(tft_output); + //TJpgDec.setCallback(tft_output); - memset(blockDelta, 0, sizeof(blockDelta)); + //memset(blockDelta, 0, sizeof(blockDelta)); } void jpegOpenFramebuffer() @@ -52,12 +57,146 @@ void jpegWriteFramebuffer(int offset, uint8_t bitmap[], int c) } } +//==================================================================================== +// Print information about the image +//==================================================================================== +void jpegInfo() +{ + Serial.println(F("===============")); + Serial.println(F("JPEG image info")); + Serial.println(F("===============")); + Serial.print(F("Width :")); + Serial.println(JpegDec.width); + Serial.print(F("Height :")); + Serial.println(JpegDec.height); + Serial.print(F("Components :")); + Serial.println(JpegDec.comps); + Serial.print(F("MCU / row :")); + Serial.println(JpegDec.MCUSPerRow); + Serial.print(F("MCU / col :")); + Serial.println(JpegDec.MCUSPerCol); + Serial.print(F("Scan type :")); + Serial.println(JpegDec.scanType); + Serial.print(F("MCU width :")); + Serial.println(JpegDec.MCUWidth); + Serial.print(F("MCU height :")); + Serial.println(JpegDec.MCUHeight); + Serial.println(F("===============")); +} + +//==================================================================================== +// Decode and paint onto the TFT screen +//==================================================================================== +void renderJPEG(int xpos, int ypos) +{ + + // retrieve infomration about the image + uint16_t *pImg; + uint16_t mcu_w = JpegDec.MCUWidth; + uint16_t mcu_h = JpegDec.MCUHeight; + uint32_t max_x = JpegDec.width; + uint32_t max_y = JpegDec.height; + + // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs) + // Typically these MCUs are 16x16 pixel blocks + // Determine the width and height of the right and bottom edge image blocks + uint32_t min_w = minimum(mcu_w, max_x % mcu_w); + uint32_t min_h = minimum(mcu_h, max_y % mcu_h); + + // save the current image block size + uint32_t win_w = mcu_w; + uint32_t win_h = mcu_h; + + // record the current time so we can measure how long it takes to draw an image + uint32_t drawTime = millis(); + + // save the coordinate of the right and bottom edges to assist image cropping + // to the screen size + max_x += xpos; + max_y += ypos; + + // read each MCU block until there are no more + while (JpegDec.read()) + { + + // save a pointer to the image block + pImg = JpegDec.pImage; + + // calculate where the image block should be drawn on the screen + int mcu_x = JpegDec.MCUx * mcu_w + xpos; + int mcu_y = JpegDec.MCUy * mcu_h + ypos; + + // check if the image block size needs to be changed for the right and bottom edges + if (mcu_x + mcu_w <= max_x) + win_w = mcu_w; + else + win_w = min_w; + if (mcu_y + mcu_h <= max_y) + win_h = mcu_h; + else + win_h = min_h; + + // calculate how many pixels must be drawn + uint32_t mcu_pixels = win_w * win_h; + + // draw image block if it will fit on the screen + if ((mcu_x + win_w) <= display.width() && (mcu_y + win_h) <= display.height()) + { + // TODO + //display.drawRGBBitmap(mcu_x, mcu_y, pImg, win_w, win_h); + tft_output(mcu_x, mcu_y, win_w, win_h, pImg); + + /* + // open a window onto the screen to paint the pixels into + //TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); + TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); + // push all the image block pixels to the screen + while (mcu_pixels--) + TFTscreen.pushColor(*pImg++); // Send to TFT 16 bits at a time + */ + } + + // stop drawing blocks if the bottom of the screen has been reached + // the abort function will close the file + else if ((mcu_y + win_h) >= display.height()) + { + JpegDec.abort(); + } + } + + // calculate how long it took to draw the image + drawTime = millis() - drawTime; // Calculate the time it took + + // print the results to the serial port + Serial.print("Total render time was : "); + Serial.print(drawTime); + Serial.println(" ms"); + Serial.println("====================================="); +} + void jpegFlushFramebuffer() { if (tmpFileBuffer) { tmpFileBuffer.close(); + if (!SPIFFS.exists("/tmp.jpeg")) + { + Serial.println("=== /tmp.jpeg missing"); + } + + // initialise the decoder to give access to image information + int ret = JpegDec.decodeFile("/tmp.jpeg"); + Serial.print("decodeFile ret = "); + Serial.println(ret); + + // print information about the image to the serial port + jpegInfo(); + + // render the image onto the screen at coordinate 0,0 + renderJPEG(0, 0); + + /* uint16_t w = 0, h = 0; TJpgDec.getFsJpgSize(&w, &h, "/tmp.jpeg"); Serial.print("Image size: "); @@ -65,44 +204,10 @@ void jpegFlushFramebuffer() Serial.print("x"); Serial.println(h); TJpgDec.drawFsJpg(0, 0, "/tmp.jpeg"); + */ } } -void draw_XXX(uint32_t x, uint32_t y, uint8_t color) -{ - //uint8_t r = ((color >> 11) & 0x1F); - //uint8_t g = ((color >> 5) & 0x3F); - //uint8_t b = (color & 0x1F); - /* - uint8_t r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6; - uint8_t g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6; - uint8_t b = (((color & 0x1F) * 527) + 23) >> 6; - */ - uint32_t blue = color & 0x001F; // 5 bits blue - uint32_t green = color & 0x07E0; // 6 bits green - uint32_t red = color & 0xF800; // 5 bits red - - int16_t gray = round(red * 0.3 + green * 0.59 + blue * 0.11); - int16_t blackOrWhite; - - // Add errors to color if there are - if (ImageProcess.dithering) - { - gray += curRowDeltaJ[x]; - } - - if (gray <= 127) - { - blackOrWhite = 0; - } - else - { - blackOrWhite = 255; - } - - displayWritePixel(ImageProcess.x + x, ImageProcess.y + y, blackOrWhite); -} - void on_drawPixel(uint32_t x, uint32_t y, uint32_t color) { pixelCount++; @@ -124,7 +229,6 @@ void on_drawPixel(uint32_t x, uint32_t y, uint32_t color) uint32_t originX = _x; uint32_t originY = originOffsetY + _y + (blockPageY * 16); uint8_t originColor = blockDelta[(_y * MAX_WIDTH) + _x]; - //draw_XXX(originX, originY, originColor); uint8_t blue = originColor & 0x001F; // 5 bits blue uint8_t green = originColor & 0x07E0; // 6 bits green @@ -192,31 +296,19 @@ bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) return 0; } - // This might work instead if you adapt the sketch to use the Adafruit_GFX library - display.drawRGBBitmap(x, y, bitmap, w, h); - int16_t _y = y; for (int16_t j = 0; j < h; j++, _y++) { for (int16_t i = 0; i < w; i++) { - // geht richtig - //display.writePixel(x + i, y, bitmap[j * w + i]); - - if (_y == 0 && x + i <= 70) + // debug + if (_y == 10 && x + i >= 200 && x + i <= 250) { uint32_t originColor = bitmap[j * w + i]; - uint8_t blue = originColor & 0x001F; // 5 bits blue - uint8_t green = originColor & 0x07E0; // 6 bits green - uint8_t red = originColor & 0xF800; // 5 bits red - - //uint8_t r = ((((originColor >> 11) & 0x1F) * 527) + 23) >> 6; - //uint8_t g = ((((originColor >> 5) & 0x3F) * 259) + 33) >> 6; - //uint8_t b = (((originColor & 0x1F) * 527) + 23) >> 6; - uint8_t r = red; - uint8_t g = green; - uint8_t b = blue; + uint8_t b = originColor & 0x001F; // 5 bits blue + uint8_t g = originColor & 0x07E0; // 6 bits green + uint8_t r = originColor & 0xF800; // 5 bits red Serial.print("Pixel @ y: "); Serial.print(_y);