Add PNG Support

This commit is contained in:
Kwabena W. Agyeman 2022-01-23 19:16:07 -08:00 committed by iabdalkader
parent 4dac638338
commit f12a4659c8
17 changed files with 559 additions and 168 deletions

View File

@ -73,6 +73,7 @@ SRCS += $(addprefix imlib/, \
jpegd.c \
jpeg.c \
lodepng.c \
png.c \
kmeans.c \
lab_tab.c \
lbp.c \

View File

@ -149,4 +149,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -146,4 +146,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -149,4 +149,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -149,4 +149,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -149,4 +149,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -149,4 +149,8 @@
// Enable STM32 DMA2D
#define IMLIB_ENABLE_DMA2D
// Enable PNG encoder/decoder
#define IMLIB_ENABLE_PNG_ENCODER
#define IMLIB_ENABLE_PNG_DECODER
#endif //__IMLIB_CONFIG_H__

View File

@ -2695,7 +2695,8 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
}
// Special destination?
bool is_jpeg = (src_img->pixfmt == PIXFORMAT_JPEG);
bool is_jpeg = src_img->pixfmt == PIXFORMAT_JPEG;
bool is_png = src_img->pixfmt == PIXFORMAT_PNG;
// Best format to convert yuv/bayer/jpeg image to.
int new_not_mutable_pixfmt = (rgb_channel != -1) ? PIXFORMAT_RGB565 :
(color_palette ? PIXFORMAT_GRAYSCALE :
@ -2726,7 +2727,7 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
bool is_color_conversion_scaling = is_color_conversion && is_scaling;
// Make a deep copy of the source image.
if (need_deep_copy || is_color_conversion_scaling || is_jpeg) {
if (need_deep_copy || is_color_conversion_scaling || is_jpeg || is_png) {
new_src_img.w = src_img->w; // same width as source image
new_src_img.h = src_img->h; // same height as source image
@ -2743,6 +2744,8 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_binary(&new_src_img, src_img);
} else if (is_png) {
png_decompress(&new_src_img, src_img);
}
break;
}
@ -2753,6 +2756,8 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_grayscale(&new_src_img, src_img);
} else if (is_png) {
png_decompress(&new_src_img, src_img);
}
break;
}
@ -2763,6 +2768,8 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
imlib_deyuv_image(&new_src_img, src_img);
} else if (is_jpeg) {
jpeg_decompress_image_to_rgb565(&new_src_img, src_img);
} else if (is_png) {
png_decompress(&new_src_img, src_img);
}
break;
}
@ -2772,6 +2779,9 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
break;
}
default : {
if (is_png) {
png_decompress(&new_src_img, src_img);
}
break;
}
}

View File

@ -138,7 +138,7 @@ void framebuffer_update_jpeg_buffer()
if (src->pixfmt != PIXFORMAT_INVALID &&
framebuffer->streaming_enabled && jpeg_framebuffer->enabled) {
if (src->pixfmt == PIXFORMAT_JPEG) {
if (src->is_compressed) {
bool does_not_fit = false;
if (mutex_try_lock_alternate(&jpeg_framebuffer->lock, MUTEX_TID_OMV)) {
@ -154,7 +154,7 @@ void framebuffer_update_jpeg_buffer()
}
if (does_not_fit) {
printf("Warning: JPEG too big! Trying framebuffer transfer using fallback method!\n");
printf("Warning: JPEG/PNG too big! Trying framebuffer transfer using fallback method!\n");
int new_size = fb_encode_for_ide_new_size(src);
fb_alloc_mark();
uint8_t *temp = fb_alloc(new_size, FB_ALLOC_NO_HINT);

View File

@ -268,7 +268,7 @@ size_t image_size(image_t *ptr)
case PIXFORMAT_YUV_ANY: { // re-use
return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h;
}
case PIXFORMAT_JPEG: {
case PIXFORMAT_COMPRESSED_ANY: {
return ptr->size;
}
default: {
@ -506,6 +506,12 @@ static save_image_format_t imblib_parse_extension(image_t *img, const char *path
&& ((p[-4] == '.') || (p[-4] == '.'))) {
// Will convert to JPG if not.
return FORMAT_JPG;
} else if (((p[-1] == 'g') || (p[-1] == 'G'))
&& ((p[-2] == 'n') || (p[-2] == 'N'))
&& ((p[-3] == 'p') || (p[-3] == 'P'))
&& ((p[-4] == '.') || (p[-4] == '.'))) {
// Will convert to PNG if not.
return FORMAT_PNG;
} else if (((p[-1] == 'p') || (p[-1] == 'P'))
&& ((p[-2] == 'm') || (p[-2] == 'M'))
&& ((p[-3] == 'b') || (p[-3] == 'B'))
@ -547,8 +553,8 @@ static save_image_format_t imblib_parse_extension(image_t *img, const char *path
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs)
{
file_read_open(fp, path);
char magic[2];
read_data(fp, &magic, 2);
char magic[4];
read_data(fp, &magic, 4);
file_close(fp);
bool vflipped = false;
@ -570,6 +576,12 @@ bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_setti
// Do not use file_buffer_on() here.
jpeg_read_geometry(fp, img, path, &rs->jpg_rs);
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
} else if ((magic[0]==0x89) && (magic[1]==0x50) && (magic[2]==0x4E) && (magic[3]==0x47)) { // PNG
rs->format = FORMAT_PNG;
file_read_open(fp, path);
// Do not use file_buffer_on() here.
png_read_geometry(fp, img, path, &rs->png_rs);
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
} else {
ff_unsupported_format(NULL);
}
@ -721,8 +733,8 @@ void imlib_load_image(image_t *img, const char *path)
{
FIL fp;
file_read_open(&fp, path);
char magic[2];
read_data(&fp, &magic, 2);
char magic[4];
read_data(&fp, &magic, 4);
file_close(&fp);
if ((magic[0]=='P')
@ -733,6 +745,8 @@ void imlib_load_image(image_t *img, const char *path)
bmp_read(img, path);
} else if ((magic[0]==0xFF) && (magic[1]==0xD8)) { // JPEG
jpeg_read(img, path);
} else if ((magic[0]==0x89) && (magic[1]==0x50) && (magic[2]==0x4E) && (magic[3]==0x47)) { // PNG
png_read(img, path);
} else {
ff_unsupported_format(NULL);
}
@ -758,13 +772,20 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
case FORMAT_JPG:
jpeg_write(img, path, quality);
break;
case FORMAT_PNG:
png_write(img, path);
break;
case FORMAT_DONT_CARE:
// Path doesn't have an extension.
if (IM_IS_JPEG(img)) {
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5, FB_ALLOC_NO_HINT), path), ".jpg");
jpeg_write(img, new_path, quality);
fb_free();
} else if (IM_IS_BAYER(img)) {
} else if (img->pixfmt == PIXFORMAT_PNG) {
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5, FB_ALLOC_NO_HINT), path), ".png");
png_write(img, new_path);
fb_free();
}else if (IM_IS_BAYER(img)) {
FIL fp;
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5, FB_ALLOC_NO_HINT), path), ".raw");
file_write_open(&fp, new_path);

View File

@ -344,6 +344,8 @@ typedef enum {
PIXFORMAT_ID_BAYER = 4,
PIXFORMAT_ID_YUV422 = 5,
PIXFORMAT_ID_JPEG = 6,
PIXFORMAT_ID_PNG = 7,
PIXFORMAT_ID_ARGB8 = 8,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_id_t;
@ -368,6 +370,7 @@ typedef enum {
PIXFORMAT_BPP_RGB565 = 2,
PIXFORMAT_BPP_BAYER = 1,
PIXFORMAT_BPP_YUV422 = 2,
PIXFORMAT_BPP_ARGB8 = 4,
/* Note: Update PIXFORMAT_IS_VALID when adding new formats */
} pixformat_bpp_t;
@ -388,25 +391,29 @@ typedef enum {
// <RESERVED> YF MF CF JF RF <PIXFORMAT_ID> <SUBFORMAT_ID> <BYTES_PER_PIX>
// NOTE: Bit 31-30 must Not be used for pixformat_t to be used as mp_int_t.
typedef enum {
PIXFORMAT_INVALID = (0),
PIXFORMAT_INVALID = (0x00000000U),
PIXFORMAT_BINARY = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_BINARY << 16) | (0 << 8) | PIXFORMAT_BPP_BINARY ),
PIXFORMAT_GRAYSCALE = (PIXFORMAT_FLAGS_M | (PIXFORMAT_ID_GRAY << 16) | (SUBFORMAT_ID_GRAY8 << 8) | PIXFORMAT_BPP_GRAY8 ),
PIXFORMAT_RGB565 = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_RGB565 << 16) | (0 << 8) | PIXFORMAT_BPP_RGB565 ),
PIXFORMAT_ARGB8 = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_ARGB8 << 16) | (0 << 8) | PIXFORMAT_BPP_ARGB8 ),
PIXFORMAT_BAYER = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_BGGR = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_BGGR << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GBRG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GBRG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_GRBG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_GRBG << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_BAYER_RGGB = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER << 16) | (SUBFORMAT_ID_RGGB << 8) | PIXFORMAT_BPP_BAYER ),
PIXFORMAT_YUV = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YUV422 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_YUV422 = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YUV422 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_YVU422 = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YVU422 << 8) | PIXFORMAT_BPP_YUV422 ),
PIXFORMAT_JPEG = (PIXFORMAT_FLAGS_CJ | (PIXFORMAT_ID_JPEG << 16) | (0 << 8) | 0 ),
PIXFORMAT_LAST = 0xFFFFFFFFU,
PIXFORMAT_PNG = (PIXFORMAT_FLAGS_CJ | (PIXFORMAT_ID_PNG << 16) | (0 << 8) | 0 ),
PIXFORMAT_LAST = (0xFFFFFFFFU),
} pixformat_t;
#define PIXFORMAT_MUTABLE_ANY \
PIXFORMAT_BINARY: \
case PIXFORMAT_GRAYSCALE: \
case PIXFORMAT_RGB565 \
case PIXFORMAT_RGB565: \
case PIXFORMAT_ARGB8 \
#define PIXFORMAT_BAYER_ANY \
PIXFORMAT_BAYER_BGGR: \
@ -418,17 +425,23 @@ typedef enum {
PIXFORMAT_YUV422: \
case PIXFORMAT_YVU422 \
#define PIXFORMAT_COMPRESSED_ANY \
PIXFORMAT_JPEG: \
case PIXFORMAT_PNG \
#define IMLIB_PIXFORMAT_IS_VALID(x) \
((x == PIXFORMAT_BINARY) \
|| (x == PIXFORMAT_GRAYSCALE) \
|| (x == PIXFORMAT_RGB565) \
|| (x == PIXFORMAT_ARGB8) \
|| (x == PIXFORMAT_BAYER_BGGR) \
|| (x == PIXFORMAT_BAYER_GBRG) \
|| (x == PIXFORMAT_BAYER_GRBG) \
|| (x == PIXFORMAT_BAYER_RGGB) \
|| (x == PIXFORMAT_YUV422) \
|| (x == PIXFORMAT_YVU422) \
|| (x == PIXFORMAT_JPEG)) \
|| (x == PIXFORMAT_JPEG) \
|| (x == PIXFORMAT_PNG)) \
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define PIXFORMAT_STRUCT \
@ -864,11 +877,18 @@ typedef struct jpg_read_settings {
int32_t jpg_size;
} jpg_read_settings_t;
typedef struct png_read_settings {
int32_t png_w;
int32_t png_h;
int32_t png_size;
} png_read_settings_t;
typedef enum save_image_format {
FORMAT_DONT_CARE,
FORMAT_BMP,
FORMAT_PNM,
FORMAT_JPG,
FORMAT_PNG,
FORMAT_RAW,
} save_image_format_t;
@ -877,6 +897,7 @@ typedef struct img_read_settings {
bmp_read_settings_t bmp_rs;
ppm_read_settings_t ppm_rs;
jpg_read_settings_t jpg_rs;
png_read_settings_t png_rs;
};
save_image_format_t format;
} img_read_settings_t;
@ -1113,6 +1134,12 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
void jpeg_read_pixels(FIL *fp, image_t *img);
void jpeg_read(image_t *img, const char *path);
void jpeg_write(image_t *img, const char *path, int quality);
void png_decompress(image_t *dst, image_t *src);
bool png_compress(image_t *src, image_t *dst);
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs);
void png_read_pixels(FIL *fp, image_t *img);
void png_read(image_t *img, const char *path);
void png_write(image_t *img, const char *path);
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs);
void imlib_image_operation(image_t *img, const char *path, image_t *other, int scalar, line_op_t op, void *data);
void imlib_load_image(image_t *img, const char *path);

View File

@ -1064,6 +1064,8 @@ bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc)
JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE;
JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING;
break;
default:
break;
}
if (memcmp(&JPEG_Config, &JPEG_Info, sizeof(JPEG_ConfTypeDef))) {
@ -1089,6 +1091,10 @@ bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc)
dst->data = fb_alloc(dst->size, FB_ALLOC_PREFER_SIZE | FB_ALLOC_CACHE_ALIGN);
}
if (src->is_compressed) {
return true;
}
// Compute size of the APP0 header with cache alignment padding.
int app0_size = sizeof(JPEG_APP0);
int app0_unalign_size = app0_size % __SCB_DCACHE_LINE_SIZE;
@ -1840,6 +1846,10 @@ bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc)
dst->size = IMLIB_IMAGE_MAX_SIZE(size);
}
if (src->is_compressed) {
return true;
}
// JPEG buffer
jpeg_buf_t jpeg_buf = {
.idx = 0,

337
src/omv/imlib/png.c Normal file
View File

@ -0,0 +1,337 @@
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* PNG CODEC
*/
#include <stdio.h>
#include "imlib.h"
#include "py/mphal.h"
#include "py/runtime.h"
#include "ff_wrapper.h"
#if defined(IMLIB_ENABLE_PNG_ENCODER) || defined(IMLIB_ENABLE_PNG_DECODER)
#include "lodepng.h"
#include "umm_malloc.h"
#define TIME_PNG (0)
void* lodepng_malloc(size_t size)
{
return umm_malloc(size);
}
void* lodepng_realloc(void* ptr, size_t new_size)
{
return umm_realloc(ptr, new_size);
}
void lodepng_free(void* ptr)
{
return umm_free(ptr);
}
unsigned lodepng_convert_cb(unsigned char* out, const unsigned char* in,
const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h)
{
unsigned error = 0;
unsigned numpixels = w * h;
if (mode_in->colortype == LCT_CUSTOM) {
// Compression.
// Note: we're always encoding to 8 bits.
switch (mode_in->customfmt) {
case PIXFORMAT_RGB565: {
uint16_t *pixels = (uint16_t*) in;
if (mode_out->colortype == LCT_RGB) {
// RGB565 -> RGB888
for (int i=0; i < numpixels; i++, out += 3) {
out[0] = COLOR_RGB565_TO_R8(pixels[i]);
out[1] = COLOR_RGB565_TO_G8(pixels[i]);
out[2] = COLOR_RGB565_TO_B8(pixels[i]);
}
} else if (mode_out->colortype == LCT_RGBA) {
// RGB565 -> RGBA888
for (int i=0; i < numpixels; i++, out += 4) {
out[0] = COLOR_RGB565_TO_R8(pixels[i]);
out[1] = COLOR_RGB565_TO_G8(pixels[i]);
out[2] = COLOR_RGB565_TO_B8(pixels[i]);
out[3] = 255;
}
} else {
error = 56; // unsupported color mode conversion.
}
break;
}
case PIXFORMAT_YUV_ANY:
// YUV -> RGB888
case PIXFORMAT_BAYER_ANY:
// BAYER -> RGB888
default:
error = 56; // unsupported color mode conversion.
break;
}
} else if (mode_out->colortype == LCT_CUSTOM) {
// Decompression.
// NOTE: decode from 16 bits needs to be implemented.
switch (mode_out->customfmt) {
case PIXFORMAT_RGB565: {
uint16_t *pixels = (uint16_t*) out;
if (mode_in->colortype == LCT_RGB) {
// RGB888 -> RGB565
for (int i=0; i < numpixels; i++, in += 3) {
pixels[i] = COLOR_R8_G8_B8_TO_RGB565(in[0], in[1], in[2]);
}
} else if (mode_in->colortype == LCT_RGBA) {
// RGBA888 -> RGB565
for (int i=0; i < numpixels; i++, in += 4) {
pixels[i] = COLOR_R8_G8_B8_TO_RGB565(in[0], in[1], in[2]);
}
} else if (mode_in->colortype == LCT_GREY && mode_in->bitdepth == 8) {
// GRAYSCALE -> RGB565
for (int i=0; i < numpixels; i++, in ++) {
pixels[i] = COLOR_R8_G8_B8_TO_RGB565(in[0], in[0], in[0]);
}
} else {
error = 56; // unsupported color mode conversion.
}
break;
}
default:
error = 56; // unsupported color mode conversion.
break;
}
} else {
error = 56; // unsupported color mode conversion.
}
return error;
}
#if defined(IMLIB_ENABLE_PNG_ENCODER)
bool png_compress(image_t *src, image_t *dst)
{
#if (TIME_PNG==1)
mp_uint_t start = mp_hal_ticks_ms();
#endif
if (src->is_compressed) {
return true;
}
umm_init_x(fb_avail());
LodePNGState state;
lodepng_state_init(&state);
// Invoked on custom formats.
state.lodepng_convert = &lodepng_convert_cb;
// Faster compression.
state.encoder.zlibsettings.windowsize = 1024;
switch (src->pixfmt) {
case PIXFORMAT_BINARY:
state.info_raw.bitdepth = 1;
state.info_raw.colortype = LCT_GREY;
state.encoder.auto_convert = false;
state.info_png.color.bitdepth = 8;
state.info_png.color.colortype = LCT_GREY;
break;
case PIXFORMAT_GRAYSCALE:
state.info_raw.bitdepth = 8;
state.info_raw.colortype = LCT_GREY;
state.encoder.auto_convert = false;
state.info_png.color.bitdepth = 8;
state.info_png.color.colortype = LCT_GREY;
break;
case PIXFORMAT_RGB565:
state.info_raw.bitdepth = 16;
state.info_raw.colortype = LCT_CUSTOM;
state.info_raw.customfmt = PIXFORMAT_RGB565;
state.encoder.auto_convert = false;
state.info_png.color.bitdepth = 8;
state.info_png.color.colortype = LCT_RGB;
break;
case PIXFORMAT_YUV_ANY:
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Input format is not supported"));
break;
case PIXFORMAT_BAYER_ANY:
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Input format is not supported"));
break;
}
size_t png_size = 0;
uint8_t *png_data = NULL;
unsigned error = lodepng_encode(&png_data, &png_size, src->data, src->w, src->h, &state);
lodepng_state_cleanup(&state);
if (error) {
mp_raise_msg(&mp_type_RuntimeError, (mp_rom_error_text_t) lodepng_error_text(error));
}
if (dst->data == NULL) {
dst->data = png_data;
dst->size = png_size;
// fb_alloc() memory ill be free'd by called.
} else {
if (image_size(dst) <= png_size) {
dst->size = png_size;
memcpy(dst->data, png_data, png_size);
} else {
mp_raise_msg_varg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Failed to compress image in place"));
}
// free fb_alloc() memory used for umm_init_x().
fb_free(); // umm_init_x();
}
#if (TIME_PNG==1)
printf("time: %u ms\n", mp_hal_ticks_ms() - start);
#endif
return false;
}
#endif // IMLIB_ENABLE_PNG_ENCODER
#if defined(IMLIB_ENABLE_PNG_DECODER)
void png_decompress(image_t *dst, image_t *src)
{
#if (TIME_PNG==1)
mp_uint_t start = mp_hal_ticks_ms();
#endif
umm_init_x(fb_avail());
LodePNGState state;
lodepng_state_init(&state);
// Invoked on custom formats.
state.lodepng_convert = &lodepng_convert_cb;
switch (dst->pixfmt) {
case PIXFORMAT_BINARY:
state.info_raw.bitdepth = 1;
state.info_raw.colortype = LCT_GREY;
break;
case PIXFORMAT_GRAYSCALE:
state.info_raw.bitdepth = 8;
state.info_raw.colortype = LCT_GREY;
break;
case PIXFORMAT_RGB565:
state.info_raw.bitdepth = 16;
state.info_raw.colortype = LCT_CUSTOM;
state.info_raw.customfmt = PIXFORMAT_RGB565;
break;
}
uint8_t *png_data = NULL;
uint32_t img_size = image_size(dst);
unsigned error = lodepng_decode(&png_data, (unsigned *) &dst->w, (unsigned *) &dst->h, &state, src->data, src->size);
lodepng_state_cleanup(&state);
if (error) {
mp_raise_msg(&mp_type_RuntimeError, (mp_rom_error_text_t) lodepng_error_text(error));
}
uint32_t new_img_size = image_size(dst);
if (new_img_size <= img_size) {
memcpy(dst->data, png_data, new_img_size);
} else {
mp_raise_msg_varg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Failed to compress image in place"));
}
// free fb_alloc() memory used for umm_init_x().
fb_free(); // umm_init_x();
#if (TIME_PNG==1)
printf("time: %u ms\n", mp_hal_ticks_ms() - start);
#endif
}
#endif // IMLIB_ENABLE_PNG_DECODER
#endif // IMLIB_ENABLE_PNG_ENCODER || IMLIB_ENABLE_PNG_DECODER
#if !defined(IMLIB_ENABLE_PNG_ENCODER)
bool png_compress(image_t *src, image_t *dst)
{
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("PNG encoder is not enabled"));
}
#endif
#if !defined(IMLIB_ENABLE_PNG_DECODER)
void png_decompress(image_t *dst, image_t *src)
{
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("PNG decoder is not enabled"));
}
#endif
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
// This function inits the geometry values of an image.
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs)
{
uint32_t header;
file_seek(fp, 12); // start of IHDR
read_long(fp, &header);
if (header == 0x52444849) { // IHDR
uint32_t width, height;
read_long(fp, &width);
read_long(fp, &height);
width = __builtin_bswap32(width);
height = __builtin_bswap32(height);
rs->png_w = width;
rs->png_h = height;
rs->png_size = IMLIB_IMAGE_MAX_SIZE(f_size(fp));
img->w = rs->png_w;
img->h = rs->png_h;
img->size = rs->png_size;
img->pixfmt = PIXFORMAT_PNG;
} else {
ff_file_corrupted(fp);
}
}
// This function reads the pixel values of an image.
void png_read_pixels(FIL *fp, image_t *img)
{
file_seek(fp, 0);
read_data(fp, img->pixels, img->size);
}
void png_read(image_t *img, const char *path)
{
FIL fp;
png_read_settings_t rs;
file_read_open(&fp, path);
// Do not use file_buffer_on() here.
png_read_geometry(&fp, img, path, &rs);
if (!img->pixels) {
img->pixels = xalloc(img->size);
}
png_read_pixels(&fp, img);
file_close(&fp);
}
void png_write(image_t *img, const char *path)
{
FIL fp;
file_write_open(&fp, path);
if (img->pixfmt == PIXFORMAT_PNG) {
write_data(&fp, img->pixels, img->size);
} else {
image_t out = { .w=img->w, .h=img->h, .pixfmt=PIXFORMAT_PNG, .size=0, .pixels=NULL }; // alloc in png compress
png_compress(img, &out);
write_data(&fp, out.pixels, out.size);
fb_free(); // frees alloc in png_compress()
}
file_close(&fp);
}
#endif //IMLIB_ENABLE_IMAGE_FILE_IO)

View File

@ -280,8 +280,8 @@ mp_obj_t py_image_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
switch (op) {
case MP_UNARY_OP_LEN: {
image_t *img = &self->_cobj;
if (img->pixfmt == PIXFORMAT_JPEG) {
// For JPEG images we create a 1D array.
if (img->is_compressed) {
// For JPEG/PNG images we create a 1D array.
return mp_obj_new_int(img->size);
} else {
// For other formats, 2D array is created.
@ -338,7 +338,7 @@ STATIC mp_obj_t py_image_it_iternext(mp_obj_t self_in)
return row;
}
}
default: {// JPEG
default: { // JPEG/PNG
if (self->cur >= img->size) {
return MP_OBJ_STOP_ITERATION;
} else {
@ -362,7 +362,7 @@ STATIC mp_obj_t py_image_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf)
static void py_image_print(const mp_print_t *print, mp_obj_t self, mp_print_kind_t kind)
{
image_t *image = py_image_cobj(self);
if (image->pixfmt == PIXFORMAT_JPEG
if (image->is_compressed
&& image->pixels[0] == 0xFE
&& image->pixels[image->size-1] == 0xFE) {
// print for ide.
@ -380,7 +380,8 @@ static void py_image_print(const mp_print_t *print, mp_obj_t self, mp_print_kind
(image->pixfmt == PIXFORMAT_BAYER_RGGB) ? "bayer_rggb" :
(image->pixfmt == PIXFORMAT_YUV422) ? "yuv422" :
(image->pixfmt == PIXFORMAT_YVU422) ? "yvu422" :
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" : "unknown",
(image->pixfmt == PIXFORMAT_JPEG) ? "jpeg" :
(image->pixfmt == PIXFORMAT_PNG) ? "png" : "unknown",
image_size(image));
}
}
@ -457,7 +458,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_obj_new_int(COLOR_RGB565_TO_B8(p))});
}
}
case PIXFORMAT_JPEG: {
case PIXFORMAT_JPEG:
case PIXFORMAT_PNG: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->size, index, &slice)) {
@ -587,7 +589,8 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
IMAGE_PUT_RGB565_PIXEL(image, i % image->w, i / image->w, p);
return mp_const_none;
}
case PIXFORMAT_JPEG: {
case PIXFORMAT_JPEG:
case PIXFORMAT_PNG: {
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(image->size, index, &slice)) {
@ -666,8 +669,12 @@ static mp_obj_t py_image_format(mp_obj_t img_obj)
return mp_obj_new_int(PIXFORMAT_BAYER);
case PIXFORMAT_YUV_ANY:
return mp_obj_new_int(PIXFORMAT_YUV422);
default:
case PIXFORMAT_JPEG:
return mp_obj_new_int(PIXFORMAT_JPEG);
case PIXFORMAT_PNG:
return mp_obj_new_int(PIXFORMAT_PNG);
default:
return mp_obj_new_int(PIXFORMAT_INVALID);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
@ -908,7 +915,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midp
#endif // IMLIB_ENABLE_MIDPOINT_POOLING
static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_palette, bool copy_to_fb,
uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
mp_obj_t copy_default, bool encode_for_ide_default, uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *src_img = py_image_cobj(args[0]);
@ -967,15 +974,22 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
}
mp_obj_t copy_obj = py_helper_keyword_object(n_args, args, 11, kw_args,
MP_OBJ_NEW_QSTR(copy_to_fb ? MP_QSTR_copy_to_fb : MP_QSTR_copy), NULL);
MP_OBJ_NEW_QSTR(copy_to_fb ? MP_QSTR_copy_to_fb : MP_QSTR_copy), copy_default);
bool copy = false;
image_t *arg_other = copy_to_fb ? NULL : src_img;
int arg_q = py_helper_keyword_int(n_args, args, 12, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 90);
if ((arg_q < 1) || (100 < arg_q)) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("1 <= quality <= 100!"));
}
bool arg_e = py_helper_keyword_int(n_args, args, 13, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_encode_for_ide), encode_for_ide_default);
if (copy_obj) {
if (mp_obj_is_integer(copy_obj)) {
copy = mp_obj_get_int(copy_obj);
} else {
arg_other = py_helper_arg_to_image_not_compressed(copy_obj);
arg_other = py_image_cobj(copy_obj);
}
}
@ -986,11 +1000,13 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
image_t dst_img = {
.w = fast_floorf(arg_roi.w * arg_x_scale),
.h = fast_floorf(arg_roi.h * arg_y_scale),
.size = src_img->size,
.pixfmt = (pixfmt == PIXFORMAT_INVALID) ? src_img->pixfmt : pixfmt,
.size = src_img->size,
.pixels = NULL,
};
image_t dst_img_tmp = dst_img;
if (dst_img.is_bayer) {
if (((arg_x_scale != 1) && (arg_x_scale != -1)) ||
((arg_y_scale != 1) && (arg_y_scale != -1)) ||
@ -1071,18 +1087,50 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
IMAGE_HINT_EXTRACT_RGB_CHANNEL_FIRST |
IMAGE_HINT_APPLY_COLOR_PALETTE_FIRST);
}
} else if (dst_img.pixfmt == PIXFORMAT_JPEG) {
if ((arg_x_scale != 1) ||
(arg_y_scale != 1) ||
(arg_roi.x != 0) ||
(arg_roi.y != 0) ||
(arg_roi.w != src_img->w) ||
(arg_roi.h != src_img->h) ||
(arg_rgb_channel != -1) ||
(arg_alpha != 256) ||
(color_palette != NULL) ||
(alpha_palette != NULL)) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Only jpeg copying is supported!"));
} else if (dst_img.is_compressed) {
fb_alloc_mark();
bool simple = (arg_x_scale == 1) &&
(arg_y_scale == 1) &&
(arg_roi.x == 0) &&
(arg_roi.y == 0) &&
(arg_roi.w == src_img->w) &&
(arg_roi.h == src_img->h) &&
(arg_rgb_channel == -1) &&
(arg_alpha == 256) &&
(color_palette == NULL) &&
(alpha_palette == NULL);
if ((dst_img.pixfmt != src_img->pixfmt) || (!simple)) {
image_t temp;
memcpy(&temp, src_img, sizeof(image_t));
if (src_img->is_compressed || (!simple)) {
temp.w = dst_img.w;
temp.h = dst_img.h;
temp.pixfmt = PIXFORMAT_RGB565; // TODO PIXFORMAT_ARGB8888
temp.size = 0;
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
imlib_draw_image(&temp, src_img, 0, 0, arg_x_scale, arg_y_scale, &arg_roi,
arg_rgb_channel, arg_alpha, color_palette, alpha_palette,
(hint & (~IMAGE_HINT_CENTER)) | IMAGE_HINT_BLACK_BACKGROUND, NULL, NULL);
}
if (((dst_img.pixfmt == PIXFORMAT_JPEG) && jpeg_compress(&temp, &dst_img_tmp, arg_q, false))
|| ((dst_img.pixfmt == PIXFORMAT_PNG) && png_compress(&temp, &dst_img_tmp))) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Compression Failed!"));
}
} else if (arg_e) {
dst_img_tmp.data = fb_alloc(image_size(&dst_img_tmp), FB_ALLOC_NO_HINT);
memcpy(dst_img_tmp.data, src_img->data, dst_img_tmp.size);
} else {
dst_img_tmp.data = src_img->data;
}
if (arg_e) {
dst_img.size = fb_encode_for_ide_new_size(&dst_img_tmp);
} else {
dst_img.size = dst_img_tmp.size;
}
}
@ -1106,10 +1154,13 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
dst_img.data = xalloc(size);
}
if (dst_img.pixfmt == PIXFORMAT_JPEG) {
if (dst_img.data != src_img->data) {
memcpy(dst_img.data, src_img->data, dst_img.size);
if (dst_img.is_compressed) {
if (arg_e) {
fb_encode_for_ide(dst_img.data, &dst_img_tmp);
} else if (dst_img.data != dst_img_tmp.data) {
memcpy(dst_img.data, dst_img_tmp.data, dst_img.size);
}
fb_alloc_free_till_mark();
} else {
fb_alloc_mark();
imlib_draw_image(&dst_img, src_img, 0, 0, arg_x_scale, arg_y_scale, &arg_roi,
@ -1127,170 +1178,73 @@ static mp_obj_t py_image_to(pixformat_t pixfmt, const uint16_t *default_color_pa
static mp_obj_t py_image_to_bitmap(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_BINARY, NULL, false, n_args, args, kw_args);
return py_image_to(PIXFORMAT_BINARY, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_bitmap_obj, 1, py_image_to_bitmap);
static mp_obj_t py_image_to_grayscale(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_GRAYSCALE, NULL, false, n_args, args, kw_args);
return py_image_to(PIXFORMAT_GRAYSCALE, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_grayscale_obj, 1, py_image_to_grayscale);
static mp_obj_t py_image_to_rgb565(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_RGB565, NULL, false, n_args, args, kw_args);
return py_image_to(PIXFORMAT_RGB565, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rgb565_obj, 1, py_image_to_rgb565);
static mp_obj_t py_image_to_rainbow(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_RGB565, rainbow_table, false, n_args, args, kw_args);
return py_image_to(PIXFORMAT_RGB565, rainbow_table, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rainbow_obj, 1, py_image_to_rainbow);
static mp_obj_t py_image_to_ironbow(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_RGB565, ironbow_table, false,NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_ironbow_obj, 1, py_image_to_ironbow);
static mp_obj_t py_image_to_jpeg(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_JPEG, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_jpeg_obj, 1, py_image_to_jpeg);
static mp_obj_t py_image_to_png(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_PNG, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_png_obj, 1, py_image_to_png);
static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_INVALID, NULL, true, n_args, args, kw_args);
return py_image_to(PIXFORMAT_INVALID, NULL, true, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy);
static mp_obj_t py_image_crop(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(PIXFORMAT_INVALID, NULL, false, n_args, args, kw_args);
return py_image_to(PIXFORMAT_INVALID, NULL, false, NULL, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_crop_obj, 1, py_image_crop);
static mp_obj_t py_image_jpeg_encode_for_ide(mp_obj_t img_obj)
{
image_t *arg_img = py_image_cobj(img_obj);
PY_ASSERT_TRUE_MSG(arg_img->pixfmt == PIXFORMAT_JPEG, "Image format is not supported!");
PY_ASSERT_TRUE_MSG(py_helper_is_equal_to_framebuffer(arg_img), "Can't compress in place!");
int new_size = fb_encode_for_ide_new_size(arg_img);
fb_alloc_mark();
uint8_t *temp = fb_alloc(new_size, FB_ALLOC_NO_HINT);
fb_encode_for_ide(temp, arg_img);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.size = new_size;
py_helper_set_to_framebuffer(&out);
arg_img->size = new_size;
memcpy(arg_img->data, temp, new_size);
fb_alloc_free_till_mark();
return img_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_jpeg_encode_for_ide_obj, py_image_jpeg_encode_for_ide);
static mp_obj_t py_image_jpeg_encoded_for_ide(mp_obj_t img_obj)
{
image_t *arg_img = py_image_cobj(img_obj);
PY_ASSERT_TRUE_MSG(arg_img->pixfmt == PIXFORMAT_JPEG, "Image format is not supported!");
int new_size = fb_encode_for_ide_new_size(arg_img);
uint8_t *temp = xalloc(new_size);
fb_encode_for_ide(temp, arg_img);
arg_img->size = new_size;
return py_image(arg_img->w, arg_img->h, arg_img->pixfmt, new_size, temp);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_jpeg_encoded_for_ide_obj, py_image_jpeg_encoded_for_ide);
static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return args[0];
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
fb_alloc_mark();
image_t out = { .w=arg_img->w, .h=arg_img->h, .pixfmt=PIXFORMAT_JPEG, .size=0, .data=NULL }; // alloc in jpeg compress
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
PY_ASSERT_TRUE_MSG(out.size <= image_size(arg_img), "Can't compress in place!");
memcpy(arg_img->data, out.data, out.size);
arg_img->pixfmt = PIXFORMAT_JPEG;
arg_img->size = out.size;
fb_alloc_free_till_mark();
py_helper_update_framebuffer(arg_img);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_obj, 1, py_image_compress);
static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return py_image_jpeg_encode_for_ide(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
fb_alloc_mark();
image_t out = { .w=arg_img->w, .h=arg_img->h, .pixfmt=PIXFORMAT_JPEG, .size=0, .data=NULL }; // alloc in jpeg compress
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
int new_size = fb_encode_for_ide_new_size(&out);
PY_ASSERT_TRUE_MSG(new_size <= image_size(arg_img), "Can't compress in place!");
fb_encode_for_ide(arg_img->data, &out);
arg_img->pixfmt = PIXFORMAT_JPEG;
arg_img->size = new_size;
fb_alloc_free_till_mark();
py_helper_update_framebuffer(arg_img);
return args[0];
return py_image_to(PIXFORMAT_JPEG, NULL, false, NULL, true, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_for_ide_obj, 1, py_image_compress_for_ide);
static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
if (IM_IS_JPEG(arg_img)) {
image_t out = { .w=arg_img->w, .h=arg_img->h, .pixfmt=PIXFORMAT_JPEG, .size=arg_img->size, .data=xalloc(arg_img->size) };
memcpy(out.data, arg_img->data, arg_img->size);
return py_image_from_struct(&out);
}
arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
fb_alloc_mark();
image_t out = { .w=arg_img->w, .h=arg_img->h, .pixfmt=PIXFORMAT_JPEG, .size=0, .data=NULL }; // alloc in jpeg compress
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
uint8_t *temp = xalloc(out.size);
memcpy(temp, out.data, out.size);
out.data = temp;
fb_alloc_free_till_mark();
return py_image_from_struct(&out);
return py_image_to(PIXFORMAT_JPEG, NULL, false, mp_const_true, false, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_obj, 1, py_image_compressed);
static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (IM_IS_JPEG((image_t *) py_image_cobj(args[0]))) return py_image_jpeg_encoded_for_ide(args[0]);
image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50);
PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!");
fb_alloc_mark();
image_t out = { .w=arg_img->w, .h=arg_img->h, .pixfmt=PIXFORMAT_JPEG, .size=0, .data=NULL }; // alloc in jpeg compress
PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!");
int new_size = fb_encode_for_ide_new_size(&out);
uint8_t *temp = xalloc(new_size);
fb_encode_for_ide(temp, &out);
out.size = new_size;
out.data = temp;
fb_alloc_free_till_mark();
return py_image_from_struct(&out);
return py_image_to(PIXFORMAT_JPEG, NULL, false, mp_const_true, true, n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide);
@ -6049,12 +6003,15 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_to_grayscale), MP_ROM_PTR(&py_image_to_grayscale_obj)},
{MP_ROM_QSTR(MP_QSTR_to_rgb565), MP_ROM_PTR(&py_image_to_rgb565_obj)},
{MP_ROM_QSTR(MP_QSTR_to_rainbow), MP_ROM_PTR(&py_image_to_rainbow_obj)},
{MP_ROM_QSTR(MP_QSTR_compress), MP_ROM_PTR(&py_image_compress_obj)},
{MP_ROM_QSTR(MP_QSTR_to_ironbow), MP_ROM_PTR(&py_image_to_ironbow_obj)},
{MP_ROM_QSTR(MP_QSTR_to_jpeg), MP_ROM_PTR(&py_image_to_jpeg_obj)},
{MP_ROM_QSTR(MP_QSTR_to_png), MP_ROM_PTR(&py_image_to_png_obj)},
{MP_ROM_QSTR(MP_QSTR_compress), MP_ROM_PTR(&py_image_to_jpeg_obj)},
{MP_ROM_QSTR(MP_QSTR_compress_for_ide), MP_ROM_PTR(&py_image_compress_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_compressed), MP_ROM_PTR(&py_image_compressed_obj)},
{MP_ROM_QSTR(MP_QSTR_compressed_for_ide), MP_ROM_PTR(&py_image_compressed_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_jpeg_encode_for_ide), MP_ROM_PTR(&py_image_jpeg_encode_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_jpeg_encoded_for_ide),MP_ROM_PTR(&py_image_jpeg_encoded_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_jpeg_encode_for_ide), MP_ROM_PTR(&py_image_compress_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_jpeg_encoded_for_ide),MP_ROM_PTR(&py_image_compressed_for_ide_obj)},
{MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&py_image_copy_obj)},
{MP_ROM_QSTR(MP_QSTR_crop), MP_ROM_PTR(&py_image_crop_obj)},
{MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&py_image_crop_obj)},
@ -6978,6 +6935,7 @@ static const mp_rom_map_elem_t globals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_BAYER), MP_ROM_INT(PIXFORMAT_BAYER)}, /* 1BPP/RAW*/
{MP_ROM_QSTR(MP_QSTR_YUV422), MP_ROM_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/
{MP_ROM_QSTR(MP_QSTR_JPEG), MP_ROM_INT(PIXFORMAT_JPEG)}, /* JPEG/COMPRESSED*/
{MP_ROM_QSTR(MP_QSTR_PNG), MP_ROM_INT(PIXFORMAT_PNG)}, /* PNG/COMPRESSED*/
{MP_ROM_QSTR(MP_QSTR_AREA), MP_ROM_INT(IMAGE_HINT_AREA)},
{MP_ROM_QSTR(MP_QSTR_BILINEAR), MP_ROM_INT(IMAGE_HINT_BILINEAR)},
{MP_ROM_QSTR(MP_QSTR_BICUBIC), MP_ROM_INT(IMAGE_HINT_BICUBIC)},

View File

@ -152,6 +152,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
jpegd.o \
jpeg.o \
lodepng.o \
png.o \
kmeans.o \
lab_tab.o \
lbp.o \

View File

@ -150,6 +150,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/imlib/jpegd.c
${TOP_DIR}/${OMV_DIR}/imlib/jpeg.c
${TOP_DIR}/${OMV_DIR}/imlib/lodepng.c
${TOP_DIR}/${OMV_DIR}/imlib/png.c
${TOP_DIR}/${OMV_DIR}/imlib/kmeans.c
${TOP_DIR}/${OMV_DIR}/imlib/lab_tab.c
${TOP_DIR}/${OMV_DIR}/imlib/lbp.c

View File

@ -190,6 +190,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
jpegd.o \
jpeg.o \
lodepng.o \
png.o \
kmeans.o \
lab_tab.o \
lbp.o \