diff --git a/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c b/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c index 92d74e1f6e..98d5b675e1 100644 --- a/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c +++ b/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c @@ -1,1367 +1,35 @@ #ifdef HAVE_CONFIG_H -# include +# include "config.h" #endif -#include +#include -#ifdef HAVE_EVIL -# include -#endif - -#ifdef _WIN32 -# define XMD_H /* This prevents libjpeg to redefine INT32 */ -#endif - -#include -#include - -#include "evas_common_private.h" -#include "evas_private.h" - -typedef struct _JPEG_error_mgr *emptr; -struct _JPEG_error_mgr -{ - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; +#include "Evas_Loader.h" typedef struct _Evas_Loader_Internal Evas_Loader_Internal; struct _Evas_Loader_Internal { - Eina_File *f; - Evas_Image_Load_Opts *opts; + Emile_Image *image; + + Eina_Rectangle region; }; - -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, 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); -#endif - -static void -_JPEGFatalErrorHandler(j_common_ptr cinfo) -{ - emptr errmgr; - - errmgr = (emptr) cinfo->err; - /* cinfo->err->output_message(cinfo);*/ - longjmp(errmgr->setjmp_buffer, 1); - return; -} - -static void -_JPEGErrorHandler(j_common_ptr cinfo EINA_UNUSED) -{ -/* emptr errmgr; */ - -/* errmgr = (emptr) cinfo->err; */ - /* cinfo->err->output_message(cinfo);*/ - /* longjmp(errmgr->setjmp_buffer, 1);*/ - return; -} - -static void -_JPEGErrorHandler2(j_common_ptr cinfo EINA_UNUSED, int msg_level EINA_UNUSED) -{ -/* emptr errmgr; */ - -/* errmgr = (emptr) cinfo->err; */ - /* cinfo->err->output_message(cinfo);*/ - /* longjmp(errmgr->setjmp_buffer, 1);*/ - return; -} - -struct jpeg_membuf_src -{ - struct jpeg_source_mgr pub; - - const unsigned char *buf; - size_t len; - struct jpeg_membuf_src *self; -}; - -static void -_evas_jpeg_membuf_src_init(j_decompress_ptr cinfo EINA_UNUSED) -{ -} - -static boolean -_evas_jpeg_membuf_src_fill(j_decompress_ptr cinfo) -{ - static const JOCTET jpeg_eoi[2] = { 0xFF, JPEG_EOI }; - struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src; - - src->pub.bytes_in_buffer = sizeof(jpeg_eoi); - src->pub.next_input_byte = jpeg_eoi; - - return TRUE; -} - -static void -_evas_jpeg_membuf_src_skip(j_decompress_ptr cinfo, - long num_bytes) -{ - struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src; - - if ((((long)src->pub.bytes_in_buffer - (long)src->len) > num_bytes) || - ((long)src->pub.bytes_in_buffer < num_bytes)) - { - (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)); - return; - } - src->pub.bytes_in_buffer -= num_bytes; - src->pub.next_input_byte += num_bytes; -} - -static void -_evas_jpeg_membuf_src_term(j_decompress_ptr cinfo) -{ - struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src; - if (!src) return; - free(src); - cinfo->src = NULL; -} - -static int -_evas_jpeg_membuf_src(j_decompress_ptr cinfo, - void *map, size_t length) -{ - struct jpeg_membuf_src *src; - - src = calloc(1, sizeof(*src)); - if (!src) - return -1; - - src->self = src; - - cinfo->src = &src->pub; - src->buf = map; - src->len = length; - src->pub.init_source = _evas_jpeg_membuf_src_init; - src->pub.fill_input_buffer = _evas_jpeg_membuf_src_fill; - src->pub.skip_input_data = _evas_jpeg_membuf_src_skip; - src->pub.resync_to_restart = jpeg_resync_to_restart; - src->pub.term_source = _evas_jpeg_membuf_src_term; - src->pub.bytes_in_buffer = src->len; - src->pub.next_input_byte = src->buf; - - return 0; -} - -/*! Magic number for EXIF header, App0, App1*/ -static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; -static const unsigned char JfifHeader[] = {0x4A, 0x46, 0x49, 0x46, 0x00}; -static const unsigned char JfxxHeader[] = {0x4A, 0x46, 0x58, 0x58, 0x00}; -static const unsigned char App0[] = {0xff, 0xe0}; -static const unsigned char App1[] = {0xff, 0xe1}; -static const unsigned char II[] = {0x49, 0x49}; -static const unsigned char MM[] = {0x4d, 0x4d}; -typedef enum { - EXIF_BYTE_ALIGN_II, - EXIF_BYTE_ALIGN_MM -} ExifByteAlign; - -static Eina_Bool -_get_next_app0(unsigned char *map, size_t fsize, size_t *position) -{ - unsigned short length = 0; - unsigned int w = 0, h = 0; - unsigned int format = 0; - unsigned int data_size = 0; - unsigned char *app0_head, *p; - - /* header_mark:2, length:2, identifier:5 version:2, unit:1, den=4 thum=2 */ - if ((*position + 16) >= fsize) return EINA_FALSE; - app0_head = map + *position; - - /* p is appn's start pointer excluding app0 marker */ - p = app0_head + 2; - - length = ((*p << 8) + *(p + 1)); - - /* JFIF segment format */ - if (!memcmp(p + 2, JfifHeader, sizeof (JfifHeader))) - { - format = 3; - w = *(p + 14); - h = *(p + 15); - } - else if (!memcmp(p + 2, JfxxHeader, sizeof (JfxxHeader))) - { - if (*(p + 7) == 0x11) - format = 1; - else - format = 3; - w = *(p + 8); - h = *(p + 9); - } - - data_size = format * w * h; - - if ((*position + 2+ length + data_size) > fsize) - return EINA_FALSE; - - *position = *position + 2 + length + data_size; - - return EINA_TRUE; -} - -/* If app1 data is abnormal, returns EINA_FALSE. - If app1 data is normal, returns EINA_TRUE. - If app1 data is normal but not orientation data, orientation value is -1. - */ - -static Eina_Bool -_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]; - ExifByteAlign byte_align; - unsigned int num_directory = 0; - unsigned int i, j; - int direction; - unsigned int data_size = 0; - - /* app1 mark:2, data_size:2, exif:6 tiff:8 */ - if ((*position + 18) >= fsize) return EINA_FALSE; - app1_head = map + *position; - buf = app1_head; - - data_size = ((*(buf + 2) << 8) + *(buf + 3)); - if ((*position + 2 + data_size) > fsize) return EINA_FALSE; - - if (memcmp(buf + 4, ExifHeader, sizeof (ExifHeader))) - { - *position = *position + 2 + data_size; - *orientation_res = -1; - return EINA_TRUE; - } - - /* 2. get 10&11 byte get info of "II(0x4949)" or "MM(0x4d4d)" */ - /* 3. get [18]&[19] get directory entry # */ - if (!memcmp(buf + 10, MM, sizeof (MM))) - { - byte_align = EXIF_BYTE_ALIGN_MM; - num_directory = ((*(buf + 18) << 8) + *(buf + 19)); - orientation[0] = 0x01; - orientation[1] = 0x12; - } - else if (!memcmp(buf + 10, II, sizeof (II))) - { - byte_align = EXIF_BYTE_ALIGN_II; - num_directory = ((*(buf + 19) << 8) + *(buf + 18)); - orientation[0] = 0x12; - orientation[1] = 0x01; - } - else return EINA_FALSE; - - /* check num_directory data */ - if ((*position + (12 * num_directory + 20)) > fsize) return EINA_FALSE; - - buf = app1_head + 20; - - j = 0; - - for (i = 0; i < num_directory; i++ ) - { - if (!memcmp(buf + j, orientation, 2)) - { - /*get orientation tag */ - if (byte_align == EXIF_BYTE_ALIGN_MM) - direction = *(buf+ j + 9); - else direction = *(buf+ j + 8); - switch (direction) - { - case 3: - *orientation_res = 180; - *flipped = EINA_FALSE; - return EINA_TRUE; - case 4: - *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; - *flipped = EINA_TRUE; - return EINA_TRUE; - case 5: - *orientation_res = 270; - *flipped = EINA_TRUE; - return EINA_TRUE; - case 8: - *orientation_res = 270; - *flipped = EINA_FALSE; - return EINA_TRUE; - case 2: - *orientation_res = 0; - *flipped = EINA_TRUE; - return EINA_TRUE; - default: - *orientation_res = 0; - *flipped = EINA_FALSE; - return EINA_TRUE; - } - } - else - j = j + 12; - } - return EINA_FALSE; -} - -static int -_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 */ - if (length < 22) return 0; - buf = (unsigned char *)map; - - position = 2; - /* 2. check 2,3 bypte with APP0(0xFFE0) or APP1(0xFFE1) */ - while((length - position) > 0) - { - if (!memcmp(buf + position, App0, sizeof (App0))) - { - res = _get_next_app0(map, length, &position); - if (!res) break; - } - else if (!memcmp(buf + position, App1, sizeof (App1))) - { - res = _get_orientation_app1(map, length, &position, &orientation, flipped); - if (!res) break; - if (orientation != -1) return orientation; - } - else break; - } - 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) -{ - unsigned int scalew, scaleh; - struct jpeg_decompress_struct cinfo; - struct _JPEG_error_mgr jerr; - - /* for rotation decoding */ - int degree = 0; - Eina_Bool change_wh = EINA_FALSE; - unsigned int load_opts_w = 0, load_opts_h = 0; - - memset(&cinfo, 0, sizeof(cinfo)); - cinfo.err = jpeg_std_error(&(jerr.pub)); - jerr.pub.error_exit = _JPEGFatalErrorHandler; - jerr.pub.emit_message = _JPEGErrorHandler2; - jerr.pub.output_message = _JPEGErrorHandler; - if (setjmp(jerr.setjmp_buffer)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - if (cinfo.saw_JFIF_marker) - *error = EVAS_LOAD_ERROR_CORRUPT_FILE; - else - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; - } - jpeg_create_decompress(&cinfo); - - if (_evas_jpeg_membuf_src(&cinfo, map, length)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return EINA_FALSE; - } - - jpeg_read_header(&cinfo, TRUE); - cinfo.do_fancy_upsampling = FALSE; - cinfo.do_block_smoothing = FALSE; - cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) - cinfo.dither_mode = JDITHER_ORDERED; - cinfo.buffered_image = TRUE; // buffered mode in case jpg is progressive - jpeg_start_decompress(&cinfo); - - /* rotation decoding */ - if (opts->orientation) - { - degree = _get_orientation(map, length, flipped); - if (degree != 0 || *flipped) - { - opts->degree = degree; - *rotated = EINA_TRUE; - - if (degree == 90 || degree == 270) - change_wh = EINA_TRUE; - } - - } - - /* head decoding */ - *w = cinfo.output_width; - *h = cinfo.output_height; - if ((*w < 1) || (*h < 1) || (*w > IMG_MAX_SIZE) || (*h > IMG_MAX_SIZE) || - (IMG_TOO_BIG(*w, *h))) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - if (IMG_TOO_BIG(*w, *h)) - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - else - *error = EVAS_LOAD_ERROR_GENERIC; - return EINA_FALSE; - } - if (opts->scale_down_by > 1) - { - *w /= opts->scale_down_by; - *h /= opts->scale_down_by; - } - else if (opts->dpi > 0.0) - { - *w = (*w * opts->dpi) / 90.0; - *h = (*h * opts->dpi) / 90.0; - } - else if ((opts->w > 0) && (opts->h > 0)) - { - unsigned int w2 = *w, h2 = *h; - /* user set load_opts' w,h on the assumption - that image already rotated according to it's orientation info */ - if (change_wh) - { - load_opts_w = opts->w; - load_opts_h = opts->h; - opts->w = load_opts_h; - opts->h = load_opts_w; - } - - if (opts->w > 0) - { - w2 = opts->w; - h2 = (opts->w * *h) / *w; - if ((opts->h > 0) && (h2 > opts->h)) - { - unsigned int w3; - h2 = opts->h; - w3 = (opts->h * *w) / *h; - if (w3 > w2) - w2 = w3; - } - } - else if (opts->h > 0) - { - h2 = opts->h; - w2 = (opts->h * *w) / *h; - } - *w = w2; - *h = h2; - if (change_wh) - { - opts->w = load_opts_w; - opts->h = load_opts_h; - } - } - if (*w < 1) *w = 1; - if (*h < 1) *h = 1; - - if ((*w != cinfo.output_width) || (*h != cinfo.output_height)) - { - scalew = cinfo.output_width / *w; - scaleh = cinfo.output_height / *h; - - *scale = scalew; - if (scaleh < scalew) *scale = scaleh; - - if (*scale > 8) *scale = 8; - else if (*scale < 1) *scale = 1; - - if (*scale == 3) *scale = 2; - else if (*scale == 5) *scale = 4; - else if (*scale == 6) *scale = 4; - else if (*scale == 7) *scale = 4; - } - - if (*scale > 1) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - jpeg_create_decompress(&cinfo); - - if (_evas_jpeg_membuf_src(&cinfo, map, length)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return EINA_FALSE; - } - - jpeg_read_header(&cinfo, TRUE); - cinfo.do_fancy_upsampling = FALSE; - cinfo.do_block_smoothing = FALSE; - cinfo.scale_num = 1; - cinfo.scale_denom = *scale; - cinfo.buffered_image = TRUE; // buffered mode in case jpg is progressive - jpeg_calc_output_dimensions(&(cinfo)); - jpeg_start_decompress(&cinfo); - } - - *w = cinfo.output_width; - *h = cinfo.output_height; - - // be nice and clip region to image. if its totally outside, fail load - if ((opts->region.w > 0) && (opts->region.h > 0)) - { - unsigned int load_region_x = opts->region.x, load_region_y = opts->region.y; - unsigned int load_region_w = opts->region.w, load_region_h = opts->region.h; - if (*rotated) - { - _rotate_region(&load_region_x, &load_region_y, &load_region_w, &load_region_h, - opts->region.x, opts->region.y, opts->region.w, opts->region.h, - *w, *h, degree, *flipped); - } - RECTS_CLIP_TO_RECT(load_region_x, load_region_y, - load_region_w, load_region_h, - 0, 0, *w, *h); - if ((load_region_w <= 0) || (load_region_h <= 0)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_GENERIC; - return EINA_FALSE; - } - *w = load_region_w; - *h = load_region_h; - } -/* end head decoding */ - - if (change_wh) - { - unsigned int tmp; - tmp = *w; - *w = *h; - *h = tmp; - } - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE; -} - -/* -static double -get_time(void) -{ - struct timeval timev; - - gettimeofday(&timev, NULL); - return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000); -} -*/ - -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, - void *pixels, - void *map, size_t size, - int *error) -{ - unsigned int w, h; - struct jpeg_decompress_struct cinfo; - struct _JPEG_error_mgr jerr; - DATA8 *ptr, *line[16], *data; - DATA32 *ptr2, *ptr_rotate = NULL; - unsigned int x, y, l, i, scans; - int region = 0; - /* rotation setting */ - unsigned int ie_w = 0, ie_h = 0; - struct { - unsigned int x, y, w, h; - } opts_region; - volatile int degree = 0; - volatile Eina_Bool change_wh = EINA_FALSE; - Eina_Bool line_done = EINA_FALSE; - - memset(&cinfo, 0, sizeof(cinfo)); - if (prop->rotated) - { - degree = opts->degree; - if (degree == 90 || degree == 270) - change_wh = EINA_TRUE; - } - - cinfo.err = jpeg_std_error(&(jerr.pub)); - jerr.pub.error_exit = _JPEGFatalErrorHandler; - jerr.pub.emit_message = _JPEGErrorHandler2; - jerr.pub.output_message = _JPEGErrorHandler; - if (setjmp(jerr.setjmp_buffer)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_CORRUPT_FILE; - return EINA_FALSE; - } - jpeg_create_decompress(&cinfo); - - if (_evas_jpeg_membuf_src(&cinfo, map, size)) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return 0; - } - - jpeg_read_header(&cinfo, TRUE); - cinfo.do_fancy_upsampling = FALSE; - cinfo.do_block_smoothing = FALSE; - cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) - cinfo.dither_mode = JDITHER_ORDERED; - - if (prop->scale > 1) - { - cinfo.scale_num = 1; - cinfo.scale_denom = prop->scale; - } - - /* Colorspace conversion options */ - /* libjpeg can do the following conversions: */ - /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */ - switch (cinfo.jpeg_color_space) - { - case JCS_UNKNOWN: - break; - case JCS_GRAYSCALE: - case JCS_RGB: - case JCS_YCbCr: - cinfo.out_color_space = JCS_RGB; - break; - case JCS_CMYK: - case JCS_YCCK: - cinfo.out_color_space = JCS_CMYK; - break; - default: - cinfo.out_color_space = JCS_RGB; - break; - } - -/* head decoding */ - jpeg_calc_output_dimensions(&(cinfo)); - jpeg_start_decompress(&cinfo); - - w = cinfo.output_width; - h = cinfo.output_height; - - if (change_wh) - { - ie_w = prop->h; - ie_h = prop->w; - } - else - { - ie_w = prop->w; - ie_h = prop->h; - } - - if ((opts->region.w > 0) && (opts->region.h > 0)) - { - region = 1; - - opts_region.x = opts->region.x; - opts_region.y = opts->region.y; - opts_region.w = opts->region.w; - opts_region.h = opts->region.h; - - if (prop->rotated) - { - unsigned int load_region_x = 0, load_region_y = 0; - unsigned int load_region_w = 0, load_region_h = 0; - - load_region_x = opts->region.x; - load_region_y = opts->region.y; - load_region_w = opts->region.w; - load_region_h = opts->region.h; - - _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; - cinfo.region_y = opts_region.y; - cinfo.region_w = opts_region.w; - cinfo.region_h = opts_region.h; -#endif - } - if ((!region) && ((w != ie_w) || (h != ie_h))) - { - // race condition, the file could have change from when we call header - // this test will not solve the problem with region code. - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_GENERIC; - return EINA_FALSE; - } - if ((region) && - ((ie_w != opts_region.w) || (ie_h != opts_region.h))) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_GENERIC; - return EINA_FALSE; - /* ie_w = opts_region.w; */ - /* ie_h = opts_region.h; */ - /* if (change_wh) */ - /* { */ - /* ie->w = ie_h; */ - /* ie->h = ie_w; */ - /* } */ - /* else */ - /* { */ - /* ie->w = ie_w; */ - /* ie->h = ie_h; */ - /* } */ - } - - if (!(((cinfo.out_color_space == JCS_RGB) && - ((cinfo.output_components == 3) || (cinfo.output_components == 1))) || - ((cinfo.out_color_space == JCS_CMYK) && (cinfo.output_components == 4)))) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; - } - -/* end head decoding */ -/* data decoding */ - if (cinfo.rec_outbuf_height > 16) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; - } - data = alloca(w * 16 * cinfo.output_components); - if ((prop->rotated) && change_wh) - { - ptr2 = malloc(w * h * sizeof(DATA32)); - ptr_rotate = ptr2; - } - else - ptr2 = pixels; - - if (!ptr2) - { - *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; - return EINA_FALSE; - } - - /* We handle first CMYK (4 components) */ - if (cinfo.output_components == 4) - { - // FIXME: handle region - for (i = 0; (int)i < cinfo.rec_outbuf_height; i++) - line[i] = data + (i * w * 4); - for (l = 0; l < h; l += cinfo.rec_outbuf_height) - { - jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); - scans = cinfo.rec_outbuf_height; - if ((h - l) < scans) scans = h - l; - ptr = data; - if (!region) - { - for (y = 0; y < scans; y++) - { - if (cinfo.saw_Adobe_marker) - { - for (x = 0; x < w; x++) - { - /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */ - /* that is C is replaces by 255 - C, etc...*/ - /* See the comment below for the computation of RGB values from CMYK ones. */ - *ptr2 = - (0xff000000) | - ((ptr[0] * ptr[3] / 255) << 16) | - ((ptr[1] * ptr[3] / 255) << 8) | - ((ptr[2] * ptr[3] / 255)); - ptr += 4; - ptr2++; - } - } - else - { - for (x = 0; x < w; x++) - { - /* Conversion from CMYK to RGB is done in 2 steps: */ - /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */ - /* after computation, if C, M, Y and K are between 0 and 1, we have: */ - /* R = (1 - C) * (1 - K) * 255 */ - /* G = (1 - M) * (1 - K) * 255 */ - /* B = (1 - Y) * (1 - K) * 255 */ - /* libjpeg stores CMYK values between 0 and 255, */ - /* so we replace C by C * 255 / 255, etc... and we obtain: */ - /* R = (255 - C) * (255 - K) / 255 */ - /* G = (255 - M) * (255 - K) / 255 */ - /* B = (255 - Y) * (255 - K) / 255 */ - /* with C, M, Y and K between 0 and 255. */ - *ptr2 = - (0xff000000) | - (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) | - (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) | - (((255 - ptr[2]) * (255 - ptr[3]) / 255)); - ptr += 4; - ptr2++; - } - } - } - } - else - { - // if line # > region last line, break - if (l >= (opts_region.y + opts_region.h)) - { - line_done = EINA_TRUE; - /* if rotation flag is set , we have to rotate image */ - goto done; - /*jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_FALSE;*/ - } - // els if scan block intersects region start or later - else if ((l + scans) > - (opts_region.y)) - { - for (y = 0; y < scans; y++) - { - if (((y + l) >= opts_region.y) && - ((y + l) < (opts_region.y + opts_region.h))) - { - ptr += opts_region.x; - if (cinfo.saw_Adobe_marker) - { - for (x = 0; x < opts_region.w; x++) - { - /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */ - /* that is C is replaces by 255 - C, etc...*/ - /* See the comment below for the computation of RGB values from CMYK ones. */ - *ptr2 = - (0xff000000) | - ((ptr[0] * ptr[3] / 255) << 16) | - ((ptr[1] * ptr[3] / 255) << 8) | - ((ptr[2] * ptr[3] / 255)); - ptr += 4; - ptr2++; - } - } - else - { - for (x = 0; x < opts_region.w; x++) - { - /* Conversion from CMYK to RGB is done in 2 steps: */ - /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */ - /* after computation, if C, M, Y and K are between 0 and 1, we have: */ - /* R = (1 - C) * (1 - K) * 255 */ - /* G = (1 - M) * (1 - K) * 255 */ - /* B = (1 - Y) * (1 - K) * 255 */ - /* libjpeg stores CMYK values between 0 and 255, */ - /* so we replace C by C * 255 / 255, etc... and we obtain: */ - /* R = (255 - C) * (255 - K) / 255 */ - /* G = (255 - M) * (255 - K) / 255 */ - /* B = (255 - Y) * (255 - K) / 255 */ - /* with C, M, Y and K between 0 and 255. */ - *ptr2 = - (0xff000000) | - (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) | - (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) | - (((255 - ptr[2]) * (255 - ptr[3]) / 255)); - ptr += 4; - ptr2++; - } - } - ptr += (4 * (w - (opts_region.x + opts_region.w))); - } - else - ptr += (4 * w); - } - } - } - } - } - /* We handle then RGB with 3 components */ - else if (cinfo.output_components == 3) - { -/* - double t; - if (region) - { - // debug for now - printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ", - ie, - ie->w, ie->h, - ie->file, - opts_region.x, - opts_region.y, - opts_region.w, - opts_region.h); - } - t = get_time(); - */ - for (i = 0; (int)i < cinfo.rec_outbuf_height; i++) - line[i] = data + (i * w * 3); - for (l = 0; l < h; l += cinfo.rec_outbuf_height) - { - jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); - scans = cinfo.rec_outbuf_height; - if ((h - l) < scans) scans = h - l; - ptr = data; - if (!region) - { - for (y = 0; y < scans; y++) - { - for (x = 0; x < w; x++) - { - *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]); - ptr += 3; - ptr2++; - } - } - } - else - { - // if line # > region last line, break - // but not return immediately for rotation job - if (l >= (opts_region.y + opts_region.h)) - { - line_done = EINA_TRUE; - /* if rotation flag is set , we have to rotate image */ - goto done; - } - // else if scan block intersects region start or later - else if ((l + scans) > - (opts_region.y)) - { - for (y = 0; y < scans; y++) - { - if (((y + l) >= opts_region.y) && - ((y + l) < (opts_region.y + opts_region.h))) - { - ptr += (3 * opts_region.x); - for (x = 0; x < opts_region.w; x++) - { - *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]); - ptr += 3; - ptr2++; - } - ptr += (3 * (w - (opts_region.x + opts_region.w))); - } - else - ptr += (3 * w); - } - } - } - } -/* - t = get_time() - t; - printf("%3.3f\n", t); - */ - } - /* We finally handle RGB with 1 component */ - else if (cinfo.output_components == 1) - { - for (i = 0; (int)i < cinfo.rec_outbuf_height; i++) - line[i] = data + (i * w); - for (l = 0; l < h; l += cinfo.rec_outbuf_height) - { - jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); - scans = cinfo.rec_outbuf_height; - if ((h - l) < scans) scans = h - l; - ptr = data; - if (!region) - { - for (y = 0; y < scans; y++) - { - for (x = 0; x < w; x++) - { - *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]); - ptr++; - ptr2++; - } - } - } - else - { - // if line # > region last line, break - if (l >= (opts_region.y + opts_region.h)) - { - line_done = EINA_TRUE; - /* if rotation flag is set , we have to rotate image */ - goto done; - /*jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE;*/ - } - // els if scan block intersects region start or later - else if ((l + scans) > - (opts_region.y)) - { - for (y = 0; y < scans; y++) - { - if (((y + l) >= opts_region.y) && - ((y + l) < (opts_region.y + opts_region.h))) - { - ptr += opts_region.x; - for (x = 0; x < opts_region.w; x++) - { - *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]); - ptr++; - ptr2++; - } - ptr += w - (opts_region.x + opts_region.w); - } - else - ptr += w; - } - } - } - } - } - /* if rotation operation need, rotate it */ -done: - - if (prop->rotated) - { - DATA32 *to; - int hw; - - hw = w * h; - to = pixels; - - switch (degree) - { - 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) - { - free(ptr_rotate); - ptr_rotate = NULL; - } - } - - if (line_done) - { - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_FALSE; - } - /* end data decoding */ - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - _evas_jpeg_membuf_src_term(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE; -} - -#if 0 /* not used at the moment */ -static Eina_Bool -evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *error) -{ - int w, h; - struct jpeg_decompress_struct cinfo; - struct _JPEG_error_mgr jerr; - DATA8 *ptr, *line[16], *data; - DATA32 *ptr2; - int x, y, l, i, scans, prevy; - - if (!f) - { - *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; - return EINA_FALSE; - } - cinfo.err = jpeg_std_error(&(jerr.pub)); - jerr.pub.error_exit = _JPEGFatalErrorHandler; - jerr.pub.emit_message = _JPEGErrorHandler2; - jerr.pub.output_message = _JPEGErrorHandler; - if (setjmp(jerr.setjmp_buffer)) - { - jpeg_destroy_decompress(&cinfo); - *error = EVAS_LOAD_ERROR_CORRUPT_FILE; - return EINA_FALSE; - } - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, f); - jpeg_read_header(&cinfo, TRUE); - cinfo.do_fancy_upsampling = FALSE; - cinfo.do_block_smoothing = FALSE; - jpeg_start_decompress(&cinfo); - -/* head decoding */ - ie->w = w = cinfo.output_width; - ie->h = h = cinfo.output_height; -/* end head decoding */ -/* data decoding */ - if (cinfo.rec_outbuf_height > 16) - { - jpeg_destroy_decompress(&cinfo); - *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; - return EINA_FALSE; - } - data = alloca(w * 16 * 3); - if (!ie->flags.loaded) - { - jpeg_destroy_decompress(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE; - } - ptr2 = evas_cache_image_pixels(ie); - prevy = 0; - if (cinfo.output_components == 3) - { - for (i = 0; i < cinfo.rec_outbuf_height; i++) - line[i] = data + (i * w * 3); - for (l = 0; l < h; l += cinfo.rec_outbuf_height) - { - jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); - scans = cinfo.rec_outbuf_height; - if ((h - l) < scans) scans = h - l; - ptr = data; - for (y = 0; y < scans; y++) - { - for (x = 0; x < w; x++) - { - *ptr2 = - ((*ptr2) & 0x00ffffff) | - (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24); - ptr += 3; - ptr2++; - } - } - } - } - else if (cinfo.output_components == 1) - { - for (i = 0; i < cinfo.rec_outbuf_height; i++) - line[i] = data + (i * w); - for (l = 0; l < h; l += cinfo.rec_outbuf_height) - { - jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); - scans = cinfo.rec_outbuf_height; - if ((h - l) < scans) scans = h - l; - ptr = data; - for (y = 0; y < scans; y++) - { - for (x = 0; x < w; x++) - { - *ptr2 = - ((*ptr2) & 0x00ffffff) | - ((ptr[0]) << 24); - ptr++; - ptr2++; - } - } - } - } -/* end data decoding */ - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - *error = EVAS_LOAD_ERROR_NONE; - return EINA_TRUE; -} -#endif - static void * evas_image_load_file_open_jpeg(Eina_File *f, Eina_Stringshare *key EINA_UNUSED, - Evas_Image_Load_Opts *opts, - Evas_Image_Animated *animated EINA_UNUSED, - int *error) + Evas_Image_Load_Opts *opts, + Evas_Image_Animated *animated EINA_UNUSED, + int *error) { Evas_Loader_Internal *loader; + Emile_Image *image; + Emile_Image_Load_Error image_error; + + image = emile_image_jpeg_file_open(f, opts, NULL, &image_error); + if (!image) + { + *error = image_error; + return NULL; + } loader = calloc(1, sizeof (Evas_Loader_Internal)); if (!loader) @@ -1370,84 +38,71 @@ evas_image_load_file_open_jpeg(Eina_File *f, Eina_Stringshare *key EINA_UNUSED, return NULL; } - loader->f = f; - loader->opts = opts; + loader->image = image; + if (opts && (opts->region.w > 0) && (opts->region.h > 0)) + { + EINA_RECTANGLE_SET(&loader->region, + opts->region.x, + opts->region.y, + opts->region.w, + opts->region.h); + } + else + { + EINA_RECTANGLE_SET(&loader->region, + 0, 0, + -1, -1); + } return loader; } + static void evas_image_load_file_close_jpeg(void *loader_data) { - free(loader_data); + Evas_Loader_Internal *loader = loader_data; + + emile_image_close(loader->image); + free(loader); } static Eina_Bool evas_image_load_file_head_jpeg(void *loader_data, - Evas_Image_Property *prop, - int *error) + Evas_Image_Property *prop, + int *error) { Evas_Loader_Internal *loader = loader_data; - Evas_Image_Load_Opts *opts; - Eina_File *f; - void *map; - Eina_Bool val; + Emile_Image_Load_Error image_error; + Eina_Bool ret; - opts = loader->opts; - f = loader->f; + ret = emile_image_head(loader->image, + prop, sizeof (Emile_Image_Property), + &image_error); + *error = image_error; - map = eina_file_map_all(f, EINA_FILE_RANDOM); - if (!map) - { - *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; - return EINA_FALSE; - } - - val = evas_image_load_file_head_jpeg_internal(&prop->w, &prop->h, - &prop->scale, &prop->rotated, - &prop->flipped, - opts, - map, eina_file_size_get(f), - error); - - eina_file_map_free(f, map); - - return val; + return ret; } -static Eina_Bool +Eina_Bool evas_image_load_file_data_jpeg(void *loader_data, - Evas_Image_Property *prop, - void *pixels, - int *error) + Evas_Image_Property *prop, + void *pixels, + int *error) { Evas_Loader_Internal *loader = loader_data; - Evas_Image_Load_Opts *opts; - Eina_File *f; - void *map; - Eina_Bool val = EINA_FALSE; + Emile_Image_Load_Error image_error; + Eina_Bool ret; - f = loader->f; - opts = loader->opts; - - map = eina_file_map_all(f, EINA_FILE_WILLNEED); - if (!map) - { - *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; - goto on_error; - } - - val = evas_image_load_file_data_jpeg_internal(opts, prop, pixels, - map, eina_file_size_get(f), - error); - - eina_file_map_free(f, map); - - on_error: - return val; + ret = emile_image_data(loader->image, + prop, sizeof (Emile_Image_Property), + pixels, + &image_error); + *error = image_error; + return ret; } -static Evas_Image_Load_Func evas_image_load_jpeg_func = +Evas_Image_Load_Func evas_image_load_jpeg_func = { evas_image_load_file_open_jpeg, evas_image_load_file_close_jpeg, @@ -1455,7 +110,7 @@ static Evas_Image_Load_Func evas_image_load_jpeg_func = evas_image_load_file_data_jpeg, NULL, EINA_TRUE, - EINA_TRUE + EINA_FALSE }; static int