bitbank2 / JPEGDEC

An optimized JPEG decoder for Arduino
Apache License 2.0
365 stars 47 forks source link

RED tint on image files on Arduino GIGA and I believe Teensy boards as well #70

Open KurtE opened 5 months ago

KurtE commented 5 months ago

I am currently running on Version 1.4.1 - I tried to sync up and build with your current sources. (last change) Fix 64 bit support - and I am getting compiler errors.

All of the JPEG files are now seeing a RED tint, like: image

Others are seeing it as well up on Arduino forum: https://forum.arduino.cc/t/display-jpg-from-a-sd-card/1204519/26

Not sure if this helps, but this sketch is setup to run on Arduino GIGA with the GIGA shield. (I was seeing it as well when displaying on ILI9341).

tft_picture_view_sd_giga_shield-240203a.zip

PNG files with your decoder appear OK, also BMP files that I load directly also look fine. image

Small-Drake


2401C188 Loading JPG image 'Small-Drake.jpg' 54453
Image size: 400x320Scale: 1/1 Image Offsets (200, 80)
!!File:Small-Drake.jpg Time:332 writeRect calls:0

This one was loaded from SD Card, can also load them from USB memory stick (which is slower) on GIGA.

Let me know if you need any additional information

KurtE commented 5 months ago

Quick update, I just synced the sources again as I see a couple of commits... Still does not build:

"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\7-2017q4/bin/arm-none-eabi-g++" -c -x assembler-with-cpp -mcpu=cortex-m7 -mfpu=fpv5-d16 -DARDUINO=10607 -DARDUINO_GIGA -DARDUINO_ARCH_MBED_GIGA -DARDUINO_ARCH_MBED "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\cores\\arduino" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\variants\\GIGA" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\Arduino_USBHostMbed5\\src" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\libraries\\SPI" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\SdFat_real\\src" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\elapsedMillis" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\GIGA_digitalWriteFast" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\JPEGDEC\\src" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\PNGdec\\src" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\Arduino_GigaDisplay_GFX\\src" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\libraries\\Arduino_H7_Video\\src" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\Adafruit_GFX_Library" "-Ic:\\Users\\kurte\\Documents\\Arduino\\libraries\\Adafruit_BusIO" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\libraries\\Wire" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\libraries\\Portenta_SDRAM\\src" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\libraries\\ea_malloc" -DCM4_BINARY_START=0x60000000 -DCM4_BINARY_END=0x60040000 -DCM4_RAM_END=0x60080000 "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\cores\\arduino/api/deprecated" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\cores\\arduino/api/deprecated-avr-comp" "-iprefixC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\cores\\arduino" "@C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\mbed_giga\\4.0.10\\variants\\GIGA/../GIGA/includes.txt" "c:\\Users\\kurte\\Documents\\Arduino\\libraries\\JPEGDEC\\src\\s3_simd_dequant.S" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino\\sketches\\1B3D878E0D4E79C3B2F3E4B9EAB8241D\\libraries\\JPEGDEC\\s3_simd_dequant.S.o"
In file included from c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\JPEGDEC.cpp:32:0:
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl: In function 'int JPEGMakeHuffTables(JPEGIMAGE*, int)':
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl:1116:37: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
             if (iTable * HUFF11SIZE >= sizeof(pJPEG->usHuffAC) / 2)
                 ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl: In function 'void JPEGIDCT(JPEGIMAGE*, int, int)':
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl:2204:17: error: 'ucMaxACCol' was not declared in this scope
     ucColMask = ucMaxACCol | 1; // column 0 must always be calculated
                 ^~~~~~~~~~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl:2210:19: error: 'ucMaxACRow' was not declared in this scope
             if (!(ucMaxACRow & (1<<iCol))) // simpler calculations if only half populated
                   ^~~~~~~~~~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl: In function 'void JPEGPixelLE(uint16_t*, int, int, int)':
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl:2703:40: warning: left shift of negative value [-Wshift-negative-value]
     uint32_t ulTmp = -1409 | (-2925 << 16); // for green calc
                                        ^~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl: In function 'void JPEGPixel2LE(uint16_t*, int, int, int, int)':
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\jpeg.inl:2779:48: warning: left shift of negative value [-Wshift-negative-value]
     uint32_t ulTmp2, ulTmp = -1409 | (-2925 << 16); // for green calc
                                                ^~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\JPEGDEC.cpp: In member function 'void JPEGDEC::setFramebuffer(void*)':
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\JPEGDEC.cpp:36:5: error: 'JPEG_setFramebuffer' was not declared in this scope
     JPEG_setFramebuffer(&_jpeg, pFramebuffer);
     ^~~~~~~~~~~~~~~~~~~
c:\Users\kurte\Documents\Arduino\libraries\JPEGDEC\src\JPEGDEC.cpp:36:5: note: suggested alternative: 'setFramebuffer'
     JPEG_setFramebuffer(&_jpeg, pFramebuffer);
     ^~~~~~~~~~~~~~~~~~~
     setFramebuffer
Multiple libraries were found for "SdFat.h"
  Used: C:\Users\kurte\Documents\Arduino\libraries\SdFat_real
  Not used: C:\Users\kurte\Documents\Arduino\libraries\SdFat_-_Adafruit_Fork
Using library Arduino_USBHostMbed5 at version 0.3.1 in folder: D:\github\Arduino_USBHostMbed5 

image

bitbank2 commented 5 months ago

What pixel type are you outputting? Can you share the calls you're making to the library? I've been testing on ESP32-S3 hardware, but I can switch back to M7. The latest changes aren't in the release build and are for desktop PC optimizations.

KurtE commented 5 months ago

Again Note: current code does not build on GIGA nor Teensy MicroMod or 3.6

#if !defined (HAS_SSE) && !defined(HAS_NEON)
    // do columns first
    ucColMask = ucMaxACCol | 1; // column 0 must always be calculated
    for (iCol = 0; iCol < 8 && ucColMask; iCol++)
    {
        if (ucColMask & (1<<iCol)) // column has data in it
        {
            ucColMask &= ~(1<<iCol); // unmark this col after use
            if (!(ucMaxACRow & (1<<iCol))) // simpler calculations if only half populated

ucMaxACRow is not defined...

Here is some of the code calling it:

void processJPGFile(WrapperFile &jpgFile, const char *name, bool fErase) {
  int image_size = jpgFile.size();
  jpgFile.seek(0);
  Serial.println();
  Serial.print((uint32_t)&jpgFile, HEX);
  Serial.print(F(" Loading JPG image '"));
  Serial.print(name);
  Serial.print("' ");
  Serial.println(image_size, DEC);
  uint8_t scale = 1;
  if (jpeg.open((void *)&jpgFile, image_size, nullptr, myReadJPG, mySeekJPG, JPEGDraw)) {
    int image_width = jpeg.getWidth();
    int image_height = jpeg.getHeight();
    int decode_options = 0;
    Serial.print("Image size: ");
    Serial.print(image_width);
    Serial.print("x");
    Serial.print(image_height);
    switch (g_JPGScale) {
      case 1:
        scale = 1;
        decode_options = 0;
        break;
      case 2:
        scale = 2;
        decode_options = JPEG_SCALE_HALF;
        break;
      case 4:
        scale = 4;
        decode_options = JPEG_SCALE_QUARTER;
        break;
      case 8:
        scale = 8;
        decode_options = JPEG_SCALE_EIGHTH;
        break;
      default:
        {
          if ((image_width > g_jpg_scale_x_above[SCL_16TH]) || (image_height > g_jpg_scale_y_above[SCL_16TH])) {
            decode_options = JPEG_SCALE_EIGHTH | JPEG_SCALE_HALF;
            scale = 16;
          } else if ((image_width > g_jpg_scale_x_above[SCL_EIGHTH]) || (image_height > g_jpg_scale_y_above[SCL_EIGHTH])) {
            decode_options = JPEG_SCALE_EIGHTH;
            scale = 8;
          } else if ((image_width > g_jpg_scale_x_above[SCL_QUARTER]) || (image_height > g_jpg_scale_y_above[SCL_QUARTER])) {
            decode_options = JPEG_SCALE_QUARTER;
            scale = 4;
          } else if ((image_width > g_jpg_scale_x_above[SCL_HALF]) || (image_height > g_jpg_scale_y_above[SCL_HALF])) {
            decode_options = JPEG_SCALE_HALF;
            scale = 2;
          }
        }
    }
    if (fErase && ((image_width / scale < g_tft_width) || (image_height / scale < g_tft_height))) {
      tft.fillScreen((uint16_t)g_background_color);
    }

    if (g_center_image) {
      g_image_offset_x = (g_tft_width - image_width / scale) / 2;
      g_image_offset_y = (g_tft_height - image_height / scale) / 2;
    } else {
      g_image_offset_x = 0;
      g_image_offset_y = 0;
    }
    g_image_scale = scale;
    Serial.print("Scale: 1/");
    Serial.print(g_image_scale);
    Serial.print(" Image Offsets (");
    Serial.print(g_image_offset_x);
    Serial.print(", ");
    Serial.print(g_image_offset_y), Serial.println(")");

    jpeg.decode(0, 0, decode_options);
    jpeg.close();
  } else {
    Serial.println("Was not a valid jpeg file");
  }
  jpgFile.close();
}

int32_t myReadJPG(JPEGFILE *pjpegfile, uint8_t *buffer, int32_t length) {
  if (!pjpegfile || !pjpegfile->fHandle) return 0;
  return ((WrapperFile *)(pjpegfile->fHandle))->read(buffer, length);
}
int32_t mySeekJPG(JPEGFILE *pjpegfile, int32_t position) {
  if (!pjpegfile || !pjpegfile->fHandle) return 0;
  return ((WrapperFile *)(pjpegfile->fHandle))->seek(position);
}

int JPEGDraw(JPEGDRAW *pDraw) {
  if (g_debug_output) {
    Serial.print("jpeg draw: x,y=");
    Serial.print(pDraw->x);
    Serial.print(",");
    Serial.print(pDraw->y);
    Serial.print(", cx,cy = ");
    Serial.print(pDraw->iWidth);
    Serial.print(",");
    Serial.println(pDraw->iHeight);
  }
  writeClippedRect(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, pDraw->pPixels);
  return 1;
}
#endif
bitbank2 commented 5 months ago

I can reproduce the problem - I'll post a fix shortly.

bitbank2 commented 5 months ago

I pushed a fix which temporarily disables the M4/M7 SIMD code. The problem started when Teensyduino removed the M4 intrinsics. I added my own and perhaps the definitions are not equivalent. I'll continue to investigate.

wdx04 commented 3 weeks ago

Got the same problem on a NUCLEO-F413ZH board. Disabling SIMD fixed the problem, though the decoding time is longer(49630 us to decode a 14K 120x180 image without SIMD, compared to 45340 us when SIMD is used).

bitbank2 commented 3 weeks ago

Are you using the release version or what's on Github at the moment? @wdx04

wdx04 commented 3 weeks ago

Are you using the release version or what's on Github at the moment? @wdx04

I think I'm using the current master branch. I download the code as a zip file earlier this year, the JPEGDEC-master folder inside the zip file was last modified at March 23.

bitbank2 commented 3 weeks ago

Correction - I didn't push the fix yet because I have a bunch of new functionality that I am unsure about giving away for free. I've had second thoughts about everyone using my work and I get nothing in return.

bitbank2 commented 3 weeks ago

I guess I can cherry pick this particular fix, hang on

bitbank2 commented 3 weeks ago

ok, try it now

wdx04 commented 3 weeks ago

ok, try it now

Thank you. There is a compilation error at line 2781, because the 'ulTmp' variable is undefined:

uint32_t ulTmp2 = 0xfa7f /*-1409*/ | 0xf4930000 /*(-2925 << 16)*/; // for green calc     

I tried to fix the error and recompile:

uint32_t ulTmp2, ulTmp = 0xfa7f /*-1409*/ | 0xf4930000 /*(-2925 << 16)*/; // for green calc     

But the decoded images seem to be unaffected by the fix, I still see red images after the fix.

bitbank2 commented 3 weeks ago

ok, thanks for trying. I need to set up a build environment and PCB to test these for all pixel types. I had given up on using CM4 SIMD because it's nearly useless.