Merge pull request #1122 from kwagyeman/kwabena/cleanup_to_ops

Kwabena/cleanup to ops
This commit is contained in:
Ibrahim Abd Elkader 2021-01-16 20:44:33 +02:00 committed by GitHub
commit 730efc65aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 313 additions and 599 deletions

View File

@ -439,7 +439,14 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int
void imlib_draw_row_setup(imlib_draw_row_data_t *data)
{
size_t image_row_size = image_size(data->dst_img) / data->dst_img->h;
image_t temp;
temp.w = data->dst_img->w;
temp.h = data->dst_img->h;
temp.bpp = data->src_img_bpp;
// Image Row Size should be the width of the destination image
// but with the bpp of the source image.
size_t image_row_size = image_size(&temp) / data->dst_img->h;
data->toggle = 0;
data->row_buffer[0] = fb_alloc(image_row_size, FB_ALLOC_NO_HINT);
@ -2663,6 +2670,29 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
color_palette = NULL;
}
bool no_scaling_nearest_neighbor = (dst_delta_x == 1)
&& (dst_x_start == 0) && (src_x_start == 0)
&& (src_x_frac == 65536) && (src_y_frac == 65536);
// If we are scaling just make a deep copy.
bool is_scaling = (hint & (IMAGE_HINT_AREA | IMAGE_HINT_BICUBIC | IMAGE_HINT_BILINEAR))
|| (!no_scaling_nearest_neighbor);
// Otherwise, we only have to do a deep copy if the image is growing.
size_t src_img_row_bytes = image_size(src_img) / src_img->h;
size_t dst_img_row_bytes = image_size(dst_img) / dst_img->h;
// In-place (by definition mutually exclusive to the above)...
if ((dst_img->data == src_img->data) && (is_scaling || (src_img_row_bytes < dst_img_row_bytes))) {
size_t size = image_size(src_img);
new_src_img.w = src_img->w; // same width as source image
new_src_img.h = src_img->h; // same height as source image
new_src_img.bpp = src_img->bpp;
new_src_img.data = fb_alloc(size, FB_ALLOC_NO_HINT);
memcpy(new_src_img.data, src_img->data, size);
src_img = &new_src_img;
}
imlib_draw_row_data_t imlib_draw_row_data;
imlib_draw_row_data.dst_img = dst_img;
imlib_draw_row_data.src_img_bpp = src_img->bpp;
@ -4360,7 +4390,116 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
break;
}
}
} else if ((dst_delta_x == 1) && (dst_x_start == 0) && (src_x_start == 0) && (src_x_frac == 65536) && (src_y_frac == 65536)) { // copy
} else if (no_scaling_nearest_neighbor) { // copy
if (dst_img->data == src_img->data) { // In-Place
switch (src_img->bpp) {
case IMAGE_BPP_BINARY: {
while (y_not_done) {
uint32_t *src_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(src_img, next_src_y_index);
// Must be called per loop to get the address of the temp buffer to blend with
uint32_t *dst_row_ptr = (uint32_t *) imlib_draw_row_get_row_buffer(&imlib_draw_row_data);
// X loop iteration variables
int dst_x = dst_x_reset;
long src_x_accum = src_x_accum_reset;
int next_src_x_index = src_x_accum >> 16;
int x = dst_x_start;
bool x_not_done = x < dst_x_end;
while (x_not_done) {
int pixel = IMAGE_GET_BINARY_PIXEL_FAST(src_row_ptr, next_src_x_index);
IMAGE_PUT_BINARY_PIXEL_FAST(dst_row_ptr, dst_x, pixel);
// Increment offsets
dst_x += dst_delta_x;
src_x_accum += src_x_frac;
next_src_x_index = src_x_accum >> 16;
x_not_done = ++x < dst_x_end;
} // while x
imlib_draw_row(dst_x_start, dst_x_end, dst_y, &imlib_draw_row_data);
// Increment offsets
dst_y += dst_delta_y;
src_y_accum += src_y_frac;
next_src_y_index = src_y_accum >> 16;
y_not_done = ++y < dst_y_end;
} // while y
break;
}
case IMAGE_BPP_GRAYSCALE: {
while (y_not_done) {
uint8_t *src_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(src_img, next_src_y_index);
// Must be called per loop to get the address of the temp buffer to blend with
uint8_t *dst_row_ptr = (uint8_t *) imlib_draw_row_get_row_buffer(&imlib_draw_row_data);
// X loop iteration variables
int dst_x = dst_x_reset;
long src_x_accum = src_x_accum_reset;
int next_src_x_index = src_x_accum >> 16;
int x = dst_x_start;
bool x_not_done = x < dst_x_end;
while (x_not_done) {
int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(src_row_ptr, next_src_x_index);
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(dst_row_ptr, dst_x, pixel);
// Increment offsets
dst_x += dst_delta_x;
src_x_accum += src_x_frac;
next_src_x_index = src_x_accum >> 16;
x_not_done = ++x < dst_x_end;
} // while x
imlib_draw_row(dst_x_start, dst_x_end, dst_y, &imlib_draw_row_data);
// Increment offsets
dst_y += dst_delta_y;
src_y_accum += src_y_frac;
next_src_y_index = src_y_accum >> 16;
y_not_done = ++y < dst_y_end;
} // while y
break;
}
case IMAGE_BPP_RGB565: {
while (y_not_done) {
uint16_t *src_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src_img, next_src_y_index);
// Must be called per loop to get the address of the temp buffer to blend with
uint16_t *dst_row_ptr = (uint16_t *) imlib_draw_row_get_row_buffer(&imlib_draw_row_data);
// X loop iteration variables
int dst_x = dst_x_reset;
long src_x_accum = src_x_accum_reset;
int next_src_x_index = src_x_accum >> 16;
int x = dst_x_start;
bool x_not_done = x < dst_x_end;
while (x_not_done) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(src_row_ptr, next_src_x_index);
IMAGE_PUT_RGB565_PIXEL_FAST(dst_row_ptr, dst_x, pixel);
// Increment offsets
dst_x += dst_delta_x;
src_x_accum += src_x_frac;
next_src_x_index = src_x_accum >> 16;
x_not_done = ++x < dst_x_end;
} // while x
imlib_draw_row(dst_x_start, dst_x_end, dst_y, &imlib_draw_row_data);
// Increment offsets
dst_y += dst_delta_y;
src_y_accum += src_y_frac;
next_src_y_index = src_y_accum >> 16;
y_not_done = ++y < dst_y_end;
} // while y
break;
}
default: {
break;
}
}
} else { // Out-of-Place
switch (src_img->bpp) {
case IMAGE_BPP_BINARY: {
while (y_not_done) {
@ -4408,6 +4547,7 @@ void imlib_draw_image(image_t *dst_img, image_t *src_img, int dst_x_start, int d
break;
}
}
}
} else { // nearest neighbor
switch (src_img->bpp) {
case IMAGE_BPP_BINARY: {

View File

@ -867,435 +867,156 @@ static mp_obj_t py_image_midpoint_pooled(uint n_args, const mp_obj_t *args, mp_m
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midpoint_pooled);
#endif // IMLIB_ENABLE_MIDPOINT_POOLING
static mp_obj_t py_image_to(int bpp, const uint16_t *default_color_palette, bool copy_to_fb,
uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *src_img = py_helper_arg_to_image_mutable(args[0]);
float arg_x_scale = 1.f;
bool got_x_scale = py_helper_keyword_float_maybe(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), &arg_x_scale);
float arg_y_scale = 1.f;
bool got_y_scale = py_helper_keyword_float_maybe(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), &arg_y_scale);
rectangle_t arg_roi;
py_helper_keyword_rectangle_roi(src_img, n_args, args, 3, kw_args, &arg_roi);
int arg_rgb_channel = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
if ((arg_rgb_channel < -1) || (2 < arg_rgb_channel)) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("-1 <= rgb_channel <= 2!"));
}
int arg_alpha = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 256);
if ((arg_alpha < 0) || (256 < arg_alpha)) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("0 <= alpha <= 256!"));
}
const uint16_t *color_palette = py_helper_keyword_color_palette(n_args, args, 6, kw_args, default_color_palette);
const uint8_t *alpha_palette = py_helper_keyword_alpha_palette(n_args, args, 7, kw_args, NULL);
image_hint_t hint = py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hint), 0);
int arg_x_size;
bool got_x_size = py_helper_keyword_int_maybe(n_args, args, 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_size), &arg_x_size);
int arg_y_size;
bool got_y_size = py_helper_keyword_int_maybe(n_args, args, 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_size), &arg_y_size);
if (got_x_scale && got_x_size) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Choose either x_scale or x_size not both!"));
}
if (got_y_scale && got_y_size) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Choose either y_scale or y_size not both!"));
}
if (got_x_size) {
arg_x_scale = arg_x_size / ((float) arg_roi.w);
}
if (got_y_size) {
arg_y_scale = arg_y_size / ((float) arg_roi.h);
}
if ((!got_x_scale) && (!got_x_size) && got_y_size) {
arg_x_scale = arg_y_scale;
}
if ((!got_y_scale) && (!got_y_size) && got_x_size) {
arg_y_scale = arg_x_scale;
}
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);
bool copy = false;
image_t *arg_other = copy_to_fb ? NULL : src_img;
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_mutable(copy_obj);
}
}
if (copy_to_fb && copy) {
fb_update_jpeg_buffer();
}
image_t dst_img;
dst_img.w = fast_floorf(arg_roi.w * arg_x_scale);
dst_img.h = fast_floorf(arg_roi.h * arg_y_scale);
dst_img.bpp = (bpp >= 0) ? bpp : src_img->bpp;
if (copy) {
if (copy_to_fb) {
py_helper_set_to_framebuffer(&dst_img);
} else {
dst_img.data = xalloc(image_size(&dst_img));
}
} else if (arg_other) {
bool fb = py_helper_is_equal_to_framebuffer(arg_other);
size_t size = fb ? framebuffer_get_buffer_size() : image_size(arg_other);
PY_ASSERT_TRUE_MSG((image_size(&dst_img) <= size),
"The new image won't fit in the target frame buffer!");
// DO NOT MODIFY arg_other YET (as it could point to src_img)!
dst_img.data = arg_other->data;
py_helper_update_framebuffer(&dst_img);
} else {
dst_img.data = xalloc(image_size(&dst_img));
}
fb_alloc_mark();
imlib_draw_image(&dst_img, 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);
fb_alloc_free_till_mark();
if (arg_other) {
arg_other->w = dst_img.w;
arg_other->h = dst_img.h;
arg_other->bpp = dst_img.bpp;
}
return py_image_from_struct(&dst_img);
}
static mp_obj_t py_image_to_bitmap(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_BINARY;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy) memcpy(out.data, arg_img->data, image_size(&out));
break;
}
case IMAGE_BPP_GRAYSCALE: {
PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint8_t))) || copy,
"Can't convert to bitmap in place!");
fb_alloc_mark();
uint32_t *out_row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out), FB_ALLOC_NO_HINT);
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x,
COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)));
}
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y),
out_row_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out));
}
fb_alloc_free_till_mark();
break;
}
case IMAGE_BPP_RGB565: {
PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint16_t))) || copy,
"Can't convert to bitmap in place!");
fb_alloc_mark();
uint32_t *out_row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out), FB_ALLOC_NO_HINT);
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_RGB565_TO_R5(pixel) > (((COLOR_R5_MAX - COLOR_R5_MIN) / 2) + COLOR_R5_MIN);
break;
}
case 1: {
pixel = COLOR_RGB565_TO_G6(pixel) > (((COLOR_G6_MAX - COLOR_G6_MIN) / 2) + COLOR_G6_MIN);
break;
}
case 2: {
pixel = COLOR_RGB565_TO_B5(pixel) > (((COLOR_B5_MAX - COLOR_B5_MIN) / 2) + COLOR_B5_MIN);
break;
}
default: {
pixel = COLOR_RGB565_TO_BINARY(pixel);
break;
}
}
IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
}
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y),
out_row_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out));
}
fb_alloc_free_till_mark();
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_BINARY;
py_helper_update_framebuffer(&out);
}
return py_image_from_struct(&out);
return py_image_to(IMAGE_BPP_BINARY, 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)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_GRAYSCALE;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (!py_helper_is_equal_to_framebuffer(&out))) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to grayscale in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x,
COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
py_helper_set_to_framebuffer(&out);
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x,
COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy) memcpy(out.data, arg_img->data, image_size(&out));
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_RGB565_TO_R8(pixel);
break;
}
case 1: {
pixel = COLOR_RGB565_TO_G8(pixel);
break;
}
case 2: {
pixel = COLOR_RGB565_TO_B8(pixel);
break;
}
default: {
pixel = COLOR_RGB565_TO_GRAYSCALE(pixel);
break;
}
}
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_GRAYSCALE;
py_helper_update_framebuffer(&out);
}
return py_image_from_struct(&out);
return py_image_to(IMAGE_BPP_GRAYSCALE, 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)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_RGB565;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (!py_helper_is_equal_to_framebuffer(&out))) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to grayscale in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX, 0, 0));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
py_helper_set_to_framebuffer(&out);
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX, 0, 0));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy || (!py_helper_is_equal_to_framebuffer(&out))) {
PY_ASSERT_TRUE_MSG(copy,
"Can't convert to rgb565 in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), 0, 0));
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
py_helper_set_to_framebuffer(&out);
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), 0, 0));
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = COLOR_R5_G6_B5_TO_RGB565(COLOR_RGB565_TO_R5(pixel), 0, 0);
break;
}
case 1: {
pixel = COLOR_R5_G6_B5_TO_RGB565(0, COLOR_RGB565_TO_G6(pixel), 0);
break;
}
case 2: {
pixel = COLOR_R5_G6_B5_TO_RGB565(0, 0, COLOR_RGB565_TO_B5(pixel));
break;
}
default: {
break;
}
}
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_RGB565;
py_helper_update_framebuffer(&out);
}
return py_image_from_struct(&out);
return py_image_to(IMAGE_BPP_RGB565, 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)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false);
int channel = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
int palette = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), COLOR_PALETTE_RAINBOW);
const uint16_t *color_palette = NULL;
if (palette == COLOR_PALETTE_RAINBOW) {
color_palette = rainbow_table;
} else if (palette == COLOR_PALETTE_IRONBOW) {
color_palette = ironbow_table;
} else {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid color palette!"));
}
image_t out;
out.w = arg_img->w;
out.h = arg_img->h;
out.bpp = IMAGE_BPP_RGB565;
out.data = copy ? xalloc(image_size(&out)) : arg_img->data;
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
if (copy || (!py_helper_is_equal_to_framebuffer(&out))) {
PY_ASSERT_TRUE_MSG((out.w == 1) || copy,
"Can't convert to rainbow in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX]);
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
py_helper_set_to_framebuffer(&out);
for (int y = 0, yy = out.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX]);
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
if (copy || (!py_helper_is_equal_to_framebuffer(&out))) {
PY_ASSERT_TRUE_MSG(copy,
"Can't convert to rainbow in place!");
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)]);
}
}
} else {
image_t temp;
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
py_helper_set_to_framebuffer(&out);
for (int y = 0, yy = out.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x,
color_palette[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)]);
}
}
fb_alloc_free_till_mark();
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = out.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y);
uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y);
for (int x = 0, xx = out.w; x < xx; x++) {
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
switch (channel) {
case 0: {
pixel = color_palette[COLOR_RGB565_TO_R8(pixel)];
break;
}
case 1: {
pixel = color_palette[COLOR_RGB565_TO_G8(pixel)];
break;
}
case 2: {
pixel = color_palette[COLOR_RGB565_TO_B8(pixel)];
break;
}
default: {
pixel = color_palette[COLOR_RGB565_TO_GRAYSCALE(pixel)];
break;
}
}
IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
}
}
break;
}
default: {
break;
}
}
if (!copy) {
arg_img->bpp = IMAGE_BPP_RGB565;
py_helper_update_framebuffer(&out);
}
return py_image_from_struct(&out);
return py_image_to(IMAGE_BPP_RGB565, rainbow_table, 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_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_to(-1, NULL, true, 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(-1, 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);
@ -1434,153 +1155,6 @@ static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, m
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide);
static mp_obj_t py_image_copy_int(uint n_args, const mp_obj_t *args, mp_map_t *kw_args, bool mode)
{
// mode == false -> copy behavior
// mode == true -> crop/scale behavior
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
rectangle_t roi;
py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi);
float arg_x_scale =
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_x_scale), "Error: 0.0 <= x_scale!");
float arg_y_scale =
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), 1.0f);
PY_ASSERT_TRUE_MSG((0.0f <= arg_y_scale), "Error: 0.0 <= y_scale!");
mp_obj_t copy_to_fb_obj = py_helper_keyword_object(n_args, args, 4, kw_args,
MP_OBJ_NEW_QSTR(mode ? MP_QSTR_copy : MP_QSTR_copy_to_fb), NULL);
bool copy_to_fb = false;
image_t *arg_other = mode ? arg_img : NULL;
if (copy_to_fb_obj) {
if (mp_obj_is_integer(copy_to_fb_obj)) {
if (!mode) {
copy_to_fb = mp_obj_get_int(copy_to_fb_obj);
} else if (mp_obj_get_int(copy_to_fb_obj)) {
arg_other = NULL;
}
} else {
arg_other = py_helper_arg_to_image_mutable(copy_to_fb_obj);
}
}
if (copy_to_fb) {
fb_update_jpeg_buffer();
}
image_t image;
image.w = fast_floorf(roi.w * arg_x_scale);
PY_ASSERT_TRUE_MSG(image.w >= 1, "Output image width is 0!");
image.h = fast_floorf(roi.h * arg_y_scale);
PY_ASSERT_TRUE_MSG(image.h >= 1, "Output image height is 0!");
image.bpp = arg_img->bpp;
image.data = NULL;
if (copy_to_fb) {
py_helper_set_to_framebuffer(&image);
} else if (arg_other) {
PY_ASSERT_TRUE_MSG((image_size(&image) <= image_size(arg_other)), "The new image won't fit in the target frame buffer!");
image.data = arg_other->data;
} else {
image.data = xalloc(image_size(&image));
}
bool in_place = arg_img->data == image.data;
image_t temp;
if (in_place) {
memcpy(&temp, arg_img, sizeof(image_t));
fb_alloc_mark();
temp.data = fb_alloc(image_size(&temp), FB_ALLOC_NO_HINT);
memcpy(temp.data, arg_img->data, image_size(&temp));
arg_img = &temp;
if (copy_to_fb) {
py_helper_set_to_framebuffer(&image);
}
}
float over_xscale = IM_DIV(1.0, arg_x_scale), over_yscale = IM_DIV(1.0f, arg_y_scale);
switch(arg_img->bpp) {
case IMAGE_BPP_BINARY: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
case IMAGE_BPP_GRAYSCALE: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
case IMAGE_BPP_RGB565: {
for (int y = 0, yy = image.h; y < yy; y++) {
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y);
uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y);
for (int x = 0, xx = image.w; x < xx; x++) {
IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x,
IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x));
}
}
break;
}
default: {
break;
}
}
if (in_place) {
fb_alloc_free_till_mark();
}
py_helper_update_framebuffer(&image);
if (copy_to_fb) {
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
if (py_helper_is_equal_to_framebuffer(arg_img)) {
arg_img->w = image.w;
arg_img->h = image.h;
arg_img->bpp = image.bpp;
}
} else {
if (arg_other) {
arg_other->w = image.w;
arg_other->h = image.h;
arg_other->bpp = image.bpp;
}
}
return py_image_from_struct(&image);
}
static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return py_image_copy_int(n_args, args, kw_args, false);
}
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_copy_int(n_args, args, kw_args, true);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_crop_obj, 1, py_image_crop);
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{