2024-10-11 21:31:35 +02:00
|
|
|
/**
|
2024-02-23 09:42:19 +01:00
|
|
|
* @file lv_test_assert.c
|
|
|
|
*
|
|
|
|
* Copyright 2002-2010 Guillaume Cottenceau.
|
|
|
|
*
|
|
|
|
* This software may be freely redistributed under the terms
|
|
|
|
* of the X11 license.
|
|
|
|
*
|
|
|
|
*/
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
/*********************
|
|
|
|
* INCLUDES
|
|
|
|
*********************/
|
2023-11-15 12:59:16 +01:00
|
|
|
#if LV_BUILD_TEST
|
2021-06-03 16:38:58 +02:00
|
|
|
#include "../lvgl.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2024-04-18 09:12:50 -04:00
|
|
|
#include <errno.h>
|
2021-06-03 16:38:58 +02:00
|
|
|
#include "unity.h"
|
|
|
|
#define PNG_DEBUG 3
|
|
|
|
#include <png.h>
|
|
|
|
|
2024-04-18 09:12:50 -04:00
|
|
|
#ifdef _WIN32
|
2024-08-13 16:08:05 +08:00
|
|
|
#include <direct.h>
|
|
|
|
#define mkdir(pathname, mode) _mkdir(pathname)
|
|
|
|
#define strtok_r strtok_s
|
2024-04-18 09:12:50 -04:00
|
|
|
#else
|
2024-08-13 16:08:05 +08:00
|
|
|
#include <sys/stat.h>
|
2024-04-18 09:12:50 -04:00
|
|
|
#endif
|
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
/*********************
|
|
|
|
* DEFINES
|
|
|
|
*********************/
|
2024-06-08 04:29:13 +08:00
|
|
|
|
|
|
|
#ifndef REF_IMGS_PATH
|
2024-08-13 16:08:05 +08:00
|
|
|
#define REF_IMGS_PATH "ref_imgs/"
|
2024-06-08 04:29:13 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef REF_IMG_TOLERANCE
|
2024-08-13 16:08:05 +08:00
|
|
|
#define REF_IMG_TOLERANCE 0
|
2024-06-08 04:29:13 +08:00
|
|
|
#endif
|
|
|
|
|
2022-09-21 22:10:11 +02:00
|
|
|
#define ERR_FILE_NOT_FOUND -1
|
|
|
|
#define ERR_PNG -2
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
/**********************
|
|
|
|
* TYPEDEFS
|
|
|
|
**********************/
|
|
|
|
typedef struct {
|
|
|
|
int width, height;
|
|
|
|
png_byte color_type;
|
|
|
|
png_byte bit_depth;
|
|
|
|
|
|
|
|
png_structp png_ptr;
|
|
|
|
png_infop info_ptr;
|
|
|
|
int number_of_passes;
|
|
|
|
png_bytep * row_pointers;
|
2023-09-14 20:12:31 +02:00
|
|
|
} png_image_t;
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
/**********************
|
|
|
|
* STATIC PROTOTYPES
|
|
|
|
**********************/
|
2024-06-08 04:29:13 +08:00
|
|
|
static bool screenshot_compare(const char * fn_ref, const char * mode, uint8_t tolerance);
|
2023-09-14 20:12:31 +02:00
|
|
|
static int read_png_file(png_image_t * p, const char * file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
static int write_png_file(void * raw_img, uint32_t width, uint32_t height, char * file_name);
|
2023-09-14 20:12:31 +02:00
|
|
|
static void png_release(png_image_t * p);
|
2024-08-13 16:08:05 +08:00
|
|
|
static void buf_to_xrgb8888(const lv_draw_buf_t * draw_buf, uint8_t * buf_out);
|
2024-02-23 09:42:19 +01:00
|
|
|
static void create_folders_if_needed(const char * path) ;
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
/**********************
|
|
|
|
* STATIC VARIABLES
|
|
|
|
**********************/
|
|
|
|
|
|
|
|
/**********************
|
|
|
|
* MACROS
|
|
|
|
**********************/
|
|
|
|
|
|
|
|
/**********************
|
|
|
|
* GLOBAL FUNCTIONS
|
|
|
|
**********************/
|
|
|
|
|
2023-09-14 20:12:31 +02:00
|
|
|
bool lv_test_assert_image_eq(const char * fn_ref)
|
2021-06-03 16:38:58 +02:00
|
|
|
{
|
2023-11-15 09:47:34 +01:00
|
|
|
bool pass;
|
|
|
|
|
|
|
|
lv_obj_t * scr = lv_screen_active();
|
|
|
|
lv_obj_invalidate(scr);
|
|
|
|
|
2024-06-08 04:29:13 +08:00
|
|
|
pass = screenshot_compare(fn_ref, "full refresh", REF_IMG_TOLERANCE);
|
2023-11-15 09:47:34 +01:00
|
|
|
if(!pass) return false;
|
|
|
|
|
|
|
|
//Software has minor rounding errors when not the whole image is updated
|
|
|
|
//so ignore stripe invalidation for now
|
|
|
|
// uint32_t i;
|
|
|
|
// for(i = 0; i < 800; i += 50 ) {
|
|
|
|
// lv_area_t a;
|
|
|
|
// a.y1 = 0;
|
|
|
|
// a.y2 = 479;
|
|
|
|
// a.x1 = i;
|
|
|
|
// a.x2 = i + 12;
|
|
|
|
// lv_obj_invalidate_area(scr, &a);
|
|
|
|
//
|
|
|
|
// a.x1 = i + 25;
|
|
|
|
// a.x2 = i + 32;
|
|
|
|
// lv_obj_invalidate_area(scr, &a);
|
|
|
|
// }
|
|
|
|
//
|
2024-06-08 04:29:13 +08:00
|
|
|
// pass = screenshot_compare(fn_ref, "vertical stripes", 32);
|
2023-11-15 09:47:34 +01:00
|
|
|
// if(!pass) return false;
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// for(i = 0; i < 480; i += 40) {
|
|
|
|
// lv_area_t a;
|
|
|
|
// a.x1 = 0;
|
|
|
|
// a.x2 = 799;
|
|
|
|
// a.y1 = i;
|
|
|
|
// a.y2 = i + 9;
|
|
|
|
// lv_obj_invalidate_area(scr, &a);
|
|
|
|
//
|
|
|
|
// a.y1 = i + 25;
|
|
|
|
// a.y2 = i + 32;
|
|
|
|
// lv_obj_invalidate_area(scr, &a);
|
|
|
|
// }
|
|
|
|
//
|
2024-06-08 04:29:13 +08:00
|
|
|
// pass = screenshot_compare(fn_ref, "horizontal stripes", 32);
|
2023-11-15 09:47:34 +01:00
|
|
|
// if(!pass) return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************
|
|
|
|
* STATIC FUNCTIONS
|
|
|
|
**********************/
|
|
|
|
|
2023-11-15 12:51:48 +01:00
|
|
|
static uint8_t screen_buf_xrgb8888[800 * 480 * 4];
|
2023-11-15 09:47:34 +01:00
|
|
|
/**
|
|
|
|
* Compare the content of the frame buffer with a reference image
|
|
|
|
* @param fn_ref reference image name
|
|
|
|
* @param mode arbitrary string to tell more about the compare
|
|
|
|
* @return true: test passed; false: test failed
|
|
|
|
*/
|
2024-06-08 04:29:13 +08:00
|
|
|
static bool screenshot_compare(const char * fn_ref, const char * mode, uint8_t tolerance)
|
2023-11-15 09:47:34 +01:00
|
|
|
{
|
|
|
|
|
2023-11-27 11:46:23 +01:00
|
|
|
char fn_ref_full[256];
|
2024-01-15 19:20:04 +08:00
|
|
|
lv_snprintf(fn_ref_full, sizeof(fn_ref_full), "%s%s", REF_IMGS_PATH, fn_ref);
|
2021-06-03 16:38:58 +02:00
|
|
|
|
2024-02-23 09:42:19 +01:00
|
|
|
create_folders_if_needed(fn_ref_full);
|
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
lv_refr_now(NULL);
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2024-08-13 16:08:05 +08:00
|
|
|
lv_draw_buf_t * draw_buf = lv_display_get_buf_active(NULL);
|
|
|
|
buf_to_xrgb8888(draw_buf, screen_buf_xrgb8888);
|
2021-06-03 16:38:58 +02:00
|
|
|
|
2023-09-14 20:12:31 +02:00
|
|
|
png_image_t p;
|
2022-09-21 22:10:11 +02:00
|
|
|
int res = read_png_file(&p, fn_ref_full);
|
|
|
|
if(res == ERR_FILE_NOT_FOUND) {
|
|
|
|
TEST_PRINTF("%s%s", fn_ref_full, " was not found, creating is now from the rendered screen");
|
|
|
|
fflush(stderr);
|
2023-11-15 12:51:48 +01:00
|
|
|
write_png_file(screen_buf_xrgb8888, 800, 480, fn_ref_full);
|
2022-09-21 22:10:11 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if(res == ERR_PNG) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
uint8_t * ptr_act = NULL;
|
|
|
|
const png_byte * ptr_ref = NULL;
|
2021-06-03 16:38:58 +02:00
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
bool err = false;
|
2023-11-15 09:47:34 +01:00
|
|
|
int x, y;
|
2022-09-19 11:19:10 +02:00
|
|
|
for(y = 0; y < p.height; y++) {
|
2023-11-15 12:51:48 +01:00
|
|
|
uint8_t * screen_buf_tmp = screen_buf_xrgb8888 + 800 * 4 * y;
|
2022-09-19 11:19:10 +02:00
|
|
|
png_byte * row = p.row_pointers[y];
|
|
|
|
for(x = 0; x < p.width; x++) {
|
|
|
|
ptr_ref = &(row[x * 3]);
|
2023-11-15 09:47:34 +01:00
|
|
|
ptr_act = screen_buf_tmp;
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2024-06-08 04:29:13 +08:00
|
|
|
if(LV_ABS((int32_t) ptr_act[0] - (int32_t) ptr_ref[0]) > tolerance ||
|
|
|
|
LV_ABS((int32_t) ptr_act[1] - (int32_t) ptr_ref[1]) > tolerance ||
|
|
|
|
LV_ABS((int32_t) ptr_act[2] - (int32_t) ptr_ref[2]) > tolerance) {
|
2023-11-15 12:51:48 +01:00
|
|
|
uint32_t act_px = (ptr_act[2] << 16) + (ptr_act[1] << 8) + (ptr_act[0] << 0);
|
|
|
|
uint32_t ref_px = 0;
|
|
|
|
memcpy(&ref_px, ptr_ref, 3);
|
|
|
|
TEST_PRINTF("\nScreenshot compare error\n"
|
|
|
|
" - File: %s\n"
|
|
|
|
" - Mode: %s\n"
|
|
|
|
" - At x:%d, y:%d.\n"
|
|
|
|
" - Expected: %X\n"
|
2024-06-08 04:29:13 +08:00
|
|
|
" - Actual: %X\n"
|
|
|
|
" - Tolerance: %d",
|
|
|
|
fn_ref_full, mode, x, y, ref_px, act_px, tolerance);
|
2023-11-09 18:37:33 +08:00
|
|
|
fflush(stderr);
|
2022-09-19 11:19:10 +02:00
|
|
|
err = true;
|
|
|
|
break;
|
|
|
|
}
|
2023-11-15 09:47:34 +01:00
|
|
|
screen_buf_tmp += 4;
|
2021-06-18 14:13:05 +02:00
|
|
|
}
|
2022-09-19 11:19:10 +02:00
|
|
|
if(err) break;
|
|
|
|
}
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
if(err) {
|
2023-11-27 11:46:23 +01:00
|
|
|
char fn_ref_no_ext[128];
|
2024-05-22 08:14:12 -04:00
|
|
|
lv_strlcpy(fn_ref_no_ext, fn_ref, sizeof(fn_ref_no_ext));
|
2023-07-05 13:05:19 +02:00
|
|
|
fn_ref_no_ext[strlen(fn_ref_no_ext) - 4] = '\0';
|
|
|
|
|
2023-11-27 11:46:23 +01:00
|
|
|
char fn_err_full[256];
|
2024-01-15 19:20:04 +08:00
|
|
|
lv_snprintf(fn_err_full, sizeof(fn_err_full), "%s%s_err.png", REF_IMGS_PATH, fn_ref_no_ext);
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2023-11-15 12:51:48 +01:00
|
|
|
write_png_file(screen_buf_xrgb8888, 800, 480, fn_err_full);
|
2022-09-19 11:19:10 +02:00
|
|
|
}
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
png_release(&p);
|
2022-02-11 16:59:24 +01:00
|
|
|
|
2023-11-09 18:37:33 +08:00
|
|
|
fflush(stdout);
|
2022-09-19 11:19:10 +02:00
|
|
|
return !err;
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
|
|
|
|
2023-09-14 20:12:31 +02:00
|
|
|
static int read_png_file(png_image_t * p, const char * file_name)
|
2021-06-03 16:38:58 +02:00
|
|
|
{
|
|
|
|
char header[8]; // 8 is the maximum size that can be checked
|
|
|
|
|
|
|
|
/*open file and test for it being a png*/
|
2022-09-19 11:19:10 +02:00
|
|
|
FILE * fp = fopen(file_name, "rb");
|
|
|
|
if(!fp) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] could not be opened for reading", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_FILE_NOT_FOUND;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
size_t rcnt = fread(header, 1, 8, fp);
|
2022-09-19 11:19:10 +02:00
|
|
|
if(rcnt != 8 || png_sig_cmp((png_const_bytep)header, 0, 8)) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] not recognized as a PNG file", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_PNG;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
/*initialize stuff*/
|
|
|
|
p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
|
|
|
2022-09-19 11:19:10 +02:00
|
|
|
if(!p->png_ptr) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] png_create_read_struct failed", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_PNG;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
p->info_ptr = png_create_info_struct(p->png_ptr);
|
2022-09-19 11:19:10 +02:00
|
|
|
if(!p->info_ptr) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] png_create_info_struct failed", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_PNG;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
2022-09-19 11:19:10 +02:00
|
|
|
if(setjmp(png_jmpbuf(p->png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] Error during init_io", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_PNG;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
|
|
|
png_init_io(p->png_ptr, fp);
|
|
|
|
png_set_sig_bytes(p->png_ptr, 8);
|
|
|
|
|
|
|
|
png_read_info(p->png_ptr, p->info_ptr);
|
|
|
|
|
|
|
|
p->width = png_get_image_width(p->png_ptr, p->info_ptr);
|
|
|
|
p->height = png_get_image_height(p->png_ptr, p->info_ptr);
|
|
|
|
p->color_type = png_get_color_type(p->png_ptr, p->info_ptr);
|
|
|
|
p->bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr);
|
|
|
|
|
|
|
|
p->number_of_passes = png_set_interlace_handling(p->png_ptr);
|
|
|
|
png_read_update_info(p->png_ptr, p->info_ptr);
|
|
|
|
|
|
|
|
/*read file*/
|
2022-09-19 11:19:10 +02:00
|
|
|
if(setjmp(png_jmpbuf(p->png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[read_png_file %s] Error during read_image", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return ERR_PNG;
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
2022-09-19 11:19:10 +02:00
|
|
|
p->row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * p->height);
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
int y;
|
2022-09-19 11:19:10 +02:00
|
|
|
for(y = 0; y < p->height; y++)
|
|
|
|
p->row_pointers[y] = (png_byte *) malloc(png_get_rowbytes(p->png_ptr, p->info_ptr));
|
2021-06-03 16:38:58 +02:00
|
|
|
|
|
|
|
png_read_image(p->png_ptr, p->row_pointers);
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-21 22:10:11 +02:00
|
|
|
static int write_png_file(void * raw_img, uint32_t width, uint32_t height, char * file_name)
|
|
|
|
{
|
|
|
|
png_structp png_ptr;
|
|
|
|
png_infop info_ptr;
|
|
|
|
|
|
|
|
/* create file */
|
|
|
|
FILE * fp = fopen(file_name, "wb");
|
|
|
|
if(!fp) {
|
2023-07-05 13:05:19 +02:00
|
|
|
printf("###### %s\n", file_name);
|
|
|
|
fflush(stdout);
|
|
|
|
TEST_PRINTF("[write_png_file %s] could not be opened for writing", file_name);
|
|
|
|
TEST_PRINTF("%s", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize stuff */
|
|
|
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if(!png_ptr) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] png_create_write_struct failed", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
info_ptr = png_create_info_struct(png_ptr);
|
|
|
|
if(!info_ptr) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] png_create_info_struct failed", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(setjmp(png_jmpbuf(png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] Error during init_io", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
png_init_io(png_ptr, fp);
|
|
|
|
|
|
|
|
/* write header */
|
|
|
|
if(setjmp(png_jmpbuf(png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] Error during writing header", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
png_set_IHDR(png_ptr, info_ptr, width, height,
|
|
|
|
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
|
|
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
|
|
|
|
|
|
|
png_write_info(png_ptr, info_ptr);
|
|
|
|
|
|
|
|
/* write bytes */
|
|
|
|
if(setjmp(png_jmpbuf(png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] Error during writing bytes", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t * raw_img8 = (uint8_t *)raw_img;
|
|
|
|
png_bytep * row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * height);
|
|
|
|
for(uint32_t y = 0; y < height; y++) {
|
|
|
|
row_pointers[y] = malloc(3 * width);
|
|
|
|
uint8_t * line = raw_img8 + y * width * 4;
|
|
|
|
for(uint32_t x = 0; x < width; x++) {
|
2023-11-15 12:51:48 +01:00
|
|
|
row_pointers[y][x * 3 + 0] = line[x * 4 + 0];
|
2022-09-21 22:10:11 +02:00
|
|
|
row_pointers[y][x * 3 + 1] = line[x * 4 + 1];
|
2023-11-15 12:51:48 +01:00
|
|
|
row_pointers[y][x * 3 + 2] = line[x * 4 + 2];
|
2022-09-21 22:10:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
png_write_image(png_ptr, row_pointers);
|
|
|
|
|
|
|
|
/* end write */
|
|
|
|
if(setjmp(png_jmpbuf(png_ptr))) {
|
2023-07-05 13:05:19 +02:00
|
|
|
TEST_PRINTF("[write_png_file %s] Error during end of write", file_name);
|
2022-09-21 22:10:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
png_write_end(png_ptr, NULL);
|
|
|
|
|
|
|
|
/* cleanup heap allocation */
|
|
|
|
for(uint32_t y = 0; y < height; y++) free(row_pointers[y]);
|
|
|
|
free(row_pointers);
|
|
|
|
|
|
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-14 20:12:31 +02:00
|
|
|
static void png_release(png_image_t * p)
|
2021-06-03 16:38:58 +02:00
|
|
|
{
|
|
|
|
int y;
|
2022-09-19 11:19:10 +02:00
|
|
|
for(y = 0; y < p->height; y++) free(p->row_pointers[y]);
|
2022-03-21 18:25:51 +08:00
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
free(p->row_pointers);
|
2022-01-23 09:58:55 -05:00
|
|
|
|
|
|
|
png_destroy_read_struct(&p->png_ptr, &p->info_ptr, NULL);
|
2021-06-03 16:38:58 +02:00
|
|
|
}
|
|
|
|
|
2024-08-13 16:08:05 +08:00
|
|
|
static void buf_to_xrgb8888(const lv_draw_buf_t * draw_buf, uint8_t * buf_out)
|
2023-11-15 12:51:48 +01:00
|
|
|
{
|
2024-08-13 16:08:05 +08:00
|
|
|
uint32_t stride = draw_buf->header.stride;
|
|
|
|
lv_color_format_t cf_in = draw_buf->header.cf;
|
|
|
|
const uint8_t * buf_in = draw_buf->data;
|
|
|
|
|
2023-11-15 12:51:48 +01:00
|
|
|
if(cf_in == LV_COLOR_FORMAT_RGB565) {
|
|
|
|
uint32_t y;
|
|
|
|
for(y = 0; y < 480; y++) {
|
|
|
|
|
|
|
|
uint32_t x;
|
|
|
|
for(x = 0; x < 800; x++) {
|
|
|
|
const lv_color16_t * c16 = (const lv_color16_t *)&buf_in[x * 2];
|
|
|
|
|
|
|
|
buf_out[x * 4 + 3] = 0xff;
|
|
|
|
buf_out[x * 4 + 2] = (c16->blue * 2106) >> 8; /*To make it rounded*/
|
|
|
|
buf_out[x * 4 + 1] = (c16->green * 1037) >> 8;
|
|
|
|
buf_out[x * 4 + 0] = (c16->red * 2106) >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(cf_in == LV_COLOR_FORMAT_ARGB8888 || cf_in == LV_COLOR_FORMAT_XRGB8888) {
|
|
|
|
uint32_t y;
|
|
|
|
for(y = 0; y < 480; y++) {
|
|
|
|
uint32_t x;
|
|
|
|
for(x = 0; x < 800; x++) {
|
|
|
|
buf_out[x * 4 + 3] = buf_in[x * 4 + 3];
|
|
|
|
buf_out[x * 4 + 2] = buf_in[x * 4 + 0];
|
|
|
|
buf_out[x * 4 + 1] = buf_in[x * 4 + 1];
|
|
|
|
buf_out[x * 4 + 0] = buf_in[x * 4 + 2];
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(cf_in == LV_COLOR_FORMAT_RGB888) {
|
|
|
|
uint32_t y;
|
|
|
|
for(y = 0; y < 480; y++) {
|
|
|
|
uint32_t x;
|
|
|
|
for(x = 0; x < 800; x++) {
|
|
|
|
buf_out[x * 4 + 3] = 0xff;
|
|
|
|
buf_out[x * 4 + 2] = buf_in[x * 3 + 0];
|
|
|
|
buf_out[x * 4 + 1] = buf_in[x * 3 + 1];
|
|
|
|
buf_out[x * 4 + 0] = buf_in[x * 3 + 2];
|
|
|
|
}
|
|
|
|
|
2024-04-20 13:14:25 +02:00
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(cf_in == LV_COLOR_FORMAT_L8) {
|
|
|
|
uint32_t y;
|
|
|
|
for(y = 0; y < 480; y++) {
|
|
|
|
uint32_t x;
|
|
|
|
for(x = 0; x < 800; x++) {
|
|
|
|
buf_out[x * 4 + 3] = 0xff;
|
|
|
|
buf_out[x * 4 + 2] = buf_in[x];
|
|
|
|
buf_out[x * 4 + 1] = buf_in[x];
|
|
|
|
buf_out[x * 4 + 0] = buf_in[x];
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 16:08:05 +08:00
|
|
|
else if(cf_in == LV_COLOR_FORMAT_AL88) {
|
2024-04-20 13:14:25 +02:00
|
|
|
uint32_t y;
|
2024-08-13 16:08:05 +08:00
|
|
|
for(y = 0; y < 480; y++) {
|
2024-04-20 13:14:25 +02:00
|
|
|
uint32_t x;
|
2024-08-13 16:08:05 +08:00
|
|
|
for(x = 0; x < 800; x++) {
|
2024-04-20 13:14:25 +02:00
|
|
|
buf_out[x * 4 + 3] = buf_in[x * 2 + 1];
|
|
|
|
buf_out[x * 4 + 2] = buf_in[x * 2 + 0];
|
|
|
|
buf_out[x * 4 + 1] = buf_in[x * 2 + 0];
|
|
|
|
buf_out[x * 4 + 0] = buf_in[x * 2 + 0];
|
|
|
|
}
|
|
|
|
|
2024-07-19 12:10:28 +02:00
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 16:08:05 +08:00
|
|
|
else if(cf_in == LV_COLOR_FORMAT_I1) {
|
2024-07-19 12:10:28 +02:00
|
|
|
uint32_t y;
|
2024-08-13 16:08:05 +08:00
|
|
|
for(y = 0; y < 480; y++) {
|
2024-07-19 12:10:28 +02:00
|
|
|
uint32_t x;
|
2024-08-13 16:08:05 +08:00
|
|
|
for(x = 0; x < 800; x++) {
|
2024-07-19 12:10:28 +02:00
|
|
|
const uint8_t byte = buf_in[x / 8];
|
|
|
|
const uint8_t bit_pos = x % 8;
|
|
|
|
const uint8_t pixel = (byte >> (7 - bit_pos)) & 0x01;
|
|
|
|
|
|
|
|
buf_out[x * 4 + 3] = 0xff;
|
|
|
|
buf_out[x * 4 + 2] = pixel ? 0xff : 0x00;
|
|
|
|
buf_out[x * 4 + 1] = pixel ? 0xff : 0x00;
|
|
|
|
buf_out[x * 4 + 0] = pixel ? 0xff : 0x00;
|
|
|
|
}
|
|
|
|
|
2023-11-15 12:51:48 +01:00
|
|
|
buf_in += stride;
|
|
|
|
buf_out += 800 * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-23 09:42:19 +01:00
|
|
|
static void create_folders_if_needed(const char * path)
|
|
|
|
{
|
|
|
|
char * ptr;
|
|
|
|
char * pathCopy = strdup(path);
|
|
|
|
if(pathCopy == NULL) {
|
|
|
|
perror("Error duplicating path");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
char * token = strtok_r(pathCopy, "/", &ptr);
|
|
|
|
char current_path[1024] = {'\0'}; // Adjust the size as needed
|
|
|
|
|
|
|
|
while(token && ptr && *ptr != '\0') {
|
|
|
|
strcat(current_path, token);
|
|
|
|
strcat(current_path, "/");
|
|
|
|
|
2024-04-18 09:12:50 -04:00
|
|
|
int mkdir_retval = mkdir(current_path, 0777);
|
2024-08-13 16:08:05 +08:00
|
|
|
if(mkdir_retval == 0) {
|
2024-02-23 09:42:19 +01:00
|
|
|
printf("Created folder: %s\n", current_path);
|
|
|
|
}
|
2024-08-13 16:08:05 +08:00
|
|
|
else if(errno != EEXIST) {
|
2024-04-18 09:12:50 -04:00
|
|
|
perror("Error creating folder");
|
|
|
|
free(pathCopy);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2024-02-23 09:42:19 +01:00
|
|
|
|
|
|
|
token = strtok_r(NULL, "/", &ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pathCopy);
|
|
|
|
}
|
|
|
|
|
2021-06-03 16:38:58 +02:00
|
|
|
#endif
|