bitbank2 / PNGenc

An embedded-friendly PNG encoder
Apache License 2.0
39 stars 8 forks source link

From TFT to PNG, incorrect colors? #9

Closed rdlauer closed 1 year ago

rdlauer commented 1 year ago

First of all, this library is amazing. Seriously. However, I'm having one odd issue that I can't seem to fix that follows on this issue https://github.com/bitbank2/PNGenc/issues/4

When I dump a screen from a tft display and save an bmp file to SD, I get the correct colors (on the left below). However, when using the code sample at the bottom of that referenced issue and save the png to SD, I get the colors on the right. Any idea what I might be doing wrong?

image

bitbank2 commented 1 year ago

It's hard to guess what you're doing wrong without seeing a working example.

rdlauer commented 1 year ago

Sorry - code samples are always useful. Basically took the generatePNG method from that other issue and made some minor tweaks:

void generatePNG()
{

  uint16_t WIDTH = 240;
  uint16_t HEIGHT = 184;

  char filename[11] = "image1.png";
  SD.begin(chipSelect);

  while (SD.exists(filename))
  {
    filename[5]++;
  }

  int rc, iDataSize, x, y;
  uint8_t ucLine[WIDTH * 3];
  uint16_t awColors[WIDTH];
  long l;
  uint8_t r, g, b;
  Serial.printf("WIDTH = %d, HEIGHT = %d\n", WIDTH, HEIGHT);
  l = micros();
  rc = png.open(filename, myOpen, myClose, myRead, myWrite, mySeek);
  if (rc == PNG_SUCCESS)
  {
    rc = png.encodeBegin(WIDTH, HEIGHT, PNG_PIXEL_TRUECOLOR, 24, NULL, 9);
    if (rc == PNG_SUCCESS)
    {
      for (uint16_t y = 0; y < HEIGHT && rc == PNG_SUCCESS; y++)
      {
        Display.readRect(0, y, WIDTH, 1, awColors);
        rc = png.addRGB565Line(awColors, ucLine);
        if (rc != PNG_SUCCESS)
          Serial.printf("Faile to write Line %d\n", y);
      } // for y
      iDataSize = png.close();
      l = micros() - l;
      Serial.printf("%d bytes of data written to file in %d us\n", iDataSize, (int)l);
    }
    else
    {
      Serial.println("Failed to begin encoder!");
    }
  }
  else
  {
    Serial.println("Failed to create the file on the SD card!");
  }
}
bitbank2 commented 1 year ago

I believe I've figured out the issue. You're getting data from the LCD as RGB565 (big endian) format, but my library expects little-endian format. This is why the colors are all wrong. Swap the upper/lower byte of each pixel and that should fix it. I suppose I need to add another flag to that function to do it for you, but try pre-fixing the data yourself to confirm that's what is wrong.

rdlauer commented 1 year ago

Yeah that makes sense. Only downside is I'm not sure how to accomplish that with this display in Arduino/C (I'm definitely a C noob). The fact that I have anything in png format is a bonus and if you get to adding that flag to the library it would be great, but I know the OSS life can be a drag and thankless :)

bitbank2 commented 1 year ago

Use the __bswap16() intrinsic. It usually compiles to a single instruction on many CPUs. Like this:

uint16_t lePixel, bePixel;

bePixel = < from the LCD > lePixel = __bswap16(bePixel); give little-endian pixel to my library