efl/legacy/evas/src/modules/loaders/jpeg/evas_image_load_jpeg.c

438 lines
10 KiB
C

#include "evas_common.h"
#include "evas_private.h"
#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(Image_Entry *ie, FILE *f);
static int evas_image_load_file_data_jpeg_internal(Image_Entry *ie, FILE *f);
#if 0 /* not used at the moment */
static int evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f);
#endif
int evas_image_load_file_head_jpeg(Image_Entry *ie, const char *file, const char *key);
int evas_image_load_file_data_jpeg(Image_Entry *ie, 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(Image_Entry *ie, FILE *f)
{
int w, h, scalew, scaleh;
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;
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 > 8192) || (h > 8192))
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
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))
{
int w2, h2;
w2 = ie->load_opts.w;
h2 = (ie->load_opts.w * h) / w;
if (h2 > ie->load_opts.h)
{
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;
/* end head decoding */
jpeg_destroy_decompress(&cinfo);
return 1;
}
static int
evas_image_load_file_data_jpeg_internal(Image_Entry *ie, 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;
cinfo.dct_method = JDCT_IFAST;
cinfo.dither_mode = JDITHER_ORDERED;
if (ie->scale > 1)
{
cinfo.scale_num = 1;
cinfo.scale_denom = ie->scale;
}
/* head decoding */
jpeg_calc_output_dimensions(&(cinfo));
jpeg_start_decompress(&cinfo);
w = cinfo.output_width;
h = cinfo.output_height;
if ((w != ie->w) || (h != ie->h))
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
/* end head decoding */
/* data decoding */
if (cinfo.rec_outbuf_height > 16)
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
data = alloca(w * 16 * 3);
evas_cache_image_surface_alloc(ie, w, h);
if (ie->flags.loaded)
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
ptr2 = evas_cache_image_pixels(ie);
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(Image_Entry *ie, 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 */
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);
return 0;
}
data = alloca(w * 16 * 3);
if (!ie->flags.loaded)
{
jpeg_destroy_decompress(&cinfo);
return 0;
}
ptr2 = evas_cache_image_pixels(ie);
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(Image_Entry *ie, 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(ie, f);
fclose(f);
return val;
key = 0;
}
int
evas_image_load_file_data_jpeg(Image_Entry *ie, 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(ie, f);
fclose(f);
return val;
key = 0;
}
EAPI int
module_open(Evas_Module *em)
{
if (!em) return 0;
em->functions = (void *)(&evas_image_load_jpeg_func);
return 1;
}
EAPI void
module_close(void)
{
}
EAPI Evas_Module_Api evas_modapi =
{
EVAS_MODULE_API_VERSION,
EVAS_MODULE_TYPE_IMAGE_LOADER,
"jpeg",
"none"
};