1 /**
2 * @file lv_bmp.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../draw/lv_image_decoder_private.h"
10 #include "../../../lvgl.h"
11 #if LV_USE_BMP
12
13 #include <string.h>
14 #include "../../core/lv_global.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 #define DECODER_NAME "BMP"
21
22 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
23
24 /**********************
25 * TYPEDEFS
26 **********************/
27
28 typedef struct {
29 lv_fs_file_t f;
30 unsigned int px_offset;
31 int px_width;
32 int px_height;
33 unsigned int bpp;
34 int row_size_bytes;
35 } bmp_dsc_t;
36
37 /**********************
38 * STATIC PROTOTYPES
39 **********************/
40 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * src, lv_image_header_t * header);
41 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
42
43 static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
44 const lv_area_t * full_area, lv_area_t * decoded_area);
45
46 static void decoder_close(lv_image_decoder_t * dec, lv_image_decoder_dsc_t * dsc);
47
48 /**********************
49 * STATIC VARIABLES
50 **********************/
51
52 /**********************
53 * MACROS
54 **********************/
55
56 /**********************
57 * GLOBAL FUNCTIONS
58 **********************/
lv_bmp_init(void)59 void lv_bmp_init(void)
60 {
61 lv_image_decoder_t * dec = lv_image_decoder_create();
62 lv_image_decoder_set_info_cb(dec, decoder_info);
63 lv_image_decoder_set_open_cb(dec, decoder_open);
64 lv_image_decoder_set_get_area_cb(dec, decoder_get_area);
65 lv_image_decoder_set_close_cb(dec, decoder_close);
66
67 dec->name = DECODER_NAME;
68 }
69
lv_bmp_deinit(void)70 void lv_bmp_deinit(void)
71 {
72 lv_image_decoder_t * dec = NULL;
73 while((dec = lv_image_decoder_get_next(dec)) != NULL) {
74 if(dec->info_cb == decoder_info) {
75 lv_image_decoder_delete(dec);
76 break;
77 }
78 }
79 }
80
81 /**********************
82 * STATIC FUNCTIONS
83 **********************/
84
85 /**
86 * Get info about a BMP image
87 * @param dsc image descriptor containing the source and type of the image and other info.
88 * @param header store the info here
89 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't get the info
90 */
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)91 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
92 {
93 LV_UNUSED(decoder);
94
95 const void * src = dsc->src;
96 lv_image_src_t src_type = dsc->src_type; /*Get the source type*/
97
98 /*If it's a BMP file...*/
99 if(src_type == LV_IMAGE_SRC_FILE) {
100 const char * fn = src;
101 if(lv_strcmp(lv_fs_get_ext(fn), "bmp") == 0) { /*Check the extension*/
102 /*Save the data in the header*/
103 uint8_t headers[54];
104
105 lv_fs_read(&dsc->file, headers, 54, NULL);
106 uint32_t w;
107 uint32_t h;
108 lv_memcpy(&w, headers + 18, 4);
109 lv_memcpy(&h, headers + 22, 4);
110 header->w = w;
111 header->h = h;
112
113 uint16_t bpp;
114 lv_memcpy(&bpp, headers + 28, 2);
115 switch(bpp) {
116 case 16:
117 header->cf = LV_COLOR_FORMAT_RGB565;
118 break;
119 case 24:
120 header->cf = LV_COLOR_FORMAT_RGB888;
121 break;
122 case 32:
123 header->cf = LV_COLOR_FORMAT_ARGB8888;
124 break;
125 default:
126 LV_LOG_WARN("Not supported bpp: %d", bpp);
127 return LV_RESULT_OK;
128 }
129 return LV_RESULT_OK;
130 }
131 }
132 /* BMP file as data not supported for simplicity.
133 * Convert them to LVGL compatible C arrays directly. */
134 else if(src_type == LV_IMAGE_SRC_VARIABLE) {
135 return LV_RESULT_INVALID;
136 }
137
138 return LV_RESULT_INVALID; /*If didn't succeeded earlier then it's an error*/
139 }
140
141 /**
142 * Open a BMP image and return the decided image
143 * @param decoder pointer to the decoder
144 * @param dsc pointer to the decoder descriptor
145 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
146 */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)147 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
148 {
149 LV_UNUSED(decoder);
150
151 /*If it's a BMP file...*/
152 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
153 const char * fn = dsc->src;
154
155 if(lv_strcmp(lv_fs_get_ext(fn), "bmp") != 0) {
156 return LV_RESULT_INVALID; /*Check the extension*/
157 }
158
159 bmp_dsc_t b;
160 lv_memset(&b, 0x00, sizeof(b));
161
162 lv_fs_res_t res = lv_fs_open(&b.f, dsc->src, LV_FS_MODE_RD);
163 if(res != LV_FS_RES_OK) return LV_RESULT_INVALID;
164
165 uint8_t header[54];
166 lv_fs_read(&b.f, header, 54, NULL);
167
168 if(0x42 != header[0] || 0x4d != header[1]) {
169 lv_fs_close(&b.f);
170 return LV_RESULT_INVALID;
171 }
172
173 lv_memcpy(&b.px_offset, header + 10, 4);
174 lv_memcpy(&b.px_width, header + 18, 4);
175 lv_memcpy(&b.px_height, header + 22, 4);
176 lv_memcpy(&b.bpp, header + 28, 2);
177 b.row_size_bytes = ((b.bpp * b.px_width + 31) / 32) * 4;
178
179 dsc->user_data = lv_malloc(sizeof(bmp_dsc_t));
180 LV_ASSERT_MALLOC(dsc->user_data);
181 if(dsc->user_data == NULL) return LV_RESULT_INVALID;
182 lv_memcpy(dsc->user_data, &b, sizeof(b));
183 return LV_RESULT_OK;
184 }
185 /* BMP file as data not supported for simplicity.
186 * Convert them to LVGL compatible C arrays directly. */
187 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
188 return LV_RESULT_INVALID;
189 }
190
191 return LV_RESULT_INVALID; /*If not returned earlier then it failed*/
192 }
193
decoder_get_area(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,const lv_area_t * full_area,lv_area_t * decoded_area)194 static lv_result_t decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
195 const lv_area_t * full_area, lv_area_t * decoded_area)
196 {
197 LV_UNUSED(decoder);
198 bmp_dsc_t * b = dsc->user_data;
199 lv_draw_buf_t * decoded = (void *)dsc->decoded;
200
201 if(decoded_area->y1 == LV_COORD_MIN) {
202 *decoded_area = *full_area;
203 decoded_area->y2 = decoded_area->y1;
204 int32_t w_px = lv_area_get_width(full_area);
205 lv_draw_buf_t * reshaped = lv_draw_buf_reshape(decoded, dsc->header.cf, w_px, 1, LV_STRIDE_AUTO);
206 if(reshaped == NULL) {
207 if(decoded != NULL) {
208 lv_draw_buf_destroy(decoded);
209 decoded = NULL;
210 dsc->decoded = NULL;
211 }
212 decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, w_px, 1, dsc->header.cf, LV_STRIDE_AUTO);
213 if(decoded == NULL) return LV_RESULT_INVALID;
214 }
215 else {
216 decoded = reshaped;
217 }
218 dsc->decoded = decoded;
219 }
220 else {
221 decoded_area->y1++;
222 decoded_area->y2++;
223 }
224
225 if(decoded_area->y1 > full_area->y2) {
226 return LV_RESULT_INVALID;
227 }
228 else {
229 int32_t y = (b->px_height - 1) - (decoded_area->y1); /*BMP images are stored upside down*/
230 uint32_t p = b->px_offset + b->row_size_bytes * y;
231 p += (decoded_area->x1) * (b->bpp / 8);
232 lv_fs_seek(&b->f, p, LV_FS_SEEK_SET);
233 uint32_t line_width_byte = lv_area_get_width(full_area) * (b->bpp / 8);
234 lv_fs_read(&b->f, decoded->data, line_width_byte, NULL);
235
236 return LV_RESULT_OK;
237 }
238 }
239
240 /**
241 * Free the allocated resources
242 */
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)243 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
244 {
245 LV_UNUSED(decoder);
246 bmp_dsc_t * b = dsc->user_data;
247 lv_fs_close(&b->f);
248 lv_free(dsc->user_data);
249 if(dsc->decoded) lv_draw_buf_destroy((void *)dsc->decoded);
250
251 }
252
253 #endif /*LV_USE_BMP*/
254