add some code
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
idf_component_register(SRCS "tjpgd_test.c" "test_tjpgd_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES "unity"
|
||||
WHOLE_ARCHIVE
|
||||
EMBED_FILES "logo.jpg" "usb_camera.jpg" "usb_camera_2.jpg")
|
||||
@@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
espressif/esp_jpeg:
|
||||
version: "*"
|
||||
override_path: "../../"
|
||||
@@ -0,0 +1,64 @@
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def jpg_to_rgb888_hex_c_array(input_filename: str, output_filename: str) -> str:
|
||||
"""
|
||||
Convert a .jpg file to RGB888 hex data and format it as a C-style array.
|
||||
|
||||
Parameters:
|
||||
input_filename (str): The path to the JPEG file.
|
||||
|
||||
Returns:
|
||||
str: A string representing the RGB888 hex data formatted as a C array.
|
||||
"""
|
||||
# Open the image file
|
||||
with Image.open(input_filename) as img:
|
||||
# Ensure the image is in RGB mode
|
||||
rgb_img = img.convert("RGB")
|
||||
|
||||
# Get image dimensions
|
||||
width, height = rgb_img.size
|
||||
|
||||
# List to store hex values as C-style entries
|
||||
hex_data = []
|
||||
|
||||
# Iterate over each pixel to get RGB values
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
r, g, b = rgb_img.getpixel((x, y))
|
||||
# Format each RGB value as C-style hex (e.g., 0xRRGGBB)
|
||||
hex_data.append(f"0x{r:02X}{g:02X}{b:02X}")
|
||||
|
||||
# Format as a C-style array with line breaks for readability
|
||||
hex_array = ",\n ".join(hex_data)
|
||||
c_array = f"unsigned int image_data[{width * height}] = {{\n {hex_array}\n}};"
|
||||
|
||||
# Write the C array to the output file
|
||||
with open(output_filename, "w") as file:
|
||||
file.write(c_array)
|
||||
|
||||
print(f"C-style RGB888 hex array saved to {output_filename}")
|
||||
|
||||
return c_array
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to convert a JPEG file to an RGB888 C-style hex array.
|
||||
|
||||
Instructions:
|
||||
1. Replace 'input.jpg' with the path to your JPEG file.
|
||||
2. Run the script to get the C-style array output.
|
||||
"""
|
||||
# Input JPEG file path
|
||||
input_filename = "usb_camera.jpg" # Replace with your JPEG file path
|
||||
|
||||
# Output file path for the C array
|
||||
output_filename = "output_array.c" # Specify your desired output filename
|
||||
|
||||
# Convert JPEG to C-style RGB888 hex array
|
||||
jpg_to_rgb888_hex_c_array(input_filename, output_filename)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
managed_components/espressif__esp_jpeg/test_apps/main/logo.jpg
Normal file
BIN
managed_components/espressif__esp_jpeg/test_apps/main/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,7 @@
|
||||
// JPEG encoded image 46x46, 7561 bytes
|
||||
extern const unsigned char logo_jpg[] asm("_binary_logo_jpg_start");
|
||||
|
||||
extern char _binary_logo_jpg_start;
|
||||
extern char _binary_logo_jpg_end;
|
||||
// Must be defined as macro because extern variables are not known at compile time (but at link time)
|
||||
#define logo_jpg_len (&_binary_logo_jpg_end - &_binary_logo_jpg_start)
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_newlib.h"
|
||||
|
||||
#include "unity_test_utils_memory.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
unity_utils_evaluate_leaks_direct(0);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Running esp_jpeg component tests\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Raw data from Logitech C170 USB camera was reconstructed to usb_camera_2.jpg
|
||||
It was converted to RGB888 array with jpg_to_rgb888_hex.py
|
||||
*/
|
||||
|
||||
// JPEG encoded frame 160x120, 1384 bytes, has broken 0xFFFF marker
|
||||
extern const unsigned char camera_2_jpg[] asm("_binary_usb_camera_2_jpg_start");
|
||||
|
||||
extern char _binary_usb_camera_2_jpg_start;
|
||||
extern char _binary_usb_camera_2_jpg_end;
|
||||
// Must be defined as macro because extern variables are not known at compile time (but at link time)
|
||||
#define camera_2_jpg_len (&_binary_usb_camera_2_jpg_end - &_binary_usb_camera_2_jpg_start)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Raw data from Logitech C270 USB camera was reconstructed to usb_camera.jpg
|
||||
It was converted to RGB888 array with jpg_to_rgb888_hex.py
|
||||
*/
|
||||
|
||||
// JPEG encoded frame 160x120, 2632 bytes, no huffman tables, double block size (16x8 pixels)
|
||||
extern const unsigned char jpeg_no_huffman[] asm("_binary_usb_camera_jpg_start");
|
||||
|
||||
extern char _binary_usb_camera_jpg_start;
|
||||
extern char _binary_usb_camera_jpg_end;
|
||||
// Must be defined as macro because extern variables are not known at compile time (but at link time)
|
||||
#define jpeg_no_huffman_len (&_binary_usb_camera_jpg_end - &_binary_usb_camera_jpg_start)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
|
||||
|
||||
#include "jpeg_decoder.h"
|
||||
#include "test_logo_jpg.h"
|
||||
#include "test_logo_rgb888.h"
|
||||
#include "test_usb_camera_2_jpg.h"
|
||||
#include "test_usb_camera_2_rgb888.h"
|
||||
|
||||
#define TESTW 46
|
||||
#define TESTH 46
|
||||
|
||||
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 decoded_outsize = TESTW * TESTH * 3;
|
||||
|
||||
decoded = malloc(decoded_outsize);
|
||||
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,
|
||||
}
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
esp_jpeg_print_ascii(decoded, &outimg);
|
||||
|
||||
free(decoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief JPEG unknown size test
|
||||
*
|
||||
* This test case verifies the functionality of the JPEG decompression library
|
||||
* when decoding an image with unknown size. The image is decoded from a
|
||||
* JPEG file, and the output size is determined dynamically. The test checks
|
||||
* that the decoded image dimensions match the expected values and that the
|
||||
* pixel data is within an acceptable tolerance range.
|
||||
*/
|
||||
TEST_CASE("Test JPEG unknown size", "[esp_jpeg]")
|
||||
{
|
||||
unsigned char *decoded, *p;
|
||||
const unsigned char *o;
|
||||
|
||||
/* JPEG decode */
|
||||
esp_jpeg_image_cfg_t jpeg_cfg = {
|
||||
.indata = (uint8_t *)logo_jpg,
|
||||
.indata_size = logo_jpg_len,
|
||||
.out_format = JPEG_IMAGE_FORMAT_RGB888,
|
||||
};
|
||||
|
||||
// 1. Get required output size
|
||||
esp_jpeg_image_output_t outimg;
|
||||
esp_err_t err = esp_jpeg_get_image_info(&jpeg_cfg, &outimg);
|
||||
TEST_ASSERT_EQUAL(err, ESP_OK);
|
||||
TEST_ASSERT_EQUAL(TESTW * TESTH * 3, outimg.output_len);
|
||||
TEST_ASSERT_EQUAL(outimg.width, TESTW);
|
||||
TEST_ASSERT_EQUAL(outimg.height, TESTH);
|
||||
|
||||
// 2. Allocate output buffer and assign it to the config
|
||||
decoded = malloc(outimg.output_len);
|
||||
TEST_ASSERT_NOT_NULL(decoded);
|
||||
jpeg_cfg.outbuf = decoded;
|
||||
jpeg_cfg.outbuf_size = outimg.output_len;
|
||||
|
||||
// 3. Decode the image
|
||||
err = esp_jpeg_decode(&jpeg_cfg, &outimg);
|
||||
TEST_ASSERT_EQUAL(err, ESP_OK);
|
||||
|
||||
/* Decoded image size */
|
||||
TEST_ASSERT_EQUAL(TESTW * TESTH * 3, outimg.output_len);
|
||||
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(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);
|
||||
}
|
||||
|
||||
#if CONFIG_JD_DEFAULT_HUFFMAN
|
||||
#include "test_usb_camera_jpg.h"
|
||||
#include "test_usb_camera_rgb888.h"
|
||||
|
||||
/**
|
||||
* @brief Test for JPEG decompression without Huffman tables
|
||||
*
|
||||
* This test case verifies the functionality of the JPEG decompression library
|
||||
* when decoding an image that lacks Huffman tables, such as a USB frame
|
||||
* from a Logitech C270 USB camera. The image was reconstructed from raw USB data
|
||||
* (using `hex_to_jpg.py`) and then converted into an RGB888 C-style array
|
||||
* (using `jpg_to_rgb888_hex.py`).
|
||||
*
|
||||
* Due to the unique structure of the JPEG data (double block size, 16x8 pixels)
|
||||
* and absence of Huffman tables, this test assesses whether the decompression
|
||||
* library correctly decodes the image and outputs RGB888 pixel data within
|
||||
* an acceptable tolerance range.
|
||||
*
|
||||
* The test performs the following steps:
|
||||
* - Allocates a buffer for the decoded image.
|
||||
* - Configures and runs the JPEG decoder with the RGB888 output format.
|
||||
* - Checks that the decoded image dimensions match expected values.
|
||||
* - Compares the decompressed image data against the reference RGB888 data,
|
||||
* allowing a tolerance of ±16 in each color component due to potential
|
||||
* differences in Huffman tables or decompression accuracy.
|
||||
*
|
||||
* @note This test allows a margin of error in pixel values due to potential
|
||||
* differences in how color data is interpreted across different decoders.
|
||||
*
|
||||
* @param None
|
||||
*
|
||||
* @return None
|
||||
*
|
||||
* @test Requirements:
|
||||
* - JPEG decompression library support for images without Huffman tables.
|
||||
* - JPEG decompression accuracy within acceptable error margins.
|
||||
*/
|
||||
TEST_CASE("Test JPEG decompression library: No Huffman tables", "[esp_jpeg]")
|
||||
{
|
||||
unsigned char *decoded, *p;
|
||||
const unsigned int *o;
|
||||
int decoded_outsize = 160 * 120 * 3;
|
||||
|
||||
decoded = malloc(decoded_outsize);
|
||||
|
||||
/* JPEG decode */
|
||||
esp_jpeg_image_cfg_t jpeg_cfg = {
|
||||
.indata = (uint8_t *)jpeg_no_huffman,
|
||||
.indata_size = jpeg_no_huffman_len,
|
||||
.outbuf = decoded,
|
||||
.outbuf_size = decoded_outsize,
|
||||
.out_format = JPEG_IMAGE_FORMAT_RGB888,
|
||||
.out_scale = JPEG_IMAGE_SCALE_0,
|
||||
.flags = {
|
||||
.swap_color_bytes = 0,
|
||||
}
|
||||
};
|
||||
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, 160);
|
||||
TEST_ASSERT_EQUAL(outimg.height, 120);
|
||||
|
||||
p = decoded;
|
||||
o = jpeg_no_huffman_rgb888;
|
||||
for (int x = 0; x < outimg.width * outimg.height; x++) {
|
||||
/* The color can be +- 16 */
|
||||
// Here we allow bigger decoding error
|
||||
// It might be that the Windows decoder used slightly different Huffman tables
|
||||
TEST_ASSERT_UINT8_WITHIN(16, (*o) & 0xff, p[0]);
|
||||
TEST_ASSERT_UINT8_WITHIN(16, (*o >> 8) & 0xff, p[1]);
|
||||
TEST_ASSERT_UINT8_WITHIN(16, (*o >> 16) & 0xff, p[2]);
|
||||
|
||||
p += 3; // this is uint8_t
|
||||
o ++; // this is unt32_t
|
||||
}
|
||||
|
||||
free(decoded);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Invalid JPEG marker test
|
||||
*
|
||||
* This test case verifies the behavior of the JPEG decompression library
|
||||
* when encountering an invalid marker (0xFFFF) in the JPEG data stream.
|
||||
* The test uses a known JPEG image (camera_2_jpg) that contains this invalid
|
||||
* marker. The test checks whether the library can handle the invalid marker
|
||||
* gracefully and still decode the image correctly.
|
||||
*/
|
||||
TEST_CASE("Test JPEG invalid marker 0xFFFF", "[esp_jpeg]")
|
||||
{
|
||||
unsigned char *decoded;
|
||||
int decoded_outsize = 160 * 120 * 3;
|
||||
|
||||
decoded = malloc(decoded_outsize);
|
||||
assert(decoded);
|
||||
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 *)camera_2_jpg,
|
||||
.indata_size = camera_2_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,
|
||||
}
|
||||
};
|
||||
esp_jpeg_image_output_t outimg;
|
||||
esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
/* Decoded image size */
|
||||
TEST_ASSERT_EQUAL(160, outimg.width);
|
||||
TEST_ASSERT_EQUAL(120, outimg.height);
|
||||
|
||||
free(decoded);
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Reference in New Issue
Block a user