diff options
author | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
---|---|---|
committer | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
commit | f5c598b518d1f906148534d015f50075d3e8242d (patch) | |
tree | 21dd70add5b366c3dd80641b77f6b18e0baa009e /src/png.c | |
parent | e98d02a01ffeb18ede86af025e51ae1ec011c75a (diff) | |
parent | 5f0fc0e48b8cbee7e1795935da0abff6627fd498 (diff) |
merge
Diffstat (limited to 'src/png.c')
-rw-r--r-- | src/png.c | 227 |
1 files changed, 104 insertions, 123 deletions
@@ -4,6 +4,7 @@ * * Geoff Lane nov 1999 zzassgl@twirl.mcc.ac.uk * Luca Rota, Jorge Arellano Cid, Eric Gaudet 2000 + * Jorge Arellano Cid 2009 * * "PNG: The Definitive Guide" by Greg Roelofs, O'Reilly * ISBN 1-56592-542-4 @@ -12,12 +13,8 @@ #include <config.h> #ifdef ENABLE_PNG -#include <stdio.h> -#include <string.h> #include <stdlib.h> /* For abort() */ -#include <zlib.h> - #ifdef HAVE_LIBPNG_PNG_H #include <libpng/png.h> #else @@ -26,10 +23,8 @@ #include "msg.h" #include "image.hh" -#include "web.hh" #include "cache.h" #include "dicache.h" -#include "prefs.h" enum prog_state { IS_finished, IS_init, IS_nextdata @@ -58,7 +53,7 @@ static char *prog_state_name[] = * structure below so that processing can be suspended or resumed at any * point within an input image. * - * In the case of the libpng library, it maintains it's own state in + * In the case of the libpng library, it maintains its own state in * png_ptr and into_ptr so the FSM is very simple - much simpler than the * ones for XBM and PNM are. */ @@ -67,19 +62,19 @@ typedef struct _DilloPng { DilloImage *Image; /* Image meta data */ DilloUrl *url; /* Primary Key for the dicache */ - int version; /* Secondary Key for the dicache */ + int version; /* Secondary Key for the dicache */ double display_exponent; /* gamma correction */ - ulong_t width; /* png image width */ - ulong_t height; /* png image height */ + ulong_t width; /* png image width */ + ulong_t height; /* png image height */ png_structp png_ptr; /* libpng private data */ png_infop info_ptr; /* libpng private info */ - uchar_t *image_data; /* decoded image data */ - uchar_t **row_pointers; /* pntr to row starts */ + uchar_t *image_data; /* decoded image data */ + uchar_t **row_pointers; /* pntr to row starts */ jmp_buf jmpbuf; /* png error processing */ - int error; /* error flag */ + int error; /* error flag */ png_uint_32 previous_row; - int rowbytes; /* No. bytes in image row */ + int rowbytes; /* No. bytes in image row */ short passes; short channels; /* No. image channels */ @@ -92,13 +87,13 @@ struct _DilloPng { * ipbuf ipbufstart ipbufsize */ - uchar_t *ipbuf; /* image data in buffer */ - int ipbufstart; /* first valid image byte */ - int ipbufsize; /* size of valid data in */ + uchar_t *ipbuf; /* image data in buffer */ + int ipbufstart; /* first valid image byte */ + int ipbufsize; /* size of valid data in */ enum prog_state state; /* FSM current state */ - uchar_t *linebuf; /* o/p raster data */ + uchar_t *linebuf; /* o/p raster data */ } DilloPng; @@ -106,13 +101,6 @@ struct _DilloPng { #define BLACK 0 #define WHITE 255 -/* - * Forward declarations - */ -/* exported function */ -void *a_Png_image(const char *Type, void *Ptr, CA_Callback_t *Call, - void **Data); - static void Png_error_handling(png_structp png_ptr, png_const_charp msg) @@ -146,6 +134,15 @@ Png_datainfo_callback(png_structp png_ptr, png_infop info_ptr) png_get_IHDR(png_ptr, info_ptr, &png->width, &png->height, &bit_depth, &color_type, &interlace_type, NULL, NULL); + /* check max image size */ + if (png->width <= 0 || png->height <= 0 || + png->width > IMAGE_MAX_AREA / png->height) { + MSG("Png_datainfo_callback: suspicious image size request %ldx%ld\n", + png->width, png->height); + Png_error_handling(png_ptr, "Aborting..."); + return; /* not reached */ + } + _MSG("Png_datainfo_callback: png->width = %ld\n" "Png_datainfo_callback: png->height = %ld\n", png->width, png->height); @@ -185,7 +182,7 @@ Png_datainfo_callback(png_structp png_ptr, png_infop info_ptr) png->passes = png_set_interlace_handling(png_ptr); } - /* get libpng to update it's state */ + /* get libpng to update its state */ png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &png->width, &png->height, @@ -230,14 +227,15 @@ static void png_progressive_combine_row(png_ptr, png->row_pointers[row_num], new_row); + _MSG("png: row_num=%u previous_row=%u\n", row_num, png->previous_row); if (row_num < png->previous_row) { - a_Dicache_new_scan(png->Image, png->url, png->version); + a_Dicache_new_scan(png->url, png->version); } png->previous_row = row_num; switch (png->channels) { case 3: - a_Dicache_write(png->Image, png->url, png->version, + a_Dicache_write(png->url, png->version, png->image_data + (row_num * png->rowbytes), (uint_t)row_num); break; @@ -275,79 +273,67 @@ static void data++; } } - a_Dicache_write(png->Image, png->url, png->version, - png->linebuf, (uint_t)row_num); + a_Dicache_write(png->url, png->version, png->linebuf, (uint_t)row_num); break; } default: - MSG("Png_datarow_callback: unexpected number of channels = %d\n", - png->channels); + MSG("Png_datarow_callback: unexpected number of channels=%d pass=%d\n", + png->channels, pass); abort(); } } -static void - Png_dataend_callback(png_structp png_ptr, png_infop info_ptr) +static void Png_dataend_callback(png_structp png_ptr, png_infop info_ptr) { DilloPng *png; _MSG("Png_dataend_callback:\n"); + if (!info_ptr) + MSG("Png_dataend_callback: info_ptr = NULL\n"); png = png_get_progressive_ptr(png_ptr); png->state = IS_finished; } - /* - * Op: Operation to perform. - * If (Op == 0) - * start or continue processing an image if image data exists. - * else - * terminate processing, cleanup any allocated memory, - * close down the decoding process. - * - * Client->CbData : pointer to previously allocated DilloPng work area. - * This holds the current state of the image processing and is saved - * across calls to this routine. - * Client->Buf : Pointer to data start. - * Client->BufSize : the size of the data buffer. - * - * You have to keep track of where you are in the image data and - * how much has been processed. - * - * It's entirely possible that you will not see the end of the data. The - * user may terminate transfer via a Stop button or there may be a network - * failure. This means that you can't just wait for all the data to be - * presented before starting conversion and display. + * Free up the resources for this image. */ -static void Png_callback(int Op, CacheClient_t *Client) +static void Png_free(DilloPng *png) { - DilloPng *png = Client->CbData; - - if (Op) { - /* finished - free up the resources for this image */ - a_Dicache_close(png->url, png->version, Client); - dFree(png->image_data); - dFree(png->row_pointers); - dFree(png->linebuf); - - if (setjmp(png->jmpbuf)) - MSG_WARN("PNG: can't destroy read structure\n"); - else if (png->png_ptr) - png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); - dFree(png); - return; - } + _MSG("Png_free: png=%p\n", png); + + dFree(png->image_data); + dFree(png->row_pointers); + dFree(png->linebuf); + if (setjmp(png->jmpbuf)) + MSG_WARN("PNG: can't destroy read structure\n"); + else if (png->png_ptr) + png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); + dFree(png); +} - /* Let's make some sound if we have been called with no data */ - dReturn_if_fail ( Client->Buf != NULL && Client->BufSize > 0 ); +/* + * Finish the decoding process (and free the memory) + */ +static void Png_close(DilloPng *png, CacheClient_t *Client) +{ + _MSG("Png_close\n"); + /* Let dicache know decoding is over */ + a_Dicache_close(png->url, png->version, Client); + Png_free(png); +} - _MSG("Png_callback BufSize = %d\n", Client->BufSize); +/* + * Receive and process new chunks of PNG image data + */ +static void Png_write(DilloPng *png, void *Buf, uint_t BufSize) +{ + dReturn_if_fail ( Buf != NULL && BufSize > 0 ); /* Keep local copies so we don't have to pass multiple args to * a number of functions. */ - png->ipbuf = Client->Buf; - png->ipbufsize = Client->BufSize; + png->ipbuf = Buf; + png->ipbufsize = BufSize; /* start/resume the FSM here */ while (png->state != IS_finished && DATASIZE) { @@ -359,8 +345,7 @@ static void Png_callback(int Op, CacheClient_t *Client) return; /* need MORE data */ } /* check the image signature - DON'T update ipbufstart! */ - if (!png_check_sig(png->ipbuf, DATASIZE)) { - /* you lied to me about it being a PNG image */ + if (png_sig_cmp(png->ipbuf, 0, DATASIZE)) { MSG_WARN("\"%s\" is not a PNG file.\n", URL_STR(png->url)); png->state = IS_finished; break; @@ -408,11 +393,47 @@ static void Png_callback(int Op, CacheClient_t *Client) } /* + * Op: Operation to perform. + * If (Op == 0) + * start or continue processing an image if image data exists. + * else + * terminate processing, cleanup any allocated memory, + * close down the decoding process. + * + * Client->CbData : pointer to previously allocated DilloPng work area. + * This holds the current state of the image processing and is kept + * across calls to this routine. + * Client->Buf : Pointer to data start. + * Client->BufSize : the size of the data buffer. + * + * You have to keep track of where you are in the image data and + * how much has been processed. + * + * It's entirely possible that you will not see the end of the data. The + * user may terminate transfer via a Stop button or there may be a network + * failure. This means that you can't just wait for all the data to be + * presented before starting conversion and display. + */ +void a_Png_callback(int Op, void *data) +{ + if (Op == CA_Send) { + CacheClient_t *Client = data; + Png_write(Client->CbData, Client->Buf, Client->BufSize); + } else if (Op == CA_Close) { + CacheClient_t *Client = data; + Png_close(Client->CbData, Client); + } else if (Op == CA_Abort) { + Png_free(data); + } +} + +/* * Create the image state data that must be kept between calls */ -static DilloPng *Png_new(DilloImage *Image, DilloUrl *url, int version) +void *a_Png_new(DilloImage *Image, DilloUrl *url, int version) { DilloPng *png = dNew0(DilloPng, 1); + _MSG("a_Png_new: png=%p\n", png); png->Image = Image; png->url = url; @@ -430,49 +451,9 @@ static DilloPng *Png_new(DilloImage *Image, DilloUrl *url, int version) return png; } -/* - * MIME handler for "image/png" type - * (Sets Png_callback or a_Dicache_callback as the cache-client) - */ -void *a_Png_image(const char *Type, void *Ptr, CA_Callback_t *Call, - void **Data) -{ -/* - * Type: MIME type - * Ptr: points to a Web structure - * Call: Dillo calls this with more data/eod - * Data: raw image data - */ +#else /* ENABLE_PNG */ - DilloWeb *web = Ptr; - DICacheEntry *DicEntry; - - _MSG("a_Png_image: Type = %s\n" - "a_Png_image: libpng - Compiled %s; using %s.\n" - "a_Png_image: zlib - Compiled %s; using %s.\n", - Type, PNG_LIBPNG_VER_STRING, png_libpng_ver,ZLIB_VERSION,zlib_version); - - if (!web->Image) - web->Image = a_Image_new(0, 0, NULL, prefs.bg_color); - - /* Add an extra reference to the Image (for dicache usage) */ - a_Image_ref(web->Image); - - DicEntry = a_Dicache_get_entry(web->url); - if (!DicEntry) { - /* Let's create an entry for this image... */ - DicEntry = a_Dicache_add_entry(web->url); - - /* ... and let the decoder feed it! */ - *Data = Png_new(web->Image, DicEntry->url, DicEntry->version); - *Call = (CA_Callback_t) Png_callback; - } else { - /* Let's feed our client from the dicache */ - a_Dicache_ref(DicEntry->url, DicEntry->version); - *Data = web->Image; - *Call = (CA_Callback_t) a_Dicache_callback; - } - return (web->Image->dw); -} +void *a_Png_new() { return 0; } +void a_Png_callback() { return; } #endif /* ENABLE_PNG */ |