Xinyuan-LilyGO / LilyGo-EPD47

GNU General Public License v3.0
379 stars 119 forks source link

Image type? #23

Closed G6EJD closed 3 years ago

G6EJD commented 3 years ago

I'm beginning to make good progress now with the display, but can someone help me with the display image type?

Do we convert BMP or JPG or What and the format needed? especially if colour information is required for the 16-grey levels.

kd8bxp commented 3 years ago

I've been using GIMP, resizing the image if needed, rotating if needed, I've converted and not-converted images to grayscale (doesn't appear to matter). Export as a JPG. Then I have used the imageconvert.py script I think the script is a bit picky on the file name jpg not jpeg that sort of thing. But it works good as far as I can tell. remember if you rotate the image, the screen is still in landscape, so 0,0 is still the top left corner.

A few images I've had to play with the aspect ratio a bit to get it too look right, I've found larger images seem to scale a bit better, that maybe just me. Images are one thing I have been able to get to work fairly well on this device.

martinberlin commented 3 years ago

GxEPD library also has examples to load a BMP image from SPIFFs and so on. Maybe it can be a good start to implement something custom. I’m handling this epaper also based on EPDiy but with ESP-IDF framework if someone feels like trying to compile something different: https://github.com/martinberlin/cale-idf/wiki/Model-parallel-ED047TC1.h also touch is supported injecting it into the class (and documented in the wiki)

lbonherbe commented 3 years ago

Hello all! I am struggling like hell to do something rather simple : download a BMP file (24 bits RGB one) fro a website and transform it to half-byte 16 scale of grey one and display it. I manage to do the download but not the display. Would anybody kindly point me in the right direction? This would be a nice demo BTW...

G6EJD commented 3 years ago

I’ve done a sort of tutorial here: https://github.com/G6EJD/LilyGo-EPD-4-7-OWM-Weather-Display

You don’t need to convert your image leave it as is and imageconvert will do the rest. You will need to be conscious of image pixel x pixel size as it all gets converted to a binary for inclusion, so can get big. Contact me if you have problems.

lbonherbe commented 3 years ago

Yes, thanks a lot for doing this I have seen it and I am currently trying to "replicate" the same. My challenge is the following : I have a graph somewhere on a website on whichever format - BMP is probably the easiest. It changes every X mins. I want to dynamically download the file, convert it to the right format on the EPD itself (because I see no other way?) and then display it. Then let the EPD sleep for X mins, and then do it all again...

G6EJD commented 3 years ago

Ok understand, so you can create the graph save it to bmp , then FTP it over to the ESP32 for display, in which case it would be better to display an image file rather than embed the image into the programme. Plus your other problem is when the ESP32 wakes how will it know to get a new image, so it has to pull the image from the website that’s the only way that’s going to work. you can use the espasychronous web server to get the image then save it for display, all viable but complex to bring it all together.

martinberlin commented 3 years ago

Here in my epaper component Cale-idf I have a grayscale example: https://github.com/martinberlin/cale-idf/tree/master/main However it was done for an epaper that supported only 4 grayscales. But the method to do it is there. This is an ESP-IDF component (Not arduino ESP32 but is also done in C++) I wrapped the EPDiy in my class and I documented as best I could here: https://github.com/martinberlin/cale-idf/wiki/Model-parallel-ED047TC1.h

This cale-grayscale what it does is to connect to WiFi and then it streams the BMP into the epaper buffer. Also does not download all the bitmap first, it kind of pushes it first to Adafruit GFX (16 bits per pixel) and then to the eink using EPDiy.

lbonherbe commented 3 years ago

Thank you all for pointing me to the right direction! I am starting to understand the right way of doing what I need to do... What I will do is the following:

  1. I have a linux server somewhere that is generating the BMP images I want to display. I will use it to transform those images into 16 level of gray files the same way the python script G6EJD mentioned. I add the width and height of the image as header and it's good to go.
  2. On the EPD side I can now download this file as it is ready and display it - and now comes the difficult part. I tried so far to do it by creating an array of 960/2540 size, just to realize it doesn't work and I run out of memory. So I did the display line by line - read a line of the file, put it in a buffer, display it and so on. It works but is super slow. So I need to understand how to use the framebuffer. I guess the examples from martinberlin will help, I am declaring the framebuffer like in the demo here, but can I handle it like an array then? Basically something like framebuffer[row column / 2] = a byte from my created file?

Thanks again for the support and feedback so far!

martinberlin commented 3 years ago

About 2: If you run out of memory then declare this array in the PSRAM. Check how buffers are declared in my header class for another 12.48 epaper (this also would be out of memory) https://github.com/martinberlin/cale-idf/blob/master/components/CalEPD/include/wave12i48BR.h#L56

You need to get ready to work with pointers but is almost the same as working with arrays. I think you would like to test Cale-IDF since the things you want to achieve are working already with tested examples.

lbonherbe commented 3 years ago

Thanks Martin I think I will indeed try your Cale-IDF.

In the meantime I am trying to make this work but using arrays of pointers is clearly above my feable C knowledges. This is what I am doing :

uint8_t framebuffer = (uint8_t )heap_caps_malloc(EPD_WIDTH EPD_HEIGHT / 2, MALLOC_CAP_SPIRAM); if (!framebuffer) Serial.println("Memory alloc failed!"); memset(framebuffer, 0xFF, EPD_WIDTH EPD_HEIGHT / 2);

(to get the framebuffer initialized)

And then this is my routine to read my file - the reading part works but the code fails because of kernel panic - I guess my usage of pointers is wrong:

uint32_t width = read32(client); uint32_t height = read32(client); int idx = 0; Serial.print("Width : "); Serial.print(width) ; Serial.print("Height : ");Serial.print(height); for (uint16_t row = 0; row < height; row++) // for each line { idx=0; for (uint16_t col = 0; col < width/2; col++) // for each pixel { delay(1); framebuffer[idx] = client.read(); idx++;
} //delay(100); } Rect_t area = {.x = 0,.y = 0, .width = width,.height = height}; Serial.print("we received everything, doing a clear and draw now"); epd_clear(); epd_draw_grayscale_image(area, (uint8_t *) framebuffer); Serial.print("OK drawn now we power off"); epd_poweroff();

What do I do wrong?

martinberlin commented 3 years ago

It’s very hard to see what it can be wrong like this without having your same settings / program where you read the image bytes. But have you understood 100% how does the frame buffer work in this display? buffer eld047 At first sight idx reset to 0 in each X line is wrong, why will you reset an index in every Line? Also order of the loop seems wrong. First do the Y (height) and then inside do the X (width) unless you are using the Epaper in a default position I’m not aware of. Like I mentioned, try already working examples, research them and get a more clear idea of what to do. Both EPDiy and Cale-IDF are repositories where you can get more insights into the right way to do it.

lbonherbe commented 3 years ago

Thanks you I finally managed to get it right thanks to your advices... I also struggled with the wifi client not being ready and some tearing appeared because of this but solved it by testing the availability of bytes at the client level. This is the final (correct) version of the reading loop FYI:

for (uint16_t row = 0; row < height; row++) // for each line { for (uint16_t col = 0; col < width/2; col++) // for each pixel { if (client.available()) { framebuffer[idx] = client.read(); idx++; }
} } Rect_t area = {.x = 0,.y = 0, .width = width,.height = height}; Serial.print("we received everything, doing a clear and draw now"); epd_clear(); epd_draw_grayscale_image(area, (uint8_t *) framebuffer);

martinberlin commented 3 years ago

Great that I could help! Hey @BatsIhor or any other person responsible for this Repository, can we close tickets that are resolved? Thanks in advance