mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add PNG Support
This commit is contained in:
parent
4dac638338
commit
f12a4659c8
@ -73,6 +73,7 @@ SRCS += $(addprefix imlib/, \
|
||||
jpegd.c \
|
||||
jpeg.c \
|
||||
lodepng.c \
|
||||
png.c \
|
||||
kmeans.c \
|
||||
lab_tab.c \
|
||||
lbp.c \
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,12 +772,19 @@ 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 (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");
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
337
src/omv/imlib/png.c
Normal 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)
|
||||
@ -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)},
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user