diff --git a/scripts/LVGLImage.py b/scripts/LVGLImage.py index 38fd65f5e..56e3b0ca0 100755 --- a/scripts/LVGLImage.py +++ b/scripts/LVGLImage.py @@ -91,6 +91,11 @@ class PngQuant: return compressed +class CompressMethod(Enum): + NONE = 0x00 + RLE = 0x01 + + class ColorFormat(Enum): UNKNOWN = 0x00 TRUECOLOR = 0x04 @@ -280,8 +285,10 @@ class LVGLImageHeader: w: int = 0, h: int = 0, stride: int = 0, - align: int = 1): + align: int = 1, + flags: int = 0): self.cf = cf + self.flags = flags self.w = w & 0xffff self.h = h & 0xffff if w > 0xffff or h > 0xffff: @@ -314,8 +321,7 @@ class LVGLImageHeader: binary = bytearray() binary += uint8_t(self.cf.value) binary += uint8_t(0) # 8bits format - binary += uint8_t(0) # 8bits user flags - binary += uint8_t(0) # 8bits reserved + binary += uint16_t(self.flags) # 16bits flags binary += uint16_t(self.w) # 16bits width binary += uint16_t(self.h) # 16bits height @@ -338,6 +344,40 @@ class LVGLImageHeader: return self +class LVGLCompressData: + + def __init__(self, + cf: ColorFormat, + method: CompressMethod, + raw_data: bytes = b''): + self.blk_size = (cf.bpp + 7) // 8 + self.compress = method + self.raw_data = raw_data + self.raw_data_len = len(raw_data) + self.compressed = self._compress(raw_data) + + def _compress(self, raw_data: bytes) -> bytearray: + if self.compress == CompressMethod.NONE: + return raw_data + + if self.compress == CompressMethod.RLE: + # RLE compression performs on pixel unit, pad data to pixel unit + pad = b'\x00' * (self.blk_size - self.raw_data_len % self.blk_size) + self.raw_data_len += len(pad) + compressed = RLEImage().rle_compress(raw_data + pad, self.blk_size) + else: + raise ParameterError(f"Invalid compress method: {self.compress}") + + self.compressed_len = len(compressed) + + bin = bytearray() + bin += uint32_t(self.compress.value) + bin += uint32_t(self.compressed_len) + bin += uint32_t(self.raw_data_len) + bin += compressed + return bin + + class LVGLImage: def __init__(self, @@ -346,12 +386,17 @@ class LVGLImage: h: int = 0, data: bytes = b'') -> None: self.stride = 0 # default no valid stride value + self.compress = CompressMethod.NONE self.set_data(cf, w, h, data) def __repr__(self) -> str: return (f"'LVGL image {self.w}x{self.h}, {self.cf.name}," f" (12+{self.data_len})Byte'") + def set_compress(self, method: CompressMethod): + # only do compression when return binary data + self.compress = method + def adjust_stride(self, stride: int = 0, align: int = 1): ''' Stride can be set directly, or by stride alignment in bytes @@ -439,9 +484,17 @@ class LVGLImage: raw data ''' bin = bytearray() - header = LVGLImageHeader(self.cf, self.w, self.h, self.stride) + flags = 0 + flags |= 0x08 if self.compress != CompressMethod.NONE else 0 + + header = LVGLImageHeader(self.cf, + self.w, + self.h, + self.stride, + flags=flags) bin += header.binary - bin += self.data + compress = LVGLCompressData(self.cf, self.compress, self.data) + bin += compress.compressed return bin @property @@ -614,7 +667,7 @@ const lv_img_dsc_t {varname} = {{ data += [0, 0, 0, a] encoder = png.Writer(self.w, self.h, greyscale=False, alpha=True) elif self.cf == ColorFormat.L8: - # to greyscale + # to grayscale encoder = png.Writer(self.w, self.h, bitdepth=self.cf.bpp, @@ -634,7 +687,7 @@ const lv_img_dsc_t {varname} = {{ with open(filename, "wb") as f: encoder.write_array(f, data) - self.adjust_stride(stride=self.stride) + self.adjust_stride(stride=old_stride) def from_png(self, filename: str, @@ -852,8 +905,8 @@ class RLEImage(LVGLImage): index = 0 data_len = len(data) compressed_data = [] + memview = memoryview(data) while index < data_len: - memview = memoryview(data) repeat_cnt = self.get_repeat_count(memview[index:], blksize) if repeat_cnt == 0: # done @@ -946,6 +999,7 @@ class PNGConverter: odir: str, background: int = 0x00, align: int = 1, + compress: CompressMethod = CompressMethod.NONE, keep_folder=True) -> None: self.files = files self.cf = cf @@ -954,6 +1008,7 @@ class PNGConverter: self.pngquant = None self.keep_folder = keep_folder self.align = align + self.compress = compress self.background = background def _replace_ext(self, input, ext): @@ -974,6 +1029,7 @@ class PNGConverter: self.cf, background=self.background) rle.adjust_stride(align=self.align) + rle.set_compress(self.compress) output.append((f, rle)) rle.to_rle(self._replace_ext(f, ".rle")) else: @@ -981,6 +1037,7 @@ class PNGConverter: self.cf, background=self.background) img.adjust_stride(align=self.align) + img.set_compress(self.compress) output.append((f, img)) if self.ofmt == OutputFormat.BIN_FILE: img.to_bin(self._replace_ext(f, ".bin")) @@ -1008,6 +1065,12 @@ def main(): "XRGB8888", "RGB565", "RGB565A8", "RGB888", "TRUECOLOR", "TRUECOLOR_ALPHA", "AUTO" ]) + + parser.add_argument('--compress', + help=("Binary data compress method, default to NONE"), + default="NONE", + choices=["NONE", "RLE"]) + parser.add_argument('--align', help="stride alignment in bytes for bin image", default=1, @@ -1048,6 +1111,7 @@ def main(): cf = ColorFormat[args.cf] ofmt = OutputFormat(args.ofmt) + compress = CompressMethod[args.compress] converter = PNGConverter(files, cf, @@ -1055,6 +1119,7 @@ def main(): args.output, background=args.background, align=args.align, + compress=compress, keep_folder=False) output = converter.convert() for f, img in output: @@ -1066,10 +1131,11 @@ def main(): def test(): logging.basicConfig(level=logging.INFO) f = "pngs/cogwheel.RGB565A8.png" - img = LVGLImage().from_png(f, cf=ColorFormat.RGB565, background=0xFF_FF_00) + img = LVGLImage().from_png(f, cf=ColorFormat.RGB888, background=0xFF_FF_00) img.adjust_stride(align=16) - img.to_bin(f + ".bin") - img.to_png(f + ".png") # convert back to png + img.set_compress(CompressMethod.RLE) + img.to_bin("output/cogwheel.RGB888.bin") + img.to_png("output/cogwheel.RGB888.png.png") # convert back to png if __name__ == "__main__": diff --git a/src/draw/lv_image_buf.h b/src/draw/lv_image_buf.h index 770da24c7..941b3603d 100644 --- a/src/draw/lv_image_buf.h +++ b/src/draw/lv_image_buf.h @@ -62,6 +62,13 @@ typedef enum _lv_image_flags_t { */ LV_IMAGE_FLAGS_VECTORS = 0x04, + /** + * The image data is compressed, so decoder needs to decode image firstly. + * If this flag is set, the whole image will be decompressed upon decode, and + * `get_area_cb` won't be necessary. + */ + LV_IMAGE_FLAGS_COMPRESSED = 0x08, + /** * Flags reserved for user, lvgl won't use these bits. */ @@ -75,6 +82,12 @@ typedef enum _lv_image_flags_t { LV_IMAGE_FLAGS_USER8 = 0x0800, } lv_image_flags_t; +typedef enum { + LV_IMAGE_COMPRESS_NONE = 0, + LV_IMAGE_COMPRESS_RLE, /*LVGL custom RLE compression*/ + LV_IMAGE_COMPRESS_LZ4, +} lv_image_compress_t; + /** * The first 8 bit is very important to distinguish the different source types. * For more info see `lv_image_get_src_type()` in lv_img.c diff --git a/src/libs/bin_decoder/lv_bin_decoder.c b/src/libs/bin_decoder/lv_bin_decoder.c index 8eaf2d00d..040adf060 100644 --- a/src/libs/bin_decoder/lv_bin_decoder.c +++ b/src/libs/bin_decoder/lv_bin_decoder.c @@ -10,6 +10,8 @@ #include "../../draw/lv_draw_image.h" #include "../../draw/lv_draw_buf.h" #include "../../stdlib/lv_string.h" +#include "../../stdlib/lv_sprintf.h" +#include "../../libs/rle/lv_rle.h" /********************* * DEFINES @@ -19,11 +21,25 @@ * TYPEDEFS **********************/ +/** + * Data format for compressed image data. + */ + +typedef struct _lv_image_compressed_t { + uint32_t method: 4; /*Compression method, see `lv_image_compress_t`*/ + uint32_t reserved : 28; /*Reserved to be used later*/ + uint32_t compressed_size; /*Compressed data size in byte*/ + uint32_t decompressed_size; /*Decompressed data size in byte*/ + const uint8_t * data; /*Compressed data*/ +} lv_image_compressed_t; + typedef struct { lv_fs_file_t * f; lv_color32_t * palette; uint8_t * img_data; lv_opa_t * opa; + uint8_t * decompressed; + lv_image_compressed_t compressed; } decoder_data_t; /********************** @@ -38,8 +54,11 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); static lv_result_t decode_indexed_line(lv_color_format_t color_format, const lv_color32_t * palette, int32_t x, int32_t w_px, const uint8_t * in, lv_color32_t * out); +static lv_result_t decode_compressed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc); -static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, uint8_t * buff, uint32_t btr, uint32_t * br); +static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, void * buff, uint32_t btr, uint32_t * br); + +static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image_compressed_t * compressed); /********************** * STATIC VARIABLES @@ -86,10 +105,8 @@ lv_result_t lv_bin_decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_src_t src_type = lv_image_src_get_type(src); if(src_type == LV_IMAGE_SRC_VARIABLE) { - header->w = ((lv_image_dsc_t *)src)->header.w; - header->h = ((lv_image_dsc_t *)src)->header.h; - header->cf = ((lv_image_dsc_t *)src)->header.cf; - header->stride = ((lv_image_dsc_t *)src)->header.stride; + lv_image_dsc_t * image = (lv_image_dsc_t *)src; + lv_memcpy(header, &image->header, sizeof(lv_image_header_t)); } else if(src_type == LV_IMAGE_SRC_FILE) { /*Support only "*.bin" files*/ @@ -170,23 +187,26 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d return LV_RESULT_INVALID; } - decoder_data->f = f; + decoder_data->f = f; /*Now free_decoder_data will take care of the file*/ lv_color_format_t cf = dsc->header.cf; - /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/ - if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { + res = decode_compressed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/ res = decode_indexed(decoder, dsc); } else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { res = decode_alpha_only(decoder, dsc); } #if LV_BIN_DECODER_RAM_LOAD - else if(cf == LV_COLOR_FORMAT_ARGB8888 || cf == LV_COLOR_FORMAT_XRGB8888 - || cf == LV_COLOR_FORMAT_RGB888 || cf == LV_COLOR_FORMAT_RGB565) { - res = decode_rgb(decoder, dsc); - } - else if(cf == LV_COLOR_FORMAT_RGB565A8) { + else if(cf == LV_COLOR_FORMAT_ARGB8888 \ + || cf == LV_COLOR_FORMAT_XRGB8888 \ + || cf == LV_COLOR_FORMAT_RGB888 \ + || cf == LV_COLOR_FORMAT_RGB565 \ + || cf == LV_COLOR_FORMAT_RGB565A8) { res = decode_rgb(decoder, dsc); } #else @@ -199,12 +219,16 @@ lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) { /*The variables should have valid data*/ - lv_image_dsc_t * img_dsc = (lv_image_dsc_t *)dsc->src; - if(img_dsc->data == NULL) { + lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src; + if(image->data == NULL) { return LV_RESULT_INVALID; } - lv_color_format_t cf = img_dsc->header.cf; + lv_color_format_t cf = image->header.cf; + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { + /*@todo*/ + res = LV_RESULT_INVALID; + } if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { /*Need decoder data to store converted image*/ decoder_data_t * decoder_data = get_decoder_data(dsc); @@ -404,6 +428,7 @@ static void free_decoder_data(lv_image_decoder_dsc_t * dsc) } lv_draw_buf_free(decoder_data->img_data); + lv_draw_buf_free(decoder_data->decompressed); lv_free(decoder_data->palette); lv_free(decoder_data); dsc->user_data = NULL; @@ -423,7 +448,13 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder const uint8_t * indexed_data = NULL; uint32_t stride = dsc->header.stride; - if(dsc->src_type == LV_IMAGE_SRC_FILE) { + bool is_compressed = dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED; + if(is_compressed) { + uint8_t * data = decoder_data->decompressed; + palette = (lv_color32_t *)data; + indexed_data = data + palette_len; + } + else if(dsc->src_type == LV_IMAGE_SRC_FILE) { /*read palette for indexed image*/ palette = lv_malloc(palette_len); LV_ASSERT_MALLOC(palette); @@ -496,14 +527,14 @@ static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder dsc->header.cf = LV_COLOR_FORMAT_ARGB8888; dsc->img_data = img_data; decoder_data->img_data = img_data; /*Free when decoder closes*/ - if(dsc->src_type == LV_IMAGE_SRC_FILE) { + if(dsc->src_type == LV_IMAGE_SRC_FILE && !is_compressed) { decoder_data->palette = (void *)palette; /*Free decoder data on close*/ lv_draw_buf_free((void *)indexed_data); } return LV_RESULT_OK; exit_with_buf: - if(dsc->src_type == LV_IMAGE_SRC_FILE) { + if(dsc->src_type == LV_IMAGE_SRC_FILE && !is_compressed) { lv_free((void *)palette); lv_draw_buf_free((void *)indexed_data); } @@ -570,7 +601,11 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco return LV_RESULT_INVALID; } - if(dsc->src_type == LV_IMAGE_SRC_FILE) { + if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) { + /*Copy from image data*/ + lv_memcpy(img_data, decoder_data->decompressed, file_len); + } + else if(dsc->src_type == LV_IMAGE_SRC_FILE) { res = fs_read_file_at(decoder_data->f, sizeof(lv_image_header_t), img_data, file_len, &rn); if(res != LV_FS_RES_OK || rn != file_len) { LV_LOG_WARN("Read header failed: %d", res); @@ -622,6 +657,87 @@ static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_deco return LV_RESULT_OK; } +static lv_result_t decode_compressed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc) +{ + uint32_t rn; + uint32_t len; + uint32_t compressed_len; + uint8_t * file_buf; + decoder_data_t * decoder_data = get_decoder_data(dsc); + lv_fs_file_t * f = decoder_data->f; + lv_result_t res; + lv_image_compressed_t * compressed = &decoder_data->compressed; + lv_memzero(compressed, sizeof(lv_image_compressed_t)); + + if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK || + lv_fs_tell(f, &compressed_len) != LV_FS_RES_OK) { + LV_LOG_WARN("Failed to get compressed file len"); + return LV_RESULT_INVALID; + } + + compressed_len -= sizeof(lv_image_header_t); + compressed_len -= 12; + + /*Read compress header*/ + len = 12; + res = fs_read_file_at(f, sizeof(lv_image_header_t), compressed, len, &rn); + if(res != LV_FS_RES_OK || rn != len) { + LV_LOG_WARN("Read compressed header failed: %d", res); + return LV_RESULT_INVALID; + } + + if(compressed->compressed_size != compressed_len) { + LV_LOG_WARN("Compressed size mismatch: %" LV_PRIu32" != %" LV_PRIu32, compressed->compressed_size, compressed_len); + return LV_RESULT_INVALID; + } + + file_buf = lv_malloc(compressed_len); + if(file_buf == NULL) { + LV_LOG_WARN("No memory for compressed file"); + return LV_RESULT_INVALID; + + } + + /*Continue to read the compressed data following compression header*/ + res = lv_fs_read(f, file_buf, compressed_len, &rn); + if(res != LV_FS_RES_OK || rn != compressed_len) { + LV_LOG_WARN("Read compressed file failed: %d", res); + lv_free(file_buf); + return LV_RESULT_INVALID; + } + + /*Decompress the image*/ + compressed->data = file_buf; + res = decompress_image(dsc, compressed); + compressed->data = NULL; /*No need to store the data any more*/ + lv_free(file_buf); + if(res != LV_RESULT_OK) { + LV_LOG_WARN("Decompress failed"); + return LV_RESULT_INVALID; + } + + /*Depends on the cf, need to further decode image like an C-array image*/ + lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src; + if(image->data == NULL) { + return LV_RESULT_INVALID; + } + + lv_color_format_t cf = dsc->header.cf; + if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + res = decode_indexed(decoder, dsc); + } + else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { + res = decode_alpha_only(decoder, dsc); + } + else { + /*The decompressed data is the original image data.*/ + dsc->img_data = decoder_data->decompressed; + res = LV_RESULT_OK; + } + + return res; +} + static lv_result_t decode_indexed_line(lv_color_format_t color_format, const lv_color32_t * palette, int32_t x, int32_t w_px, const uint8_t * in, lv_color32_t * out) { @@ -670,7 +786,7 @@ static lv_result_t decode_indexed_line(lv_color_format_t color_format, const lv_ return LV_RESULT_OK; } -static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, uint8_t * buff, uint32_t btr, uint32_t * br) +static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, void * buff, uint32_t btr, uint32_t * br) { lv_fs_res_t res; if(br) *br = 0; @@ -687,3 +803,50 @@ static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, uint8_t * buf return LV_FS_RES_OK; } + +static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image_compressed_t * compressed) +{ + /*Need to store decompressed data to decoder to free on close*/ + decoder_data_t * decoder_data = get_decoder_data(dsc); + if(decoder_data == NULL) { + return LV_RESULT_INVALID; + } + + uint8_t * decompressed; + uint32_t input_len = compressed->compressed_size; + uint32_t out_len = compressed->decompressed_size; + + /*Note, stride must match.*/ + decompressed = lv_draw_buf_malloc(out_len, dsc->header.cf); + if(decompressed == NULL) { + LV_LOG_WARN("No memory for decompressed image, input: %" LV_PRIu32 ", output: %" LV_PRIu32, input_len, out_len); + return LV_RESULT_INVALID; + } + + if(compressed->method == LV_IMAGE_COMPRESS_RLE) { +#if LV_USE_RLE + /*Compress always happen on byte*/ + uint32_t pixel_byte; + if(dsc->header.cf == LV_COLOR_FORMAT_RGB565A8) + pixel_byte = 2; + else + pixel_byte = (lv_color_format_get_bpp(dsc->header.cf) + 7) >> 3; + const uint8_t * input = compressed->data; + uint8_t * output = decompressed; + uint32_t len; + len = lv_rle_decompress(input, input_len, output, out_len, pixel_byte); + if(len != compressed->decompressed_size) { + LV_LOG_WARN("Decompress failed: %" LV_PRIu32 ", got: %" LV_PRIu32, out_len, len); + lv_draw_buf_free(decompressed); + return LV_RESULT_INVALID; + } +#else + LV_LOG_WARN("RLE decompress is not enabled"); + lv_draw_buf_free(decompressed); + return LV_RESULT_INVALID; +#endif + } + + decoder_data->decompressed = decompressed; /*Free on decoder close*/ + return LV_RESULT_OK; +} diff --git a/src/libs/rle/lv_rle.c b/src/libs/rle/lv_rle.c new file mode 100644 index 000000000..f19660b8b --- /dev/null +++ b/src/libs/rle/lv_rle.c @@ -0,0 +1,99 @@ +/** + * @file lv_rle.c + */ + +/********************* + * INCLUDES + *********************/ + +#include "../../stdlib/lv_string.h" +#include "lv_rle.h" + +#if LV_USE_RLE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +uint32_t lv_rle_decompress(const uint8_t * input, + uint32_t input_buff_len, uint8_t * output, + uint32_t output_buff_len, uint8_t blk_size) +{ + uint32_t ctrl_byte; + uint32_t rd_len = 0; + uint32_t wr_len = 0; + + while(rd_len < input_buff_len) { + ctrl_byte = input[0]; + rd_len++; + input++; + if(rd_len > input_buff_len) + return 0; + + if(ctrl_byte & 0x80) { + /* copy directly from input to output */ + uint32_t bytes = blk_size * (ctrl_byte & 0x7f); + rd_len += bytes; + if(rd_len > input_buff_len) + return 0; + + wr_len += bytes; + if(wr_len > output_buff_len) + return 0; + + lv_memcpy(output, input, bytes); + output += bytes; + input += bytes; + } + else { + rd_len += blk_size; + if(rd_len > input_buff_len) + return 0; + + wr_len += blk_size * ctrl_byte; + if(wr_len > output_buff_len) + return 0; + + if(blk_size == 1) { + /* optimize the most common case. */ + lv_memset(output, input[0], ctrl_byte); + output += ctrl_byte; + } + else { + for(uint32_t i = 0; i < ctrl_byte; i++) { + lv_memcpy(output, input, blk_size); + output += blk_size; + } + } + input += blk_size; + } + } + + return wr_len; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_RLE*/ diff --git a/src/libs/rle/lv_rle.h b/src/libs/rle/lv_rle.h new file mode 100644 index 000000000..a6298cbca --- /dev/null +++ b/src/libs/rle/lv_rle.h @@ -0,0 +1,46 @@ +/** + * @file lv_rle.h + * + */ + +#ifndef LV_RLE_H +#define LV_RLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../lvgl.h" + +#if LV_USE_RLE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +uint32_t lv_rle_decompress(const uint8_t * input, + uint32_t input_buff_len, uint8_t * output, + uint32_t output_buff_len, uint8_t blk_size); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_RLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_RLE_H*/ diff --git a/tests/ref_imgs/draw/image_format_rle_compressed.png b/tests/ref_imgs/draw/image_format_rle_compressed.png new file mode 100644 index 000000000..b41165fad Binary files /dev/null and b/tests/ref_imgs/draw/image_format_rle_compressed.png differ diff --git a/tests/ref_imgs/draw/image_format_rle_compressed_rotate.png b/tests/ref_imgs/draw/image_format_rle_compressed_rotate.png new file mode 100644 index 000000000..d06225348 Binary files /dev/null and b/tests/ref_imgs/draw/image_format_rle_compressed_rotate.png differ diff --git a/tests/ref_imgs/draw/image_format_rle_compressed_rotate_recolor.png b/tests/ref_imgs/draw/image_format_rle_compressed_rotate_recolor.png new file mode 100644 index 000000000..3211dfa88 Binary files /dev/null and b/tests/ref_imgs/draw/image_format_rle_compressed_rotate_recolor.png differ diff --git a/tests/src/test_cases/draw/test_image_formats.c b/tests/src/test_cases/draw/test_image_formats.c index 79de1ec99..4489e4a80 100644 --- a/tests/src/test_cases/draw/test_image_formats.c +++ b/tests/src/test_cases/draw/test_image_formats.c @@ -159,6 +159,7 @@ void test_image_built_in_decode_rotate_and_recolor(void) void test_image_rle_decode(void) { +#if LV_USE_RLE img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", false, false); img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", false, false); img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", false, false); @@ -174,10 +175,12 @@ void test_image_rle_decode(void) img_create("rleARGB8888", "A:src/test_files/binimages/cogwheel.ARGB8888.rle", false, false); TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle.png"); +#endif } void test_image_rle_decode_rotate(void) { +#if LV_USE_RLE img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", true, false); img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", true, false); img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", true, false); @@ -193,10 +196,12 @@ void test_image_rle_decode_rotate(void) img_create("rleARGB8888", "A:src/test_files/binimages/cogwheel.ARGB8888.rle", true, false); TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle_rotate.png"); +#endif } void test_image_rle_decode_rotate_recolor(void) { +#if LV_USE_RLE img_create("rleA1", "A:src/test_files/binimages/cogwheel.A1.rle", true, true); img_create("rleA2", "A:src/test_files/binimages/cogwheel.A2.rle", true, true); img_create("rleA4", "A:src/test_files/binimages/cogwheel.A4.rle", true, true); @@ -212,6 +217,70 @@ void test_image_rle_decode_rotate_recolor(void) img_create("rleARGB8888", "A:src/test_files/binimages/cogwheel.ARGB8888.rle", true, true); TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle_rotate_recolor.png"); +#endif +} + +void test_image_rle_compressed_decode(void) +{ +#if LV_USE_RLE + img_create("rleA1", "A:src/test_files/rle_compressed/cogwheel.A1.bin", false, false); + img_create("rleA2", "A:src/test_files/rle_compressed/cogwheel.A2.bin", false, false); + img_create("rleA4", "A:src/test_files/rle_compressed/cogwheel.A4.bin", false, false); + img_create("rleA8", "A:src/test_files/rle_compressed/cogwheel.A8.bin", false, false); + img_create("rleI1", "A:src/test_files/rle_compressed/cogwheel.I1.bin", false, false); + img_create("rleI2", "A:src/test_files/rle_compressed/cogwheel.I2.bin", false, false); + img_create("rleI4", "A:src/test_files/rle_compressed/cogwheel.I4.bin", false, false); + img_create("rleI8", "A:src/test_files/rle_compressed/cogwheel.I8.bin", false, false); + img_create("rleRGB565A8", "A:src/test_files/rle_compressed/cogwheel.RGB565A8.bin", false, false); + img_create("rleRGB565", "A:src/test_files/rle_compressed/cogwheel.RGB565.bin", false, false); + img_create("rleRGB888", "A:src/test_files/rle_compressed/cogwheel.RGB888.bin", false, false); + img_create("rleXRGB8888", "A:src/test_files/rle_compressed/cogwheel.XRGB8888.bin", false, false); + img_create("rleARGB8888", "A:src/test_files/rle_compressed/cogwheel.ARGB8888.bin", false, false); + + TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle_compressed.png"); +#endif +} + +void test_image_rle_compressed_decode_rotate(void) +{ +#if LV_USE_RLE + img_create("rleA1", "A:src/test_files/rle_compressed/cogwheel.A1.bin", true, false); + img_create("rleA2", "A:src/test_files/rle_compressed/cogwheel.A2.bin", true, false); + img_create("rleA4", "A:src/test_files/rle_compressed/cogwheel.A4.bin", true, false); + img_create("rleA8", "A:src/test_files/rle_compressed/cogwheel.A8.bin", true, false); + img_create("rleI1", "A:src/test_files/rle_compressed/cogwheel.I1.bin", true, false); + img_create("rleI2", "A:src/test_files/rle_compressed/cogwheel.I2.bin", true, false); + img_create("rleI4", "A:src/test_files/rle_compressed/cogwheel.I4.bin", true, false); + img_create("rleI8", "A:src/test_files/rle_compressed/cogwheel.I8.bin", true, false); + img_create("rleRGB565A8", "A:src/test_files/rle_compressed/cogwheel.RGB565A8.bin", true, false); + img_create("rleRGB565", "A:src/test_files/rle_compressed/cogwheel.RGB565.bin", true, false); + img_create("rleRGB888", "A:src/test_files/rle_compressed/cogwheel.RGB888.bin", true, false); + img_create("rleXRGB8888", "A:src/test_files/rle_compressed/cogwheel.XRGB8888.bin", true, false); + img_create("rleARGB8888", "A:src/test_files/rle_compressed/cogwheel.ARGB8888.bin", true, false); + + TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle_compressed_rotate.png"); +#endif +} + +void test_image_rle_compressed_decode_rotate_recolor(void) +{ +#if LV_USE_RLE + img_create("rleA1", "A:src/test_files/rle_compressed/cogwheel.A1.bin", true, true); + img_create("rleA2", "A:src/test_files/rle_compressed/cogwheel.A2.bin", true, true); + img_create("rleA4", "A:src/test_files/rle_compressed/cogwheel.A4.bin", true, true); + img_create("rleA8", "A:src/test_files/rle_compressed/cogwheel.A8.bin", true, true); + img_create("rleI1", "A:src/test_files/rle_compressed/cogwheel.I1.bin", true, true); + img_create("rleI2", "A:src/test_files/rle_compressed/cogwheel.I2.bin", true, true); + img_create("rleI4", "A:src/test_files/rle_compressed/cogwheel.I4.bin", true, true); + img_create("rleI8", "A:src/test_files/rle_compressed/cogwheel.I8.bin", true, true); + img_create("rleRGB565A8", "A:src/test_files/rle_compressed/cogwheel.RGB565A8.bin", true, true); + img_create("rleRGB565", "A:src/test_files/rle_compressed/cogwheel.RGB565.bin", true, true); + img_create("rleRGB888", "A:src/test_files/rle_compressed/cogwheel.RGB888.bin", true, true); + img_create("rleXRGB8888", "A:src/test_files/rle_compressed/cogwheel.XRGB8888.bin", true, true); + img_create("rleARGB8888", "A:src/test_files/rle_compressed/cogwheel.ARGB8888.bin", true, true); + + TEST_ASSERT_EQUAL_SCREENSHOT("draw/image_format_rle_compressed_rotate_recolor.png"); +#endif } #endif diff --git a/tests/src/test_files/rle_compressed/cogwheel.A1.bin b/tests/src/test_files/rle_compressed/cogwheel.A1.bin new file mode 100644 index 000000000..baeee9182 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.A1.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.A2.bin b/tests/src/test_files/rle_compressed/cogwheel.A2.bin new file mode 100644 index 000000000..d71b47867 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.A2.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.A4.bin b/tests/src/test_files/rle_compressed/cogwheel.A4.bin new file mode 100644 index 000000000..b6d6fb843 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.A4.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.A8.bin b/tests/src/test_files/rle_compressed/cogwheel.A8.bin new file mode 100644 index 000000000..4ff27ce07 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.A8.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.ARGB8888.bin b/tests/src/test_files/rle_compressed/cogwheel.ARGB8888.bin new file mode 100644 index 000000000..f8f1e3217 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.ARGB8888.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.I1.bin b/tests/src/test_files/rle_compressed/cogwheel.I1.bin new file mode 100644 index 000000000..1367d8f4a Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.I1.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.I2.bin b/tests/src/test_files/rle_compressed/cogwheel.I2.bin new file mode 100644 index 000000000..2eddaae1e Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.I2.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.I4.bin b/tests/src/test_files/rle_compressed/cogwheel.I4.bin new file mode 100644 index 000000000..e2a90be4d Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.I4.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.I8.bin b/tests/src/test_files/rle_compressed/cogwheel.I8.bin new file mode 100644 index 000000000..df2d90d85 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.I8.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.RGB565.bin b/tests/src/test_files/rle_compressed/cogwheel.RGB565.bin new file mode 100644 index 000000000..45ec73c41 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.RGB565.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.RGB565A8.bin b/tests/src/test_files/rle_compressed/cogwheel.RGB565A8.bin new file mode 100644 index 000000000..8bb285ff7 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.RGB565A8.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.RGB888.bin b/tests/src/test_files/rle_compressed/cogwheel.RGB888.bin new file mode 100644 index 000000000..3e654cbb4 Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.RGB888.bin differ diff --git a/tests/src/test_files/rle_compressed/cogwheel.XRGB8888.bin b/tests/src/test_files/rle_compressed/cogwheel.XRGB8888.bin new file mode 100644 index 000000000..c42f5210a Binary files /dev/null and b/tests/src/test_files/rle_compressed/cogwheel.XRGB8888.bin differ