JPEGDEC icon indicating copy to clipboard operation
JPEGDEC copied to clipboard

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

Open KurtE opened this issue 6 months ago • 13 comments

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 avatar Feb 03 '24 20:02 KurtE

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

KurtE avatar Feb 03 '24 20:02 KurtE

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.

bitbank2 avatar Feb 03 '24 22:02 bitbank2

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

KurtE avatar Feb 03 '24 22:02 KurtE

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

bitbank2 avatar Feb 03 '24 22:02 bitbank2

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.

bitbank2 avatar Feb 04 '24 00:02 bitbank2