From 2e758a7c946b82d00943691fbf4eed1e07b42ac5 Mon Sep 17 00:00:00 2001 From: Tom Gilbert Date: Mon, 30 Oct 2000 00:58:02 +0000 Subject: [PATCH] jpeg and png should do the right thing with quality _or_ compression now SVN revision: 3789 --- loaders/loader_jpeg.c | 480 +++++++++++++++--------------- loaders/loader_png.c | 668 +++++++++++++++++++++--------------------- 2 files changed, 586 insertions(+), 562 deletions(-) diff --git a/loaders/loader_jpeg.c b/loaders/loader_jpeg.c index 8aafd81..6ffe0b8 100644 --- a/loaders/loader_jpeg.c +++ b/loaders/loader_jpeg.c @@ -13,25 +13,26 @@ struct ImLib_JPEG_error_mgr { - struct jpeg_error_mgr pub; - sigjmp_buf setjmp_buffer; + struct jpeg_error_mgr pub; + sigjmp_buf setjmp_buffer; }; typedef struct ImLib_JPEG_error_mgr *emptr; void _JPEGFatalErrorHandler(j_common_ptr cinfo); void _JPEGErrorHandler(j_common_ptr cinfo); void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); -char load (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity, char immediate_load); -char save (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity); -void formats (ImlibLoader *l); +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, + + char progress_granularity); +void formats(ImlibLoader * l); void _JPEGFatalErrorHandler(j_common_ptr cinfo) { - emptr errmgr; - + emptr errmgr; + errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ siglongjmp(errmgr->setjmp_buffer, 1); @@ -41,8 +42,8 @@ _JPEGFatalErrorHandler(j_common_ptr cinfo) void _JPEGErrorHandler(j_common_ptr cinfo) { - emptr errmgr; - + emptr errmgr; + errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ /* siglongjmp(errmgr->setjmp_buffer, 1);*/ @@ -52,8 +53,8 @@ _JPEGErrorHandler(j_common_ptr cinfo) void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) { - emptr errmgr; - + emptr errmgr; + errmgr = (emptr) cinfo->err; /* cinfo->err->output_message(cinfo);*/ /* siglongjmp(errmgr->setjmp_buffer, 1);*/ @@ -61,15 +62,15 @@ _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) msg_level = 0; } -char -load (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity, char immediate_load) +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) { - int w, h; - struct jpeg_decompress_struct cinfo; - struct ImLib_JPEG_error_mgr jerr; - FILE *f; - + int w, h; + struct jpeg_decompress_struct cinfo; + struct ImLib_JPEG_error_mgr jerr; + FILE *f; + if (im->data) return 0; f = fopen(im->file, "rb"); @@ -80,11 +81,11 @@ load (ImlibImage *im, ImlibProgressFunction progress, jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (sigsetjmp(jerr.setjmp_buffer, 1)) - { - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 0; - } + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, f); jpeg_read_header(&cinfo, TRUE); @@ -92,158 +93,156 @@ load (ImlibImage *im, ImlibProgressFunction progress, cinfo.do_block_smoothing = FALSE; jpeg_start_decompress(&cinfo); if ((!im->loader) && (!im->data)) - { - im->w = w = cinfo.output_width; - im->h = h = cinfo.output_height; - UNSET_FLAG(im->flags, F_HAS_ALPHA); - im->format = strdup("jpeg"); - } + { + im->w = w = cinfo.output_width; + im->h = h = cinfo.output_height; + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("jpeg"); + } if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) - { - DATA8 *ptr, *line[16], *data; - DATA32 *ptr2; - int x, y, l, i, scans, count, prevy; - - im->w = w = cinfo.output_width; - im->h = h = cinfo.output_height; - - if (cinfo.rec_outbuf_height > 16) - { - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 0; - } - data = malloc(w * 16 * 3); - if (!data) - { - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 0; - } - /* must set the im->data member before callign progress function */ - ptr2 = im->data = malloc(w * h * sizeof(DATA32)); - if (!im->data) - { - free(data); - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 0; - } - 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 ++; - } - } - if (progress) - { - int per; - - per = (l * 100) / h; - if (((per - count) >= progress_granularity) || - ((h - l) <= cinfo.rec_outbuf_height)) - { - count = per; - if(!progress(im, per, 0, prevy, w, scans + l - prevy)) - { - free(data); - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 2; - } - prevy = l + scans; - } - } - } - } - 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 ++; - } - } - if (progress) - { - int per; - - per = (l * 100) / h; - if (((per - count) >= progress_granularity) || - ((h - l) <= cinfo.rec_outbuf_height)) - { - count = per; - if(!progress(im, per, 0, prevy, w, l + scans - prevy)) - { - free(data); - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(f); - return 2; - } - prevy = l + scans; - } - } - } - } - free(data); - } + { + DATA8 *ptr, *line[16], *data; + DATA32 *ptr2; + int x, y, l, i, scans, count, prevy; + + im->w = w = cinfo.output_width; + im->h = h = cinfo.output_height; + + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + data = malloc(w * 16 * 3); + if (!data) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + /* must set the im->data member before callign progress function */ + ptr2 = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(data); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 0; + } + 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++; + } + } + if (progress) + { + int per; + + per = (l * 100) / h; + if (((per - count) >= progress_granularity) + || ((h - l) <= cinfo.rec_outbuf_height)) + { + count = per; + if (!progress(im, per, 0, prevy, w, scans + l - prevy)) + { + free(data); + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 2; + } + prevy = l + scans; + } + } + } + } + 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++; + } + } + if (progress) + { + int per; + + per = (l * 100) / h; + if (((per - count) >= progress_granularity) + || ((h - l) <= cinfo.rec_outbuf_height)) + { + count = per; + if (!progress(im, per, 0, prevy, w, l + scans - prevy)) + { + free(data); + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return 2; + } + prevy = l + scans; + } + } + } + } + free(data); + } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(f); return 1; } -char -save (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity) +char +save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity) { - struct jpeg_compress_struct cinfo; - struct ImLib_JPEG_error_mgr jerr; - FILE *f; - DATA8 *buf; - DATA32 *ptr; - JSAMPROW *jbuf; - int y = 0, quality = 75; - ImlibImageTag *tag; - int i, j, pl = 0; - char pper = 0; - + struct jpeg_compress_struct cinfo; + struct ImLib_JPEG_error_mgr jerr; + FILE *f; + DATA8 *buf; + DATA32 *ptr; + JSAMPROW *jbuf; + int y = 0, quality = 75, compression = 2; + ImlibImageTag *tag; + int i, j, pl = 0; + char pper = 0; + /* no image data? abort */ if (!im->data) @@ -254,33 +253,48 @@ save (ImlibImage *im, ImlibProgressFunction progress, return 0; f = fopen(im->file, "wb"); if (!f) - { - free(buf); - return 0; - } + { + free(buf); + return 0; + } /* set up error handling */ jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; cinfo.err = jpeg_std_error(&(jerr.pub)); if (sigsetjmp(jerr.setjmp_buffer, 1)) - { - jpeg_destroy_compress(&cinfo); - free(buf); - fclose(f); - return 0; - } + { + jpeg_destroy_compress(&cinfo); + free(buf); + fclose(f); + return 0; + } /* setup compress params */ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); - cinfo.image_width = im->w; - cinfo.image_height = im->h; + cinfo.image_width = im->w; + cinfo.image_height = im->h; 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 */ /* settigns etc. - thsi si the "api" to hint for extra information for */ /* 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"); if (tag) quality = tag->val; @@ -297,62 +311,60 @@ save (ImlibImage *im, ImlibProgressFunction progress, ptr = im->data; /* go one scanline at a time... and save */ while (cinfo.next_scanline < cinfo.image_height) - { - /* convcert scaline from ARGB to RGB packed */ - for (j = 0, i = 0; i < im->w; i++) - { - buf[j++] = ((*ptr) >> 16) & 0xff; - buf[j++] = ((*ptr) >> 8 ) & 0xff; - buf[j++] = ((*ptr) ) & 0xff; - ptr++; - } - /* write scanline */ - jbuf = (JSAMPROW *)(&buf); - jpeg_write_scanlines(&cinfo, jbuf, 1); - y++; - if (progress) - { - char per; - int l; - - per = (char)((100 * y) / im->h); - if (((per - pper) >= progress_granularity) || - (y == (im->h - 1))) - { - l = y - pl; - if(!progress(im, per, 0, (y - l), im->w, l)) - { - jpeg_finish_compress(&cinfo); - free(buf); - fclose(f); - return 2; - } - pper = per; - pl = y; - } - } - } + { + /* convcert scaline from ARGB to RGB packed */ + for (j = 0, i = 0; i < im->w; i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + ptr++; + } + /* write scanline */ + jbuf = (JSAMPROW *) (&buf); + jpeg_write_scanlines(&cinfo, jbuf, 1); + y++; + if (progress) + { + char per; + int l; + + per = (char) ((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || (y == (im->h - 1))) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + jpeg_finish_compress(&cinfo); + free(buf); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + } /* finish off */ - jpeg_finish_compress(&cinfo); + jpeg_finish_compress(&cinfo); free(buf); fclose(f); return 1; progress = NULL; } -void -formats (ImlibLoader *l) -{ - char *list_formats[] = - { "jpg", "jpeg", "jfif", "jfi" }; +void +formats(ImlibLoader * l) +{ + char *list_formats[] = { "jpg", "jpeg", "jfif", "jfi" }; - { - 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]); - } + { + 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]); + } } - diff --git a/loaders/loader_png.c b/loaders/loader_png.c index 5611c44..07b415e 100644 --- a/loaders/loader_png.c +++ b/loaders/loader_png.c @@ -15,24 +15,25 @@ /* PNG stuff */ #define PNG_BYTES_TO_CHECK 4 -char load (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity, char immediate_load); -char save (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity); -void formats (ImlibLoader *l); +char load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save(ImlibImage * im, ImlibProgressFunction progress, -char -load (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity, char immediate_load) + char progress_granularity); +void formats(ImlibLoader * l); + +char +load(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) { - png_uint_32 w32, h32; - int w, h; - char hasa = 0, hasg = 0; - FILE *f; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - int bit_depth, color_type, interlace_type; - + png_uint_32 w32, h32; + int w, h; + char hasa = 0, hasg = 0; + FILE *f; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + int bit_depth, color_type, interlace_type; + /* if immediate_load is 1, then dont delay image laoding as below, or */ /* already data in this image - dont load it again */ if (im->data) @@ -42,303 +43,315 @@ load (ImlibImage *im, ImlibProgressFunction progress, return 0; /* read header */ if (!im->data) - { - unsigned char buf[PNG_BYTES_TO_CHECK]; - - /* if we havent read the header before, set the header data */ - fread(buf, 1, PNG_BYTES_TO_CHECK, f); - if (!png_check_sig(buf, PNG_BYTES_TO_CHECK)) - { - fclose(f); - return 0; - } - rewind(f); - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, - NULL); - if (!png_ptr) - { - fclose(f); - return 0; - } - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, NULL, NULL); - fclose(f); - return 0; - } - if (setjmp(png_ptr->jmpbuf)) - { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - fclose(f); - return 0; - } - png_init_io(png_ptr, f); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, - (png_uint_32 *)(&w32), (png_uint_32 *)(&h32), - &bit_depth, &color_type, &interlace_type, NULL, NULL); - im->w = (int)w32; - im->h = (int)h32; - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png_ptr); - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - hasa = 1; - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - hasa = 1; - hasg = 1; - } - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) - hasg = 1; - if (hasa) - SET_FLAG(im->flags, F_HAS_ALPHA); - else - UNSET_FLAG(im->flags, F_HAS_ALPHA); - /* set the format string member to the lower-case full extension */ - /* name for the format - so example names would be: */ - /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ - if (!im->loader) - im->format = strdup("png"); - } + { + unsigned char buf[PNG_BYTES_TO_CHECK]; + + /* if we havent read the header before, set the header data */ + fread(buf, 1, PNG_BYTES_TO_CHECK, f); + if (!png_check_sig(buf, PNG_BYTES_TO_CHECK)) + { + fclose(f); + return 0; + } + rewind(f); + png_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fclose(f); + return 0; + } + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fclose(f); + return 0; + } + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(f); + return 0; + } + png_init_io(png_ptr, f); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), + (png_uint_32 *) (&h32), &bit_depth, &color_type, + &interlace_type, NULL, NULL); + im->w = (int) w32; + im->h = (int) h32; + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + hasa = 1; + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + hasa = 1; + hasg = 1; + } + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) + hasg = 1; + if (hasa) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + if (!im->loader) + im->format = strdup("png"); + } /* if its the second phase load OR its immediate load or a progress */ /* callback is set then load the data */ if ((im->loader) || (immediate_load) || (progress)) - { - unsigned char **lines; - int i; - - w = im->w; - h = im->h; - if (hasa) - png_set_expand(png_ptr); - /* we want ARGB */ + { + unsigned char **lines; + int i; + + w = im->w; + h = im->h; + if (hasa) + png_set_expand(png_ptr); + /* we want ARGB */ /* note form raster: */ /* thanks to mustapha for helping debug this on PPC Linux remotely by */ /* sending across screenshots all the tiem and me figuring out form them */ /* what the hell was up with the colors */ /* now png loading shoudl work on big endian machines nicely */ #ifdef WORDS_BIGENDIAN - png_set_swap_alpha(png_ptr); - png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); -#else - png_set_bgr(png_ptr); - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); -#endif - /* 16bit color -> 8bit color */ - png_set_strip_16(png_ptr); - /* pack all pixels to byte boundaires */ - png_set_packing(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand(png_ptr); - if (im->data) - free(im->data); - im->data = malloc(w * h * sizeof(DATA32)); - if (!im->data) - { - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(f); - return 0; - } - lines = (unsigned char **)malloc(h * sizeof(unsigned char *)); - if (!lines) - { - free(im->data); - im->data = NULL; - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(f); - return 0; - } - if (hasg) - { - DATA8 *line; - int y, count, prevy, pass, number_passes, per, nrows = 1; - - line = malloc(w * 2); - if (!line) - { - free(lines); - im->data = NULL; - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(f); - return 0; - } - count = 0; - number_passes = png_set_interlace_handling(png_ptr); - for (pass = 0; pass < number_passes; pass++) - { - prevy = 0; - per = 0; - for (y = 0; y < h; y += nrows) - { - DATA32 *ptr; - - lines[0] = line; - png_read_rows(png_ptr, &lines[0], NULL, nrows); - ptr = im->data + (y * w); - for (i = 0; i < w; i++) - { - ptr[0] = - (line[i << 1] << 16) | - (line[i << 1] << 8) | - (line[i << 1]) | - (line[(i << 1) + 1] << 24); - ptr++; - } - if (progress) - { - per = (((pass * h) + y) * 100) / (h * number_passes); - 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))) + png_set_swap_alpha(png_ptr); + png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); +#else + png_set_bgr(png_ptr); + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); +#endif + /* 16bit color -> 8bit color */ + png_set_strip_16(png_ptr); + /* pack all pixels to byte boundaires */ + png_set_packing(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (im->data) + free(im->data); + im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 0; + } + lines = (unsigned char **) malloc(h * sizeof(unsigned char *)); + + if (!lines) + { + free(im->data); + im->data = NULL; + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 0; + } + if (hasg) + { + DATA8 *line; + int y, count, prevy, pass, number_passes, per, nrows = 1; + + line = malloc(w * 2); + if (!line) + { + free(lines); + im->data = NULL; + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + fclose(f); + return 0; + } + count = 0; + number_passes = png_set_interlace_handling(png_ptr); + for (pass = 0; pass < number_passes; pass++) + { + prevy = 0; + per = 0; + for (y = 0; y < h; y += nrows) + { + DATA32 *ptr; + + lines[0] = line; + png_read_rows(png_ptr, &lines[0], NULL, nrows); + ptr = im->data + (y * w); + for (i = 0; i < w; i++) + { + ptr[0] = + (line[i << 1] << 16) | (line[i << 1] << 8) | + (line[i << 1]) | (line[(i << 1) + 1] << 24); + ptr++; + } + if (progress) + { + per = (((pass * h) + y) * 100) / (h * number_passes); + if ((per - count) >= progress_granularity) { - free(lines); - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(f); - return 2; + count = per; + progress(im, per, 0, prevy, w, y - prevy + 1); + prevy = y + 1; } - } - free(line); - } - else - { - for (i = 0; i < h; i++) - lines[i] = ((unsigned char *)(im->data)) + (i * w * sizeof(DATA32)); - if (progress) - { - int y, count, prevy, pass, number_passes, per, nrows = 1; - - count = 0; - number_passes = png_set_interlace_handling(png_ptr); - for (pass = 0; pass < number_passes; pass++) - { - prevy = 0; - per = 0; - for (y = 0; y < h; y += nrows) - { - png_read_rows(png_ptr, &lines[y], NULL, nrows); - - per = (((pass * h) + y) * 100) / (h * number_passes); - if ((per - count) >= progress_granularity) - { - count = per; - if(!progress(im, per, 0, prevy, w, y - prevy + 1)) - { - free(lines); - png_read_end(png_ptr, info_ptr); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - fclose(f); - return 2; - } - prevy = y + 1; - } - } - if(!progress(im, per, 0, prevy, w, y - prevy + 1)) - { - 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); + } + } + if ((progress) + && (!progress(im, per, 0, prevy, w, y - prevy + 1))) + { + free(lines); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp) NULL); + fclose(f); + return 2; + } + } + free(line); + } + else + { + for (i = 0; i < h; i++) + lines[i] = + ((unsigned char *) (im->data)) + (i * w * sizeof(DATA32)); + if (progress) + { + int y, count, prevy, pass, number_passes, per, nrows = 1; + + count = 0; + number_passes = png_set_interlace_handling(png_ptr); + for (pass = 0; pass < number_passes; pass++) + { + prevy = 0; + per = 0; + for (y = 0; y < h; y += nrows) + { + png_read_rows(png_ptr, &lines[y], NULL, nrows); + + per = (((pass * h) + y) * 100) / (h * number_passes); + if ((per - count) >= progress_granularity) + { + count = per; + if (!progress(im, per, 0, prevy, w, y - prevy + 1)) + { + free(lines); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp) NULL); + fclose(f); + return 2; + } + prevy = y + 1; + } + } + if (!progress(im, per, 0, prevy, w, y - prevy + 1)) + { + 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); return 1; } -char -save (ImlibImage *im, ImlibProgressFunction progress, - char progress_granularity) +char +save(ImlibImage * im, ImlibProgressFunction progress, + char progress_granularity) { - FILE *f; - png_structp png_ptr; - png_infop info_ptr; - DATA32 *ptr; - int x, y, j; - png_bytep row_ptr, data = NULL; - png_color_8 sig_bit; - int pl = 0; - char pper = 0; - ImlibImageTag *tag; - int quality = 75, compression; - + FILE *f; + png_structp png_ptr; + png_infop info_ptr; + DATA32 *ptr; + int x, y, j; + png_bytep row_ptr, data = NULL; + png_color_8 sig_bit; + int pl = 0; + char pper = 0; + ImlibImageTag *tag; + int quality = 75, compression = 3; + f = fopen(im->file, "wb"); if (!f) return 0; - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) - { - fclose(f); - return 0; - } + { + fclose(f); + return 0; + } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) - { - fclose(f); - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - return 0; - } + { + fclose(f); + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + return 0; + } if (setjmp(png_ptr->jmpbuf)) - { - fclose(f); - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - return 0; - } + { + fclose(f); + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + return 0; + } png_init_io(png_ptr, f); if (im->flags & F_HAS_ALPHA) - { - png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + { + png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #ifdef WORDS_BIGENDIAN - png_set_swap_alpha(png_ptr); + png_set_swap_alpha(png_ptr); #else - png_set_bgr(png_ptr); + png_set_bgr(png_ptr); #endif - } + } else - { - png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - data = malloc(im->w * 3 * sizeof(char)); - } + { + png_set_IHDR(png_ptr, info_ptr, im->w, im->h, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + data = malloc(im->w * 3 * sizeof(char)); + } sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); - /* compression */ + /* quality */ tag = __imlib_GetTag(im, "quality"); if (tag) + { quality = tag->val; - if (quality < 10) - quality = 10; - if (quality > 99) - quality = 99; - /* translate to png-relevant value */ + if (quality < 1) + quality = 1; + if (quality > 99) + quality = 99; + } + /* convert to compression */ quality = quality / 10; - compression = 10 - quality; - /* should be 1-9 now */ + compression = 9 - quality; + /* 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_write_info(png_ptr, info_ptr); png_set_shift(png_ptr, &sig_bit); @@ -346,49 +359,49 @@ save (ImlibImage *im, ImlibProgressFunction progress, ptr = im->data; for (y = 0; y < im->h; y++) - { - if (im->flags & F_HAS_ALPHA) - row_ptr = (png_bytep)ptr; - else - { - for (j = 0, x = 0; x < im->w; x++) - { - data[j++] = (ptr[x] >> 16) & 0xff; - data[j++] = (ptr[x] >> 8 ) & 0xff; - data[j++] = (ptr[x] ) & 0xff; - } - row_ptr = (png_bytep)data; - } - png_write_rows(png_ptr, &row_ptr, 1); - if (progress) - { - char per; - int l; - - per = (char)((100 * y) / im->h); - if ((per - pper) >= progress_granularity) - { - l = y - pl; - if(!progress(im, per, 0, (y - l), im->w, l)) - { - if (data) - free(data); - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - fclose(f); - return 2; - } - pper = per; - pl = y; - } - } - ptr += im->w; - } + { + if (im->flags & F_HAS_ALPHA) + row_ptr = (png_bytep) ptr; + else + { + for (j = 0, x = 0; x < im->w; x++) + { + data[j++] = (ptr[x] >> 16) & 0xff; + data[j++] = (ptr[x] >> 8) & 0xff; + data[j++] = (ptr[x]) & 0xff; + } + row_ptr = (png_bytep) data; + } + png_write_rows(png_ptr, &row_ptr, 1); + if (progress) + { + char per; + int l; + + per = (char) ((100 * y) / im->h); + if ((per - pper) >= progress_granularity) + { + l = y - pl; + if (!progress(im, per, 0, (y - l), im->w, l)) + { + if (data) + free(data); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + fclose(f); + return 2; + } + pper = per; + pl = y; + } + } + ptr += im->w; + } if (data) free(data); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - + fclose(f); return 1; } @@ -400,22 +413,21 @@ save (ImlibImage *im, ImlibProgressFunction progress, /* your laoder CAN load more than one format if it likes - like: */ /* loader->formats = { "gif", "png", "jpeg", "jpg"} */ /* if it can load those formats. */ -void -formats (ImlibLoader *l) -{ +void +formats(ImlibLoader * l) +{ /* this is the only bit you have to change... */ - char *list_formats[] = - { "png" }; + char *list_formats[] = { "png" }; /* don't bother changing any of this - it just reads this in and sets */ /* the struct values and makes copies */ - { - 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]); - } -} + { + 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]); + } +}