bitbank2 / PNGenc

An embedded-friendly PNG encoder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use to dump a screen shot from a display

mjs513 opened this issue · comments

@bitbank2
Good morning
I was playing with this to try and get a screen shot of a ILI9341 display to save as a PNG. But think I need a bit of a better understanding on how the library works.

For instance encodeBegin requires:
int iWidth, int iHeight, uint8_t ucPixelType, uint8_t ucBpp, uint8_t *pPalette, uint8_t ucCompLevel

Width and Height are easy to understand.
ucBpp = bits per pixel, in my case each pixel is 16 bits so, ucBpp = 16?
ucPixelType = PNG_PIXEL_TRUECOLOR ? since I am using a palette or alpha channel ? or should this be something else.
pPalette = NULL, since no palette?
ucCompLevel = NOT SURE WHAT THIS IS or should be set to?

Now the addLine function is defined as a unit8_t so if I am using 16bpp do I have to break the 16bit pixel up into 2 bytes, if so, then is upper byte first and lower byte next?

Any help would be appreciated it.

Thanks
Mike

PS. just thought you might like to know that I did get PNGdec resize to work and we have it working on pretty much all displays including ILI9341, ILI9488, ST7735/ST7789, RA8875 and RA8876's. Even got your animatedGIF library working on the same displays :) Great libraries. We are using the Teensies for this effort not the Arduino so we do have a bit more flexibility is memory usage. So thanks again for your great libraries.

EDIT: Oops just found the wiki. So think I got my answer.
PNG_PIXEL_TRUECOLOR - 24-bpp (8x3) RGB triplets, so have to provide ucLine is rgb values in that order correct

Hi Mike,
I'm glad you find my libraries useful.
The details you're asking about are all explained in the Wiki of this repo.
PNG doesn't support RGB565, so you'll need to convert the pixels into either TRUECOLOR (RGB888) or some other form that's supported. This is why I have a function in my PNG decoder to convert the pixels to RGB565 for LCD displays. I suppose this issue can be resolved by me adding a new function to this library to convert incoming RGB565 pixels for you automatically :)

Found the wiki right after I posted the question :)

Would be nice to have it built into the library to make it easier :)

ok, I'll work on it this week. I'm busy with lots of projects, but it shouldn't take long...

Thanks - haven't had much luck in getting it work for me from within the sketch:

void generatePNG() {
  int rc, iDataSize, x, y;
  uint8_t ucLine[WIDTH*3];
  uint16_t awColors[WIDTH];
  long l;
  uint8_t r, g, b;
  uint8_t offset = 0;

  l = micros();
  rc = png.open("/disptestimg.png", myOpen, myClose, myRead, myWrite, mySeek);

  if (rc == PNG_SUCCESS) {
        rc = png.encodeBegin(WIDTH, HEIGHT, PNG_PIXEL_TRUECOLOR, 24, NULL, 3);
        if (rc == PNG_SUCCESS) {
            for (int y=0; y<HEIGHT && rc == PNG_SUCCESS; y++) {
              tft.readRect(0, y, WIDTH, 1, awColors);
              for(int16_t j = 0; j < WIDTH; j++) {
                tft.color565toRGB(awColors[j], r, g, b);
                Serial.println(b);
                ucLine[j+offset] = r;
                ucLine[j+1+offset] = g;
                ucLine[j+2+offset] = b;
                offset = 3 * j;
              }
              rc = png.addLine(ucLine);
            } // 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!");
  }
}

where

  // color565toRGB		- converts 565 format 16 bit color to RGB
  static void color565toRGB(uint16_t color, uint8_t &r, uint8_t &g,
                            uint8_t &b) {
    r = (color >> 8) & 0x00F8;
    g = (color >> 3) & 0x00FC;
    b = (color << 3) & 0x00F8;
  }

The image is coming out looking like a rainbow of alternating color lines - so any help is appreciated

The bpp value is bits per color stimulus, not total. This should be 8, not 24.

Your calculation of the offset is incorrect; you're overwriting the previous pixels because you're using j + an offset that's calculated too late. Simplify it - for example:

            ucLine[j*3] = r;
            ucLine[j*3+1] = g;
            ucLine[j*3+2] = b;

Thanks for the corrections. Gave it a try but still not quite right.
disptestimg

Basically should be a yellow and blue rectangle in the middle of the screen:

  tft.fillRect(30, 120, 100, 65,ILI9341_YELLOW);
  tft.fillRect(100, 170, 120,60,ILI9341_BLUE);

Getting late so will do some debugging in the morning. Again, thanks for the help

Ok did a bit more debugging of the sketch by dumping some ucLines and based on the scan lines I selected it looks like ucLine is correct.

Does that mean it's working?

Unfortunately no image is still the same as I posted - still getting the same image but wanted to make sure that the sketch was actually reading pixel data correctly and ucLine was getting populated correctly.

ok, I'll create a new demo to show how to use it with RGB565.

Thanks Larry - I can't see why its not working - looks like it should.

I just pushed a change which adds the "addRGB565Line()" function. The Linux command line demo will pass RGB565 pixels and ask it to generate a true color output image if only an output filename is passed on the command line. Please give it a try and see if this solves your issue.

Thanks will give the addRGB565Line function a try in a bit - went to the dentist so a bit under the weather :(

Anyway - you want a good laugh. Was looking at the Linux example for true color and noticed that encodeBegin uses bitsize as 24 not 8 as you mentioned in the previous post:
rc = png.encodeBegin(iWidth, iHeight, PNG_PIXEL_TRUECOLOR, 24, NULL, 9);
so for the heck of it I changed the bpp value from 8 to 24 and guess what it worked.
disptestimg

Now with the addRGB565Line function code is greatly simplified:

void generatePNG() {
  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("/disptestimg.png", 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++) {
              tft.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!");
  }
}

And I get the same image if I do it the long way :)

Thanks for updating the library with the new function, really appreciate it - makes life a lot easier.

If there is anything you want me to try let me know. Going to update my TeensyOpenGL example to use PNGenc as well.

Mike

Thanks for testing it; I did misspeak about the bits per pixel parameter of my function. I'll do a new release now.