jpeg and png should do the right thing with quality _or_ compression now

SVN revision: 3789
This commit is contained in:
Tom Gilbert 2000-10-30 00:58:02 +00:00
parent 490383f4d7
commit 2e758a7c94
2 changed files with 586 additions and 562 deletions

View File

@ -13,25 +13,26 @@
struct ImLib_JPEG_error_mgr struct ImLib_JPEG_error_mgr
{ {
struct jpeg_error_mgr pub; struct jpeg_error_mgr pub;
sigjmp_buf setjmp_buffer; sigjmp_buf setjmp_buffer;
}; };
typedef struct ImLib_JPEG_error_mgr *emptr; typedef struct ImLib_JPEG_error_mgr *emptr;
void _JPEGFatalErrorHandler(j_common_ptr cinfo); void _JPEGFatalErrorHandler(j_common_ptr cinfo);
void _JPEGErrorHandler(j_common_ptr cinfo); void _JPEGErrorHandler(j_common_ptr cinfo);
void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level);
char load (ImlibImage *im, ImlibProgressFunction progress, char load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load); char progress_granularity, char immediate_load);
char save (ImlibImage *im, ImlibProgressFunction progress, char save(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity);
void formats (ImlibLoader *l); char progress_granularity);
void formats(ImlibLoader * l);
void void
_JPEGFatalErrorHandler(j_common_ptr cinfo) _JPEGFatalErrorHandler(j_common_ptr cinfo)
{ {
emptr errmgr; emptr errmgr;
errmgr = (emptr) cinfo->err; errmgr = (emptr) cinfo->err;
/* cinfo->err->output_message(cinfo);*/ /* cinfo->err->output_message(cinfo);*/
siglongjmp(errmgr->setjmp_buffer, 1); siglongjmp(errmgr->setjmp_buffer, 1);
@ -41,8 +42,8 @@ _JPEGFatalErrorHandler(j_common_ptr cinfo)
void void
_JPEGErrorHandler(j_common_ptr cinfo) _JPEGErrorHandler(j_common_ptr cinfo)
{ {
emptr errmgr; emptr errmgr;
errmgr = (emptr) cinfo->err; errmgr = (emptr) cinfo->err;
/* cinfo->err->output_message(cinfo);*/ /* cinfo->err->output_message(cinfo);*/
/* siglongjmp(errmgr->setjmp_buffer, 1);*/ /* siglongjmp(errmgr->setjmp_buffer, 1);*/
@ -52,8 +53,8 @@ _JPEGErrorHandler(j_common_ptr cinfo)
void void
_JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level)
{ {
emptr errmgr; emptr errmgr;
errmgr = (emptr) cinfo->err; errmgr = (emptr) cinfo->err;
/* cinfo->err->output_message(cinfo);*/ /* cinfo->err->output_message(cinfo);*/
/* siglongjmp(errmgr->setjmp_buffer, 1);*/ /* siglongjmp(errmgr->setjmp_buffer, 1);*/
@ -61,15 +62,15 @@ _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level)
msg_level = 0; msg_level = 0;
} }
char char
load (ImlibImage *im, ImlibProgressFunction progress, load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load) char progress_granularity, char immediate_load)
{ {
int w, h; int w, h;
struct jpeg_decompress_struct cinfo; struct jpeg_decompress_struct cinfo;
struct ImLib_JPEG_error_mgr jerr; struct ImLib_JPEG_error_mgr jerr;
FILE *f; FILE *f;
if (im->data) if (im->data)
return 0; return 0;
f = fopen(im->file, "rb"); f = fopen(im->file, "rb");
@ -80,11 +81,11 @@ load (ImlibImage *im, ImlibProgressFunction progress,
jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.emit_message = _JPEGErrorHandler2;
jerr.pub.output_message = _JPEGErrorHandler; jerr.pub.output_message = _JPEGErrorHandler;
if (sigsetjmp(jerr.setjmp_buffer, 1)) if (sigsetjmp(jerr.setjmp_buffer, 1))
{ {
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(f); fclose(f);
return 0; return 0;
} }
jpeg_create_decompress(&cinfo); jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, f); jpeg_stdio_src(&cinfo, f);
jpeg_read_header(&cinfo, TRUE); jpeg_read_header(&cinfo, TRUE);
@ -92,158 +93,156 @@ load (ImlibImage *im, ImlibProgressFunction progress,
cinfo.do_block_smoothing = FALSE; cinfo.do_block_smoothing = FALSE;
jpeg_start_decompress(&cinfo); jpeg_start_decompress(&cinfo);
if ((!im->loader) && (!im->data)) if ((!im->loader) && (!im->data))
{ {
im->w = w = cinfo.output_width; im->w = w = cinfo.output_width;
im->h = h = cinfo.output_height; im->h = h = cinfo.output_height;
UNSET_FLAG(im->flags, F_HAS_ALPHA); UNSET_FLAG(im->flags, F_HAS_ALPHA);
im->format = strdup("jpeg"); im->format = strdup("jpeg");
} }
if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) if (((!im->data) && (im->loader)) || (immediate_load) || (progress))
{ {
DATA8 *ptr, *line[16], *data; DATA8 *ptr, *line[16], *data;
DATA32 *ptr2; DATA32 *ptr2;
int x, y, l, i, scans, count, prevy; int x, y, l, i, scans, count, prevy;
im->w = w = cinfo.output_width; im->w = w = cinfo.output_width;
im->h = h = cinfo.output_height; im->h = h = cinfo.output_height;
if (cinfo.rec_outbuf_height > 16) if (cinfo.rec_outbuf_height > 16)
{ {
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(f); fclose(f);
return 0; return 0;
} }
data = malloc(w * 16 * 3); data = malloc(w * 16 * 3);
if (!data) if (!data)
{ {
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(f); fclose(f);
return 0; return 0;
} }
/* must set the im->data member before callign progress function */ /* must set the im->data member before callign progress function */
ptr2 = im->data = malloc(w * h * sizeof(DATA32)); ptr2 = im->data = malloc(w * h * sizeof(DATA32));
if (!im->data) if (!im->data)
{ {
free(data); free(data);
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(f); fclose(f);
return 0; return 0;
} }
count = 0; count = 0;
prevy = 0; prevy = 0;
if (cinfo.output_components == 3) if (cinfo.output_components == 3)
{ {
for (i = 0; i < cinfo.rec_outbuf_height; i++) for (i = 0; i < cinfo.rec_outbuf_height; i++)
line[i] = data + (i * w * 3); line[i] = data + (i * w * 3);
for (l = 0; l < h; l += cinfo.rec_outbuf_height) for (l = 0; l < h; l += cinfo.rec_outbuf_height)
{ {
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
scans = cinfo.rec_outbuf_height; scans = cinfo.rec_outbuf_height;
if ((h - l) < scans) if ((h - l) < scans)
scans = h - l; scans = h - l;
ptr = data; ptr = data;
for (y = 0; y < scans; y++) for (y = 0; y < scans; y++)
{ {
for (x = 0; x < w; x++) for (x = 0; x < w; x++)
{ {
*ptr2 = (0xff000000) | *ptr2 =
((ptr[0]) << 16) | (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) |
((ptr[1]) << 8) | (ptr[2]);
(ptr[2]); ptr += 3;
ptr += 3; ptr2++;
ptr2 ++; }
} }
} if (progress)
if (progress) {
{ int per;
int per;
per = (l * 100) / h;
per = (l * 100) / h; if (((per - count) >= progress_granularity)
if (((per - count) >= progress_granularity) || || ((h - l) <= cinfo.rec_outbuf_height))
((h - l) <= cinfo.rec_outbuf_height)) {
{ count = per;
count = per; if (!progress(im, per, 0, prevy, w, scans + l - prevy))
if(!progress(im, per, 0, prevy, w, scans + l - prevy)) {
{ free(data);
free(data); jpeg_finish_decompress(&cinfo);
jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo); fclose(f);
fclose(f); return 2;
return 2; }
} prevy = l + scans;
prevy = l + scans; }
} }
} }
} }
} else if (cinfo.output_components == 1)
else if (cinfo.output_components == 1) {
{ for (i = 0; i < cinfo.rec_outbuf_height; i++)
for (i = 0; i < cinfo.rec_outbuf_height; i++) line[i] = data + (i * w);
line[i] = data + (i * w); for (l = 0; l < h; l += cinfo.rec_outbuf_height)
for (l = 0; l < h; l += cinfo.rec_outbuf_height) {
{ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height;
scans = cinfo.rec_outbuf_height; if ((h - l) < scans)
if ((h - l) < scans) scans = h - l;
scans = h - l; ptr = data;
ptr = data; for (y = 0; y < scans; y++)
for (y = 0; y < scans; y++) {
{ for (x = 0; x < w; x++)
for (x = 0; x < w; x++) {
{ *ptr2 =
*ptr2 = (0xff000000) | (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) |
((ptr[0]) << 16) | (ptr[0]);
((ptr[0]) << 8) | ptr++;
(ptr[0]); ptr2++;
ptr ++; }
ptr2 ++; }
} if (progress)
} {
if (progress) int per;
{
int per; per = (l * 100) / h;
if (((per - count) >= progress_granularity)
per = (l * 100) / h; || ((h - l) <= cinfo.rec_outbuf_height))
if (((per - count) >= progress_granularity) || {
((h - l) <= cinfo.rec_outbuf_height)) count = per;
{ if (!progress(im, per, 0, prevy, w, l + scans - prevy))
count = per; {
if(!progress(im, per, 0, prevy, w, l + scans - prevy)) free(data);
{ jpeg_finish_decompress(&cinfo);
free(data); jpeg_destroy_decompress(&cinfo);
jpeg_finish_decompress(&cinfo); fclose(f);
jpeg_destroy_decompress(&cinfo); return 2;
fclose(f); }
return 2; prevy = l + scans;
} }
prevy = l + scans; }
} }
} }
} free(data);
} }
free(data);
}
jpeg_finish_decompress(&cinfo); jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
fclose(f); fclose(f);
return 1; return 1;
} }
char char
save (ImlibImage *im, ImlibProgressFunction progress, save(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity) char progress_granularity)
{ {
struct jpeg_compress_struct cinfo; struct jpeg_compress_struct cinfo;
struct ImLib_JPEG_error_mgr jerr; struct ImLib_JPEG_error_mgr jerr;
FILE *f; FILE *f;
DATA8 *buf; DATA8 *buf;
DATA32 *ptr; DATA32 *ptr;
JSAMPROW *jbuf; JSAMPROW *jbuf;
int y = 0, quality = 75; int y = 0, quality = 75, compression = 2;
ImlibImageTag *tag; ImlibImageTag *tag;
int i, j, pl = 0; int i, j, pl = 0;
char pper = 0; char pper = 0;
/* no image data? abort */ /* no image data? abort */
if (!im->data) if (!im->data)
@ -254,33 +253,48 @@ save (ImlibImage *im, ImlibProgressFunction progress,
return 0; return 0;
f = fopen(im->file, "wb"); f = fopen(im->file, "wb");
if (!f) if (!f)
{ {
free(buf); free(buf);
return 0; return 0;
} }
/* set up error handling */ /* set up error handling */
jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.error_exit = _JPEGFatalErrorHandler;
jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.emit_message = _JPEGErrorHandler2;
jerr.pub.output_message = _JPEGErrorHandler; jerr.pub.output_message = _JPEGErrorHandler;
cinfo.err = jpeg_std_error(&(jerr.pub)); cinfo.err = jpeg_std_error(&(jerr.pub));
if (sigsetjmp(jerr.setjmp_buffer, 1)) if (sigsetjmp(jerr.setjmp_buffer, 1))
{ {
jpeg_destroy_compress(&cinfo); jpeg_destroy_compress(&cinfo);
free(buf); free(buf);
fclose(f); fclose(f);
return 0; return 0;
} }
/* setup compress params */ /* setup compress params */
jpeg_create_compress(&cinfo); jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, f); jpeg_stdio_dest(&cinfo, f);
cinfo.image_width = im->w; cinfo.image_width = im->w;
cinfo.image_height = im->h; cinfo.image_height = im->h;
cinfo.input_components = 3; cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB; cinfo.in_color_space = JCS_RGB;
/* look for tags attached to image to get extra parameters liek quality */ /* look for tags attached to image to get extra parameters liek quality */
/* settigns etc. - thsi si the "api" to hint for extra information for */ /* settigns etc. - thsi si the "api" to hint for extra information for */
/* saver modules */ /* saver modules */
/* compression */
tag = __imlib_GetTag(im, "compression");
if (tag)
{
compression = tag->val;
if (compression < 0)
compression = 0;
if (compression > 9)
compression = 9;
}
/* convert to quality */
quality = (9 - compression) * 10;
quality = quality * 10 / 9;
/* quality */
tag = __imlib_GetTag(im, "quality"); tag = __imlib_GetTag(im, "quality");
if (tag) if (tag)
quality = tag->val; quality = tag->val;
@ -297,62 +311,60 @@ save (ImlibImage *im, ImlibProgressFunction progress,
ptr = im->data; ptr = im->data;
/* go one scanline at a time... and save */ /* go one scanline at a time... and save */
while (cinfo.next_scanline < cinfo.image_height) while (cinfo.next_scanline < cinfo.image_height)
{ {
/* convcert scaline from ARGB to RGB packed */ /* convcert scaline from ARGB to RGB packed */
for (j = 0, i = 0; i < im->w; i++) for (j = 0, i = 0; i < im->w; i++)
{ {
buf[j++] = ((*ptr) >> 16) & 0xff; buf[j++] = ((*ptr) >> 16) & 0xff;
buf[j++] = ((*ptr) >> 8 ) & 0xff; buf[j++] = ((*ptr) >> 8) & 0xff;
buf[j++] = ((*ptr) ) & 0xff; buf[j++] = ((*ptr)) & 0xff;
ptr++; ptr++;
} }
/* write scanline */ /* write scanline */
jbuf = (JSAMPROW *)(&buf); jbuf = (JSAMPROW *) (&buf);
jpeg_write_scanlines(&cinfo, jbuf, 1); jpeg_write_scanlines(&cinfo, jbuf, 1);
y++; y++;
if (progress) if (progress)
{ {
char per; char per;
int l; int l;
per = (char)((100 * y) / im->h); per = (char) ((100 * y) / im->h);
if (((per - pper) >= progress_granularity) || if (((per - pper) >= progress_granularity) || (y == (im->h - 1)))
(y == (im->h - 1))) {
{ l = y - pl;
l = y - pl; if (!progress(im, per, 0, (y - l), im->w, l))
if(!progress(im, per, 0, (y - l), im->w, l)) {
{ jpeg_finish_compress(&cinfo);
jpeg_finish_compress(&cinfo); free(buf);
free(buf); fclose(f);
fclose(f); return 2;
return 2; }
} pper = per;
pper = per; pl = y;
pl = y; }
} }
} }
}
/* finish off */ /* finish off */
jpeg_finish_compress(&cinfo); jpeg_finish_compress(&cinfo);
free(buf); free(buf);
fclose(f); fclose(f);
return 1; return 1;
progress = NULL; progress = NULL;
} }
void void
formats (ImlibLoader *l) formats(ImlibLoader * l)
{ {
char *list_formats[] = char *list_formats[] = { "jpg", "jpeg", "jfif", "jfi" };
{ "jpg", "jpeg", "jfif", "jfi" };
{ {
int i; int i;
l->num_formats = (sizeof(list_formats) / sizeof (char *)); l->num_formats = (sizeof(list_formats) / sizeof(char *));
l->formats = malloc(sizeof(char *) * l->num_formats); l->formats = malloc(sizeof(char *) * l->num_formats);
for (i = 0; i < l->num_formats; i++)
l->formats[i] = strdup(list_formats[i]); for (i = 0; i < l->num_formats; i++)
} l->formats[i] = strdup(list_formats[i]);
}
} }

View File

@ -15,24 +15,25 @@
/* PNG stuff */ /* PNG stuff */
#define PNG_BYTES_TO_CHECK 4 #define PNG_BYTES_TO_CHECK 4
char load (ImlibImage *im, ImlibProgressFunction progress, char load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load); char progress_granularity, char immediate_load);
char save (ImlibImage *im, ImlibProgressFunction progress, char save(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity);
void formats (ImlibLoader *l);
char char progress_granularity);
load (ImlibImage *im, ImlibProgressFunction progress, void formats(ImlibLoader * l);
char progress_granularity, char immediate_load)
char
load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load)
{ {
png_uint_32 w32, h32; png_uint_32 w32, h32;
int w, h; int w, h;
char hasa = 0, hasg = 0; char hasa = 0, hasg = 0;
FILE *f; FILE *f;
png_structp png_ptr = NULL; png_structp png_ptr = NULL;
png_infop info_ptr = NULL; png_infop info_ptr = NULL;
int bit_depth, color_type, interlace_type; int bit_depth, color_type, interlace_type;
/* if immediate_load is 1, then dont delay image laoding as below, or */ /* if immediate_load is 1, then dont delay image laoding as below, or */
/* already data in this image - dont load it again */ /* already data in this image - dont load it again */
if (im->data) if (im->data)
@ -42,303 +43,315 @@ load (ImlibImage *im, ImlibProgressFunction progress,
return 0; return 0;
/* read header */ /* read header */
if (!im->data) if (!im->data)
{ {
unsigned char buf[PNG_BYTES_TO_CHECK]; unsigned char buf[PNG_BYTES_TO_CHECK];
/* if we havent read the header before, set the header data */ /* if we havent read the header before, set the header data */
fread(buf, 1, PNG_BYTES_TO_CHECK, f); fread(buf, 1, PNG_BYTES_TO_CHECK, f);
if (!png_check_sig(buf, PNG_BYTES_TO_CHECK)) if (!png_check_sig(buf, PNG_BYTES_TO_CHECK))
{ {
fclose(f); fclose(f);
return 0; return 0;
} }
rewind(f); rewind(f);
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, png_ptr =
NULL); png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) if (!png_ptr)
{ {
fclose(f); fclose(f);
return 0; return 0;
} }
info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) if (!info_ptr)
{ {
png_destroy_read_struct(&png_ptr, NULL, NULL); png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(f); fclose(f);
return 0; return 0;
} }
if (setjmp(png_ptr->jmpbuf)) if (setjmp(png_ptr->jmpbuf))
{ {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f); fclose(f);
return 0; return 0;
} }
png_init_io(png_ptr, f); png_init_io(png_ptr, f);
png_read_info(png_ptr, info_ptr); png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
(png_uint_32 *)(&w32), (png_uint_32 *)(&h32), (png_uint_32 *) (&h32), &bit_depth, &color_type,
&bit_depth, &color_type, &interlace_type, NULL, NULL); &interlace_type, NULL, NULL);
im->w = (int)w32; im->w = (int) w32;
im->h = (int)h32; im->h = (int) h32;
if (color_type == PNG_COLOR_TYPE_PALETTE) if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr); png_set_expand(png_ptr);
if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
hasa = 1; hasa = 1;
if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{ {
hasa = 1; hasa = 1;
hasg = 1; hasg = 1;
} }
if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)
hasg = 1; hasg = 1;
if (hasa) if (hasa)
SET_FLAG(im->flags, F_HAS_ALPHA); SET_FLAG(im->flags, F_HAS_ALPHA);
else else
UNSET_FLAG(im->flags, F_HAS_ALPHA); UNSET_FLAG(im->flags, F_HAS_ALPHA);
/* set the format string member to the lower-case full extension */ /* set the format string member to the lower-case full extension */
/* name for the format - so example names would be: */ /* name for the format - so example names would be: */
/* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */
if (!im->loader) if (!im->loader)
im->format = strdup("png"); im->format = strdup("png");
} }
/* if its the second phase load OR its immediate load or a progress */ /* if its the second phase load OR its immediate load or a progress */
/* callback is set then load the data */ /* callback is set then load the data */
if ((im->loader) || (immediate_load) || (progress)) if ((im->loader) || (immediate_load) || (progress))
{ {
unsigned char **lines; unsigned char **lines;
int i; int i;
w = im->w; w = im->w;
h = im->h; h = im->h;
if (hasa) if (hasa)
png_set_expand(png_ptr); png_set_expand(png_ptr);
/* we want ARGB */ /* we want ARGB */
/* note form raster: */ /* note form raster: */
/* thanks to mustapha for helping debug this on PPC Linux remotely by */ /* thanks to mustapha for helping debug this on PPC Linux remotely by */
/* sending across screenshots all the tiem and me figuring out form them */ /* sending across screenshots all the tiem and me figuring out form them */
/* what the hell was up with the colors */ /* what the hell was up with the colors */
/* now png loading shoudl work on big endian machines nicely */ /* now png loading shoudl work on big endian machines nicely */
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
png_set_swap_alpha(png_ptr); png_set_swap_alpha(png_ptr);
png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
#else #else
png_set_bgr(png_ptr); png_set_bgr(png_ptr);
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
#endif #endif
/* 16bit color -> 8bit color */ /* 16bit color -> 8bit color */
png_set_strip_16(png_ptr); png_set_strip_16(png_ptr);
/* pack all pixels to byte boundaires */ /* pack all pixels to byte boundaires */
png_set_packing(png_ptr); png_set_packing(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr); png_set_expand(png_ptr);
if (im->data) if (im->data)
free(im->data); free(im->data);
im->data = malloc(w * h * sizeof(DATA32)); im->data = malloc(w * h * sizeof(DATA32));
if (!im->data) if (!im->data)
{ {
png_read_end(png_ptr, info_ptr); png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
fclose(f); fclose(f);
return 0; return 0;
} }
lines = (unsigned char **)malloc(h * sizeof(unsigned char *)); lines = (unsigned char **) malloc(h * sizeof(unsigned char *));
if (!lines)
{ if (!lines)
free(im->data); {
im->data = NULL; free(im->data);
png_read_end(png_ptr, info_ptr); im->data = NULL;
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); png_read_end(png_ptr, info_ptr);
fclose(f); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
return 0; fclose(f);
} return 0;
if (hasg) }
{ if (hasg)
DATA8 *line; {
int y, count, prevy, pass, number_passes, per, nrows = 1; DATA8 *line;
int y, count, prevy, pass, number_passes, per, nrows = 1;
line = malloc(w * 2);
if (!line) line = malloc(w * 2);
{ if (!line)
free(lines); {
im->data = NULL; free(lines);
png_read_end(png_ptr, info_ptr); im->data = NULL;
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); png_read_end(png_ptr, info_ptr);
fclose(f); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
return 0; fclose(f);
} return 0;
count = 0; }
number_passes = png_set_interlace_handling(png_ptr); count = 0;
for (pass = 0; pass < number_passes; pass++) number_passes = png_set_interlace_handling(png_ptr);
{ for (pass = 0; pass < number_passes; pass++)
prevy = 0; {
per = 0; prevy = 0;
for (y = 0; y < h; y += nrows) per = 0;
{ for (y = 0; y < h; y += nrows)
DATA32 *ptr; {
DATA32 *ptr;
lines[0] = line;
png_read_rows(png_ptr, &lines[0], NULL, nrows); lines[0] = line;
ptr = im->data + (y * w); png_read_rows(png_ptr, &lines[0], NULL, nrows);
for (i = 0; i < w; i++) ptr = im->data + (y * w);
{ for (i = 0; i < w; i++)
ptr[0] = {
(line[i << 1] << 16) | ptr[0] =
(line[i << 1] << 8) | (line[i << 1] << 16) | (line[i << 1] << 8) |
(line[i << 1]) | (line[i << 1]) | (line[(i << 1) + 1] << 24);
(line[(i << 1) + 1] << 24); ptr++;
ptr++; }
} if (progress)
if (progress) {
{ per = (((pass * h) + y) * 100) / (h * number_passes);
per = (((pass * h) + y) * 100) / (h * number_passes); if ((per - count) >= progress_granularity)
if ((per - count) >= progress_granularity)
{
count = per;
progress(im, per, 0, prevy, w, y - prevy + 1);
prevy = y + 1;
}
}
}
if ((progress) && (!progress(im, per, 0, prevy, w, y - prevy + 1)))
{ {
free(lines); count = per;
png_read_end(png_ptr, info_ptr); progress(im, per, 0, prevy, w, y - prevy + 1);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); prevy = y + 1;
fclose(f);
return 2;
} }
} }
free(line); }
} if ((progress)
else && (!progress(im, per, 0, prevy, w, y - prevy + 1)))
{ {
for (i = 0; i < h; i++) free(lines);
lines[i] = ((unsigned char *)(im->data)) + (i * w * sizeof(DATA32)); png_read_end(png_ptr, info_ptr);
if (progress) png_destroy_read_struct(&png_ptr, &info_ptr,
{ (png_infopp) NULL);
int y, count, prevy, pass, number_passes, per, nrows = 1; fclose(f);
return 2;
count = 0; }
number_passes = png_set_interlace_handling(png_ptr); }
for (pass = 0; pass < number_passes; pass++) free(line);
{ }
prevy = 0; else
per = 0; {
for (y = 0; y < h; y += nrows) for (i = 0; i < h; i++)
{ lines[i] =
png_read_rows(png_ptr, &lines[y], NULL, nrows); ((unsigned char *) (im->data)) + (i * w * sizeof(DATA32));
if (progress)
per = (((pass * h) + y) * 100) / (h * number_passes); {
if ((per - count) >= progress_granularity) int y, count, prevy, pass, number_passes, per, nrows = 1;
{
count = per; count = 0;
if(!progress(im, per, 0, prevy, w, y - prevy + 1)) number_passes = png_set_interlace_handling(png_ptr);
{ for (pass = 0; pass < number_passes; pass++)
free(lines); {
png_read_end(png_ptr, info_ptr); prevy = 0;
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); per = 0;
fclose(f); for (y = 0; y < h; y += nrows)
return 2; {
} png_read_rows(png_ptr, &lines[y], NULL, nrows);
prevy = y + 1;
} per = (((pass * h) + y) * 100) / (h * number_passes);
} if ((per - count) >= progress_granularity)
if(!progress(im, per, 0, prevy, w, y - prevy + 1)) {
{ count = per;
free(lines); if (!progress(im, per, 0, prevy, w, y - prevy + 1))
png_read_end(png_ptr, info_ptr); {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(lines);
fclose(f); png_read_end(png_ptr, info_ptr);
return 2; png_destroy_read_struct(&png_ptr, &info_ptr,
} (png_infopp) NULL);
} fclose(f);
} return 2;
else }
png_read_image(png_ptr, lines); prevy = y + 1;
} }
free(lines); }
png_read_end(png_ptr, info_ptr); if (!progress(im, per, 0, prevy, w, y - prevy + 1))
} {
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(lines);
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr,
(png_infopp) NULL);
fclose(f);
return 2;
}
}
}
else
png_read_image(png_ptr, lines);
}
free(lines);
png_read_end(png_ptr, info_ptr);
}
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
fclose(f); fclose(f);
return 1; return 1;
} }
char char
save (ImlibImage *im, ImlibProgressFunction progress, save(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity) char progress_granularity)
{ {
FILE *f; FILE *f;
png_structp png_ptr; png_structp png_ptr;
png_infop info_ptr; png_infop info_ptr;
DATA32 *ptr; DATA32 *ptr;
int x, y, j; int x, y, j;
png_bytep row_ptr, data = NULL; png_bytep row_ptr, data = NULL;
png_color_8 sig_bit; png_color_8 sig_bit;
int pl = 0; int pl = 0;
char pper = 0; char pper = 0;
ImlibImageTag *tag; ImlibImageTag *tag;
int quality = 75, compression; int quality = 75, compression = 3;
f = fopen(im->file, "wb"); f = fopen(im->file, "wb");
if (!f) if (!f)
return 0; return 0;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
NULL, NULL, NULL);
if (!png_ptr) if (!png_ptr)
{ {
fclose(f); fclose(f);
return 0; return 0;
} }
info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) if (info_ptr == NULL)
{ {
fclose(f); fclose(f);
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
return 0; return 0;
} }
if (setjmp(png_ptr->jmpbuf)) if (setjmp(png_ptr->jmpbuf))
{ {
fclose(f); fclose(f);
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
return 0; return 0;
} }
png_init_io(png_ptr, f); png_init_io(png_ptr, f);
if (im->flags & F_HAS_ALPHA) if (im->flags & F_HAS_ALPHA)
{ {
png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
png_set_swap_alpha(png_ptr); png_set_swap_alpha(png_ptr);
#else #else
png_set_bgr(png_ptr); png_set_bgr(png_ptr);
#endif #endif
} }
else else
{ {
png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, PNG_COLOR_TYPE_RGB,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); PNG_FILTER_TYPE_BASE);
data = malloc(im->w * 3 * sizeof(char)); data = malloc(im->w * 3 * sizeof(char));
} }
sig_bit.red = 8; sig_bit.red = 8;
sig_bit.green = 8; sig_bit.green = 8;
sig_bit.blue = 8; sig_bit.blue = 8;
sig_bit.alpha = 8; sig_bit.alpha = 8;
png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_sBIT(png_ptr, info_ptr, &sig_bit);
/* compression */ /* quality */
tag = __imlib_GetTag(im, "quality"); tag = __imlib_GetTag(im, "quality");
if (tag) if (tag)
{
quality = tag->val; quality = tag->val;
if (quality < 10) if (quality < 1)
quality = 10; quality = 1;
if (quality > 99) if (quality > 99)
quality = 99; quality = 99;
/* translate to png-relevant value */ }
/* convert to compression */
quality = quality / 10; quality = quality / 10;
compression = 10 - quality; compression = 9 - quality;
/* should be 1-9 now */ /* compression */
tag = __imlib_GetTag(im, "compression");
if (tag)
compression = tag->val;
if (compression < 0)
compression = 0;
if (compression > 9)
compression = 9;
png_set_compression_level(png_ptr, compression); png_set_compression_level(png_ptr, compression);
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);
png_set_shift(png_ptr, &sig_bit); png_set_shift(png_ptr, &sig_bit);
@ -346,49 +359,49 @@ save (ImlibImage *im, ImlibProgressFunction progress,
ptr = im->data; ptr = im->data;
for (y = 0; y < im->h; y++) for (y = 0; y < im->h; y++)
{ {
if (im->flags & F_HAS_ALPHA) if (im->flags & F_HAS_ALPHA)
row_ptr = (png_bytep)ptr; row_ptr = (png_bytep) ptr;
else else
{ {
for (j = 0, x = 0; x < im->w; x++) for (j = 0, x = 0; x < im->w; x++)
{ {
data[j++] = (ptr[x] >> 16) & 0xff; data[j++] = (ptr[x] >> 16) & 0xff;
data[j++] = (ptr[x] >> 8 ) & 0xff; data[j++] = (ptr[x] >> 8) & 0xff;
data[j++] = (ptr[x] ) & 0xff; data[j++] = (ptr[x]) & 0xff;
} }
row_ptr = (png_bytep)data; row_ptr = (png_bytep) data;
} }
png_write_rows(png_ptr, &row_ptr, 1); png_write_rows(png_ptr, &row_ptr, 1);
if (progress) if (progress)
{ {
char per; char per;
int l; int l;
per = (char)((100 * y) / im->h); per = (char) ((100 * y) / im->h);
if ((per - pper) >= progress_granularity) if ((per - pper) >= progress_granularity)
{ {
l = y - pl; l = y - pl;
if(!progress(im, per, 0, (y - l), im->w, l)) if (!progress(im, per, 0, (y - l), im->w, l))
{ {
if (data) if (data)
free(data); free(data);
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fclose(f); fclose(f);
return 2; return 2;
} }
pper = per; pper = per;
pl = y; pl = y;
} }
} }
ptr += im->w; ptr += im->w;
} }
if (data) if (data)
free(data); free(data);
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp) NULL); png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fclose(f); fclose(f);
return 1; return 1;
} }
@ -400,22 +413,21 @@ save (ImlibImage *im, ImlibProgressFunction progress,
/* your laoder CAN load more than one format if it likes - like: */ /* your laoder CAN load more than one format if it likes - like: */
/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ /* loader->formats = { "gif", "png", "jpeg", "jpg"} */
/* if it can load those formats. */ /* if it can load those formats. */
void void
formats (ImlibLoader *l) formats(ImlibLoader * l)
{ {
/* this is the only bit you have to change... */ /* this is the only bit you have to change... */
char *list_formats[] = char *list_formats[] = { "png" };
{ "png" };
/* don't bother changing any of this - it just reads this in and sets */ /* don't bother changing any of this - it just reads this in and sets */
/* the struct values and makes copies */ /* the struct values and makes copies */
{ {
int i; int i;
l->num_formats = (sizeof(list_formats) / sizeof (char *));
l->formats = malloc(sizeof(char *) * l->num_formats);
for (i = 0; i < l->num_formats; i++)
l->formats[i] = strdup(list_formats[i]);
}
}
l->num_formats = (sizeof(list_formats) / sizeof(char *));
l->formats = malloc(sizeof(char *) * l->num_formats);
for (i = 0; i < l->num_formats; i++)
l->formats[i] = strdup(list_formats[i]);
}
}