Skip to content

Commit

Permalink
Merge pull request #444 from espressif/feature/esp_jpeg_configurable_…
Browse files Browse the repository at this point in the history
…pool

feat(esp_jpeg): Add configuration option for working buffer size
  • Loading branch information
tore-espressif authored Nov 11, 2024
2 parents d3e5a00 + a24c4bc commit d402e9c
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 18 deletions.
28 changes: 28 additions & 0 deletions esp_jpeg/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## 1.2.0

- Added option to for passing user defined working buffer

## 1.1.0

- Added support for decoding images without Huffman tables
- Fixed undefined configuration options from Kconfig

## 1.0.5~3

- Added option to swap output color bytes regardless of JD_FORMAT

## 1.0.4

- Added ROM implementation support for ESP32-C6

## 1.0.2

- Fixed compiler warnings

## 1.0.1

- Fixed: exclude ESP32-C2 from list of ROM implementations

## 1.0.0

- Initial version
1 change: 1 addition & 0 deletions esp_jpeg/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# JPEG Decoder: TJpgDec - Tiny JPEG Decompressor

[![Component Registry](https://components.espressif.com/components/espressif/esp_jpeg/badge.svg)](https://components.espressif.com/components/espressif/esp_jpeg)
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)

TJpgDec is a lightweight JPEG image decompressor optimized for embedded systems with minimal memory consumption.

Expand Down
4 changes: 4 additions & 0 deletions esp_jpeg/examples/get_started/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
#
CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y
2 changes: 1 addition & 1 deletion esp_jpeg/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "1.1.0"
version: "1.2.0"
description: "JPEG Decoder: TJpgDec"
url: https://github.com/espressif/idf-extra-components/tree/master/esp_jpeg/
dependencies:
Expand Down
7 changes: 7 additions & 0 deletions esp_jpeg/include/jpeg_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ typedef struct esp_jpeg_image_cfg_s {
uint8_t swap_color_bytes: 1; /*!< Swap first and last color bytes */
} flags;

struct {
void *working_buffer; /*!< If set to NULL, a working buffer will be allocated in esp_jpeg_decode().
Tjpgd does not use dynamic allocation, se we pass this buffer to Tjpgd that uses it as scratchpad */
size_t working_buffer_size; /*!< Size of the working buffer. Must be set it working_buffer != NULL.
Default size is 3.1kB or 65kB if JD_FASTDECODE == 2 */
} advanced;

struct {
uint32_t read; /*!< Internal count of read bytes */
} priv;
Expand Down
16 changes: 12 additions & 4 deletions esp_jpeg/jpeg_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,21 @@ esp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *im
assert(cfg != NULL);
assert(img != NULL);

workbuf = heap_caps_malloc(JPEG_WORK_BUF_SIZE, MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(workbuf, ESP_ERR_NO_MEM, err, TAG, "no mem for JPEG work buffer");
const bool allocate_buffer = (cfg->advanced.working_buffer == NULL);
const size_t workbuf_size = allocate_buffer ? JPEG_WORK_BUF_SIZE : cfg->advanced.working_buffer_size;
if (allocate_buffer) {
workbuf = heap_caps_malloc(JPEG_WORK_BUF_SIZE, MALLOC_CAP_DEFAULT);
ESP_GOTO_ON_FALSE(workbuf, ESP_ERR_NO_MEM, err, TAG, "no mem for JPEG work buffer");
} else {
workbuf = cfg->advanced.working_buffer;
ESP_RETURN_ON_FALSE(workbuf_size != 0, ESP_ERR_INVALID_ARG, TAG, "Working buffer size not defined!");
}


cfg->priv.read = 0;

/* Prepare image */
res = jd_prepare(&JDEC, jpeg_decode_in_cb, workbuf, JPEG_WORK_BUF_SIZE, cfg);
res = jd_prepare(&JDEC, jpeg_decode_in_cb, workbuf, workbuf_size, cfg);
ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, "Error in preparing JPEG image! %d", res);

uint8_t scale_div = jpeg_get_div_by_scale(cfg->out_scale);
Expand All @@ -104,7 +112,7 @@ esp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *im
ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, "Error in decoding JPEG image! %d", res);

err:
if (workbuf) {
if (workbuf && allocate_buffer) {
free(workbuf);
}

Expand Down
86 changes: 73 additions & 13 deletions esp_jpeg/test_apps/main/tjpgd_test.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
Expand All @@ -18,16 +18,29 @@
#define TESTW 46
#define TESTH 46

TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
void esp_jpeg_print_ascii(unsigned char *rgb888, esp_jpeg_image_output_t *outimg)
{
char aapix[] = " .:;+=xX$$";
unsigned char *p = rgb888 + 2;

for (int y = 0; y < outimg->width; y++) {
for (int x = 0; x < outimg->height; x++) {
int v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
p += 3;
}
printf("%c%c", ' ', '\n');
}
}

TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
{
unsigned char *decoded, *p;
const unsigned char *o;
int x, y, v;
int decoded_outsize = TESTW * TESTH * 3;

decoded = malloc(decoded_outsize);
for (x = 0; x < decoded_outsize; x += 2) {
for (int x = 0; x < decoded_outsize; x += 2) {
decoded[x] = 0;
decoded[x + 1] = 0xff;
}
Expand All @@ -54,7 +67,7 @@ TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")

p = decoded;
o = logo_rgb888;
for (x = 0; x < outimg.width * outimg.height; x++) {
for (int x = 0; x < outimg.width * outimg.height; x++) {
/* The color can be +- 2 */
TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);
TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);
Expand All @@ -64,17 +77,64 @@ TEST_CASE("Test JPEG decompression library", "[esp_jpeg]")
o += 3;
}

p = decoded + 2;
for (y = 0; y < outimg.width; y++) {
for (x = 0; x < outimg.height; x++) {
v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
p += 3;
}
printf("%c%c", ' ', '\n');
esp_jpeg_print_ascii(decoded, &outimg);

free(decoded);
}

#define WORKING_BUFFER_SIZE 4096
TEST_CASE("Test JPEG decompression library: User defined working buffer", "[esp_jpeg]")
{
unsigned char *decoded, *p;
const unsigned char *o;
int decoded_outsize = TESTW * TESTH * 3;

decoded = malloc(decoded_outsize);
uint8_t *working_buf = malloc(WORKING_BUFFER_SIZE);
assert(decoded);
assert(working_buf);

for (int x = 0; x < decoded_outsize; x += 2) {
decoded[x] = 0;
decoded[x + 1] = 0xff;
}

/* JPEG decode */
esp_jpeg_image_cfg_t jpeg_cfg = {
.indata = (uint8_t *)logo_jpg,
.indata_size = logo_jpg_len,
.outbuf = decoded,
.outbuf_size = decoded_outsize,
.out_format = JPEG_IMAGE_FORMAT_RGB888,
.out_scale = JPEG_IMAGE_SCALE_0,
.flags = {
.swap_color_bytes = 0,
},
.advanced = {
.working_buffer = working_buf,
.working_buffer_size = WORKING_BUFFER_SIZE,
},
};
esp_jpeg_image_output_t outimg;
esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);
TEST_ASSERT_EQUAL(err, ESP_OK);

/* Decoded image size */
TEST_ASSERT_EQUAL(outimg.width, TESTW);
TEST_ASSERT_EQUAL(outimg.height, TESTH);

p = decoded;
o = logo_rgb888;
for (int x = 0; x < outimg.width * outimg.height; x++) {
/* The color can be +- 2 */
TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);
TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);
TEST_ASSERT_UINT8_WITHIN(2, o[2], p[2]);

p += 3;
o += 3;
}
free(working_buf);
free(decoded);
}

Expand Down

0 comments on commit d402e9c

Please sign in to comment.