#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "evas_macros.h" #include "evas_cserve2.h" #include "evas_cserve2_slave.h" typedef struct _JPEG_error_mgr *emptr; struct _JPEG_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; 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 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 & App1*/ static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; static const unsigned char App1[] = {0xff, 0xe1}; typedef enum { EXIF_BYTE_ALIGN_II, EXIF_BYTE_ALIGN_MM } ExifByteAlign; static int _get_orientation(void *map, size_t length) { char *buf; char orientation[2]; ExifByteAlign byte_align; unsigned int num_directory = 0; unsigned int i, j; int direction; /* open file and get 22 byte frome file */ if (!map) return 0; /* 1. read 22byte */ if (length < 22) return 0; buf = (char *)map; /* 2. check 2,3 bypte with APP1(0xFFE1) */ if (memcmp(buf + 2, App1, sizeof (App1))) return 0; /* 3. check 6~11bype with Exif Header (0x45786966 0000) */ if (memcmp(buf + 6, ExifHeader, sizeof (ExifHeader))) return 0; /* 4. get 12&13 byte get info of "II(0x4949)" or "MM(0x4d4d)" */ /* 5. get [20]&[21] get directory entry # */ if (!strncmp(buf + 12, "MM", 2)) { byte_align = EXIF_BYTE_ALIGN_MM; num_directory = ((*(buf + 20) << 8) + *(buf + 21)); orientation[0] = 0x01; orientation[1] = 0x12; } else if (!strncmp(buf + 12, "II", 2)) { byte_align = EXIF_BYTE_ALIGN_II; num_directory = ((*(buf + 21) << 8) + *(buf + 20)); orientation[0] = 0x12; orientation[1] = 0x01; } else return 0; buf = (char *)map + 22; if (length < (12 * num_directory + 22)) return 0; j = 0; for (i = 0; i < num_directory; i++ ) { if (!strncmp(buf + j, orientation, 2)) { /*get orientation tag */ if (byte_align == EXIF_BYTE_ALIGN_MM) direction = *(buf+ j + 11); else direction = *(buf+ j + 8); switch (direction) { case 3: case 4: return 180; case 6: case 7: return 90; case 5: case 8: return 270; default: return 0; } } else j = j + 12; } return 0; } static Eina_Bool evas_image_load_file_head_jpeg_internal(Evas_Img_Load_Params *ilp, void *map, size_t length, int *error) { unsigned int w, h, 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; 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 = CSERVE2_CORRUPT_FILE; else *error = CSERVE2_UNKNOWN_FORMAT; return EINA_FALSE; } degree = 0; change_wh = 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 = CSERVE2_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; jpeg_start_decompress(&cinfo); /* rotation decoding */ if (ilp->opts.orientation) { degree = _get_orientation(map, length); if (degree != 0) { ilp->degree = degree; ilp->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 = CSERVE2_RESOURCE_ALLOCATION_FAILED; else *error = CSERVE2_GENERIC; return EINA_FALSE; } if (ilp->opts.scale_down_by > 1) { w /= ilp->opts.scale_down_by; h /= ilp->opts.scale_down_by; } else if (ilp->opts.dpi > 0.0) { w = (w * ilp->opts.dpi) / 90.0; h = (h * ilp->opts.dpi) / 90.0; } else if ((ilp->opts.w > 0) && (ilp->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 = ilp->opts.w; load_opts_h = ilp->opts.h; ilp->opts.w = load_opts_h; ilp->opts.h = load_opts_w; } if (ilp->opts.w > 0) { w2 = ilp->opts.w; h2 = (ilp->opts.w * h) / w; if ((ilp->opts.h > 0) && (h2 > ilp->opts.h)) { unsigned int w3; h2 = ilp->opts.h; w3 = (ilp->opts.h * w) / h; if (w3 > w2) w2 = w3; } } else if (ilp->opts.h > 0) { h2 = ilp->opts.h; w2 = (ilp->opts.h * w) / h; } w = w2; h = h2; if (change_wh) { ilp->opts.w = load_opts_w; ilp->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; ilp->scale = scalew; if (scaleh < scalew) ilp->scale = scaleh; if (ilp->scale > 8) ilp->scale = 8; else if (ilp->scale < 1) ilp->scale = 1; if (ilp->scale == 3) ilp->scale = 2; else if (ilp->scale == 5) ilp->scale = 4; else if (ilp->scale == 6) ilp->scale = 4; else if (ilp->scale == 7) ilp->scale = 4; } if (ilp->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 = CSERVE2_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 = ilp->scale; jpeg_calc_output_dimensions(&(cinfo)); jpeg_start_decompress(&cinfo); } ilp->w = cinfo.output_width; ilp->h = cinfo.output_height; // be nice and clip region to image. if its totally outside, fail load if ((ilp->opts.rw > 0) && (ilp->opts.rh > 0)) { unsigned int load_region_x = 0, load_region_y = 0; unsigned int load_region_w = 0, load_region_h = 0; if (ilp->rotated) { load_region_x = ilp->opts.rx; load_region_y = ilp->opts.ry; load_region_w = ilp->opts.rw; load_region_h = ilp->opts.rh; switch (degree) { case 90: ilp->opts.rx = load_region_y; ilp->opts.ry = h - (load_region_x + load_region_w); ilp->opts.rw = load_region_h; ilp->opts.rh = load_region_w; break; case 180: ilp->opts.rx = w - (load_region_x+ load_region_w); ilp->opts.ry = h - (load_region_y + load_region_h); break; case 270: ilp->opts.rx = w - (load_region_y + load_region_h); ilp->opts.ry = load_region_x; ilp->opts.rw = load_region_h; ilp->opts.rh = load_region_w; break; default: break; } } RECTS_CLIP_TO_RECT(ilp->opts.rx, ilp->opts.ry, ilp->opts.rw, ilp->opts.rh, 0, 0, ilp->w, ilp->h); if ((ilp->opts.rw <= 0) || (ilp->opts.rh <= 0)) { jpeg_destroy_decompress(&cinfo); _evas_jpeg_membuf_src_term(&cinfo); *error = CSERVE2_GENERIC; return EINA_FALSE; } ilp->w = ilp->opts.rw; ilp->h = ilp->opts.rh; if (ilp->rotated) { ilp->opts.rx = load_region_x; ilp->opts.ry = load_region_y; ilp->opts.rw = load_region_w; ilp->opts.rh = load_region_h; } } /* end head decoding */ if (change_wh) { unsigned int tmp; tmp = ilp->w; ilp->w = ilp->h; ilp->h = tmp; } jpeg_destroy_decompress(&cinfo); _evas_jpeg_membuf_src_term(&cinfo); *error = CSERVE2_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 Eina_Bool evas_image_load_file_data_jpeg_internal(Evas_Img_Load_Params *ilp, 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 tmp; unsigned int load_region_x = 0, load_region_y = 0; unsigned int load_region_w = 0, load_region_h = 0; volatile int degree = 0; volatile Eina_Bool change_wh = EINA_FALSE; Eina_Bool line_done = EINA_FALSE; if (ilp->rotated) { degree = ilp->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 = CSERVE2_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 = CSERVE2_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 (ilp->scale > 1) { cinfo.scale_num = 1; cinfo.scale_denom = ilp->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: /* unhandled format, do something */ break; } /* head decoding */ jpeg_calc_output_dimensions(&(cinfo)); jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; if (change_wh) { tmp = ilp->w; ilp->w = ilp->h; ilp->h = tmp; } if ((ilp->opts.rw > 0) && (ilp->opts.rh > 0)) { region = 1; if (ilp->rotated) { load_region_x = ilp->opts.rx; load_region_y = ilp->opts.ry; load_region_w = ilp->opts.rw; load_region_h = ilp->opts.rh; switch (degree) { case 90: ilp->opts.rx = load_region_y; ilp->opts.ry = h - (load_region_x + load_region_w); ilp->opts.rw = load_region_h; ilp->opts.rh = load_region_w; break; case 180: ilp->opts.rx = w - (load_region_x+ load_region_w); ilp->opts.ry = h - (load_region_y + load_region_h); break; case 270: ilp->opts.rx = w - (load_region_y + load_region_h); ilp->opts.ry = load_region_x; ilp->opts.rw = load_region_h; ilp->opts.rh = load_region_w; break; default: break; } } #ifdef BUILD_LOADER_JPEG_REGION cinfo.region_x = ilp->opts.rx; cinfo.region_y = ilp->opts.ry; cinfo.region_w = ilp->opts.rw; cinfo.region_h = ilp->opts.rh; #endif } /* what to do about this? We'll check for this kind of races on loaders * or cache invalidation due to file modification should always be * detected by the server? */ if ((!region) && ((w != ilp->w) || (h != ilp->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 = CSERVE2_GENERIC; return EINA_FALSE; } if ((region) && ((ilp->w != ilp->opts.rw) || (ilp->h != ilp->opts.rh))) { ilp->w = ilp->opts.rw; ilp->h = ilp->opts.rh; } 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 = CSERVE2_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 = CSERVE2_UNKNOWN_FORMAT; return EINA_FALSE; } data = alloca(w * 16 * cinfo.output_components); if ((ilp->rotated) && change_wh) { ptr2 = malloc(ilp->w * ilp->h * sizeof(DATA32)); ptr_rotate = ptr2; } else ptr2 = ilp->buffer;; if (!ptr2) { *error = CSERVE2_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 >= (ilp->opts.ry + ilp->opts.rh)) { 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 = NONE; return EINA_FALSE;*/ } // els if scan block intersects region start or later else if ((l + scans) > (ilp->opts.ry)) { for (y = 0; y < scans; y++) { if (((y + l) >= ilp->opts.ry) && ((y + l) < (ilp->opts.ry + ilp->opts.rh))) { ptr += ilp->opts.rx; if (cinfo.saw_Adobe_marker) { for (x = 0; x < ilp->opts.rw; 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 < ilp->opts.rw; 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 - (ilp->opts.rx + ilp->opts.rw))); } 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, ilp->opts.rx, ilp->opts.ry, ilp->opts.rw, ilp->opts.rh); } 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 >= (ilp->opts.ry + ilp->opts.rh)) { 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) > (ilp->opts.ry)) { for (y = 0; y < scans; y++) { if (((y + l) >= ilp->opts.ry) && ((y + l) < (ilp->opts.ry + ilp->opts.rh))) { ptr += (3 * ilp->opts.rx); for (x = 0; x < ilp->opts.rw; x++) { *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]); ptr += 3; ptr2++; } ptr += (3 * (w - (ilp->opts.rx + ilp->opts.rw))); } 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 >= (ilp->opts.ry + ilp->opts.rh)) { 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 = NONE; return EINA_TRUE;*/ } // els if scan block intersects region start or later else if ((l + scans) > (ilp->opts.ry)) { for (y = 0; y < scans; y++) { if (((y + l) >= ilp->opts.ry) && ((y + l) < (ilp->opts.ry + ilp->opts.rh))) { ptr += ilp->opts.rx; for (x = 0; x < ilp->opts.rw; x++) { *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]); ptr++; ptr2++; } ptr += w - (ilp->opts.rx + ilp->opts.rw); } else ptr += w; } } } } } /* if rotation operation need, rotate it */ done: if (ilp->rotated) { DATA32 *data1, *data2, *to, *from; int lx, ly, lw, lh, hw; if (change_wh) { tmp = ilp->w; ilp->w = ilp->h; ilp->h = tmp; } lw = ilp->w; lh = ilp->h; hw = lw * lh; data1 = ilp->buffer; if (degree == 180) { 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 + lw - 1; hw = -hw - 1; } else if (degree == 270) { to = data1 + hw - lw; lw = -lw; hw = hw + 1; } if (to) { from = data2; for (lx = ilp->w; --lx >= 0;) { for (ly = ilp->h; --ly >= 0;) { *to = *from; from++; to += lw; } to += hw; } } if (ptr_rotate) { free(ptr_rotate); ptr_rotate = NULL; } } if (region) { ilp->opts.rx = load_region_x; ilp->opts.ry = load_region_y; ilp->opts.rw = load_region_w; ilp->opts.rh = load_region_h; } } if (line_done) { jpeg_destroy_decompress(&cinfo); _evas_jpeg_membuf_src_term(&cinfo); if (ptr2) free(ptr2); *error = CSERVE2_NONE; return EINA_FALSE; } /* end data decoding */ jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); _evas_jpeg_membuf_src_term(&cinfo); if (ptr2) free(ptr2); *error = CSERVE2_NONE; return EINA_TRUE; } Eina_Bool evas_image_load_file_head_jpeg(Evas_Img_Load_Params *ilp, const char *file, const char *key EINA_UNUSED, int *error) { Eina_File *f; void *map; Eina_Bool val = EINA_FALSE; f = eina_file_open(file, EINA_FALSE); if (!f) { *error = CSERVE2_DOES_NOT_EXIST; return EINA_FALSE; } map = eina_file_map_all(f, EINA_FILE_WILLNEED); if (!map) { *error = CSERVE2_DOES_NOT_EXIST; goto on_error; } val = evas_image_load_file_head_jpeg_internal(ilp, map, eina_file_size_get(f), error); eina_file_map_free(f, map); on_error: eina_file_close(f); return val; } static Eina_Bool evas_image_load_file_data_jpeg(Evas_Img_Load_Params *ilp, const char *file, const char *key EINA_UNUSED, int *error) { Eina_File *f; void *map; Eina_Bool val = EINA_FALSE; f = eina_file_open(file, EINA_FALSE); if (!f) { *error = CSERVE2_DOES_NOT_EXIST; return EINA_FALSE; } map = eina_file_map_all(f, EINA_FILE_WILLNEED); if (!map) { *error = CSERVE2_DOES_NOT_EXIST; goto on_error; } val = evas_image_load_file_data_jpeg_internal(ilp, map, eina_file_size_get(f), error); eina_file_map_free(f, map); on_error: eina_file_close(f); return val; } static Evas_Loader_Module_Api modapi = { EVAS_CSERVE2_MODULE_API_VERSION, "jpeg", evas_image_load_file_head_jpeg, evas_image_load_file_data_jpeg }; static Eina_Bool module_init(void) { return evas_cserve2_loader_register(&modapi); } static void module_shutdown(void) { } EINA_MODULE_INIT(module_init); EINA_MODULE_SHUTDOWN(module_shutdown);