2006-10-27 20:02:23 -07:00
|
|
|
#include "evas_common.h"
|
|
|
|
#include "evas_private.h"
|
|
|
|
|
2006-01-14 12:03:42 -08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <jpeglib.h>
|
|
|
|
#include <setjmp.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 int evas_image_load_file_head_jpeg_internal(RGBA_Image *im, FILE *f);
|
|
|
|
static int evas_image_load_file_data_jpeg_internal(RGBA_Image *im, FILE *f);
|
|
|
|
#if 0 /* not used at the moment */
|
|
|
|
static int evas_image_load_file_data_jpeg_alpha_internal(RGBA_Image *im, FILE *f);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int evas_image_load_file_head_jpeg(RGBA_Image *im, const char *file, const char *key);
|
|
|
|
int evas_image_load_file_data_jpeg(RGBA_Image *im, const char *file, const char *key);
|
|
|
|
|
|
|
|
Evas_Image_Load_Func evas_image_load_jpeg_func =
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
emptr errmgr;
|
|
|
|
|
|
|
|
errmgr = (emptr) cinfo->err;
|
|
|
|
/* cinfo->err->output_message(cinfo);*/
|
|
|
|
/* longjmp(errmgr->setjmp_buffer, 1);*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_JPEGErrorHandler2(j_common_ptr cinfo, int msg_level)
|
|
|
|
{
|
|
|
|
emptr errmgr;
|
|
|
|
|
|
|
|
errmgr = (emptr) cinfo->err;
|
|
|
|
/* cinfo->err->output_message(cinfo);*/
|
|
|
|
/* longjmp(errmgr->setjmp_buffer, 1);*/
|
|
|
|
return;
|
|
|
|
msg_level = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
evas_image_load_file_head_jpeg_internal(RGBA_Image *im, FILE *f)
|
|
|
|
{
|
2006-08-18 18:48:13 -07:00
|
|
|
int w, h, scalew, scaleh;
|
2006-01-14 12:03:42 -08:00
|
|
|
struct jpeg_decompress_struct cinfo;
|
|
|
|
struct _JPEG_error_mgr jerr;
|
|
|
|
|
|
|
|
if (!f) return 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);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
jpeg_create_decompress(&cinfo);
|
|
|
|
jpeg_stdio_src(&cinfo, f);
|
|
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
|
|
cinfo.do_block_smoothing = FALSE;
|
2008-04-11 17:32:30 -07:00
|
|
|
cinfo.dct_method = JDCT_IFAST;
|
|
|
|
cinfo.dither_mode = JDITHER_ORDERED;
|
2006-01-14 12:03:42 -08:00
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
|
|
|
|
/* head decoding */
|
2006-08-18 18:48:13 -07:00
|
|
|
w = cinfo.output_width;
|
|
|
|
h = cinfo.output_height;
|
2006-11-04 21:07:53 -08:00
|
|
|
if ((w < 1) || (h < 1) || (w > 8192) || (h > 8192))
|
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-04-11 17:32:30 -07:00
|
|
|
if (im->cache_entry.load_opts.scale_down_by > 1)
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
2008-04-11 17:32:30 -07:00
|
|
|
w /= im->cache_entry.load_opts.scale_down_by;
|
|
|
|
h /= im->cache_entry.load_opts.scale_down_by;
|
2006-08-18 18:48:13 -07:00
|
|
|
}
|
2008-04-11 17:32:30 -07:00
|
|
|
else if (im->cache_entry.load_opts.dpi > 0.0)
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
2008-04-11 17:32:30 -07:00
|
|
|
w = (w * im->cache_entry.load_opts.dpi) / 90.0;
|
|
|
|
h = (h * im->cache_entry.load_opts.dpi) / 90.0;
|
2006-08-18 18:48:13 -07:00
|
|
|
}
|
2008-04-11 17:32:30 -07:00
|
|
|
else if ((im->cache_entry.load_opts.w > 0) &&
|
|
|
|
(im->cache_entry.load_opts.h > 0))
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
|
|
|
int w2, h2;
|
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
w2 = im->cache_entry.load_opts.w;
|
|
|
|
h2 = (im->cache_entry.load_opts.w * h) / w;
|
|
|
|
if (h2 > im->cache_entry.load_opts.h)
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
2008-04-11 17:32:30 -07:00
|
|
|
h2 = im->cache_entry.load_opts.h;
|
|
|
|
w2 = (im->cache_entry.load_opts.h * w) / h;
|
2006-08-18 18:48:13 -07:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
im->cache_entry.scale = scalew;
|
|
|
|
if (scaleh < scalew) im->cache_entry.scale = scaleh;
|
2006-08-18 18:48:13 -07:00
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
if (im->cache_entry.scale > 8) im->cache_entry.scale = 8;
|
|
|
|
else if (im->cache_entry.scale < 1) im->cache_entry.scale = 1;
|
2006-08-18 18:48:13 -07:00
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
if (im->cache_entry.scale == 3) im->cache_entry.scale = 2;
|
|
|
|
else if (im->cache_entry.scale == 5) im->cache_entry.scale = 4;
|
|
|
|
else if (im->cache_entry.scale == 6) im->cache_entry.scale = 4;
|
|
|
|
else if (im->cache_entry.scale == 7) im->cache_entry.scale = 4;
|
2006-08-18 18:48:13 -07:00
|
|
|
}
|
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
if (im->cache_entry.scale > 1)
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
|
|
|
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;
|
2008-04-11 17:32:30 -07:00
|
|
|
cinfo.scale_denom = im->cache_entry.scale;
|
2006-08-18 18:48:13 -07:00
|
|
|
jpeg_calc_output_dimensions(&(cinfo));
|
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
}
|
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
im->cache_entry.w = cinfo.output_width;
|
|
|
|
im->cache_entry.h = cinfo.output_height;
|
2006-01-14 12:03:42 -08:00
|
|
|
/* end head decoding */
|
|
|
|
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
evas_image_load_file_data_jpeg_internal(RGBA_Image *im, FILE *f)
|
|
|
|
{
|
|
|
|
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, count, prevy;
|
|
|
|
|
|
|
|
if (!f) return 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);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
jpeg_create_decompress(&cinfo);
|
|
|
|
jpeg_stdio_src(&cinfo, f);
|
|
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
|
|
cinfo.do_block_smoothing = FALSE;
|
2006-08-18 18:48:13 -07:00
|
|
|
cinfo.dct_method = JDCT_IFAST;
|
2008-04-11 17:32:30 -07:00
|
|
|
cinfo.dither_mode = JDITHER_ORDERED;
|
|
|
|
|
|
|
|
if (im->cache_entry.scale > 1)
|
2006-08-18 18:48:13 -07:00
|
|
|
{
|
|
|
|
cinfo.scale_num = 1;
|
2008-04-11 17:32:30 -07:00
|
|
|
cinfo.scale_denom = im->cache_entry.scale;
|
2006-08-18 18:48:13 -07:00
|
|
|
}
|
|
|
|
|
2006-01-14 12:03:42 -08:00
|
|
|
/* head decoding */
|
2006-08-18 18:48:13 -07:00
|
|
|
jpeg_calc_output_dimensions(&(cinfo));
|
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
|
|
|
|
w = cinfo.output_width;
|
|
|
|
h = cinfo.output_height;
|
2006-08-18 18:49:33 -07:00
|
|
|
|
2008-04-11 17:32:30 -07:00
|
|
|
if ((w != im->cache_entry.w) || (h != im->cache_entry.h))
|
2006-08-18 18:49:33 -07:00
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-08-18 18:48:13 -07:00
|
|
|
|
2006-01-14 12:03:42 -08:00
|
|
|
/* end head decoding */
|
|
|
|
/* data decoding */
|
|
|
|
if (cinfo.rec_outbuf_height > 16)
|
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
data = alloca(w * 16 * 3);
|
2008-04-11 17:32:30 -07:00
|
|
|
evas_cache_image_surface_alloc(&im->cache_entry, w, h);
|
|
|
|
if (!im->image.data)
|
2006-01-14 12:03:42 -08:00
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-04-11 17:32:30 -07:00
|
|
|
ptr2 = im->image.data;
|
2006-01-14 12:03:42 -08:00
|
|
|
count = 0;
|
|
|
|
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 =
|
|
|
|
(0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]);
|
|
|
|
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 =
|
|
|
|
(0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]);
|
|
|
|
ptr++;
|
|
|
|
ptr2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* end data decoding */
|
|
|
|
jpeg_finish_decompress(&cinfo);
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 /* not used at the moment */
|
|
|
|
static int
|
|
|
|
evas_image_load_file_data_jpeg_alpha_internal(RGBA_Image *im, FILE *f)
|
|
|
|
{
|
|
|
|
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, count, prevy;
|
|
|
|
|
|
|
|
if (!f) return 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);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
im->image->w = w = cinfo.output_width;
|
|
|
|
im->image->h = h = cinfo.output_height;
|
|
|
|
/* end head decoding */
|
|
|
|
/* data decoding */
|
|
|
|
if (cinfo.rec_outbuf_height > 16)
|
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
data = alloca(w * 16 * 3);
|
|
|
|
if (!im->image->data)
|
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ptr2 = im->image->data;
|
|
|
|
count = 0;
|
|
|
|
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);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_image_load_file_head_jpeg(RGBA_Image *im, const char *file, const char *key)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
if ((!file)) return 0;
|
|
|
|
f = fopen(file, "rb");
|
|
|
|
if (!f) return 0;
|
|
|
|
val = evas_image_load_file_head_jpeg_internal(im, f);
|
|
|
|
fclose(f);
|
|
|
|
return val;
|
|
|
|
key = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
evas_image_load_file_data_jpeg(RGBA_Image *im, const char *file, const char *key)
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
if ((!file)) return 0;
|
|
|
|
f = fopen(file, "rb");
|
|
|
|
if (!f) return 0;
|
|
|
|
val = evas_image_load_file_data_jpeg_internal(im, f);
|
|
|
|
fclose(f);
|
|
|
|
return val;
|
|
|
|
key = 0;
|
|
|
|
}
|
|
|
|
|
2006-09-06 00:28:46 -07:00
|
|
|
EAPI int
|
|
|
|
module_open(Evas_Module *em)
|
2006-01-14 12:03:42 -08:00
|
|
|
{
|
|
|
|
if (!em) return 0;
|
|
|
|
em->functions = (void *)(&evas_image_load_jpeg_func);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-09-06 00:28:46 -07:00
|
|
|
EAPI void
|
|
|
|
module_close(void)
|
2006-01-14 12:03:42 -08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-09-06 00:28:46 -07:00
|
|
|
EAPI Evas_Module_Api evas_modapi =
|
2006-01-14 12:03:42 -08:00
|
|
|
{
|
|
|
|
EVAS_MODULE_API_VERSION,
|
|
|
|
EVAS_MODULE_TYPE_IMAGE_LOADER,
|
|
|
|
"jpeg",
|
|
|
|
"none"
|
|
|
|
};
|