Image converter question for RGB888

Important: unclear posts may not receive useful answers.

Before posting

  • Get familiar with Markdown to format and structure your post
  • Be sure to update lvgl from the latest version from the master branch.
  • Read the

Delete this section if you read and applied the mentioned points.


My display controller accepts 8bits each of R, G and B… but the LVGL image converter has only one entry for RGB888 with a 4th byte 0f 0xFF (#if LV_COLOR_DEPTH == 32
/*Pixel format: Blue: 8 bit, Green: 8 bit, Red: 8 bit, Fix 0xFF: 8 bit, */)… Unfortunately my display controller doesn’t deal with this very well and obviously renders some messy stuff…

  1. I am noob and hence might be a stupid question is LV_COLOR_DEPTH of 24 possible at all ? I know it’s not defined anywhere(I only see 1, 8,16 and 32 defined though I noticed lvgl_flush_cb_24bit function).
  2. Is there a way to create an array with just a simple 3 byte RGB instead of 4 bytes ? Or should I write a script to do that ? is there a reason why you only have 32 bit color depth for RGB888 ?

What MCU/Processor/Board and compiler are you using?

Nrf5340 MCU, Custom board, RM69090 Display controller (QSPI), 320%360 AMOLED display. Zephyr RTOS with Nordic NCS (SDK) with built-in gcc tools)
NCS version: 1.5.1
LVGL version: ## v7.6.1 (06.10.2020)
Zephyr RTOS version: 2.4.99

What do you want to achieve?

display a image on my display screen

What have you tried so far?

displayed button and text… so i know basic stuff is up and running

Code to reproduce

Add the relevant code snippets here.

The code block(s) should be between ```c and ``` tags:

/*You code here*/

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.


It’s planned to support RGB888 but it’s really not supported now. We have only ARGB888 because addressing and array of 4 bytes is trivial but with 3 byte elements there can be issues. E.g. lv_color24_t can be 4 bytes on some systems.

What you can do is converting the rendered ARGB8888 image to RGB888 in your flush_cb. You can do the conversation in place, e.g.:

uint8_t * color24 = (uint8_t *) color_p;
uint8_t * color32 = (uint8_t *) color_p;
uint32_t size = lv_area_get_size(area);
for(init i; i < size; i++) {
  color24[0] = color32[0];
  color24[1] = color32[1];
  color24[2] = color32[2];

thanks… tried that… here’s how my cb looks like

void lvgl_flush_cb_24bit(struct _disp_drv_t *disp_drv,
		const lv_area_t *area, lv_color_t *color_p)
#if 1	
	uint8_t * color24 = (uint8_t *) color_p;
	uint8_t * color32 = (uint8_t *) color_p;
	uint32_t size = lv_area_get_size(area);
	printk("\n first converting 32 bit to 24 bit");
	for(int i; i < size; i++) {
	  color24[0] = color32[0];
	  color24[1] = color32[1];
	  color24[2] = color32[2];
	const struct device *display_dev = (const struct device *)disp_drv->user_data;
	uint16_t w = area->x2 - area->x1 + 1;
	uint16_t h = area->y2 - area->y1 + 1;
	struct display_buffer_descriptor desc;

	desc.buf_size = w * 3U * h;
	desc.width = w;
	desc.pitch = w;
	desc.height = h;
	display_write(display_dev, area->x1, area->y1, &desc, (void *) color_p);


That didn’t make too much of difference when it comes to displaying the image… but I can not display a button or text if i use this change (if I remove the change, then button and text rendering works)…

Zephyr has another callback that points to this function… and this one works one way another depending on CONFIG_LVGL_COLOR_DEPTH_32… does tis need to change too ?

void lvgl_set_px_cb_24bit(struct _disp_drv_t *disp_drv,
		uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
		lv_color_t color, lv_opa_t opa)
	uint8_t *buf_xy = buf + x * 3U + y * 3U * buf_w;
	lv_color32_t converted_color;

	if (opa != LV_OPA_COVER) {
		lv_color_t mix_color; = *buf_xy; = *(buf_xy+1); = *(buf_xy+2);
		color = lv_color_mix(color, mix_color, opa);

the actual call back is setup by zephyr as follows: (just code snip)
disp_drv->flush_cb = lvgl_flush_cb_24bit;
disp_drv->rounder_cb = NULL;
disp_drv->set_px_cb = lvgl_set_px_cb_24bit;

If lvgl_set_px_cb_24bit is set then the rendered image is already in RGB888 format. But note that it can be much faster to convert only the result image than every pixel.

I don’t know the details of the Zephyr driver, but if set px callback is set it might assume a disp_draw_buf suitable for 3 byte/px. So if you remove the set px callback be sure to use 4byte/px sized draw buffer.

thanks… looks like copying 32 bit image map to 24 bit is not needed… things seem to work right now and I am able to render images now…
thank you

1 Like