From 1cc23d4ff26ade2e58b575e295fb1ef4fc937a13 Mon Sep 17 00:00:00 2001 From: Wonguk Jeong Date: Sun, 6 Jul 2014 19:58:47 +0200 Subject: [PATCH] evas: jpeg loader - support flip, transpose, transverse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Previously, jpeg image loader support rotation (90°, 180°, 270°) only. this patch is about supporting flip(vertical, horizontal), transpose, transverse @feature Test Plan: I'm going to make tests in src/tests Reviewers: cedric, raster, jpeg CC: seoz, cedric Differential Revision: https://phab.enlightenment.org/D1126 Signed-off-by: Cedric BAIL --- src/lib/evas/Evas_Loader.h | 2 + src/lib/evas/common/evas_image_load.c | 6 +- src/lib/evas/include/evas_common_private.h | 1 + .../evas/loaders/jpeg/evas_image_load_jpeg.c | 328 ++++++++++++------ 4 files changed, 219 insertions(+), 118 deletions(-) diff --git a/src/lib/evas/Evas_Loader.h b/src/lib/evas/Evas_Loader.h index 74d6835700..6a2855031c 100644 --- a/src/lib/evas/Evas_Loader.h +++ b/src/lib/evas/Evas_Loader.h @@ -193,6 +193,8 @@ struct _Evas_Image_Property struct { unsigned char l, r, t, b; /**< Specify the dimensions of duplicated pixels borders for OpenGL compressed textures, set by the loader. @since 1.11 */ } borders; + + Eina_Bool flipped; }; struct _Evas_Image_Animated diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c index 6158e0baa8..e57bb61f6f 100644 --- a/src/lib/evas/common/evas_image_load.c +++ b/src/lib/evas/common/evas_image_load.c @@ -231,9 +231,8 @@ _evas_image_file_header(Evas_Module *em, Image_Entry *ie, int *error) ie->flags.alpha = property.alpha; if (property.cspaces) ie->cspaces = property.cspaces; - if (ie->load_opts.orientation && - ie->load_opts.degree != 0) - ie->flags.rotated = EINA_TRUE; + ie->flags.rotated = property.rotated; + ie->flags.flipped = property.flipped; r = EINA_FALSE; } else @@ -416,6 +415,7 @@ evas_common_load_rgba_image_data_from_file(Image_Entry *ie) property.h = ie->h; property.scale = ie->scale; property.rotated = ie->flags.rotated; + property.flipped = ie->flags.flipped; property.premul = EINA_FALSE; property.alpha_sparse = EINA_FALSE; property.cspace = ie->space; diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index b1cc92e944..b79cf43d2b 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -532,6 +532,7 @@ struct _Image_Entry_Flags Eina_Bool given_mmap : 1; Eina_Bool updated_data : 1; + Eina_Bool flipped : 1; }; struct _Image_Entry_Frame diff --git a/src/modules/evas/loaders/jpeg/evas_image_load_jpeg.c b/src/modules/evas/loaders/jpeg/evas_image_load_jpeg.c index 0ec2c85c00..c0047a3ea8 100644 --- a/src/modules/evas/loaders/jpeg/evas_image_load_jpeg.c +++ b/src/modules/evas/loaders/jpeg/evas_image_load_jpeg.c @@ -37,8 +37,9 @@ static void _JPEGFatalErrorHandler(j_common_ptr cinfo); static void _JPEGErrorHandler(j_common_ptr cinfo); static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); static Eina_Bool _get_next_app0(unsigned char *map, size_t fsize, size_t *position); -static Eina_Bool _get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, int *orientation); -static int _get_orientation(void *map, size_t length); +static Eina_Bool _get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, + int *orientation, Eina_Bool *flipped); +static int _get_orientation(void *map, size_t length, Eina_Bool *flipped); #if 0 /* not used at the moment */ static int evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f) EINA_ARG_NONNULL(1, 2); @@ -218,7 +219,8 @@ _get_next_app0(unsigned char *map, size_t fsize, size_t *position) */ static Eina_Bool -_get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, int *orientation_res) +_get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, + int *orientation_res, Eina_Bool *flipped) { unsigned char *app1_head, *buf; unsigned char orientation[2]; @@ -279,20 +281,37 @@ _get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, int *o switch (direction) { case 3: + *orientation_res = 180; + *flipped = EINA_FALSE; + return EINA_TRUE; case 4: - *orientation_res = 180; - return EINA_TRUE; + *orientation_res = 180; + *flipped = EINA_TRUE; + return EINA_TRUE; case 6: + *orientation_res = 90; + *flipped = EINA_FALSE; + return EINA_TRUE; case 7: - *orientation_res = 90; - return EINA_TRUE; + *orientation_res = 90; + *flipped = EINA_TRUE; + return EINA_TRUE; case 5: + *orientation_res = 270; + *flipped = EINA_TRUE; + return EINA_TRUE; case 8: - *orientation_res = 270; - return EINA_TRUE; + *orientation_res = 270; + *flipped = EINA_FALSE; + return EINA_TRUE; + case 2: + *orientation_res = 0; + *flipped = EINA_TRUE; + return EINA_TRUE; default: - *orientation_res = 0; - return EINA_TRUE; + *orientation_res = 0; + *flipped = EINA_FALSE; + return EINA_TRUE; } } else @@ -302,13 +321,15 @@ _get_orientation_app1(unsigned char *map, size_t fsize, size_t *position, int *o } static int -_get_orientation(void *map, size_t length) +_get_orientation(void *map, size_t length, Eina_Bool *flipped) { unsigned char *buf; size_t position = 0; int orientation = -1; Eina_Bool res = EINA_FALSE; + *flipped = EINA_FALSE; + /* open file and get 22 byte frome file */ if (!map) return 0; /* 1. read 22byte */ @@ -326,7 +347,7 @@ _get_orientation(void *map, size_t length) } else if (!memcmp(buf + position, App1, sizeof (App1))) { - res = _get_orientation_app1(map, length, &position, &orientation); + res = _get_orientation_app1(map, length, &position, &orientation, flipped); if (!res) break; if (orientation != -1) return orientation; } @@ -335,10 +356,69 @@ _get_orientation(void *map, size_t length) return 0; } +static void +_rotate_region(unsigned int *r_x, unsigned int *r_y, unsigned int *r_w, unsigned int *r_h, + unsigned int x, unsigned int y, unsigned int w, unsigned int h, + unsigned int output_w, unsigned int output_h, + int degree, Eina_Bool flipped) +{ + switch (degree) + { + case 90: + if (flipped) + { + *r_x = output_w - (y + h); + *r_y = output_h - (x + w); + *r_w = h; + *r_h = w; + } + else + { + *r_x = y; + *r_y = output_h - (x + y); + *r_w = h; + *r_h = w; + } + break; + case 180: + if (flipped) + { + *r_y = output_h - (y + h); + } + else + { + *r_x = output_w - (x + w); + *r_y = output_h - (y + h); + } + break; + case 270: + if (flipped) + { + *r_x = y; + *r_y = x; + *r_w = h; + *r_h = w; + } + else + { + *r_x = output_w - (y + h); + *r_y = x; + *r_w = h; + *r_h = w; + } + break; + default: + if (flipped) + *r_x = output_w - (x + w); + break; + } +} + static Eina_Bool evas_image_load_file_head_jpeg_internal(unsigned int *w, unsigned int *h, unsigned char *scale, unsigned char *rotated, + Eina_Bool *flipped, Evas_Image_Load_Opts *opts, void *map, size_t length, int *error) @@ -388,8 +468,8 @@ evas_image_load_file_head_jpeg_internal(unsigned int *w, unsigned int *h, /* rotation decoding */ if (opts->orientation) { - degree = _get_orientation(map, length); - if (degree != 0) + degree = _get_orientation(map, length, flipped); + if (degree != 0 || *flipped) { opts->degree = degree; *rotated = EINA_TRUE; @@ -522,29 +602,9 @@ evas_image_load_file_head_jpeg_internal(unsigned int *w, unsigned int *h, load_region_w = opts->region.w; load_region_h = opts->region.h; - switch (degree) - { - case 90: - opts->region.x = load_region_y; - opts->region.y = *h - (load_region_x + load_region_w); - opts->region.w = load_region_h; - opts->region.h = load_region_w; - break; - case 180: - opts->region.x = *w - (load_region_x+ load_region_w); - opts->region.y = *h - (load_region_y + load_region_h); - - break; - case 270: - opts->region.x = *w - (load_region_y + load_region_h); - opts->region.y = load_region_x; - opts->region.w = load_region_h; - opts->region.h = load_region_w; - break; - default: - break; - } - + _rotate_region(&opts->region.x, &opts->region.y, &opts->region.w, &opts->region.h, + load_region_x, load_region_y, load_region_w, load_region_h, + *w, *h, degree, *flipped); } RECTS_CLIP_TO_RECT(opts->region.x, opts->region.y, opts->region.w, opts->region.h, @@ -592,6 +652,88 @@ get_time(void) } */ +static void +_rotate_180(DATA32 *data, int w, int h) +{ + DATA32 *p1, *p2; + DATA32 pt; + int x; + + p1 = data; + p2 = data + (h * w) - 1; + for (x = (w * h) / 2; --x >= 0;) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2--; + } +} + +static void +_flip_horizontal(DATA32 *data, int w, int h) +{ + DATA32 *p1, *p2; + DATA32 pt; + int x, y; + + for (y = 0; y < h; y++) + { + p1 = data + (y * w); + p2 = data + ((y + 1) * w) - 1; + for (x = 0; x < (w >> 1); x++) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2--; + } + } +} + +static void +_flip_vertical(DATA32 *data, int w, int h) +{ + DATA32 *p1, *p2; + DATA32 pt; + int x, y; + + for (y = 0; y < (h >> 1); y++) + { + p1 = data + (y * w); + p2 = data + ((h - 1 - y) * w); + for (x = 0; x < w; x++) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2++; + } + } +} + +static void +_rotate_change_wh(DATA32 *to, DATA32 *from, + int w, int h, + int dx, int dy) +{ + int x, y; + + for (x = h; --x >= 0;) + { + for (y = w; --y >= 0;) + { + *to = *from; + from++; + to += dy; + } + to += dx; + } +} + static Eina_Bool evas_image_load_file_data_jpeg_internal(Evas_Image_Load_Opts *opts, Evas_Image_Property *prop, @@ -705,29 +847,9 @@ evas_image_load_file_data_jpeg_internal(Evas_Image_Load_Opts *opts, load_region_w = opts->region.w; load_region_h = opts->region.h; - switch (degree) - { - case 90: - opts->region.x = load_region_y; - opts->region.y = h - (load_region_x + load_region_w); - opts->region.w = load_region_h; - opts->region.h = load_region_w; - break; - case 180: - opts->region.x = w - (load_region_x+ load_region_w); - opts->region.y = h - (load_region_y + load_region_h); - - break; - case 270: - opts->region.x = w - (load_region_y + load_region_h); - opts->region.y = load_region_x; - opts->region.w = load_region_h; - opts->region.h = load_region_w; - break; - default: - break; - } - + _rotate_region(&opts->region.x, &opts->region.y, &opts->region.w, &opts->region.h, + load_region_x, load_region_y, load_region_w, load_region_h, + w, h, degree, prop->flipped); } #ifdef BUILD_LOADER_JPEG_REGION cinfo.region_x = opts->region.x; @@ -1076,61 +1198,36 @@ done: if (prop->rotated) { - DATA32 *data1, *data2, *to, *from; - int lx, ly, lw, lh, hw; + DATA32 *to; + int hw; - lw = w; - lh = h; - hw = lw * lh; + hw = w * h; + to = pixels; - data1 = pixels; - - if (degree == 180) + switch (degree) { - DATA32 tmpd; - - data2 = data1 + (lh * lw) -1; - for (lx = (lw * lh) / 2; --lx >= 0;) - { - tmpd = *data1; - *data1 = *data2; - *data2 = tmpd; - data1++; - data2--; - } - } - else - { - data2 = NULL; - to = NULL; - if (ptr_rotate) data2 = ptr_rotate; - - if (degree == 90) - { - to = data1 + lh - 1; - hw = -hw - 1; - } - else if (degree == 270) - { - to = data1 + hw - lh; - lh = -lh; - hw = hw + 1; - } - - if (to) - { - from = data2; - for (lx = h; --lx >= 0;) - { - for (ly = w; --ly >= 0;) - { - *to = *from; - from++; - to += lh; - } - to += hw; - } - } + case 90: + if (prop->flipped) + _rotate_change_wh(to + hw - 1, ptr_rotate, w, h, hw - 1, -h); + else + _rotate_change_wh(to + h - 1, ptr_rotate, w, h, -hw - 1, h); + break; + case 180: + if (prop->flipped) + _flip_vertical(to, w, h); + else + _rotate_180(to, w, h); + break; + case 270: + if (prop->flipped) + _rotate_change_wh(to, ptr_rotate, w, h, -hw + 1, h); + else + _rotate_change_wh(to + hw - h, ptr_rotate, w, h, hw + 1, -h); + break; + default: + if (prop->flipped) + _flip_horizontal(to, w, h); + break; } if (ptr_rotate) { @@ -1317,8 +1414,9 @@ evas_image_load_file_head_jpeg(void *loader_data, } val = evas_image_load_file_head_jpeg_internal(&prop->w, &prop->h, - &prop->scale, &prop->rotated, - opts, + &prop->scale, &prop->rotated, + &prop->flipped, + opts, map, eina_file_size_get(f), error);