aboutsummaryrefslogtreecommitdiff
path: root/src/png.c
diff options
context:
space:
mode:
authorJohannes Hofmann <Johannes.Hofmann@gmx.de>2010-08-20 23:24:19 +0200
committerJohannes Hofmann <Johannes.Hofmann@gmx.de>2010-08-20 23:24:19 +0200
commitf5c598b518d1f906148534d015f50075d3e8242d (patch)
tree21dd70add5b366c3dd80641b77f6b18e0baa009e /src/png.c
parente98d02a01ffeb18ede86af025e51ae1ec011c75a (diff)
parent5f0fc0e48b8cbee7e1795935da0abff6627fd498 (diff)
merge
Diffstat (limited to 'src/png.c')
-rw-r--r--src/png.c227
1 files changed, 104 insertions, 123 deletions
diff --git a/src/png.c b/src/png.c
index fa07e781..15f26e3b 100644
--- a/src/png.c
+++ b/src/png.c
@@ -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 */