Use "middle"-decoder for images

Hi,

I am trying to migrate to recent LittlevGL v6.0 and I am a little bit stucked with the image decoder.

The point is that I modified a bit lvgl v5.3 to let decode icons with RLE encoding while keep taking advantage of lvgl format convetor (more info can be found on this comment).

To summarize the problems (copy/paste from comment link):

"
The point is to use RLE for some images but not for every image. I have 4-bit indexed images and 4-bit alpha images (coded with RLE). The problems I found:

  • When you use custom decoder LittlevGL expect a pointer to a buffer where the data is fully decoded to the final format. So, when decompressing 4-bit alpha images it expects RGB565 instead of a 4-bit alpha bitmap decompresed (buffer increases a lot).

  • For my 4-bit indexed images will have the same problem, I need to decompress them to RGB565.

  • LittlevGL is already in charge of the fully decompression depending on image type.

"

So, is there any way to achieve this with the new update without any need to modify library locally?

Thanks in advance :wink:

Why can’t you decompress them to RGB565 format?

That was about v5.3. And what I basically meant was that I needed to do the decompression on my application, When LittlevGL can already be in charge of that.

The exact question you’re asking is unclear to me. Are you trying to find out the best way to decode your images in v6.0?

I’m sorry I did not explain it the best way I will try to do it again (please review this comment).

What kind of images do I have?

On my project I am working with 2 types of grayscale images:

  • Indexed 4-bit.
  • Alpha 4-bit encoded with RLE.

What was the problem on v5.3?

The problem was basically that if we had a decoder, LittlevGL will always call this decoder and expect the data to be output formatted to your lv_color_t (RGB565 in my case).

So the data flow was this one:

  • LittlevGL point to the image.

  • LittlevGL calls decoder.

  • Decoder should:

    • For alpha 4-bit images: decompress RLE and convert bitmap to lv_color_t
    • For indexed 4-bit images: convert bitmap to lv_color_t

What do I want to achive?

I would like to get rid of the neccessity to convert bitmap to lv_color_t on the decoder, since LittlevGL could be on charge of that. So the data flow could look like this:

  • LittlevGL point to the image.

  • LittlevGL calls decoder.

  • Decoder should:

    • For alpha 4-bit images: decompress RLE
    • For indexed 4-bit images: do nothing
  • LittlevGL decodes image depending on type.

I hope this could clarify things. Don’t hesitate to ask for more information.

It’d be really nice to keep this opportunity.

I can imagine the following solution (not tested just thinking aloud):

  • You can add a new decoder using a custom open, close and info function but the built-in read line function. (the built-in decoders are now static but we can change it)
  • Set a custom color format for your RLE indexed image. E.g #define MY_RLE_INDEXED_CF 20
  • In the open function decompress the image and change the color format dsc->header.cf = LV_IMG_CF_INDEXED_4BIT to allow the built-in read line to deal with it.

Theoretically, it can work but needs to be tried to be sure. :slight_smile:

1 Like

Thank you very much for the tips. I let you know what I finally did and the new problem found.

Changes within LittlevGL

  • Add new options to image color format. Could be something like this:
/*Image color format*/
enum {
    LV_IMG_CF_UNKNOWN = 0,

    LV_IMG_CF_RAW,              /**< Contains the file as it is. Needs custom decoder function*/
    LV_IMG_CF_RAW_ALPHA,        /**< Contains the file as it is. The image has alpha. Needs custom decoder
                                   function*/
    LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needs
                                   custom decoder function*/

    LV_IMG_CF_TRUE_COLOR,              /**< Color format and depth should match with LV_COLOR settings*/
    LV_IMG_CF_TRUE_COLOR_ALPHA,        /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
    LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels
                                          will be transparent*/

    LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (always chroma keyed)*/
    LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (always chroma keyed)*/
    LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (always chroma keyed)*/
    LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (always chroma keyed)*/

    LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/
    LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/
    LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/
    LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/

    LV_IMG_CF_RESERVED_0,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_1,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_2,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_3,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_4,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_5,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_6,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_7,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_8,   /**< Reserved for further use. */
    LV_IMG_CF_RESERVED_9,   /**< Reserved for further use. */

    LV_IMG_CF_USER_ENCODED_0,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_1,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_2,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_3,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_4,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_5,   /**< User holder encoding format. */
    LV_IMG_CF_USER_ENCODED_6,   /**< User holder encoding format. */
};
  • Make decoding built-in functions public:
extern lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);

extern lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);

extern lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);

extern void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);

Initialize new decoder

Initializing function looks like this:

static void APP_LVGL_initDecoder (void)
{
  appLvglCtx.decoder = lv_img_decoder_create();
  lv_img_decoder_set_open_cb(appLvglCtx.decoder, ICON_LVGL_runLength);
  lv_img_decoder_set_info_cb(appLvglCtx.decoder, lv_img_decoder_built_in_info);
  lv_img_decoder_set_read_line_cb(appLvglCtx.decoder, lv_img_decoder_built_in_read_line);
  lv_img_decoder_set_close_cb(appLvglCtx.decoder, lv_img_decoder_built_in_close);
}

Decoder open function

The starting part of the decoding function looks like this:


lv_res_t ICON_LVGL_runLength (lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 
{

  (void) decoder;

  lv_img_dsc_t* pImg = (lv_img_dsc_t*)dsc->src;

  /* RLE is only applied to user_encoded_0 images.
   *
   * Once RLE is applied, LittlevGL should treat image as alpha_4bit
   */
  if (pImg->header.cf == LV_IMG_CF_USER_ENCODED_0) {
    dsc->header.cf = LV_IMG_CF_ALPHA_4BIT;
  } else {
    return LV_RES_OK;
  }

/**************************************/
/* Make de-compression for RLE icons. */
/**************************************/
  
...

...
};

Is it working?

Yes and not!

Now the icons are painted as they should (application applies RLE, and lvgl applies 4-bit-alpha), which is great! The problem now comes for those 4-bit-indexed images. Before this change they were painted good.

Any idea or improvement to this method?

Could you send a PR on GitHub with some example images? This way I also could test it.

Done here. If you need more info, just let me know.

Thanks in advance :wink:

Thank you! Let’s continue there!