Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Icons: compression fixes & larger dimension support #3564

Merged
merged 53 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4054a17
toolbox, gui: fixes for compressed icon handling
hedger Mar 26, 2024
b9d8817
ufbt: fixes for generated vscode project
hedger Mar 27, 2024
4c6ef6d
scripts: increased max dimensions for image converter
hedger Mar 27, 2024
e61ac14
icon type changes
hedger Mar 29, 2024
fcedddd
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
hedger Apr 2, 2024
b44702b
linter fixes; api sync
hedger Apr 2, 2024
eddc988
gui: docs fix
hedger Apr 2, 2024
a3f46e9
toolbox: fixed potential decoder buffer overflow
hedger Apr 2, 2024
f31c302
minor cleanup
hedger Apr 2, 2024
6902ab6
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
hedger Apr 5, 2024
03ba7fe
Merged branch "dev"
hedger Apr 23, 2024
0a46d18
Merge branch 'dev' into hedger/icomp_fixes
hedger May 8, 2024
aeaee57
Merge branch 'dev' into hedger/icomp_fixes
skotopes May 13, 2024
7522792
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
hedger May 13, 2024
be7918b
fbt: sdk: suppressed deprecation warnings in API table
hedger May 13, 2024
7761197
Merge branch 'dev' into hedger/icomp_fixes
hedger May 13, 2024
332fcf1
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
skotopes May 15, 2024
90ee800
toolbox: compress: added unit tests
hedger May 16, 2024
53d5475
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
hedger May 16, 2024
0b1d735
toolbox: compress: review fixes, pt 1
hedger May 16, 2024
e93dca0
compress: now passes decoder buffer size as constructor argument; aut…
hedger May 17, 2024
3110e05
PVS fixes
hedger May 17, 2024
4f66e70
Merge remote-tracking branch 'origin/dev' into hedger/icomp_fixes
hedger May 17, 2024
41ef256
pvs fixes, pt2
hedger May 17, 2024
cc57870
doxygen fixes
hedger May 17, 2024
0f815bd
Merge branch 'dev' into hedger/icomp_fixes
hedger May 17, 2024
869790e
investigating unit test failures
hedger May 17, 2024
4390492
investigating unit test failures
hedger May 17, 2024
d70e9c1
investigating unit test failures
hedger May 17, 2024
52f79a5
investigating unit test failures
hedger May 17, 2024
d1619db
investigating unit test failures
hedger May 17, 2024
8e4c614
Merge branch 'dev' into hedger/icomp_fixes
skotopes May 19, 2024
31b322c
UnitTests: move all tests into plugins, brakes testing
skotopes May 19, 2024
d63aace
UnitTests: add plugin API and update plugin entrypoints
skotopes May 19, 2024
7ef041b
UniTests: Test runner that works with plugins
skotopes May 19, 2024
c875c2e
fbt: extra filtering for extapps to include in build
hedger May 19, 2024
64e695f
UnitTests: filter tests by name
skotopes May 19, 2024
cc9d928
loader: restored API table for unit_test build config
hedger May 19, 2024
6ebf6e5
Add various missing symbols to API table
skotopes May 19, 2024
b9add3d
UnitTest: fail on plugin load error
skotopes May 19, 2024
f5f1fe6
UnitTests: cleanup plugin api and reporting
skotopes May 19, 2024
0413ea5
unit_tests: composite resolver
hedger May 19, 2024
6074036
UnitTests: remove unused declaration
skotopes May 19, 2024
03ff9b8
unit_tests, nfc: moved mock nfc implementation to libnfc
hedger May 19, 2024
193ec61
unit_tests: api: removed redundant #define
hedger May 19, 2024
7962fb8
toolbox: compress: removed size_hint for icons; triggering furi_check…
hedger May 20, 2024
a3a8418
gui: icon, icon_animation: removed size hit APIs
hedger May 20, 2024
6f4b3ba
Format Sources. Cleanup code.
skotopes May 20, 2024
93f2ab4
loader: refuse to start .fal as app
hedger May 20, 2024
303b740
toolbox: compress: fixed memory corruption in operations with small d…
hedger May 20, 2024
0ef0b18
unit_tests: proper test skipping; better selective test interface
hedger May 20, 2024
7827588
unit_tests: moved 'loading' logging to proper location
hedger May 20, 2024
8c1b68a
Merge branch 'dev' into hedger/icomp_fixes
hedger May 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/example/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"label": "[Debug:unit_tests] Flash (USB)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb"
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb_full"
},
{
"label": "[Debug] Flash (USB, with resources)",
Expand Down
2 changes: 1 addition & 1 deletion applications/debug/unit_tests/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ App(
apptype=FlipperAppType.STARTUP,
entry_point="unit_tests_on_system_start",
cdefines=["APP_UNIT_TESTS"],
requires=["system_settings"],
requires=["system_settings", "subghz_start"],
provides=["delay_test"],
resources="resources",
order=100,
Expand Down
140 changes: 140 additions & 0 deletions applications/debug/unit_tests/compress/compress_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include "../minunit.h"

#include <toolbox/compress.h>

#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_random.h>

#include <storage/storage.h>

#include <stdint.h>

#define COMPRESS_UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/compress/" path)

static void compress_test_reference_comp_decomp() {
Storage* storage = furi_record_open(RECORD_STORAGE);

File* compressed_file = storage_file_alloc(storage);
File* decompressed_file = storage_file_alloc(storage);

mu_assert(
storage_file_open(
compressed_file,
COMPRESS_UNIT_TESTS_PATH("compressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open compressed file");
mu_assert(
storage_file_open(
decompressed_file,
COMPRESS_UNIT_TESTS_PATH("uncompressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open decompressed file");

uint64_t compressed_ref_size = storage_file_size(compressed_file);
uint64_t decompressed_ref_size = storage_file_size(decompressed_file);

mu_assert(compressed_ref_size > 0 && decompressed_ref_size > 0, "Invalid file sizes");

uint8_t* compressed_ref_buff = malloc(compressed_ref_size);
uint8_t* decompressed_ref_buff = malloc(decompressed_ref_size);

mu_assert(
storage_file_read(compressed_file, compressed_ref_buff, compressed_ref_size) ==
compressed_ref_size,
"Failed to read compressed file");

mu_assert(
storage_file_read(decompressed_file, decompressed_ref_buff, decompressed_ref_size) ==
decompressed_ref_size,
"Failed to read decompressed file");

storage_file_free(compressed_file);
storage_file_free(decompressed_file);
furi_record_close(RECORD_STORAGE);

uint8_t* temp_buffer = malloc(1024);
Compress* comp = compress_alloc(1024);

size_t encoded_size = 0;
mu_assert(
compress_encode(
comp, decompressed_ref_buff, decompressed_ref_size, temp_buffer, 1024, &encoded_size),
"Compress failed");

mu_assert(encoded_size == compressed_ref_size, "Encoded size is not equal to reference size");

mu_assert(
memcmp(temp_buffer, compressed_ref_buff, compressed_ref_size) == 0,
"Encoded buffer is not equal to reference");

size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, compressed_ref_buff, compressed_ref_size, temp_buffer, 1024, &decoded_size),
"Decompress failed");

mu_assert(
decoded_size == decompressed_ref_size, "Decoded size is not equal to reference size");

mu_assert(
memcmp(temp_buffer, decompressed_ref_buff, decompressed_ref_size) == 0,
"Decoded buffer is not equal to reference");

compress_free(comp);

free(temp_buffer);
free(compressed_ref_buff);
free(decompressed_ref_buff);
}

static void compress_test_random_comp_decomp() {
static const size_t src_buffer_size = 1024;
static const size_t encoded_buffer_size = 1024;

// We only fill half of the buffer with random data, so if anything goes wrong, there's no overflow
static const size_t src_data_size = src_buffer_size / 2;

Compress* comp = compress_alloc(src_buffer_size);
uint8_t* src_buff = malloc(src_buffer_size);
uint8_t* encoded_buff = malloc(encoded_buffer_size);
uint8_t* decoded_buff = malloc(src_buffer_size);

furi_hal_random_fill_buf(src_buff, src_data_size);

size_t encoded_size = 0;

mu_assert(
compress_encode(
comp, src_buff, src_data_size, encoded_buff, encoded_buffer_size, &encoded_size),
"Compress failed");

size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, encoded_buff, encoded_size, decoded_buff, src_buffer_size + 4, &decoded_size),
"Decompress failed");

mu_assert(decoded_size == src_data_size, "Decoded size is not equal to source size");

mu_assert(
memcmp(src_buff, decoded_buff, src_data_size) == 0,
"Decoded buffer is not equal to source");

free(src_buff);
free(encoded_buff);
free(decoded_buff);
compress_free(comp);
}

MU_TEST_SUITE(test_compress) {
MU_RUN_TEST(compress_test_random_comp_decomp);
MU_RUN_TEST(compress_test_reference_comp_decomp);
}

int run_minunit_test_compress(void) {
MU_RUN_SUITE(test_compress);
return MU_EXIT_CODE;
}
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions applications/debug/unit_tests/test_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ int run_minunit_test_float_tools(void);
int run_minunit_test_bt(void);
int run_minunit_test_dialogs_file_browser_options(void);
int run_minunit_test_expansion(void);
int run_minunit_test_compress(void);

typedef int (*UnitTestEntry)(void);

Expand Down Expand Up @@ -64,6 +65,7 @@ const UnitTest unit_tests[] = {
{.name = "dialogs_file_browser_options",
.entry = run_minunit_test_dialogs_file_browser_options},
{.name = "expansion", .entry = run_minunit_test_expansion},
{.name = "compress", .entry = run_minunit_test_compress},
};

void minunit_print_progress(void) {
Expand Down
1 change: 0 additions & 1 deletion applications/services/desktop/helpers/slideshow.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "slideshow.h"

#include <stddef.h>
#include <storage/storage.h>
#include <gui/icon.h>
#include <gui/icon_i.h>
Expand Down
22 changes: 17 additions & 5 deletions applications/services/gui/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const CanvasFontParameters canvas_font_params[FontTotalNumber] = {

Canvas* canvas_init(void) {
Canvas* canvas = malloc(sizeof(Canvas));
canvas->compress_icon = compress_icon_alloc();
canvas->compress_icon = compress_icon_alloc(ICON_DECOMPRESSOR_BUFFER_SIZE);

// Initialize mutex
canvas->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
Expand Down Expand Up @@ -248,7 +248,8 @@ void canvas_draw_bitmap(
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* bitmap_data = NULL;
compress_icon_decode(canvas->compress_icon, compressed_bitmap_data, &bitmap_data);
compress_icon_decode(
canvas->compress_icon, compressed_bitmap_data, &bitmap_data, (width + 7) / 8 * height);
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, IconRotation0);
}

Expand All @@ -264,7 +265,10 @@ void canvas_draw_icon_animation(
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(
canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data);
canvas->compress_icon,
icon_animation_get_data(icon_animation),
&icon_data,
icon_animation_get_decode_size(icon_animation));
canvas_draw_u8g2_bitmap(
&canvas->fb,
x,
Expand Down Expand Up @@ -390,7 +394,11 @@ void canvas_draw_icon_ex(
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
compress_icon_decode(
canvas->compress_icon,
icon_get_frame_data(icon, 0),
&icon_data,
icon_get_decode_size(icon));
canvas_draw_u8g2_bitmap(
&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, rotation);
}
Expand All @@ -402,7 +410,11 @@ void canvas_draw_icon(Canvas* canvas, int32_t x, int32_t y, const Icon* icon) {
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
compress_icon_decode(
canvas->compress_icon,
icon_get_frame_data(icon, 0),
&icon_data,
icon_get_decode_size(icon));
canvas_draw_u8g2_bitmap(
&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, IconRotation0);
}
Expand Down
2 changes: 2 additions & 0 deletions applications/services/gui/canvas_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <m-algo.h>
#include <furi.h>

#define ICON_DECOMPRESSOR_BUFFER_SIZE (128u * 64 / 8)

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
23 changes: 20 additions & 3 deletions applications/services/gui/icon.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#include "icon.h"
#include "icon_i.h"
#include <furi.h>

uint8_t icon_get_width(const Icon* instance) {
#include <furi.h>

uint16_t icon_get_width(const Icon* instance) {
furi_check(instance);

return instance->width;
}

uint8_t icon_get_height(const Icon* instance) {
uint16_t icon_get_height(const Icon* instance) {
furi_check(instance);

return instance->height;
Expand All @@ -16,5 +19,19 @@ uint8_t icon_get_height(const Icon* instance) {
const uint8_t* icon_get_data(const Icon* instance) {
furi_check(instance);

return instance->frames[0];
return icon_get_frame_data(instance, 0);
}

uint32_t icon_get_frame_count(const Icon* instance) {
return instance->frame_count;
}

const uint8_t* icon_get_frame_data(const Icon* instance, uint32_t frame) {
furi_check(frame < instance->frame_count);
return instance->frames[frame];
}

uint32_t icon_get_decode_size(const Icon* instance) {
/* Packing 8 pixels per byte. Each row is padded to the nearest byte */
return ((instance->width + 7) / 8) * instance->height;
}
36 changes: 31 additions & 5 deletions applications/services/gui/icon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#pragma once

#include <stdint.h>
#include <core/common_defines.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -19,23 +20,48 @@ typedef struct Icon Icon;
*
* @return width in pixels
*/
uint8_t icon_get_width(const Icon* instance);
uint16_t icon_get_width(const Icon* instance);

/** Get icon height
*
* @param[in] instance pointer to Icon data
*
* @return height in pixels
*/
uint8_t icon_get_height(const Icon* instance);
uint16_t icon_get_height(const Icon* instance);

/** Get Icon XBM bitmap data
/** Get Icon XBM bitmap data for the first frame
*
* @param[in] instance pointer to Icon data
*
* @return pointer to XBM bitmap data
* @return pointer to compressed XBM bitmap data
*/
const uint8_t* icon_get_data(const Icon* instance);
FURI_DEPRECATED const uint8_t* icon_get_data(const Icon* instance);
skotopes marked this conversation as resolved.
Show resolved Hide resolved

/** Get Icon frame count
*
* @param[in] instance pointer to Icon data
*
* @return frame count
*/
uint32_t icon_get_frame_count(const Icon* instance);

/** Get Icon XBM bitmap data for a particular frame
*
* @param[in] instance pointer to Icon data
* @param[in] frame frame index
*
* @return pointer to compressed XBM bitmap data
*/
const uint8_t* icon_get_frame_data(const Icon* instance, uint32_t frame);

/** Get estimate for decoded icon size
*
* @param[in] instance pointer to Icon data
*
* @return size in bytes
*/
uint32_t icon_get_decode_size(const Icon* instance);

#ifdef __cplusplus
}
Expand Down
5 changes: 5 additions & 0 deletions applications/services/gui/icon_animation.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ uint8_t icon_animation_get_height(const IconAnimation* instance) {
return instance->icon->height;
}

uint32_t icon_animation_get_decode_size(const IconAnimation* instance) {
furi_assert(instance);
return icon_get_decode_size(instance->icon);
}

void icon_animation_start(IconAnimation* instance) {
furi_check(instance);

Expand Down
8 changes: 8 additions & 0 deletions applications/services/gui/icon_animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ void icon_animation_stop(IconAnimation* instance);
*/
bool icon_animation_is_last_frame(const IconAnimation* instance);

/** Get IconAnimation frame buffer size
*
* @param instance IconAnimation instance
*
* @return frame size, in bytes
*/
uint32_t icon_animation_get_decode_size(const IconAnimation* instance);

#ifdef __cplusplus
}
#endif
6 changes: 3 additions & 3 deletions applications/services/gui/icon_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*/

#pragma once
#include "icon.h"
#include <stdint.h>

struct Icon {
const uint8_t width;
const uint8_t height;
const uint16_t width;
const uint16_t height;
const uint8_t frame_count;
const uint8_t frame_rate;
const uint8_t* const* frames;
Expand Down
Loading
Loading