forked from enlightenment/efl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1881 lines
52 KiB
1881 lines
52 KiB
#ifdef HAVE_CONFIG_H |
|
# include <config.h> |
|
#endif /* ifdef HAVE_CONFIG_H */ |
|
|
|
#ifdef HAVE_ALLOCA_H |
|
# include <alloca.h> |
|
#elif defined __GNUC__ |
|
# define alloca __builtin_alloca |
|
#elif defined _AIX |
|
# define alloca __alloca |
|
#elif defined _MSC_VER |
|
# include <malloc.h> |
|
# define alloca _alloca |
|
#else /* ifdef HAVE_ALLOCA_H */ |
|
# include <stddef.h> |
|
# ifdef __cplusplus |
|
extern "C" |
|
# endif /* ifdef __cplusplus */ |
|
void *alloca(size_t); |
|
#endif /* ifdef HAVE_ALLOCA_H */ |
|
|
|
#ifdef HAVE_NETINET_IN_H |
|
# ifdef __OpenBSD__ |
|
# include <sys/types.h> |
|
# endif /* ifdef __OpenBSD__ */ |
|
# include <netinet/in.h> |
|
#endif /* ifdef HAVE_NETINET_IN_H */ |
|
|
|
#ifdef _WIN32 |
|
# include <winsock2.h> |
|
# define HAVE_BOOLEAN |
|
#endif /* ifdef _WIN32 */ |
|
|
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <setjmp.h> |
|
#include <zlib.h> |
|
#include <jpeglib.h> |
|
|
|
#include "Eet.h" |
|
#include "Eet_private.h" |
|
|
|
#include "lz4.h" |
|
#include "lz4hc.h" |
|
|
|
/*---*/ |
|
|
|
typedef struct _JPEG_error_mgr *emptr; |
|
|
|
/*---*/ |
|
|
|
struct _JPEG_error_mgr |
|
{ |
|
struct jpeg_error_mgr pub; |
|
jmp_buf setjmp_buffer; |
|
}; |
|
|
|
struct jpeg_membuf_src |
|
{ |
|
struct jpeg_source_mgr pub; |
|
|
|
const unsigned char *buf; |
|
size_t len; |
|
struct jpeg_membuf_src *self; |
|
}; |
|
|
|
static void |
|
_eet_jpeg_membuf_src_init(j_decompress_ptr cinfo) |
|
{ |
|
/* FIXME: Use attribute unused */ |
|
(void)cinfo; |
|
} |
|
|
|
static boolean |
|
_eet_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 |
|
_eet_jpeg_membuf_src_skip(j_decompress_ptr cinfo, |
|
long num_bytes) |
|
{ |
|
struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src; |
|
|
|
src->pub.bytes_in_buffer -= num_bytes; |
|
src->pub.next_input_byte += num_bytes; |
|
} |
|
|
|
static void |
|
_eet_jpeg_membuf_src_term(j_decompress_ptr cinfo) |
|
{ |
|
struct jpeg_membuf_src *src = ((struct jpeg_membuf_src *)cinfo->src)->self; |
|
|
|
free(src); |
|
cinfo->src = NULL; |
|
} |
|
|
|
static int |
|
eet_jpeg_membuf_src(j_decompress_ptr cinfo, |
|
const void *buf, |
|
size_t len) |
|
{ |
|
struct jpeg_membuf_src *src; |
|
|
|
src = calloc(1, sizeof(*src)); |
|
if (!src) |
|
return -1; |
|
|
|
src->self = src; |
|
|
|
cinfo->src = &src->pub; |
|
src->buf = buf; |
|
src->len = len; |
|
src->pub.init_source = _eet_jpeg_membuf_src_init; |
|
src->pub.fill_input_buffer = _eet_jpeg_membuf_src_fill; |
|
src->pub.skip_input_data = _eet_jpeg_membuf_src_skip; |
|
src->pub.resync_to_restart = jpeg_resync_to_restart; |
|
src->pub.term_source = _eet_jpeg_membuf_src_term; |
|
src->pub.bytes_in_buffer = src->len; |
|
src->pub.next_input_byte = src->buf; |
|
|
|
return 0; |
|
} |
|
|
|
struct jpeg_membuf_dst |
|
{ |
|
struct jpeg_destination_mgr pub; |
|
|
|
void **dst_buf; |
|
size_t *dst_len; |
|
|
|
unsigned char *buf; |
|
size_t len; |
|
int failed; |
|
struct jpeg_membuf_dst *self; |
|
}; |
|
|
|
static void |
|
_eet_jpeg_membuf_dst_init(j_compress_ptr cinfo) |
|
{ |
|
/* FIXME: Use eina attribute */ |
|
(void)cinfo; |
|
} |
|
|
|
static boolean |
|
_eet_jpeg_membuf_dst_flush(j_compress_ptr cinfo) |
|
{ |
|
struct jpeg_membuf_dst *dst = (struct jpeg_membuf_dst *)cinfo->dest; |
|
unsigned char *buf; |
|
|
|
if (dst->len >= 0x40000000 || |
|
!(buf = realloc(dst->buf, dst->len * 2))) |
|
{ |
|
dst->failed = 1; |
|
dst->pub.next_output_byte = dst->buf; |
|
dst->pub.free_in_buffer = dst->len; |
|
return TRUE; |
|
} |
|
|
|
dst->pub.next_output_byte = |
|
buf + ((unsigned char *)dst->pub.next_output_byte - dst->buf); |
|
dst->buf = buf; |
|
dst->pub.free_in_buffer += dst->len; |
|
dst->len *= 2; |
|
|
|
return FALSE; |
|
} |
|
|
|
static void |
|
_eet_jpeg_membuf_dst_term(j_compress_ptr cinfo) |
|
{ |
|
struct jpeg_membuf_dst *dst = ((struct jpeg_membuf_dst *)cinfo->dest)->self; |
|
|
|
if (dst->failed) |
|
{ |
|
*dst->dst_buf = NULL; |
|
*dst->dst_len = 0; |
|
free(dst->buf); |
|
} |
|
else |
|
{ |
|
*dst->dst_buf = dst->buf; |
|
*dst->dst_len = (unsigned char *)dst->pub.next_output_byte - dst->buf; |
|
} |
|
|
|
free(dst); |
|
cinfo->dest = NULL; |
|
} |
|
|
|
static int |
|
eet_jpeg_membuf_dst(j_compress_ptr cinfo, |
|
void **buf, |
|
size_t *len) |
|
{ |
|
struct jpeg_membuf_dst *dst; |
|
|
|
dst = calloc(1, sizeof(*dst)); |
|
if (!dst) |
|
return -1; |
|
|
|
dst->buf = malloc(32768); |
|
if (!dst->buf) |
|
{ |
|
free(dst); |
|
return -1; |
|
} |
|
|
|
dst->self = dst; |
|
dst->len = 32768; |
|
|
|
cinfo->dest = &dst->pub; |
|
dst->pub.init_destination = _eet_jpeg_membuf_dst_init; |
|
dst->pub.empty_output_buffer = _eet_jpeg_membuf_dst_flush; |
|
dst->pub.term_destination = _eet_jpeg_membuf_dst_term; |
|
dst->pub.free_in_buffer = dst->len; |
|
dst->pub.next_output_byte = dst->buf; |
|
dst->dst_buf = buf; |
|
dst->dst_len = len; |
|
dst->failed = 0; |
|
|
|
return 0; |
|
} |
|
|
|
/*---*/ |
|
|
|
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 |
|
eet_data_image_jpeg_header_decode(const void *data, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h); |
|
static int |
|
eet_data_image_jpeg_rgb_decode(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride); |
|
static int |
|
eet_data_image_jpeg_alpha_decode(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride); |
|
static void * |
|
eet_data_image_lossless_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha); |
|
static void * |
|
eet_data_image_lossless_compressed_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int compression); |
|
static void * |
|
eet_data_image_jpeg_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int quality); |
|
static void * |
|
eet_data_image_jpeg_alpha_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int quality); |
|
|
|
/*---*/ |
|
|
|
static int _eet_image_words_bigendian = -1; |
|
|
|
/*---*/ |
|
|
|
#define SWAP64(x) (x) = \ |
|
((((unsigned long long)(x) & 0x00000000000000ffULL) << 56) | \ |
|
(((unsigned long long)(x) & 0x000000000000ff00ULL) << 40) | \ |
|
(((unsigned long long)(x) & 0x0000000000ff0000ULL) << 24) | \ |
|
(((unsigned long long)(x) & 0x00000000ff000000ULL) << 8) | \ |
|
(((unsigned long long)(x) & 0x000000ff00000000ULL) >> 8) | \ |
|
(((unsigned long long)(x) & 0x0000ff0000000000ULL) >> 24) | \ |
|
(((unsigned long long)(x) & 0x00ff000000000000ULL) >> 40) | \ |
|
(((unsigned long long)(x) & 0xff00000000000000ULL) >> 56)) |
|
#define SWAP32(x) (x) = \ |
|
((((int)(x) & 0x000000ff) << 24) | \ |
|
(((int)(x) & 0x0000ff00) << 8) | \ |
|
(((int)(x) & 0x00ff0000) >> 8) | \ |
|
(((int)(x) & 0xff000000) >> 24)) |
|
#define SWAP16(x) (x) = \ |
|
((((short)(x) & 0x00ff) << 8) | \ |
|
(((short)(x) & 0xff00) >> 8)) |
|
|
|
#ifdef CONV8 |
|
# undef CONV8 |
|
#endif /* ifdef CONV8 */ |
|
#ifdef CONV16 |
|
# undef CONV16 |
|
#endif /* ifdef CONV16 */ |
|
#ifdef CONV32 |
|
# undef CONV32 |
|
#endif /* ifdef CONV32 */ |
|
#ifdef CONV64 |
|
# undef CONV64 |
|
#endif /* ifdef CONV64 */ |
|
|
|
#define CONV8(x) |
|
#define CONV16(x) {if (_eet_image_words_bigendian) {SWAP16(x); }} |
|
#define CONV32(x) {if (_eet_image_words_bigendian) {SWAP32(x); }} |
|
#define CONV64(x) {if (_eet_image_words_bigendian) {SWAP64(x); }} |
|
|
|
/*---*/ |
|
|
|
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; |
|
} |
|
|
|
static int |
|
eet_data_image_jpeg_header_decode(const void *data, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h) |
|
{ |
|
struct jpeg_decompress_struct cinfo; |
|
struct _JPEG_error_mgr jerr; |
|
|
|
memset(&cinfo, 0, sizeof (struct jpeg_decompress_struct)); |
|
|
|
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)) |
|
return 0; |
|
|
|
jpeg_create_decompress(&cinfo); |
|
|
|
if (eet_jpeg_membuf_src(&cinfo, data, (size_t)size)) |
|
{ |
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
jpeg_read_header(&cinfo, TRUE); |
|
cinfo.do_fancy_upsampling = FALSE; |
|
cinfo.do_block_smoothing = FALSE; |
|
jpeg_start_decompress(&cinfo); |
|
|
|
/* head decoding */ |
|
*w = cinfo.output_width; |
|
*h = cinfo.output_height; |
|
|
|
free(cinfo.src); |
|
cinfo.src = NULL; |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
|
|
if ((*w < 1) || (*h < 1) || (*w > 8192) || (*h > 8192)) |
|
return 0; |
|
|
|
return 1; |
|
} |
|
|
|
static int |
|
eet_data_image_jpeg_rgb_decode(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride) |
|
{ |
|
struct jpeg_decompress_struct cinfo; |
|
struct _JPEG_error_mgr jerr; |
|
unsigned char *ptr, *line[16], *tdata = NULL; |
|
unsigned int *ptr2, *tmp; |
|
unsigned int iw, ih; |
|
unsigned int x, y, l, scans; |
|
unsigned int i; |
|
|
|
/* FIXME: handle src_x, src_y and row_stride correctly */ |
|
if (!d) |
|
return 0; |
|
|
|
memset(&cinfo, 0, sizeof (struct jpeg_decompress_struct)); |
|
|
|
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)) |
|
return 0; |
|
|
|
jpeg_create_decompress(&cinfo); |
|
|
|
if (eet_jpeg_membuf_src(&cinfo, data, (size_t)size)) |
|
{ |
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
jpeg_read_header(&cinfo, TRUE); |
|
cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) |
|
cinfo.do_fancy_upsampling = FALSE; |
|
cinfo.do_block_smoothing = FALSE; |
|
jpeg_start_decompress(&cinfo); |
|
|
|
/* head decoding */ |
|
iw = cinfo.output_width; |
|
ih = cinfo.output_height; |
|
if ((iw != w) || (ih != h)) |
|
{ |
|
free(cinfo.src); |
|
cinfo.src = NULL; |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
/* end head decoding */ |
|
/* data decoding */ |
|
if (cinfo.rec_outbuf_height > 16) |
|
{ |
|
free(cinfo.src); |
|
cinfo.src = NULL; |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
tdata = alloca((iw) * 16 * 3); |
|
ptr2 = d; |
|
|
|
if (cinfo.output_components == 3) |
|
{ |
|
for (i = 0; i < (unsigned int)cinfo.rec_outbuf_height; i++) |
|
line[i] = tdata + (i * (iw) * 3); |
|
for (l = 0; l < ih; l += cinfo.rec_outbuf_height) |
|
{ |
|
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); |
|
scans = cinfo.rec_outbuf_height; |
|
if ((ih - l) < scans) |
|
scans = ih - l; |
|
|
|
ptr = tdata; |
|
|
|
if (l + scans >= src_y && l < src_y + h) |
|
{ |
|
y = src_y - l; |
|
if (src_y < l) |
|
y = 0; |
|
|
|
for (ptr += 3 * iw * y; y < scans && (y + l) < (src_y + h); |
|
y++) |
|
{ |
|
tmp = ptr2; |
|
ptr += 3 * src_x; |
|
for (x = 0; x < w; x++) |
|
{ |
|
*ptr2 = |
|
(0xff000000) | |
|
((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); |
|
ptr += 3; |
|
ptr2++; |
|
} |
|
ptr += 3 * (iw - w); |
|
ptr2 = tmp + row_stride / 4; |
|
} |
|
} |
|
} |
|
} |
|
else if (cinfo.output_components == 1) |
|
{ |
|
for (i = 0; i < (unsigned int)cinfo.rec_outbuf_height; i++) |
|
line[i] = tdata + (i * (iw)); |
|
for (l = 0; l < (ih); l += cinfo.rec_outbuf_height) |
|
{ |
|
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); |
|
scans = cinfo.rec_outbuf_height; |
|
if (((ih) - l) < scans) |
|
scans = (ih) - l; |
|
|
|
ptr = tdata; |
|
|
|
if (l >= src_y && l < src_y + h) |
|
{ |
|
y = src_y - l; |
|
if (src_y < l) |
|
y = 0; |
|
|
|
for (ptr += iw * y; y < scans && (y + l) < (src_y + h); y++) |
|
{ |
|
tmp = ptr2; |
|
ptr += src_x; |
|
for (x = 0; x < w; x++) |
|
{ |
|
*ptr2 = |
|
(0xff000000) | |
|
((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]); |
|
ptr++; |
|
ptr2++; |
|
} |
|
ptr += iw - w; |
|
ptr2 = tmp + row_stride / 4; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* end data decoding */ |
|
jpeg_finish_decompress(&cinfo); |
|
jpeg_destroy_decompress(&cinfo); |
|
return 1; |
|
} |
|
|
|
static int |
|
eet_data_image_jpeg_alpha_decode(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride) |
|
{ |
|
struct jpeg_decompress_struct cinfo; |
|
struct _JPEG_error_mgr jerr; |
|
unsigned char *ptr, *line[16], *tdata = NULL; |
|
unsigned int *ptr2, *tmp; |
|
unsigned int x, y, l, scans; |
|
unsigned int i, iw; |
|
|
|
/* FIXME: handle src_x, src_y and row_stride correctly */ |
|
if (!d) |
|
return 0; |
|
|
|
memset(&cinfo, 0, sizeof (struct jpeg_decompress_struct)); |
|
|
|
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)) |
|
return 0; |
|
|
|
jpeg_create_decompress(&cinfo); |
|
|
|
if (eet_jpeg_membuf_src(&cinfo, data, (size_t)size)) |
|
{ |
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
jpeg_read_header(&cinfo, TRUE); |
|
cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) |
|
cinfo.do_fancy_upsampling = FALSE; |
|
cinfo.do_block_smoothing = FALSE; |
|
jpeg_start_decompress(&cinfo); |
|
|
|
/* head decoding */ |
|
iw = cinfo.output_width; |
|
if (w != cinfo.output_width |
|
|| h != cinfo.output_height) |
|
{ |
|
free(cinfo.src); |
|
cinfo.src = NULL; |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
/* end head decoding */ |
|
/* data decoding */ |
|
if (cinfo.rec_outbuf_height > 16) |
|
{ |
|
free(cinfo.src); |
|
cinfo.src = NULL; |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
return 0; |
|
} |
|
|
|
tdata = alloca(w * 16 * 3); |
|
ptr2 = d; |
|
|
|
if (cinfo.output_components == 1) |
|
{ |
|
for (i = 0; i < (unsigned int)cinfo.rec_outbuf_height; i++) |
|
line[i] = tdata + (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 = tdata; |
|
|
|
if (l >= src_y && l < src_y + h) |
|
{ |
|
y = src_y - l; |
|
if (src_y < l) |
|
y = 0; |
|
|
|
for (ptr += iw * y; y < scans && (y + l) < (src_y + h); y++) |
|
{ |
|
tmp = ptr2; |
|
ptr += src_x; |
|
for (x = 0; x < w; x++) |
|
{ |
|
*ptr2 = |
|
((*ptr2) & 0x00ffffff) | |
|
((ptr[0]) << 24); |
|
ptr++; |
|
ptr2++; |
|
} |
|
ptr += iw - w; |
|
ptr2 = tmp + row_stride / 4; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* end data decoding */ |
|
jpeg_finish_decompress(&cinfo); |
|
jpeg_destroy_decompress(&cinfo); |
|
return 1; |
|
} |
|
|
|
static void * |
|
eet_data_image_lossless_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha) |
|
{ |
|
if (_eet_image_words_bigendian == -1) |
|
{ |
|
unsigned long int v; |
|
|
|
v = htonl(0x12345678); |
|
if (v == 0x12345678) |
|
_eet_image_words_bigendian = 1; |
|
else |
|
_eet_image_words_bigendian = 0; |
|
} |
|
|
|
{ |
|
unsigned char *d; |
|
int *header; |
|
|
|
d = malloc((w * h * 4) + (8 * 4)); |
|
if (!d) |
|
return NULL; |
|
|
|
header = (int *)d; |
|
memset(d, 0, 32); |
|
|
|
header[0] = 0xac1dfeed; |
|
header[1] = w; |
|
header[2] = h; |
|
header[3] = alpha; |
|
|
|
memcpy(d + 32, data, w * h * 4); |
|
|
|
if (_eet_image_words_bigendian) |
|
{ |
|
unsigned int i; |
|
|
|
for (i = 0; i < ((w * h) + 8); i++) SWAP32(header[i]); |
|
} |
|
|
|
*size = ((w * h * 4) + (8 * 4)); |
|
return d; |
|
} |
|
} |
|
|
|
static void * |
|
eet_data_image_lossless_compressed_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int compression) |
|
{ |
|
if (_eet_image_words_bigendian == -1) |
|
{ |
|
unsigned long int v; |
|
|
|
v = htonl(0x12345678); |
|
if (v == 0x12345678) |
|
_eet_image_words_bigendian = 1; |
|
else |
|
_eet_image_words_bigendian = 0; |
|
} |
|
|
|
{ |
|
unsigned char *d, *comp; |
|
int *header, ret, ok = 1; |
|
uLongf buflen = 0; |
|
|
|
buflen = (((w * h * 101) / 100) + 3) * 4; |
|
ret = LZ4_compressBound((w * h * 4)); |
|
if ((ret > 0) && ((uLongf)ret > buflen)) buflen = ret; |
|
|
|
comp = malloc(buflen); |
|
if (!comp) return NULL; |
|
|
|
switch (compression) |
|
{ |
|
case EET_COMPRESSION_VERYFAST: |
|
ret = LZ4_compressHC((const char *)data, (char *)comp, |
|
(w * h * 4)); |
|
if (ret <= 0) ok = 0; |
|
buflen = ret; |
|
break; |
|
case EET_COMPRESSION_SUPERFAST: |
|
ret = LZ4_compress((const char *)data, (char *)comp, |
|
(w * h * 4)); |
|
if (ret <= 0) ok = 0; |
|
buflen = ret; |
|
break; |
|
default: /* zlib etc. */ |
|
ret = compress2((Bytef *)comp, &buflen, (Bytef *)(data), |
|
(uLong)(w * h * 4), compression); |
|
if (ret != Z_OK) ok = 0; |
|
break; |
|
} |
|
if ((!ok) || (buflen > (w * h * 4))) |
|
{ |
|
free(comp); |
|
*size = -1; |
|
return NULL; |
|
} |
|
|
|
d = malloc((8 * sizeof(int)) + buflen); |
|
if (!d) |
|
{ |
|
free(comp); |
|
return NULL; |
|
} |
|
|
|
header = (int *)d; |
|
memset(d, 0, 8 * sizeof(int)); |
|
header[0] = 0xac1dfeed; |
|
header[1] = w; |
|
header[2] = h; |
|
header[3] = alpha; |
|
header[4] = compression; |
|
|
|
if (_eet_image_words_bigendian) |
|
{ |
|
unsigned int i; |
|
|
|
for (i = 0; i < 8; i++) SWAP32(header[i]); |
|
} |
|
|
|
memcpy(d + (8 * sizeof(int)), comp, buflen); |
|
*size = (8 * sizeof(int)) + buflen; |
|
free(comp); |
|
return d; |
|
} |
|
} |
|
|
|
static void * |
|
eet_data_image_jpeg_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int quality) |
|
{ |
|
struct jpeg_compress_struct cinfo; |
|
struct _JPEG_error_mgr jerr; |
|
const int *ptr; |
|
void *d = NULL; |
|
size_t sz = 0; |
|
JSAMPROW *jbuf; |
|
unsigned char *buf; |
|
|
|
(void)alpha; /* unused */ |
|
|
|
buf = alloca(3 * w); |
|
|
|
memset(&cinfo, 0, sizeof (struct jpeg_compress_struct)); |
|
|
|
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)) |
|
return NULL; |
|
|
|
jpeg_create_compress(&cinfo); |
|
|
|
if (eet_jpeg_membuf_dst(&cinfo, &d, &sz)) |
|
{ |
|
jpeg_destroy_compress(&cinfo); |
|
return NULL; |
|
} |
|
|
|
cinfo.image_width = w; |
|
cinfo.image_height = h; |
|
cinfo.input_components = 3; |
|
cinfo.in_color_space = JCS_RGB; |
|
cinfo.optimize_coding = FALSE; |
|
cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) |
|
if (quality < 60) cinfo.dct_method = JDCT_IFAST; |
|
jpeg_set_defaults(&cinfo); |
|
jpeg_set_quality(&cinfo, quality, TRUE); |
|
|
|
if (quality >= 90) |
|
{ |
|
cinfo.comp_info[0].h_samp_factor = 1; |
|
cinfo.comp_info[0].v_samp_factor = 1; |
|
cinfo.comp_info[1].h_samp_factor = 1; |
|
cinfo.comp_info[1].v_samp_factor = 1; |
|
cinfo.comp_info[2].h_samp_factor = 1; |
|
cinfo.comp_info[2].v_samp_factor = 1; |
|
} |
|
|
|
jpeg_start_compress(&cinfo, TRUE); |
|
|
|
while (cinfo.next_scanline < cinfo.image_height) |
|
{ |
|
unsigned int i, j; |
|
|
|
/* convert scaline from ARGB to RGB packed */ |
|
ptr = ((const int *)data) + cinfo.next_scanline * w; |
|
for (j = 0, i = 0; i < w; i++) |
|
{ |
|
buf[j++] = ((*ptr) >> 16) & 0xff; |
|
buf[j++] = ((*ptr) >> 8) & 0xff; |
|
buf[j++] = ((*ptr)) & 0xff; |
|
ptr++; |
|
} |
|
jbuf = (JSAMPROW *)(&buf); |
|
jpeg_write_scanlines(&cinfo, jbuf, 1); |
|
} |
|
|
|
jpeg_finish_compress(&cinfo); |
|
jpeg_destroy_compress(&cinfo); |
|
|
|
*size = sz; |
|
return d; |
|
} |
|
|
|
static void * |
|
eet_data_image_jpeg_alpha_convert(int *size, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int quality) |
|
{ |
|
unsigned char *d1, *d2; |
|
unsigned char *d; |
|
int *header; |
|
int sz1, sz2; |
|
|
|
(void)alpha; /* unused */ |
|
|
|
if (_eet_image_words_bigendian == -1) |
|
{ |
|
unsigned long int v; |
|
|
|
v = htonl(0x12345678); |
|
if (v == 0x12345678) |
|
_eet_image_words_bigendian = 1; |
|
else |
|
_eet_image_words_bigendian = 0; |
|
} |
|
|
|
{ |
|
const int *ptr; |
|
void *dst = NULL; |
|
size_t sz = 0; |
|
struct _JPEG_error_mgr jerr; |
|
JSAMPROW *jbuf; |
|
struct jpeg_compress_struct cinfo; |
|
unsigned char *buf; |
|
|
|
buf = alloca(3 * w); |
|
|
|
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)) |
|
return NULL; |
|
|
|
jpeg_create_compress(&cinfo); |
|
if (eet_jpeg_membuf_dst(&cinfo, &dst, &sz)) |
|
{ |
|
jpeg_destroy_compress(&cinfo); |
|
return NULL; |
|
} |
|
|
|
cinfo.image_width = w; |
|
cinfo.image_height = h; |
|
cinfo.input_components = 3; |
|
cinfo.in_color_space = JCS_RGB; |
|
cinfo.optimize_coding = FALSE; |
|
cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss) |
|
if (quality < 60) cinfo.dct_method = JDCT_IFAST; |
|
jpeg_set_defaults(&cinfo); |
|
jpeg_set_quality(&cinfo, quality, TRUE); |
|
if (quality >= 90) |
|
{ |
|
cinfo.comp_info[0].h_samp_factor = 1; |
|
cinfo.comp_info[0].v_samp_factor = 1; |
|
cinfo.comp_info[1].h_samp_factor = 1; |
|
cinfo.comp_info[1].v_samp_factor = 1; |
|
cinfo.comp_info[2].h_samp_factor = 1; |
|
cinfo.comp_info[2].v_samp_factor = 1; |
|
} |
|
|
|
jpeg_start_compress(&cinfo, TRUE); |
|
|
|
while (cinfo.next_scanline < cinfo.image_height) |
|
{ |
|
unsigned int i, j; |
|
|
|
ptr = ((const int *)data) + cinfo.next_scanline * w; |
|
/* convert scaline from ARGB to RGB packed */ |
|
for (j = 0, i = 0; i < w; i++) |
|
{ |
|
buf[j++] = ((*ptr) >> 16) & 0xff; |
|
buf[j++] = ((*ptr) >> 8) & 0xff; |
|
buf[j++] = ((*ptr)) & 0xff; |
|
ptr++; |
|
} |
|
jbuf = (JSAMPROW *)(&buf); |
|
jpeg_write_scanlines(&cinfo, jbuf, 1); |
|
} |
|
|
|
jpeg_finish_compress(&cinfo); |
|
jpeg_destroy_compress(&cinfo); |
|
|
|
d1 = dst; |
|
sz1 = sz; |
|
} |
|
{ |
|
const int *ptr; |
|
void *dst = NULL; |
|
size_t sz = 0; |
|
struct _JPEG_error_mgr jerr; |
|
JSAMPROW *jbuf; |
|
struct jpeg_compress_struct cinfo; |
|
unsigned char *buf; |
|
|
|
buf = alloca(3 * w); |
|
|
|
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)) |
|
{ |
|
free(d1); |
|
return NULL; |
|
} |
|
|
|
jpeg_create_compress(&cinfo); |
|
if (eet_jpeg_membuf_dst(&cinfo, &dst, &sz)) |
|
{ |
|
jpeg_destroy_compress(&cinfo); |
|
free(d1); |
|
return NULL; |
|
} |
|
|
|
cinfo.image_width = w; |
|
cinfo.image_height = h; |
|
cinfo.input_components = 1; |
|
cinfo.in_color_space = JCS_GRAYSCALE; |
|
jpeg_set_defaults(&cinfo); |
|
jpeg_set_quality(&cinfo, quality, TRUE); |
|
if (quality >= 90) |
|
{ |
|
cinfo.comp_info[0].h_samp_factor = 1; |
|
cinfo.comp_info[0].v_samp_factor = 1; |
|
cinfo.comp_info[1].h_samp_factor = 1; |
|
cinfo.comp_info[1].v_samp_factor = 1; |
|
cinfo.comp_info[2].h_samp_factor = 1; |
|
cinfo.comp_info[2].v_samp_factor = 1; |
|
} |
|
|
|
jpeg_start_compress(&cinfo, TRUE); |
|
|
|
while (cinfo.next_scanline < cinfo.image_height) |
|
{ |
|
unsigned int i, j; |
|
|
|
ptr = ((const int *)data) + cinfo.next_scanline * w; |
|
/* convert scaline from ARGB to RGB packed */ |
|
for (j = 0, i = 0; i < w; i++) |
|
{ |
|
buf[j++] = ((*ptr) >> 24) & 0xff; |
|
ptr++; |
|
} |
|
jbuf = (JSAMPROW *)(&buf); |
|
jpeg_write_scanlines(&cinfo, jbuf, 1); |
|
} |
|
|
|
jpeg_finish_compress(&cinfo); |
|
jpeg_destroy_compress(&cinfo); |
|
|
|
d2 = dst; |
|
sz2 = sz; |
|
} |
|
d = malloc(12 + sz1 + sz2); |
|
if (!d) |
|
{ |
|
free(d1); |
|
free(d2); |
|
return NULL; |
|
} |
|
|
|
header = (int *)d; |
|
header[0] = 0xbeeff00d; |
|
header[1] = sz1; |
|
header[2] = sz2; |
|
if (_eet_image_words_bigendian) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < 3; i++) SWAP32(header[i]); |
|
} |
|
|
|
memcpy(d + 12, d1, sz1); |
|
memcpy(d + 12 + sz1, d2, sz2); |
|
|
|
free(d1); |
|
free(d2); |
|
*size = 12 + sz1 + sz2; |
|
return d; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_write_cipher(Eet_File *ef, |
|
const char *name, |
|
const char *cipher_key, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int comp, |
|
int quality, |
|
int lossy) |
|
{ |
|
void *d = NULL; |
|
int size = 0; |
|
|
|
d = eet_data_image_encode(data, &size, w, h, alpha, comp, quality, lossy); |
|
if (d) |
|
{ |
|
int v; |
|
|
|
v = eet_write_cipher(ef, name, d, size, 0, cipher_key); |
|
free(d); |
|
return v; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_write(Eet_File *ef, |
|
const char *name, |
|
const void *data, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int comp, |
|
int quality, |
|
int lossy) |
|
{ |
|
return eet_data_image_write_cipher(ef, |
|
name, |
|
NULL, |
|
data, |
|
w, |
|
h, |
|
alpha, |
|
comp, |
|
quality, |
|
lossy); |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_read_cipher(Eet_File *ef, |
|
const char *name, |
|
const char *cipher_key, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
unsigned int *d = NULL; |
|
void *data = NULL; |
|
int free_data = 0; |
|
int size; |
|
|
|
if (!cipher_key) |
|
data = (void *)eet_read_direct(ef, name, &size); |
|
|
|
if (!data) |
|
{ |
|
data = eet_read_cipher(ef, name, &size, cipher_key); |
|
free_data = 1; |
|
if (!data) |
|
return NULL; |
|
} |
|
|
|
d = eet_data_image_decode(data, size, w, h, alpha, comp, quality, lossy); |
|
|
|
if (free_data) |
|
free(data); |
|
|
|
return d; |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_read(Eet_File *ef, |
|
const char *name, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_read_cipher(ef, name, NULL, w, h, alpha, |
|
comp, quality, lossy); |
|
} |
|
|
|
EAPI int |
|
eet_data_image_read_to_surface_cipher(Eet_File *ef, |
|
const char *name, |
|
const char *cipher_key, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
void *data = NULL; |
|
int free_data = 0; |
|
int res = 1; |
|
int size; |
|
|
|
if (!cipher_key) |
|
data = (void *)eet_read_direct(ef, name, &size); |
|
|
|
if (!data) |
|
{ |
|
data = eet_read_cipher(ef, name, &size, cipher_key); |
|
free_data = 1; |
|
if (!data) |
|
return 0; |
|
} |
|
|
|
res = eet_data_image_decode_to_surface(data, size, src_x, src_y, d, |
|
w, h, row_stride, alpha, |
|
comp, quality, lossy); |
|
|
|
if (free_data) |
|
free(data); |
|
|
|
return res; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_read_to_surface(Eet_File *ef, |
|
const char *name, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_read_to_surface_cipher(ef, name, NULL, |
|
src_x, src_y, d, |
|
w, h, row_stride, |
|
alpha, comp, quality, |
|
lossy); |
|
} |
|
|
|
EAPI int |
|
eet_data_image_header_read_cipher(Eet_File *ef, |
|
const char *name, |
|
const char *cipher_key, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
void *data = NULL; |
|
int size = 0; |
|
int free_data = 0; |
|
int d; |
|
|
|
if (!cipher_key) |
|
data = (void *)eet_read_direct(ef, name, &size); |
|
|
|
if (!data) |
|
{ |
|
data = eet_read_cipher(ef, name, &size, cipher_key); |
|
free_data = 1; |
|
if (!data) |
|
return 0; |
|
} |
|
|
|
d = eet_data_image_header_decode(data, size, w, h, alpha, |
|
comp, quality, lossy); |
|
if (free_data) |
|
free(data); |
|
|
|
return d; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_header_read(Eet_File *ef, |
|
const char *name, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_header_read_cipher(ef, name, NULL, |
|
w, h, alpha, |
|
comp, quality, lossy); |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_encode_cipher(const void *data, |
|
const char *cipher_key, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int comp, |
|
int quality, |
|
int lossy, |
|
int *size_ret) |
|
{ |
|
void *d = NULL; |
|
void *ciphered_d = NULL; |
|
unsigned int ciphered_sz = 0; |
|
int size = 0; |
|
|
|
if (lossy == 0) |
|
{ |
|
if (comp > 0) |
|
d = eet_data_image_lossless_compressed_convert(&size, data, |
|
w, h, alpha, comp); |
|
|
|
/* eet_data_image_lossless_compressed_convert will refuse to compress something |
|
if the result is bigger than the entry. */ |
|
if (comp <= 0 || !d) |
|
d = eet_data_image_lossless_convert(&size, data, w, h, alpha); |
|
} |
|
else |
|
{ |
|
if (!alpha) |
|
d = eet_data_image_jpeg_convert(&size, data, w, h, alpha, quality); |
|
else |
|
d = eet_data_image_jpeg_alpha_convert(&size, data, |
|
w, h, alpha, quality); |
|
} |
|
|
|
if (cipher_key) |
|
{ |
|
if(!eet_cipher(d, size, cipher_key, strlen(cipher_key), &ciphered_d, |
|
&ciphered_sz)) |
|
{ |
|
if (d) |
|
free(d); |
|
|
|
d = ciphered_d; |
|
size = ciphered_sz; |
|
} |
|
else |
|
if (ciphered_d) |
|
free(ciphered_d); |
|
} |
|
|
|
if (size_ret) |
|
*size_ret = size; |
|
|
|
return d; |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_encode(const void *data, |
|
int *size_ret, |
|
unsigned int w, |
|
unsigned int h, |
|
int alpha, |
|
int comp, |
|
int quality, |
|
int lossy) |
|
{ |
|
return eet_data_image_encode_cipher(data, NULL, w, h, alpha, |
|
comp, quality, lossy, size_ret); |
|
} |
|
|
|
EAPI int |
|
eet_data_image_header_decode_cipher(const void *data, |
|
const char *cipher_key, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
int header[8]; |
|
void *deciphered_d = NULL; |
|
unsigned int deciphered_sz = 0; |
|
|
|
if (cipher_key) |
|
{ |
|
if (!eet_decipher(data, size, cipher_key, strlen(cipher_key), |
|
&deciphered_d, &deciphered_sz)) |
|
{ |
|
data = deciphered_d; |
|
size = deciphered_sz; |
|
} |
|
else |
|
if (deciphered_d) |
|
free(deciphered_d); |
|
} |
|
|
|
if (_eet_image_words_bigendian == -1) |
|
{ |
|
unsigned long int v; |
|
|
|
v = htonl(0x12345678); |
|
if (v == 0x12345678) |
|
_eet_image_words_bigendian = 1; |
|
else |
|
_eet_image_words_bigendian = 0; |
|
} |
|
|
|
if (size < 32) |
|
return 0; |
|
|
|
memcpy(header, data, 32); |
|
if (_eet_image_words_bigendian) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < 8; i++) SWAP32(header[i]); |
|
} |
|
|
|
if ((unsigned)header[0] == 0xac1dfeed) |
|
{ |
|
int iw, ih, al, cp; |
|
|
|
iw = header[1]; |
|
ih = header[2]; |
|
al = header[3]; |
|
cp = header[4]; |
|
if ((iw < 1) || (ih < 1) || (iw > 8192) || (ih > 8192)) |
|
return 0; |
|
|
|
if ((cp == 0) && (size < ((iw * ih * 4) + 32))) |
|
return 0; |
|
|
|
if (w) |
|
*w = iw; |
|
|
|
if (h) |
|
*h = ih; |
|
|
|
if (alpha) |
|
*alpha = al ? 1 : 0; |
|
|
|
if (comp) |
|
*comp = cp; |
|
|
|
if (lossy) |
|
*lossy = 0; |
|
|
|
if (quality) |
|
*quality = 100; |
|
|
|
return 1; |
|
} |
|
else if ((unsigned)header[0] == 0xbeeff00d) |
|
{ |
|
unsigned int iw = 0, ih = 0; |
|
unsigned const char *dt; |
|
int sz1; |
|
int ok; |
|
|
|
sz1 = header[1]; |
|
/* sz2 = header[2]; */ |
|
dt = data; |
|
dt += 12; |
|
ok = eet_data_image_jpeg_header_decode(dt, sz1, &iw, &ih); |
|
if (ok) |
|
{ |
|
if (w) |
|
*w = iw; |
|
|
|
if (h) |
|
*h = ih; |
|
|
|
if (alpha) |
|
*alpha = 1; |
|
|
|
if (comp) |
|
*comp = 0; |
|
|
|
if (lossy) |
|
*lossy = 1; |
|
|
|
if (quality) |
|
*quality = 75; |
|
|
|
return 1; |
|
} |
|
} |
|
else |
|
{ |
|
unsigned int iw = 0, ih = 0; |
|
int ok; |
|
|
|
ok = eet_data_image_jpeg_header_decode(data, size, &iw, &ih); |
|
if (ok) |
|
{ |
|
if (w) |
|
*w = iw; |
|
|
|
if (h) |
|
*h = ih; |
|
|
|
if (alpha) |
|
*alpha = 0; |
|
|
|
if (comp) |
|
*comp = 0; |
|
|
|
if (lossy) |
|
*lossy = 1; |
|
|
|
if (quality) |
|
*quality = 75; |
|
|
|
return 1; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_header_decode(const void *data, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_header_decode_cipher(data, |
|
NULL, |
|
size, |
|
w, |
|
h, |
|
alpha, |
|
comp, |
|
quality, |
|
lossy); |
|
} |
|
|
|
static void |
|
_eet_data_image_copy_buffer(const unsigned int *src, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int src_w, |
|
unsigned int *dst, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride) |
|
{ |
|
src += src_x + src_y * src_w; |
|
|
|
if (row_stride == src_w * 4 && w == src_w) |
|
memcpy(dst, src, row_stride * h); |
|
else |
|
{ |
|
unsigned int *over = dst; |
|
unsigned int y; |
|
|
|
for (y = 0; y < h; ++y, src += src_w, over += row_stride) |
|
memcpy(over, src, w * 4); |
|
} |
|
} |
|
|
|
static int |
|
_eet_data_image_decode_inside(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int src_w, |
|
unsigned int src_h, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride, |
|
int alpha, |
|
int comp, |
|
int quality, |
|
int lossy) |
|
{ |
|
if (lossy == 0 && quality == 100) |
|
{ |
|
unsigned int *body; |
|
|
|
body = ((unsigned int *)data) + 8; |
|
if (!comp) |
|
_eet_data_image_copy_buffer(body, src_x, src_y, src_w, d, |
|
w, h, row_stride); |
|
else |
|
{ |
|
if ((src_h == h) && (src_w == w) && (row_stride == src_w * 4)) |
|
{ |
|
switch (comp) |
|
{ |
|
case EET_COMPRESSION_VERYFAST: |
|
case EET_COMPRESSION_SUPERFAST: |
|
if (LZ4_uncompress((const char *)body, |
|
(char *)d, w * h * 4) |
|
!= (size - 32)) return 0; |
|
break; |
|
default: |
|
{ |
|
uLongf dlen = w * h * 4; |
|
|
|
if (uncompress((Bytef *)d, &dlen, (Bytef *)body, |
|
(uLongf)(size - 32)) != Z_OK) |
|
return 0; |
|
} |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
switch (comp) |
|
{ |
|
case EET_COMPRESSION_VERYFAST: |
|
case EET_COMPRESSION_SUPERFAST: |
|
{ |
|
char *dtmp; |
|
|
|
dtmp = malloc(src_w * src_h * 4); |
|
if (!dtmp) return 0; |
|
if (LZ4_uncompress((const char *)body, |
|
dtmp, w * h * 4) |
|
!= (size - 32)) |
|
{ |
|
free(dtmp); |
|
return 0; |
|
} |
|
_eet_data_image_copy_buffer((unsigned int *)dtmp, |
|
src_x, src_y, src_w, d, |
|
w, h, row_stride); |
|
free(dtmp); |
|
} |
|
break; |
|
default: |
|
{ |
|
Bytef *dtmp; |
|
uLongf dlen = src_w * src_h * 4; |
|
|
|
/* FIXME: This could create a huge alloc. So |
|
compressed data and tile could not always work.*/ |
|
dtmp = malloc(dlen); |
|
if (!dtmp) return 0; |
|
|
|
if (uncompress(dtmp, &dlen, (Bytef *)body, |
|
(uLongf)(size - 32)) != Z_OK) |
|
{ |
|
free(dtmp); |
|
return 0; |
|
} |
|
_eet_data_image_copy_buffer((unsigned int *)dtmp, |
|
src_x, src_y, src_w, d, |
|
w, h, row_stride); |
|
free(dtmp); |
|
} |
|
} |
|
} |
|
} |
|
/* Fix swapiness. */ |
|
if (_eet_image_words_bigendian) |
|
{ |
|
unsigned int x; |
|
|
|
for (x = 0; x < (w * h); x++) SWAP32(d[x]); |
|
} |
|
} |
|
else if (comp == 0 && lossy == 1) |
|
{ |
|
if (alpha) |
|
{ |
|
unsigned const char *dt; |
|
int header[8]; |
|
int sz1, sz2; |
|
|
|
memcpy(header, data, 32); |
|
if (_eet_image_words_bigendian) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < 8; i++) SWAP32(header[i]); |
|
} |
|
|
|
sz1 = header[1]; |
|
sz2 = header[2]; |
|
dt = data; |
|
dt += 12; |
|
|
|
if (eet_data_image_jpeg_rgb_decode(dt, sz1, src_x, src_y, d, w, h, |
|
row_stride)) |
|
{ |
|
dt += sz1; |
|
if (!eet_data_image_jpeg_alpha_decode(dt, sz2, src_x, src_y, |
|
d, w, h, row_stride)) |
|
return 0; |
|
} |
|
} |
|
else if (!eet_data_image_jpeg_rgb_decode(data, size, src_x, src_y, d, w, |
|
h, row_stride)) |
|
return 0; |
|
} |
|
else |
|
abort(); |
|
|
|
return 1; |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_decode_cipher(const void *data, |
|
const char *cipher_key, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
unsigned int *d = NULL; |
|
unsigned int iw, ih; |
|
int ialpha, icompress, iquality, ilossy; |
|
void *deciphered_d = NULL; |
|
unsigned int deciphered_sz = 0; |
|
|
|
if (cipher_key) |
|
{ |
|
if (!eet_decipher(data, size, cipher_key, strlen(cipher_key), |
|
&deciphered_d, &deciphered_sz)) |
|
{ |
|
data = deciphered_d; |
|
size = deciphered_sz; |
|
} |
|
else |
|
if (deciphered_d) |
|
free(deciphered_d); |
|
} |
|
|
|
/* All check are done during header decode, this simplify the code a lot. */ |
|
if (!eet_data_image_header_decode(data, size, &iw, &ih, &ialpha, &icompress, |
|
&iquality, &ilossy)) |
|
return NULL; |
|
|
|
d = malloc(iw * ih * 4); |
|
if (!d) |
|
return NULL; |
|
|
|
if (!_eet_data_image_decode_inside(data, size, 0, 0, iw, ih, d, iw, ih, iw * |
|
4, ialpha, icompress, iquality, ilossy)) |
|
{ |
|
free(d); |
|
return NULL; |
|
} |
|
|
|
if (w) |
|
*w = iw; |
|
|
|
if (h) |
|
*h = ih; |
|
|
|
if (alpha) |
|
*alpha = ialpha; |
|
|
|
if (comp) |
|
*comp = icompress; |
|
|
|
if (quality) |
|
*quality = iquality; |
|
|
|
if (lossy) |
|
*lossy = ilossy; |
|
|
|
return d; |
|
} |
|
|
|
EAPI void * |
|
eet_data_image_decode(const void *data, |
|
int size, |
|
unsigned int *w, |
|
unsigned int *h, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_decode_cipher(data, NULL, size, w, h, |
|
alpha, comp, quality, lossy); |
|
} |
|
|
|
EAPI int |
|
eet_data_image_decode_to_surface_cipher(const void *data, |
|
const char *cipher_key, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
unsigned int iw, ih; |
|
int ialpha, icompress, iquality, ilossy; |
|
void *deciphered_d = NULL; |
|
unsigned int deciphered_sz = 0; |
|
|
|
if (cipher_key) |
|
{ |
|
if (!eet_decipher(data, size, cipher_key, strlen(cipher_key), |
|
&deciphered_d, &deciphered_sz)) |
|
{ |
|
data = deciphered_d; |
|
size = deciphered_sz; |
|
} |
|
else |
|
if (deciphered_d) |
|
free(deciphered_d); |
|
} |
|
|
|
/* All check are done during header decode, this simplify the code a lot. */ |
|
if (!eet_data_image_header_decode(data, size, &iw, &ih, &ialpha, &icompress, |
|
&iquality, &ilossy)) |
|
return 0; |
|
|
|
if (!d) |
|
return 0; |
|
|
|
if (w * 4 > row_stride) |
|
return 0; |
|
|
|
if (w > iw || h > ih) |
|
return 0; |
|
|
|
if (!_eet_data_image_decode_inside(data, size, src_x, src_y, iw, ih, d, w, h, |
|
row_stride, ialpha, icompress, iquality, |
|
ilossy)) |
|
return 0; |
|
|
|
if (alpha) |
|
*alpha = ialpha; |
|
|
|
if (comp) |
|
*comp = icompress; |
|
|
|
if (quality) |
|
*quality = iquality; |
|
|
|
if (lossy) |
|
*lossy = ilossy; |
|
|
|
return 1; |
|
} |
|
|
|
EAPI int |
|
eet_data_image_decode_to_surface(const void *data, |
|
int size, |
|
unsigned int src_x, |
|
unsigned int src_y, |
|
unsigned int *d, |
|
unsigned int w, |
|
unsigned int h, |
|
unsigned int row_stride, |
|
int *alpha, |
|
int *comp, |
|
int *quality, |
|
int *lossy) |
|
{ |
|
return eet_data_image_decode_to_surface_cipher(data, NULL, size, |
|
src_x, src_y, d, |
|
w, h, row_stride, |
|
alpha, comp, quality, |
|
lossy); |
|
} |
|
|
|
|