How to Scale/Rotate image from flash memory?

Hi :grinning:

I store the image resources in SPI FLASH, and then I want to achieve image scaling and rotation.
From the source code, I can do this in the form of a code file(e.g. test_img.c),
and IMG_SRC_TYPE is LV_IMG_SRC_VARIABLE.

So I wonder if there is a better way to achieve this?

Thanks in advance!

Best regards.

If you are using C files created using the image converter, and your SPI flash is directly addressable, I suggest modifying this line and adding a section attribute to place the bitmap data into SPI flash. This is the easiest solution but it only works if SPI flash can be addressed the same way as normal flash/RAM.

If flash is not directly addressable, you would have to:

  1. Manually store the bitmap data in SPI flash using whatever tool you have available.
  2. When you want to display an image, read the bitmap data from SPI flash into RAM.
  3. Fabricate this structure and set the data member to point to wherever the bitmap data is in RAM.

Thanks for your reply. I know how to read data directly from FLASH to RAM, but many pictures are larger in size and there is no larger RAM space to store the complete picture content, so I wonder if it can be processed in parts.

As far as I know, built-in images have to be read in their entirety into some type of addressable memory before it can be drawn.

I’m thinking about it some more. I don’t think anyone has ever tried this before, but you should be able to (ab)use the image decoder interface to force LittlevGL to read line by line from the image. https://docs.littlevgl.com/en/html/overview/image.html#_CPPv428lv_img_decoder_read_line_f_t

The image decoder is designed to handle external image formats like PNG or JPEG, but it should also work with a built-in image. As you can see in the source code, it will only allocate a line-sized buffer in RAM when drawing in line-by-line mode.

There will definitely be a performance penalty to doing it this way because the image can only be flushed one line at a time, but it should cost you less RAM.

Unfortunately, zoom and rotate requires the whole image. The reason: imagine that lvgl draws x=10, y=20 pixel of the image. The image is rotated and zoom, so for (10;20) e.g. (87,33) should be drawn. But if only y = 20 line is available lvgl can’t get (87, 33).

A corner case is when rotate = 90° so the line becomes columns. When lvgl draws the pixels of a line (x, x+1, x+2, …) different lines will be required for each pixel (y, y+1, y+2).

Thansk for your reply.
I know that we can use lv_img_decoder_read_line to get the graphic content of SPI FLASH, but this method cannot be directly applied to image scaling and rotation.

Yes, I think so too, I’m seeing if there is a better way to deal with this, or can do this, read a part from SPI FLASH into RAM, and then do the calculation processing.

The problem is that is that it works the opposite way: NOT read a (random) part, transform it and draw it where required, but to draw an area, get the required image, transform it, and draw it to the current area to draw.

To make it possible a 3rd option should be added here:

Besides native (RGB) and fully buffered non-native images, there could be an option to get the required pixels on demand. However, I’m afraid it’d be very slow especially for large images.

Thank you very much for your explanation, I understand this more.

For rorating the image using point-by-point reading(from SPI FLASH), we can imagine that it’d very slow, this method is not used in general.

Because rotating an image requires processing pixels with random coords, so this is not conducive to process in parts.

For scaling the image, I think the image content can to be loaded relatively easy, and this is conducive to process in parts.

That’s my point. I also look forward to your point. :grinning:

Hmm, it would be really much easier for scaling because rows remain rows.
So someone needs to immerse in how/where to tell which rows to get for the scaled image.
It should be somewhere here:

If you are interested in dealing with it, please open an issue in GitHub to discuss it in more detail.

I think we can try this method and it should work.

1 Like