acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
image.md (16740B)
1 ```eval_rst 2 .. include:: /header.rst 3 :github_url: |github_link_base|/overview/image.md 4 ``` 5 # Images 6 7 An image can be a file or a variable which stores the bitmap itself and some metadata. 8 9 ## Store images 10 You can store images in two places 11 - as a variable in internal memory (RAM or ROM) 12 - as a file 13 14 ### Variables 15 Images stored internally in a variable are composed mainly of an `lv_img_dsc_t` structure with the following fields: 16 - **header** 17 - *cf* Color format. See [below](#color-format) 18 - *w* width in pixels (<= 2048) 19 - *h* height in pixels (<= 2048) 20 - *always zero* 3 bits which need to be always zero 21 - *reserved* reserved for future use 22 - **data** pointer to an array where the image itself is stored 23 - **data_size** length of `data` in bytes 24 25 These are usually stored within a project as C files. They are linked into the resulting executable like any other constant data. 26 27 ### Files 28 To deal with files you need to add a storage *Drive* to LVGL. In short, a *Drive* is a collection of functions (*open*, *read*, *close*, etc.) registered in LVGL to make file operations. 29 You can add an interface to a standard file system (FAT32 on SD card) or you create your simple file system to read data from an SPI Flash memory. 30 In every case, a *Drive* is just an abstraction to read and/or write data to memory. 31 See the [File system](/overview/file-system) section to learn more. 32 33 Images stored as files are not linked into the resulting executable, and must be read into RAM before being drawn. As a result, they are not as resource-friendly as images linked at compile time. However, they are easier to replace without needing to rebuild the main program. 34 35 ## Color formats 36 Various built-in color formats are supported: 37 - **LV_IMG_CF_TRUE_COLOR** Simply stores the RGB colors (in whatever color depth LVGL is configured for). 38 - **LV_IMG_CF_TRUE_COLOR_ALPHA** Like `LV_IMG_CF_TRUE_COLOR` but it also adds an alpha (transparency) byte for every pixel. 39 - **LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED** Like `LV_IMG_CF_TRUE_COLOR` but if a pixel has the `LV_COLOR_TRANSP` color (set in *lv_conf.h*) it will be transparent. 40 - **LV_IMG_CF_INDEXED_1/2/4/8BIT** Uses a palette with 2, 4, 16 or 256 colors and stores each pixel in 1, 2, 4 or 8 bits. 41 - **LV_IMG_CF_ALPHA_1/2/4/8BIT** **Only stores the Alpha value with 1, 2, 4 or 8 bits.** The pixels take the color of `style.img_recolor` and the set opacity. The source image has to be an alpha channel. This is ideal for bitmaps similar to fonts where the whole image is one color that can be altered. 42 43 The bytes of `LV_IMG_CF_TRUE_COLOR` images are stored in the following order. 44 45 For 32-bit color depth: 46 - Byte 0: Blue 47 - Byte 1: Green 48 - Byte 2: Red 49 - Byte 3: Alpha 50 51 For 16-bit color depth: 52 - Byte 0: Green 3 lower bit, Blue 5 bit 53 - Byte 1: Red 5 bit, Green 3 higher bit 54 - Byte 2: Alpha byte (only with LV_IMG_CF_TRUE_COLOR_ALPHA) 55 56 For 8-bit color depth: 57 - Byte 0: Red 3 bit, Green 3 bit, Blue 2 bit 58 - Byte 2: Alpha byte (only with LV_IMG_CF_TRUE_COLOR_ALPHA) 59 60 61 You can store images in a *Raw* format to indicate that it's not encoded with one of the built-in color formats and an external [Image decoder](#image-decoder) needs to be used to decode the image. 62 - **LV_IMG_CF_RAW** Indicates a basic raw image (e.g. a PNG or JPG image). 63 - **LV_IMG_CF_RAW_ALPHA** Indicates that an image has alpha and an alpha byte is added for every pixel. 64 - **LV_IMG_CF_RAW_CHROMA_KEYED** Indicates that an image is chroma-keyed as described in `LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED` above. 65 66 67 ## Add and use images 68 69 You can add images to LVGL in two ways: 70 - using the online converter 71 - manually create images 72 73 ### Online converter 74 The online Image converter is available here: https://lvgl.io/tools/imageconverter 75 76 Adding an image to LVGL via the online converter is easy. 77 78 1. You need to select a *BMP*, *PNG* or *JPG* image first. 79 2. Give the image a name that will be used within LVGL. 80 3. Select the [Color format](#color-formats). 81 4. Select the type of image you want. Choosing a binary will generate a `.bin` file that must be stored separately and read using the [file support](#files). Choosing a variable will generate a standard C file that can be linked into your project. 82 5. Hit the *Convert* button. Once the conversion is finished, your browser will automatically download the resulting file. 83 84 In the generated C arrays (variables), bitmaps for all the color depths (1, 8, 16 or 32) are included in the C file, but only the color depth that matches `LV_COLOR_DEPTH` in *lv_conf.h* will actually be linked into the resulting executable. 85 86 In the case of binary files, you need to specify the color format you want: 87 - RGB332 for 8-bit color depth 88 - RGB565 for 16-bit color depth 89 - RGB565 Swap for 16-bit color depth (two bytes are swapped) 90 - RGB888 for 32-bit color depth 91 92 ### Manually create an image 93 If you are generating an image at run-time, you can craft an image variable to display it using LVGL. For example: 94 95 ```c 96 uint8_t my_img_data[] = {0x00, 0x01, 0x02, ...}; 97 98 static lv_img_dsc_t my_img_dsc = { 99 .header.always_zero = 0, 100 .header.w = 80, 101 .header.h = 60, 102 .data_size = 80 * 60 * LV_COLOR_DEPTH / 8, 103 .header.cf = LV_IMG_CF_TRUE_COLOR, /*Set the color format*/ 104 .data = my_img_data, 105 }; 106 107 ``` 108 109 If the color format is `LV_IMG_CF_TRUE_COLOR_ALPHA` you can set `data_size` like `80 * 60 * LV_IMG_PX_SIZE_ALPHA_BYTE`. 110 111 Another (possibly simpler) option to create and display an image at run-time is to use the [Canvas](/widgets/core/canvas) object. 112 113 ### Use images 114 115 The simplest way to use an image in LVGL is to display it with an [lv_img](/widgets/core/img) object: 116 117 ```c 118 lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL); 119 120 /*From variable*/ 121 lv_img_set_src(icon, &my_icon_dsc); 122 123 /*From file*/ 124 lv_img_set_src(icon, "S:my_icon.bin"); 125 ``` 126 127 If the image was converted with the online converter, you should use `LV_IMG_DECLARE(my_icon_dsc)` to declare the image in the file where you want to use it. 128 129 130 ## Image decoder 131 As you can see in the [Color formats](#color-formats) section, LVGL supports several built-in image formats. In many cases, these will be all you need. LVGL doesn't directly support, however, generic image formats like PNG or JPG. 132 133 To handle non-built-in image formats, you need to use external libraries and attach them to LVGL via the *Image decoder* interface. 134 135 An image decoder consists of 4 callbacks: 136 - **info** get some basic info about the image (width, height and color format). 137 - **open** open an image: either store a decoded image or set it to `NULL` to indicate the image can be read line-by-line. 138 - **read** if *open* didn't fully open an image this function should give some decoded data (max 1 line) from a given position. 139 - **close** close an opened image, free the allocated resources. 140 141 You can add any number of image decoders. When an image needs to be drawn, the library will try all the registered image decoders until it finds one which can open the image, i.e. one which knows that format. 142 143 The `LV_IMG_CF_TRUE_COLOR_...`, `LV_IMG_INDEXED_...` and `LV_IMG_ALPHA_...` formats (essentially, all non-`RAW` formats) are understood by the built-in decoder. 144 145 ### Custom image formats 146 147 The easiest way to create a custom image is to use the online image converter and select `Raw`, `Raw with alpha` or `Raw with chroma-keyed` format. It will just take every byte of the binary file you uploaded and write it as an image "bitmap". You then need to attach an image decoder that will parse that bitmap and generate the real, renderable bitmap. 148 149 `header.cf` will be `LV_IMG_CF_RAW`, `LV_IMG_CF_RAW_ALPHA` or `LV_IMG_CF_RAW_CHROMA_KEYED` accordingly. You should choose the correct format according to your needs: a fully opaque image, using an alpha channel or using a chroma key. 150 151 After decoding, the *raw* formats are considered *True color* by the library. In other words, the image decoder must decode the *Raw* images to *True color* according to the format described in the [Color formats](#color-formats) section. 152 153 If you want to create a custom image, you should use `LV_IMG_CF_USER_ENCODED_0..7` color formats. However, the library can draw images only in *True color* format (or *Raw* but ultimately it will be in *True color* format). 154 The `LV_IMG_CF_USER_ENCODED_...` formats are not known by the library and therefore they should be decoded to one of the known formats from the [Color formats](#color-formats) section. 155 It's possible to decode an image to a non-true color format first (for example: `LV_IMG_INDEXED_4BITS`) and then call the built-in decoder functions to convert it to *True color*. 156 157 With *User encoded* formats, the color format in the open function (`dsc->header.cf`) should be changed according to the new format. 158 159 160 ### Register an image decoder 161 162 Here's an example of getting LVGL to work with PNG images. 163 164 First, you need to create a new image decoder and set some functions to open/close the PNG files. It should look like this: 165 166 ```c 167 /*Create a new decoder and register functions */ 168 lv_img_decoder_t * dec = lv_img_decoder_create(); 169 lv_img_decoder_set_info_cb(dec, decoder_info); 170 lv_img_decoder_set_open_cb(dec, decoder_open); 171 lv_img_decoder_set_close_cb(dec, decoder_close); 172 173 174 /** 175 * Get info about a PNG image 176 * @param decoder pointer to the decoder where this function belongs 177 * @param src can be file name or pointer to a C array 178 * @param header store the info here 179 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 180 */ 181 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header) 182 { 183 /*Check whether the type `src` is known by the decoder*/ 184 if(is_png(src) == false) return LV_RES_INV; 185 186 /* Read the PNG header and find `width` and `height` */ 187 ... 188 189 header->cf = LV_IMG_CF_RAW_ALPHA; 190 header->w = width; 191 header->h = height; 192 } 193 194 /** 195 * Open a PNG image and return the decided image 196 * @param decoder pointer to the decoder where this function belongs 197 * @param dsc pointer to a descriptor which describes this decoding session 198 * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 199 */ 200 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 201 { 202 203 /*Check whether the type `src` is known by the decoder*/ 204 if(is_png(src) == false) return LV_RES_INV; 205 206 /*Decode and store the image. If `dsc->img_data` is `NULL`, the `read_line` function will be called to get the image data line-by-line*/ 207 dsc->img_data = my_png_decoder(src); 208 209 /*Change the color format if required. For PNG usually 'Raw' is fine*/ 210 dsc->header.cf = LV_IMG_CF_... 211 212 /*Call a built in decoder function if required. It's not required if`my_png_decoder` opened the image in true color format.*/ 213 lv_res_t res = lv_img_decoder_built_in_open(decoder, dsc); 214 215 return res; 216 } 217 218 /** 219 * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. 220 * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL) 221 * @param decoder pointer to the decoder the function associated with 222 * @param dsc pointer to decoder descriptor 223 * @param x start x coordinate 224 * @param y start y coordinate 225 * @param len number of pixels to decode 226 * @param buf a buffer to store the decoded pixels 227 * @return LV_RES_OK: ok; LV_RES_INV: failed 228 */ 229 lv_res_t decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, 230 lv_coord_t y, lv_coord_t len, uint8_t * buf) 231 { 232 /*With PNG it's usually not required*/ 233 234 /*Copy `len` pixels from `x` and `y` coordinates in True color format to `buf` */ 235 236 } 237 238 /** 239 * Free the allocated resources 240 * @param decoder pointer to the decoder where this function belongs 241 * @param dsc pointer to a descriptor which describes this decoding session 242 */ 243 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 244 { 245 /*Free all allocated data*/ 246 247 /*Call the built-in close function if the built-in open/read_line was used*/ 248 lv_img_decoder_built_in_close(decoder, dsc); 249 250 } 251 252 ``` 253 254 So in summary: 255 - In `decoder_info`, you should collect some basic information about the image and store it in `header`. 256 - In `decoder_open`, you should try to open the image source pointed by `dsc->src`. Its type is already in `dsc->src_type == LV_IMG_SRC_FILE/VARIABLE`. 257 If this format/type is not supported by the decoder, return `LV_RES_INV`. 258 However, if you can open the image, a pointer to the decoded *True color* image should be set in `dsc->img_data`. 259 If the format is known, but you don't want to decode the entire image (e.g. no memory for it), set `dsc->img_data = NULL` and use `read_line` to get the pixel data. 260 - In `decoder_close` you should free all allocated resources. 261 - `decoder_read` is optional. Decoding the whole image requires extra memory and some computational overhead. 262 However, it can decode one line of the image without decoding the whole image, you can save memory and time. 263 To indicate that the *line read* function should be used, set `dsc->img_data = NULL` in the open function. 264 265 266 ### Manually use an image decoder 267 268 LVGL will use registered image decoders automatically if you try and draw a raw image (i.e. using the `lv_img` object) but you can use them manually too. Create an `lv_img_decoder_dsc_t` variable to describe the decoding session and call `lv_img_decoder_open()`. 269 270 The `color` parameter is used only with `LV_IMG_CF_ALPHA_1/2/4/8BIT` images to tell color of the image. 271 `frame_id` can be used if the image to open is an animation. 272 273 274 ```c 275 276 lv_res_t res; 277 lv_img_decoder_dsc_t dsc; 278 res = lv_img_decoder_open(&dsc, &my_img_dsc, color, frame_id); 279 280 if(res == LV_RES_OK) { 281 /*Do something with `dsc->img_data`*/ 282 lv_img_decoder_close(&dsc); 283 } 284 285 ``` 286 287 288 ## Image caching 289 Sometimes it takes a lot of time to open an image. 290 Continuously decoding a PNG image or loading images from a slow external memory would be inefficient and detrimental to the user experience. 291 292 Therefore, LVGL caches a given number of images. Caching means some images will be left open, hence LVGL can quickly access them from `dsc->img_data` instead of needing to decode them again. 293 294 Of course, caching images is resource intensive as it uses more RAM to store the decoded image. LVGL tries to optimize the process as much as possible (see below), but you will still need to evaluate if this would be beneficial for your platform or not. Image caching may not be worth it if you have a deeply embedded target which decodes small images from a relatively fast storage medium. 295 296 ### Cache size 297 The number of cache entries can be defined with `LV_IMG_CACHE_DEF_SIZE` in *lv_conf.h*. The default value is 1 so only the most recently used image will be left open. 298 299 The size of the cache can be changed at run-time with `lv_img_cache_set_size(entry_num)`. 300 301 ### Value of images 302 When you use more images than cache entries, LVGL can't cache all the images. Instead, the library will close one of the cached images to free space. 303 304 To decide which image to close, LVGL uses a measurement it previously made of how long it took to open the image. Cache entries that hold slower-to-open images are considered more valuable and are kept in the cache as long as possible. 305 306 If you want or need to override LVGL's measurement, you can manually set the *time to open* value in the decoder open function in `dsc->time_to_open = time_ms` to give a higher or lower value. (Leave it unchanged to let LVGL control it.) 307 308 Every cache entry has a *"life"* value. Every time an image is opened through the cache, the *life* value of all entries is decreased to make them older. 309 When a cached image is used, its *life* value is increased by the *time to open* value to make it more alive. 310 311 If there is no more space in the cache, the entry with the lowest life value will be closed. 312 313 ### Memory usage 314 Note that a cached image might continuously consume memory. For example, if three PNG images are cached, they will consume memory while they are open. 315 316 Therefore, it's the user's responsibility to be sure there is enough RAM to cache even the largest images at the same time. 317 318 ### Clean the cache 319 Let's say you have loaded a PNG image into a `lv_img_dsc_t my_png` variable and use it in an `lv_img` object. If the image is already cached and you then change the underlying PNG file, you need to notify LVGL to cache the image again. Otherwise, there is no easy way of detecting that the underlying file changed and LVGL will still draw the old image from cache. 320 321 To do this, use `lv_img_cache_invalidate_src(&my_png)`. If `NULL` is passed as a parameter, the whole cache will be cleaned. 322 323 324 ## API 325 326 327 ### Image buffer 328 329 ```eval_rst 330 331 .. doxygenfile:: lv_img_buf.h 332 :project: lvgl 333 334 ```