lv_png.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. * @file lv_png.c
  3. *
  4. */
  5. /*********************
  6. * INCLUDES
  7. *********************/
  8. #include "../../../lvgl.h"
  9. #if LV_USE_PNG
  10. #include "lv_png.h"
  11. #include "lodepng.h"
  12. #include <stdlib.h>
  13. /*********************
  14. * DEFINES
  15. *********************/
  16. #ifdef LODEPNG_COMPILE_ALLOCATORS
  17. #define lv_png_free(ptr) lv_mem_free((ptr))
  18. #else
  19. #define lv_png_free(ptr) lodepng_free((ptr))
  20. #endif
  21. /**********************
  22. * TYPEDEFS
  23. **********************/
  24. /**********************
  25. * STATIC PROTOTYPES
  26. **********************/
  27. static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
  28. static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
  29. static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
  30. static void convert_color_depth(uint8_t * img, uint32_t px_cnt);
  31. static inline lv_color_t lv_color_make_rounding(uint8_t r, uint8_t g, uint8_t b);
  32. /**********************
  33. * STATIC VARIABLES
  34. **********************/
  35. /**********************
  36. * MACROS
  37. **********************/
  38. /**********************
  39. * GLOBAL FUNCTIONS
  40. **********************/
  41. /**
  42. * Register the PNG decoder functions in LVGL
  43. */
  44. void lv_png_init(void)
  45. {
  46. lv_img_decoder_t * dec = lv_img_decoder_create();
  47. lv_img_decoder_set_info_cb(dec, decoder_info);
  48. lv_img_decoder_set_open_cb(dec, decoder_open);
  49. lv_img_decoder_set_close_cb(dec, decoder_close);
  50. }
  51. /**********************
  52. * STATIC FUNCTIONS
  53. **********************/
  54. /**
  55. * Get info about a PNG image
  56. * @param src can be file name or pointer to a C array
  57. * @param header store the info here
  58. * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
  59. */
  60. static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
  61. {
  62. (void) decoder; /*Unused*/
  63. lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
  64. /*If it's a PNG file...*/
  65. if(src_type == LV_IMG_SRC_FILE) {
  66. const char * fn = src;
  67. if(strcmp(lv_fs_get_ext(fn), "png") == 0) { /*Check the extension*/
  68. /* Read the width and height from the file. They have a constant location:
  69. * [16..23]: width
  70. * [24..27]: height
  71. */
  72. uint32_t size[2];
  73. lv_fs_file_t f;
  74. lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
  75. if(res != LV_FS_RES_OK) return LV_RES_INV;
  76. lv_fs_seek(&f, 16, LV_FS_SEEK_SET);
  77. uint32_t rn;
  78. lv_fs_read(&f, &size, 8, &rn);
  79. lv_fs_close(&f);
  80. if(rn != 8) return LV_RES_INV;
  81. /*Save the data in the header*/
  82. header->always_zero = 0;
  83. header->cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
  84. /*The width and height are stored in Big endian format so convert them to little endian*/
  85. header->w = (lv_coord_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
  86. header->h = (lv_coord_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
  87. return LV_RES_OK;
  88. }
  89. }
  90. /*If it's a PNG file in a C array...*/
  91. else if(src_type == LV_IMG_SRC_VARIABLE) {
  92. const lv_img_dsc_t * img_dsc = src;
  93. const uint32_t data_size = img_dsc->data_size;
  94. const uint32_t * size = ((uint32_t *)img_dsc->data) + 4;
  95. const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
  96. if(data_size < sizeof(magic)) return LV_RES_INV;
  97. if(memcmp(magic, img_dsc->data, sizeof(magic))) return LV_RES_INV;
  98. header->always_zero = 0;
  99. if(img_dsc->header.cf) {
  100. header->cf = img_dsc->header.cf; /*Save the color format*/
  101. }
  102. else {
  103. header->cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
  104. }
  105. if(img_dsc->header.w) {
  106. header->w = img_dsc->header.w; /*Save the image width*/
  107. }
  108. else {
  109. header->w = (lv_coord_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
  110. }
  111. if(img_dsc->header.h) {
  112. header->h = img_dsc->header.h; /*Save the color height*/
  113. }
  114. else {
  115. header->h = (lv_coord_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
  116. }
  117. return LV_RES_OK;
  118. }
  119. return LV_RES_INV; /*If didn't succeeded earlier then it's an error*/
  120. }
  121. /**
  122. * Open a PNG image and return the decided image
  123. * @param src can be file name or pointer to a C array
  124. * @param style style of the image object (unused now but certain formats might use it)
  125. * @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
  126. */
  127. static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
  128. {
  129. (void) decoder; /*Unused*/
  130. uint32_t error; /*For the return values of PNG decoder functions*/
  131. uint8_t * img_data = NULL;
  132. /*If it's a PNG file...*/
  133. if(dsc->src_type == LV_IMG_SRC_FILE) {
  134. const char * fn = dsc->src;
  135. if(strcmp(lv_fs_get_ext(fn), "png") == 0) { /*Check the extension*/
  136. /*Load the PNG file into buffer. It's still compressed (not decoded)*/
  137. unsigned char * png_data; /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/
  138. size_t png_data_size; /*Size of `png_data` in bytes*/
  139. error = lodepng_load_file(&png_data, &png_data_size, fn); /*Load the file*/
  140. if(error) {
  141. LV_LOG_WARN("error %" LV_PRIu32 ": %s\n", error, lodepng_error_text(error));
  142. return LV_RES_INV;
  143. }
  144. /*Decode the PNG image*/
  145. unsigned png_width; /*Will be the width of the decoded image*/
  146. unsigned png_height; /*Will be the width of the decoded image*/
  147. /*Decode the loaded image in ARGB8888 */
  148. error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size);
  149. lv_png_free(png_data); /*Free the loaded file*/
  150. if(error) {
  151. if(img_data != NULL) {
  152. lv_png_free(img_data);
  153. }
  154. LV_LOG_WARN("error %" LV_PRIu32 ": %s\n", error, lodepng_error_text(error));
  155. return LV_RES_INV;
  156. }
  157. /*Convert the image to the system's color depth*/
  158. convert_color_depth(img_data, png_width * png_height);
  159. dsc->img_data = img_data;
  160. return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/
  161. }
  162. }
  163. /*If it's a PNG file in a C array...*/
  164. else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
  165. const lv_img_dsc_t * img_dsc = dsc->src;
  166. unsigned png_width; /*No used, just required by he decoder*/
  167. unsigned png_height; /*No used, just required by he decoder*/
  168. /*Decode the image in ARGB8888 */
  169. error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size);
  170. if(error) {
  171. if(img_data != NULL) {
  172. lv_mem_free(img_data);
  173. }
  174. return LV_RES_INV;
  175. }
  176. /*Convert the image to the system's color depth*/
  177. convert_color_depth(img_data, png_width * png_height);
  178. dsc->img_data = img_data;
  179. return LV_RES_OK; /*Return with its pointer*/
  180. }
  181. return LV_RES_INV; /*If not returned earlier then it failed*/
  182. }
  183. /**
  184. * Free the allocated resources
  185. */
  186. static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
  187. {
  188. LV_UNUSED(decoder); /*Unused*/
  189. if(dsc->img_data) {
  190. lv_mem_free((uint8_t *)dsc->img_data);
  191. dsc->img_data = NULL;
  192. }
  193. }
  194. /**
  195. * If the display is not in 32 bit format (ARGB888) then covert the image to the current color depth
  196. * @param img the ARGB888 image
  197. * @param px_cnt number of pixels in `img`
  198. */
  199. static void convert_color_depth(uint8_t * img, uint32_t px_cnt)
  200. {
  201. #if LV_COLOR_DEPTH == 32
  202. lv_color32_t * img_argb = (lv_color32_t *)img;
  203. lv_color_t c;
  204. lv_color_t * img_c = (lv_color_t *) img;
  205. uint32_t i;
  206. for(i = 0; i < px_cnt; i++) {
  207. c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
  208. img_c[i].ch.red = c.ch.blue;
  209. img_c[i].ch.blue = c.ch.red;
  210. }
  211. #elif LV_COLOR_DEPTH == 16
  212. lv_color32_t * img_argb = (lv_color32_t *)img;
  213. lv_color_t c;
  214. uint32_t i;
  215. for(i = 0; i < px_cnt; i++) {
  216. c = lv_color_make_rounding(img_argb[i].ch.blue, img_argb[i].ch.green, img_argb[i].ch.red);
  217. img[i * 3 + 2] = img_argb[i].ch.alpha;
  218. img[i * 3 + 1] = c.full >> 8;
  219. img[i * 3 + 0] = c.full & 0xFF;
  220. }
  221. #elif LV_COLOR_DEPTH == 8
  222. lv_color32_t * img_argb = (lv_color32_t *)img;
  223. lv_color_t c;
  224. uint32_t i;
  225. for(i = 0; i < px_cnt; i++) {
  226. c = lv_color_make_rounding(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
  227. img[i * 2 + 1] = img_argb[i].ch.alpha;
  228. img[i * 2 + 0] = c.full;
  229. }
  230. #elif LV_COLOR_DEPTH == 1
  231. lv_color32_t * img_argb = (lv_color32_t *)img;
  232. uint8_t b;
  233. uint32_t i;
  234. for(i = 0; i < px_cnt; i++) {
  235. b = img_argb[i].ch.red | img_argb[i].ch.green | img_argb[i].ch.blue;
  236. img[i * 2 + 1] = img_argb[i].ch.alpha;
  237. img[i * 2 + 0] = b > 128 ? 1 : 0;
  238. }
  239. #endif
  240. }
  241. static inline lv_color_t lv_color_make_rounding(uint8_t r, uint8_t g, uint8_t b)
  242. {
  243. #if LV_COLOR_DEPTH == 16
  244. if(r <= 251) r += 4;
  245. if(g <= 253) g += 2;
  246. if(b <= 251) b += 4;
  247. #endif
  248. return lv_color_make(r, g, b);
  249. }
  250. #endif /*LV_USE_PNG*/