Bodmer / JPEGDecoder

A JPEG decoder library
Other
220 stars 64 forks source link

Bad image #35

Closed HelloDB closed 5 years ago

HelloDB commented 5 years ago

img_20190110_104039 Hi, Any suggestions for this?

[env:esp32dev]
platform = https://github.com/platformio/platform-espressif32.git#feature/stage
board = esp32dev
framework = arduino
upload_speed = 921600
/*-------------------------------------------------------------------------------------------
   examples /MCUFRIEND_kbv/ jpeg_kbv.ino

   https://github.com/Bodmer/JPEGDecoder

-------------------------------------------------------------------------------------------*/
#include "Arduino.h"

// #include <Adafruit_GFX.h>
// #include <Adafruit_ST7735.h> // Hardware-specific library
// #define TFT_CS 5
// #define TFT_DC 4
// #define TFT_RST 15
// Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

#include "Adafruit_ILI9341.h" // Hardware-specific library
#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>
#define TFT_CS 5
#define TFT_DC 4
#define TFT_RST 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

/*-------------------------------------------------------------------------------------------
    xxx

-------------------------------------------------------------------------------------------*/
#include <JPEGDecoder.h>
#define minimum(a, b) (((a) < (b)) ? (a) : (b))

#include "jpeg1.h" // 测试图

void jpegInfo() {
    Serial.println(F("==============="));
    Serial.println(F("JPEG image info"));
    Serial.println(F("==============="));
    Serial.printf("Width      : %d \n", JpegDec.width);
    Serial.printf("Height     : %d \n", JpegDec.height);
    Serial.printf("Components : %d \n", JpegDec.comps);
    Serial.printf("MCU / row  : %d \n", JpegDec.MCUSPerRow);
    Serial.printf("MCU / col  : %d \n", JpegDec.MCUSPerCol);
    Serial.printf("Scan type  : %d \n", JpegDec.scanType);
    Serial.printf("MCU width  : %d \n", JpegDec.MCUWidth);
    Serial.printf("MCU height : %d \n", JpegDec.MCUHeight);
    Serial.println(F("==============="));
}

void jpegRender(int xpos, int ypos) {

    // retrieve infomration about the image
    uint16_t *pImg;
    uint16_t mcu_w = JpegDec.MCUWidth;
    uint16_t mcu_h = JpegDec.MCUHeight;
    uint32_t max_x = JpegDec.width;
    uint32_t max_y = JpegDec.height;

    // Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
    // Typically these MCUs are 16x16 pixel blocks
    // Determine the width and height of the right and bottom edge image blocks
    uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
    uint32_t min_h = minimum(mcu_h, max_y % mcu_h);

    // save the current image block size
    uint32_t win_w = mcu_w;
    uint32_t win_h = mcu_h;

    // record the current time so we can measure how long it takes to draw an image
    uint32_t drawTime = millis();

    // save the coordinate of the right and bottom edges to assist image cropping
    // to the screen size
    max_x += xpos;
    max_y += ypos;

    // read each MCU block until there are no more
    while (JpegDec.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
        uint16_t mcu_pixels = win_w * win_h;

        // draw image MCU block only if it will fit on the screen
        if ((mcu_x + win_w) <= tft.width() && (mcu_y + win_h) <= tft.height()) {
            // if ((mcu_x + win_w) <= 80 && (mcu_y + win_h) <= 80) {
            // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1)
            tft.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);

            // Write all MCU pixels to the TFT window
            while (mcu_pixels--)
                tft.pushColor(*pImg++); // Send MCU buffer to TFT 16 bits at a time
                                        // tft.pushColors(pImg, mcu_pixels, 1);
        }

        // 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) >= tft.height())
            JpegDec.abort();
    }

    // calculate how long it took to draw the image
    drawTime = millis() - drawTime;

    // print the results to the serial port
    Serial.print("Total render time was    : ");
    Serial.print(drawTime);
    Serial.println(" ms");
    Serial.println("=====================================");
}

void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) {
    boolean decoded = JpegDec.decodeArray(arrayname, array_size);
    if (decoded) {
        // print information about the image to the serial port
        jpegInfo();
        // render the image onto the screen at given coordinates
        jpegRender(xpos, ypos);
    } else {
        Serial.println("Jpeg file format not supported!");
    }
}
/*-------------------------------------------------------------------------------------------
    xxx

-------------------------------------------------------------------------------------------*/
void setup() {
    Serial.begin(115200);
    Serial.println("Tansys_>>");

    // tft.initR(INITR_HALLOWING);
    // // tft.setRotation(4);
    // tft.fillScreen(ST77XX_RED);
    // // tft.setCursor(10, 10);

    tft.begin();
    // tft.setRotation(1);
    tft.fillScreen(ILI9341_RED);

    tft.println("TFT_init...");
    tft.printf("TFT_size >> %d * %d", tft.width(), tft.height());
    tft.println("Ready...");

    drawArrayJpeg(Baboon, sizeof(Baboon), 0, 0);
}

void loop() {
    delay(10);
}
Bodmer commented 5 years ago

Hi, I am guessing you have solved the problem since the issue has been closed. I am interested in knowing the solution in case others encounter the same problem.

HelloDB commented 5 years ago

Hi, I am guessing you have solved the problem since the issue has been closed. I am interested in knowing the solution in case others encounter the same problem.

Yes, use tft. drawRGBBitmap () to draw,It works well. Thank you for your Lib

Bodmer commented 5 years ago

Thanks for reporting the solution. I think Adafruit has made changes to their library which has broken compatibility with the decoder examples. I will update the example.

Bodmer commented 5 years ago

Hi,

I have found that Adafruit have changed the input parameters to setAddrWindow() it used to be:

setAddrWindow(x_start, y_start, x_end, y_end); 

If it now:

setAddrWindow(x_start, y_start, width, height); 

You should also use startWrite() and endWrite() to bracket low level writes, the following change will work:

    tft.startWrite(); // <<<<<<<<<<<< New

    // draw image MCU block only if it will fit on the screen
    if ( ( mcu_x + win_w) <= tft.width() && ( mcu_y + win_h) <= tft.height())
    {
      // Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1)
      // tft.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1); // Old line
      tft.setAddrWindow(mcu_x, mcu_y, win_w, win_h);  // <<<<<<<<<<<< new changed line
      // Write all MCU pixels to the TFT window
      while (mcu_pixels--) tft.pushColor(*pImg++);
    }

    else if ( ( mcu_y + win_h) >= tft.height()) JpegDec.abort();

    tft.endWrite();  // <<<<<<<<<<<< New
Bodmer commented 5 years ago

The library has been updated.

Thanks for reporting this.