789 lines
25 KiB
C
789 lines
25 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_EVIL
|
|
# include <Evil.h>
|
|
#endif
|
|
|
|
#include <setjmp.h>
|
|
#include <jpeglib.h>
|
|
|
|
#include "evas_common.h"
|
|
#include "evas_private.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 Eina_Bool evas_image_load_file_head_jpeg_internal(Image_Entry *ie, FILE *f, int *error) EINA_ARG_NONNULL(1, 2, 3);
|
|
static Eina_Bool evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f, int *error) EINA_ARG_NONNULL(1, 2, 3);
|
|
#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 Eina_Bool evas_image_load_file_head_jpeg(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
|
|
static Eina_Bool evas_image_load_file_data_jpeg(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
|
|
|
|
static Evas_Image_Load_Func evas_image_load_jpeg_func =
|
|
{
|
|
EINA_TRUE,
|
|
evas_image_load_file_head_jpeg,
|
|
evas_image_load_file_data_jpeg
|
|
};
|
|
|
|
|
|
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 __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 __UNUSED__, int msg_level __UNUSED__)
|
|
{
|
|
/* emptr errmgr; */
|
|
|
|
/* errmgr = (emptr) cinfo->err; */
|
|
/* cinfo->err->output_message(cinfo);*/
|
|
/* longjmp(errmgr->setjmp_buffer, 1);*/
|
|
return;
|
|
}
|
|
|
|
static Eina_Bool
|
|
evas_image_load_file_head_jpeg_internal(Image_Entry *ie, FILE *f, int *error)
|
|
{
|
|
unsigned int w, h, scalew, scaleh;
|
|
struct jpeg_decompress_struct cinfo;
|
|
struct _JPEG_error_mgr jerr;
|
|
|
|
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);
|
|
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);
|
|
jpeg_stdio_src(&cinfo, f);
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
cinfo.do_block_smoothing = FALSE;
|
|
cinfo.dct_method = JDCT_IFAST;
|
|
cinfo.dither_mode = JDITHER_ORDERED;
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
/* 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);
|
|
if (IMG_TOO_BIG(w, h))
|
|
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
|
|
else
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
|
return EINA_FALSE;
|
|
}
|
|
if (ie->load_opts.scale_down_by > 1)
|
|
{
|
|
w /= ie->load_opts.scale_down_by;
|
|
h /= ie->load_opts.scale_down_by;
|
|
}
|
|
else if (ie->load_opts.dpi > 0.0)
|
|
{
|
|
w = (w * ie->load_opts.dpi) / 90.0;
|
|
h = (h * ie->load_opts.dpi) / 90.0;
|
|
}
|
|
else if ((ie->load_opts.w > 0) && (ie->load_opts.h > 0))
|
|
{
|
|
unsigned int w2 = w, h2 = h;
|
|
if (ie->load_opts.w > 0)
|
|
{
|
|
w2 = ie->load_opts.w;
|
|
h2 = (ie->load_opts.w * h) / w;
|
|
if ((ie->load_opts.h > 0) && (h2 > ie->load_opts.h))
|
|
{
|
|
unsigned int w3;
|
|
h2 = ie->load_opts.h;
|
|
w3 = (ie->load_opts.h * w) / h;
|
|
if (w3 > w2)
|
|
w2 = w3;
|
|
}
|
|
}
|
|
else if (ie->load_opts.h > 0)
|
|
{
|
|
h2 = ie->load_opts.h;
|
|
w2 = (ie->load_opts.h * w) / h;
|
|
}
|
|
w = w2;
|
|
h = h2;
|
|
}
|
|
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;
|
|
|
|
ie->scale = scalew;
|
|
if (scaleh < scalew) ie->scale = scaleh;
|
|
|
|
if (ie->scale > 8) ie->scale = 8;
|
|
else if (ie->scale < 1) ie->scale = 1;
|
|
|
|
if (ie->scale == 3) ie->scale = 2;
|
|
else if (ie->scale == 5) ie->scale = 4;
|
|
else if (ie->scale == 6) ie->scale = 4;
|
|
else if (ie->scale == 7) ie->scale = 4;
|
|
}
|
|
|
|
if (ie->scale > 1)
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
rewind(f);
|
|
jpeg_create_decompress(&cinfo);
|
|
jpeg_stdio_src(&cinfo, f);
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
cinfo.do_block_smoothing = FALSE;
|
|
cinfo.scale_num = 1;
|
|
cinfo.scale_denom = ie->scale;
|
|
jpeg_calc_output_dimensions(&(cinfo));
|
|
jpeg_start_decompress(&cinfo);
|
|
}
|
|
|
|
ie->w = cinfo.output_width;
|
|
ie->h = cinfo.output_height;
|
|
|
|
// be nice and clip region to image. if its totally outside, fail load
|
|
if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
|
|
{
|
|
RECTS_CLIP_TO_RECT(ie->load_opts.region.x, ie->load_opts.region.y,
|
|
ie->load_opts.region.w, ie->load_opts.region.h,
|
|
0, 0, ie->w, ie->h);
|
|
if ((ie->load_opts.region.w <= 0) || (ie->load_opts.region.h <= 0))
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
|
return EINA_FALSE;
|
|
}
|
|
ie->w = ie->load_opts.region.w;
|
|
ie->h = ie->load_opts.region.h;
|
|
}
|
|
/* end head decoding */
|
|
|
|
jpeg_destroy_decompress(&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 Eina_Bool
|
|
evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f, int *error)
|
|
{
|
|
unsigned int w, h;
|
|
struct jpeg_decompress_struct cinfo;
|
|
struct _JPEG_error_mgr jerr;
|
|
DATA8 *ptr, *line[16], *data;
|
|
DATA32 *ptr2;
|
|
unsigned int x, y, l, i, scans;
|
|
int region = 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);
|
|
*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;
|
|
cinfo.dct_method = JDCT_IFAST;
|
|
cinfo.dither_mode = JDITHER_ORDERED;
|
|
|
|
if (ie->scale > 1)
|
|
{
|
|
cinfo.scale_num = 1;
|
|
cinfo.scale_denom = ie->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;
|
|
}
|
|
|
|
/* head decoding */
|
|
jpeg_calc_output_dimensions(&(cinfo));
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
w = cinfo.output_width;
|
|
h = cinfo.output_height;
|
|
|
|
if ((ie->load_opts.region.w > 0) && (ie->load_opts.region.h > 0))
|
|
{
|
|
region = 1;
|
|
#ifdef BUILD_LOADER_JPEG_REGION
|
|
cinfo.region_x = ie->load_opts.region.x;
|
|
cinfo.region_y = ie->load_opts.region.y;
|
|
cinfo.region_w = ie->load_opts.region.w;
|
|
cinfo.region_h = ie->load_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);
|
|
*error = EVAS_LOAD_ERROR_GENERIC;
|
|
return EINA_FALSE;
|
|
}
|
|
if ((region) &&
|
|
((ie->w != ie->load_opts.region.w) || (ie->h != ie->load_opts.region.h)))
|
|
{
|
|
ie->w = ie->load_opts.region.w;
|
|
ie->h = ie->load_opts.region.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);
|
|
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
/* 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 * cinfo.output_components);
|
|
evas_cache_image_surface_alloc(ie, ie->w, ie->h);
|
|
if (ie->flags.loaded)
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
return EINA_TRUE;
|
|
}
|
|
ptr2 = evas_cache_image_pixels(ie);
|
|
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 >= (ie->load_opts.region.y + ie->load_opts.region.h))
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
return EINA_FALSE;
|
|
}
|
|
// els if scan block intersects region start or later
|
|
else if ((l + scans) >
|
|
(ie->load_opts.region.y))
|
|
{
|
|
for (y = 0; y < scans; y++)
|
|
{
|
|
if (((y + l) >= ie->load_opts.region.y) &&
|
|
((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
|
|
{
|
|
ptr += ie->load_opts.region.x;
|
|
if (cinfo.saw_Adobe_marker)
|
|
{
|
|
for (x = 0; x < ie->load_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 < ie->load_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 - (ie->load_opts.region.x + ie->load_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,
|
|
ie->load_opts.region.x,
|
|
ie->load_opts.region.y,
|
|
ie->load_opts.region.w,
|
|
ie->load_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
|
|
if (l >= (ie->load_opts.region.y + ie->load_opts.region.h))
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
/*
|
|
t = get_time() - t;
|
|
printf("%3.3f\n", t);
|
|
*/
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
return EINA_TRUE;
|
|
}
|
|
// else if scan block intersects region start or later
|
|
else if ((l + scans) >
|
|
(ie->load_opts.region.y))
|
|
{
|
|
for (y = 0; y < scans; y++)
|
|
{
|
|
if (((y + l) >= ie->load_opts.region.y) &&
|
|
((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
|
|
{
|
|
ptr += (3 * ie->load_opts.region.x);
|
|
for (x = 0; x < ie->load_opts.region.w; x++)
|
|
{
|
|
*ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
|
|
ptr += 3;
|
|
ptr2++;
|
|
}
|
|
ptr += (3 * (w - (ie->load_opts.region.x + ie->load_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 >= (ie->load_opts.region.y + ie->load_opts.region.h))
|
|
{
|
|
jpeg_destroy_decompress(&cinfo);
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
return EINA_TRUE;
|
|
}
|
|
// els if scan block intersects region start or later
|
|
else if ((l + scans) >
|
|
(ie->load_opts.region.y))
|
|
{
|
|
for (y = 0; y < scans; y++)
|
|
{
|
|
if (((y + l) >= ie->load_opts.region.y) &&
|
|
((y + l) < (ie->load_opts.region.y + ie->load_opts.region.h)))
|
|
{
|
|
ptr += ie->load_opts.region.x;
|
|
for (x = 0; x < ie->load_opts.region.w; x++)
|
|
{
|
|
*ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
|
|
ptr++;
|
|
ptr2++;
|
|
}
|
|
ptr += w - (ie->load_opts.region.x + ie->load_opts.region.w);
|
|
}
|
|
else
|
|
ptr += w;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* end data decoding */
|
|
jpeg_finish_decompress(&cinfo);
|
|
jpeg_destroy_decompress(&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 Eina_Bool
|
|
evas_image_load_file_head_jpeg(Image_Entry *ie, const char *file, const char *key, int *error)
|
|
{
|
|
int val;
|
|
FILE *f;
|
|
|
|
f = fopen(file, "rb");
|
|
if (!f)
|
|
{
|
|
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
|
|
return EINA_FALSE;
|
|
}
|
|
val = evas_image_load_file_head_jpeg_internal(ie, f, error);
|
|
fclose(f);
|
|
return val;
|
|
key = 0;
|
|
}
|
|
|
|
static Eina_Bool
|
|
evas_image_load_file_data_jpeg(Image_Entry *ie, const char *file, const char *key, int *error)
|
|
{
|
|
int val;
|
|
FILE *f;
|
|
|
|
f = fopen(file, "rb");
|
|
if (!f)
|
|
{
|
|
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
|
|
return EINA_FALSE;
|
|
}
|
|
val = evas_image_load_file_data_jpeg_internal(ie, f, error);
|
|
fclose(f);
|
|
return val;
|
|
key = 0;
|
|
}
|
|
|
|
static int
|
|
module_open(Evas_Module *em)
|
|
{
|
|
if (!em) return 0;
|
|
em->functions = (void *)(&evas_image_load_jpeg_func);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
module_close(Evas_Module *em __UNUSED__)
|
|
{
|
|
}
|
|
|
|
static Evas_Module_Api evas_modapi =
|
|
{
|
|
EVAS_MODULE_API_VERSION,
|
|
"jpeg",
|
|
"none",
|
|
{
|
|
module_open,
|
|
module_close
|
|
}
|
|
};
|
|
|
|
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, jpeg);
|
|
|
|
#ifndef EVAS_STATIC_BUILD_JPEG
|
|
EVAS_EINA_MODULE_DEFINE(image_loader, jpeg);
|
|
#endif
|
|
|