bitbank2/JPEGDEC

JPEG_DECODE_ERROR on a large epaper screen

Opened this issue · 4 comments

doraemon
IMG_6080 Large
jpegdec_debug.zip
I use JPEGDEC to decode the jpeg file on a large 7 color e-ink screen(800x480), but I cannot show the whole and get a JPEG_DECODE_ERROR.
I try to add some debug code, and find the JPEGDecodeMCU function throw an error in the area of the code below.

 // get the DC component
    pucFast = &pJPEG->ucHuffDC[pJPEG->ucDCTable * DC_TABLE_SIZE];
    ulCode = (ulBits >> (REGISTER_WIDTH - 12 - ulBitOff)) & 0xfff; // get as lower 12 bits
    if (ulCode >= 0xf80) // it's a long code
        ulCode = (ulCode & 0xff); // point to long table and trim to 7-bits + 0x80 offset into long table
    else
        ulCode >>= 6; // it's a short code, use first 6 bits only
    ucHuff = pucFast[ulCode];
    cCoeff = (signed char)pucFast[ulCode+512]; // get pre-calculated extra bits for "small" values
    if (ucHuff == 0) {// invalid code
		Serial.println("invalid code1");//【Where the error occurred】
        return -1;
	}

The same code works well with the 2.9 inch black and white epaper.The difference of the bw and 7 color screen maybe the display buffer(800x480 use more ram).Esp32 and rp2040 get the same result.
I try to use another lib, TJpg_Decoder, which can decode without error on my 7 clolor screen.

I tried to submit the same problem in that issue, and I'm sorry for sending the code so late.

The batman.jpg is also throw the decode error on the 7 clolor screen of gxepd2 driver.

Read the jpg file from the flash or sd card, get the same result.

Here is the code, and the doraemon.h is in the zip file.

#define PIN_EPD_CS 33  ////SPI1 CSn
#define PIN_EPD_RST 26
#define PIN_EPD_DC 27  //SIP1 RX
#define PIN_EPD_BUSY 25
#define PIN_EPD_CLK 13   //SPI1 SCK
#define PIN_EPD_MOSI 14  //SIP1 TX
#define PIN_EPD_EN 32    // epd power control for my esp32s1 board

#include "JPEGDEC.h"
JPEGDEC jpeg;
#include "doraemon.h"

#include <SPI.h>
SPIClass SPIEP(HSPI);
#define SPI_PORT_EPD SPIEP

#include <GxEPD2_BW.h>
#include <GxEPD2_7C.h>
#define GxEPD2_DISPLAY_CLASS GxEPD2_7C
#define GxEPD2_DRIVER_CLASS GxEPD2_730c_ACeP_730

// somehow there should be an easier way to do this
#define GxEPD2_BW_IS_GxEPD2_BW true
#define GxEPD2_3C_IS_GxEPD2_3C true
#define GxEPD2_7C_IS_GxEPD2_7C true
#define GxEPD2_1248_IS_GxEPD2_1248 true
#define GxEPD2_1248c_IS_GxEPD2_1248c true
#define IS_GxEPD(c, x) (c##x)
#define IS_GxEPD2_BW(x) IS_GxEPD(GxEPD2_BW_IS_, x)
#define IS_GxEPD2_3C(x) IS_GxEPD(GxEPD2_3C_IS_, x)
#define IS_GxEPD2_7C(x) IS_GxEPD(GxEPD2_7C_IS_, x)
#define IS_GxEPD2_1248(x) IS_GxEPD(GxEPD2_1248_IS_, x)
#define IS_GxEPD2_1248c(x) IS_GxEPD(GxEPD2_1248c_IS_, x)

#define MAX_DISPLAY_BUFFER_SIZE 65536ul  // e.g. 64k

#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS)
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS)
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8))
#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS)
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2))
#endif

GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS*/ PIN_EPD_CS, /*DC*/ PIN_EPD_DC, /*RST*/ PIN_EPD_RST, /*BUSY*/ PIN_EPD_BUSY));

void convert_rgb_565_to_rgb(uint16_t rgb565, uint16_t *r, uint16_t *g, uint16_t *b) {
  *r = (rgb565 & 0xF800) >> 8;
  *g = (rgb565 & 0x07E0) >> 3;
  *b = (rgb565 & 0x001F) << 3;
}

int JPEGDraw_callback(JPEGDRAW *pDraw);
int JPEGDraw_callback(JPEGDRAW *pDraw) {
yield();
  bool _with_color = true;
  uint16_t red, green, blue;
  bool whitish = false;
  bool colored = false;
  uint16_t color = GxEPD_WHITE;
  int x = pDraw->x;
  int y = pDraw->y;
  int w = pDraw->iWidth;
  int h = pDraw->iHeight;

  for (int16_t i = 0; i < w; i++) {
    for (int16_t j = 0; j < h; j++) {
      convert_rgb_565_to_rgb(pDraw->pPixels[i + j * w], &red, &green, &blue);
      whitish = _with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80);  // whitish
      colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0));
      color = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3);
      if (_with_color) {
        // keep color
      } else if (whitish) {
        color = GxEPD_WHITE;
      } else if (colored && _with_color) {
        color = GxEPD_COLORED;
      } else {
        color = GxEPD_BLACK;
      }
      display.drawPixel((x + i), (y + j) , color);
    }  // for j
  }    // for i
  return 1;
} /* JPEGDraw() */

void setup() {
  Serial.begin(115200);
	
  pinMode(PIN_EPD_EN, OUTPUT);
  digitalWrite(PIN_EPD_EN, HIGH);  // turn on the screen power

  SPI_PORT_EPD.end();  // release standard SPI pins
  SPI_PORT_EPD.begin(PIN_EPD_CLK, PIN_EPD_DC, PIN_EPD_MOSI, PIN_EPD_CS);
  pinMode(PIN_EPD_CS, OUTPUT);

  display.epd2.selectSPI(SPI_PORT_EPD, SPISettings(4000000, MSBFIRST, SPI_MODE0));
  display.init(115200, true, 2, false);
  display.setRotation(0);

  if (jpeg.openFLASH((uint8_t *)doraemon, sizeof(doraemon), JPEGDraw_callback)) {
    display.firstPage();
    do {
      jpeg.decode(0, 0, 0);
    } while (display.nextPage());
  }

} /* setup() */

void loop() {
} /* loop() */