diff options
Diffstat (limited to 'src/pdflib/pdflib/p_png.c')
-rw-r--r-- | src/pdflib/pdflib/p_png.c | 426 |
1 files changed, 92 insertions, 334 deletions
diff --git a/src/pdflib/pdflib/p_png.c b/src/pdflib/pdflib/p_png.c index 42359a3..5882f2a 100644 --- a/src/pdflib/pdflib/p_png.c +++ b/src/pdflib/pdflib/p_png.c @@ -1,7 +1,7 @@ /*---------------------------------------------------------------------------* | PDFlib - A library for generating PDF on the fly | +---------------------------------------------------------------------------+ - | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + | Copyright (c) 1997-2009 Thomas Merz and PDFlib GmbH. All rights reserved. | +---------------------------------------------------------------------------+ | | | This software is subject to the PDFlib license. It is NOT in the | @@ -10,7 +10,7 @@ | | *---------------------------------------------------------------------------*/ -/* $Id: p_png.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ +/* $Id: p_png.c,v 1.2 2009/10/20 18:14:16 scuri Exp $ * * PNG processing for PDFlib * @@ -24,173 +24,22 @@ #define PDF_ALIGN16 #endif -/* SPNG - Simple PNG -** -** The items below, prefixed with spng_, or SPNG_, establish a replacement -** for LIBPNG that works very fast, but processes simple PNG images only: -** - bit_depth <= 8 (no 16-bit) -** - interlace_type 0 (no interlacing) -** - color_type 0, 2, or 3 (no alpha-channel); color type 3 requires -** libpng for palette processing -*/ -#define SPNG_SIGNATURE "\211\120\116\107\015\012\032\012" - -#define SPNG_CHUNK_IHDR 0x49484452 -#define SPNG_CHUNK_PLTE 0x504C5445 -#define SPNG_CHUNK_tRNS 0x74524E53 -#define SPNG_CHUNK_IDAT 0x49444154 -#define SPNG_CHUNK_IEND 0x49454E44 - -/* spng_init() return codes -*/ -#define SPNG_ERR_OK 0 /* no error */ -#define SPNG_ERR_NOPNG 1 /* bad PNG signature */ -#define SPNG_ERR_FMT 2 /* bad PNG file format */ - -typedef struct -{ - /* from IHDR: - */ - int width; - int height; - pdc_byte bit_depth; - pdc_byte color_type; - pdc_byte compr_type; - pdc_byte filter_type; - pdc_byte interlace_type; -} spng_info; - -static int -spng_getint(pdc_file *fp) -{ - unsigned char buf[4]; - - if (!PDC_OK_FREAD(fp, buf, 4)) - return -1; - - return (int) pdc_get_be_long(buf); -} /* spng_getint */ - -static int -spng_init(PDF *p, pdf_image *image, spng_info *spi) -{ - pdc_file *fp = image->fp; - char buf[8]; - - (void) p; - - /* check signature - */ - if (!PDC_OK_FREAD(fp, buf, 8) || - strncmp(buf, SPNG_SIGNATURE, 8) != 0) - return SPNG_ERR_NOPNG; - - /* read IHDR - */ - if (spng_getint(fp) != 13 || - spng_getint(fp) != SPNG_CHUNK_IHDR) - return SPNG_ERR_FMT; - - spi->width = spng_getint(fp); - spi->height = spng_getint(fp); - - if (!PDC_OK_FREAD(fp, buf, 5)) - return SPNG_ERR_FMT; - - spi->bit_depth = (pdc_byte) buf[0]; - spi->color_type = (pdc_byte) buf[1]; - spi->compr_type = (pdc_byte) buf[2]; - spi->filter_type = (pdc_byte) buf[3]; - spi->interlace_type = (pdc_byte) buf[4]; - - (void) spng_getint(fp); /* CRC */ - - /* decide whether this image is "simple". - */ #ifdef HAVE_LIBPNG - if (spi->bit_depth > 8 || spi->color_type > 3 || spi->interlace_type != 0) -#else - if (spi->bit_depth > 8 || spi->color_type > 2 || spi->interlace_type != 0) -#endif /* !HAVE_LIBPNG */ - { - image->use_raw = pdc_false; - return SPNG_ERR_OK; - } - else - image->use_raw = pdc_true; - - /* read (or skip) all chunks up to the first IDAT. - */ - for (/* */ ; /* */ ; /* */) - { - int len = spng_getint(fp); - int type = spng_getint(fp); - - switch (type) - { - case SPNG_CHUNK_IDAT: /* prepare data xfer */ - image->info.png.nbytes = (size_t) len; - return SPNG_ERR_OK; - - case -1: - return SPNG_ERR_FMT; - - /* if we decide to live without LIBPNG, - ** we should handle these cases, too. - */ - case SPNG_CHUNK_tRNS: /* transparency chunk */ - case SPNG_CHUNK_PLTE: /* read in palette */ - - default: - pdc_fseek(fp, len + 4, SEEK_CUR); - /* skip data & CRC */ - break; - } /* switch */ - } - - return SPNG_ERR_OK; -} /* spng_init */ - -#define PDF_PNG_BUFFERSIZE 8192 static void pdf_data_source_PNG_init(PDF *p, PDF_data_source *src) { - static const char fn[] = "pdf_data_source_PNG_init"; - pdf_image *image = (pdf_image *) src->private_data; + pdf_image *image = (pdf_image *) src->private_data; -#ifdef HAVE_LIBPNG - if (image->use_raw) - { -#endif - src->buffer_length = PDF_PNG_BUFFERSIZE; - src->buffer_start = (pdc_byte *) - pdc_malloc(p->pdc, src->buffer_length, fn); - src->bytes_available = 0; - src->next_byte = src->buffer_start; + (void) p; -#ifdef HAVE_LIBPNG - } - else - { - image->info.png.cur_line = 0; - src->buffer_length = image->info.png.rowbytes; - } -#endif + image->info.png.cur_line = 0; + src->buffer_length = image->info.png.rowbytes; } #undef min #define min(a, b) (((a) < (b)) ? (a) : (b)) -static void -spng_error(PDF *p, PDF_data_source *src) -{ - pdf_image *image = (pdf_image *) src->private_data; - - pdc_error(p->pdc, PDF_E_IMAGE_CORRUPT, "PNG", - pdf_get_image_filename(p, image), 0, 0); -} /* spng_error */ - static pdc_bool pdf_data_source_PNG_fill(PDF *p, PDF_data_source *src) { @@ -198,69 +47,18 @@ pdf_data_source_PNG_fill(PDF *p, PDF_data_source *src) PDC_TRY(p->pdc) { -#ifdef HAVE_LIBPNG - if (image->use_raw) - { -#endif - pdc_file * fp = image->fp; - size_t buf_avail = src->buffer_length; - pdc_byte *scan = src->buffer_start; - - src->bytes_available = 0; - - if (image->info.png.nbytes == 0) - { - PDC_EXIT_TRY(p->pdc); - return pdc_false; - } - - do - { - size_t nbytes = min(image->info.png.nbytes, buf_avail); - - if (!PDC_OK_FREAD(fp, scan, nbytes)) - spng_error(p, src); - - src->bytes_available += nbytes; - scan += nbytes; - buf_avail -= nbytes; - - if ((image->info.png.nbytes -= nbytes) == 0) - { - /* proceed to next IDAT chunk - */ - (void) spng_getint(fp); /* CRC */ - image->info.png.nbytes = - (size_t) spng_getint(fp); /* length */ - - if (spng_getint(fp) != SPNG_CHUNK_IDAT) - { - image->info.png.nbytes = 0; - PDC_EXIT_TRY(p->pdc); - return pdc_true; - } - } - } - while (buf_avail); - -#ifdef HAVE_LIBPNG - } - else - { - if (image->info.png.cur_line == image->height) - { - PDC_EXIT_TRY(p->pdc); - return pdc_false; - } + if (image->info.png.cur_line == image->height) + { + PDC_EXIT_TRY(p->pdc); + return pdc_false; + } - src->next_byte = image->info.png.raster + - image->info.png.cur_line * image->info.png.rowbytes; + src->next_byte = image->info.png.raster + + image->info.png.cur_line * image->info.png.rowbytes; - src->bytes_available = src->buffer_length; + src->bytes_available = src->buffer_length; - image->info.png.cur_line++; - } -#endif /* HAVE_LIBPNG */ + image->info.png.cur_line++; } PDC_CATCH(p->pdc) { @@ -273,20 +71,24 @@ pdf_data_source_PNG_fill(PDF *p, PDF_data_source *src) static void pdf_data_source_PNG_terminate(PDF *p, PDF_data_source *src) { - pdf_image *image = (pdf_image *) src->private_data; + (void) p; + (void) src; +} -#ifdef HAVE_LIBPNG - if (image->use_raw) +static void +pdf_png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + pdc_file *fp = (pdc_file *) png_ptr->io_ptr; + char *filename = (char *) pdc_file_name(fp); + + if (!PDC_OK_FREAD(fp, data, length)) { -#endif - pdc_free(p->pdc, (void *) src->buffer_start); + pdc_core *pdc = pdc_file_getpdc(fp); -#ifdef HAVE_LIBPNG + pdc_error(pdc, PDF_E_IMAGE_CORRUPT, "PNG", filename, 0, 0); } -#endif } -#ifdef HAVE_LIBPNG /* * We suppress libpng's warning message by supplying * our own error and warning handlers @@ -294,11 +96,8 @@ pdf_data_source_PNG_terminate(PDF *p, PDF_data_source *src) static void pdf_libpng_warning_handler(png_structp png_ptr, png_const_charp message) { - (void) png_ptr; /* avoid compiler warning "unreferenced parameter" */ - (void) message; /* avoid compiler warning "unreferenced parameter" */ - - /* do nothing */ - return; + PDF *p = (PDF *)png_ptr->mem_ptr; + pdc_logg_cond(p->pdc, 5, trc_image, "\tlibpng warning: %s\n", message); } /* @@ -311,11 +110,13 @@ pdf_libpng_warning_handler(png_structp png_ptr, png_const_charp message) static void pdf_libpng_error_handler(png_structp png_ptr, png_const_charp message) { + PDF *p = (PDF *)png_ptr->mem_ptr; + #ifdef PDF_ALIGN16 jmp_buf jbuf; #endif - (void) message; /* avoid compiler warning "unreferenced parameter" */ + pdc_logg_cond(p->pdc, 5, trc_image, "\tlibpng error: %s\n", message); #ifdef PDF_ALIGN16 memcpy(jbuf, png_jmpbuf(png_ptr), sizeof (jmp_buf)); @@ -355,20 +156,6 @@ pdf_is_PNG_file(PDF *p, pdc_file *fp) return pdc_true; } -static void /* CDPDF - moved to inside the HAVE_LIBPNG definition */ -pdf_png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - pdc_file *fp = (pdc_file *) png_ptr->io_ptr; - char *filename = (char *) pdc_file_name(fp); - - if (!PDC_OK_FREAD(fp, data, length)) - { - pdc_core *pdc = pdc_file_getpdc(fp); - - pdc_error(pdc, PDF_E_IMAGE_CORRUPT, "PNG", filename, 0, 0); - } -} - int pdf_process_PNG_data( PDF *p, @@ -376,7 +163,7 @@ pdf_process_PNG_data( { static const char *fn = "pdf_process_PNG_data"; pdc_file *save_fp; - spng_info s_info; + size_t bytecount; #ifdef PDF_ALIGN16 jmp_buf jbuf; #endif @@ -404,8 +191,10 @@ pdf_process_PNG_data( image->info.png.png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, - (png_error_ptr)pdf_libpng_error_handler, (png_error_ptr)pdf_libpng_warning_handler, /* CDPDF - added type cast */ - p, (png_malloc_ptr) pdf_libpng_malloc, + (png_error_ptr) pdf_libpng_error_handler, + (png_error_ptr) pdf_libpng_warning_handler, + p, + (png_malloc_ptr) pdf_libpng_malloc, (png_free_ptr) pdf_libpng_free); if (!image->info.png.png_ptr) @@ -446,7 +235,8 @@ pdf_process_PNG_data( } /* from file or from memory */ - png_set_read_fn(image->info.png.png_ptr, image->fp, (png_rw_ptr)pdf_png_read_data); /* CDPDF - added type cast */ + png_set_read_fn(image->info.png.png_ptr, image->fp, + (png_rw_ptr) pdf_png_read_data); png_set_sig_bytes(image->info.png.png_ptr, 8); png_read_info(image->info.png.png_ptr, image->info.png.info_ptr); @@ -667,6 +457,14 @@ pdf_process_PNG_data( image->info.png.rowbytes = png_get_rowbytes(image->info.png.png_ptr, image->info.png.info_ptr); + /* Check for overflow */ + bytecount = image->info.png.rowbytes * height; + if (bytecount / height != image->info.png.rowbytes) + { + errcode = PDF_E_IMAGE_TOO_LARGE; + goto PDF_PNG_ERROR; + } + image->info.png.raster = (pdc_byte *) pdc_calloc(p->pdc,image->info.png.rowbytes * height, fn); @@ -691,60 +489,50 @@ pdf_process_PNG_data( image->fp = pdc_fsearch_fopen(p->pdc, image->filename, NULL, NULL, PDC_FILE_BINARY); - if (image->fp != NULL && - spng_init(p, image, &s_info) == SPNG_ERR_OK && image->use_raw) - { - pdc_fclose(save_fp); - image->predictor = pred_png; - image->compression = pdf_comp_flate; - } - else - { - if (image->fp != (pdc_file *) 0) - pdc_fclose(image->fp); + if (image->fp != (pdc_file *) 0) + pdc_fclose(image->fp); - image->fp = save_fp; + image->fp = save_fp; + + /* Provide a suitable background for images with alpha channel */ + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_color_16p image_background; - /* Provide a suitable background for images with alpha channel */ - if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) + if (png_get_bKGD(image->info.png.png_ptr, image->info.png.info_ptr, + &image_background)) { - png_color_16p image_background; + png_set_background(image->info.png.png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + } + else + { + png_color_16 my_white; - if (png_get_bKGD(image->info.png.png_ptr, image->info.png.info_ptr, - &image_background)) + if (bit_depth == 8) { - png_set_background(image->info.png.png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + my_white.red = 0xFF; + my_white.green = 0xFF; + my_white.blue = 0xFF; + my_white.gray = 0xFF; } else { - png_color_16 my_white; - - if (bit_depth == 8) - { - my_white.red = 0xFF; - my_white.green = 0xFF; - my_white.blue = 0xFF; - my_white.gray = 0xFF; - } - else - { - my_white.red = 0xFFFF; - my_white.green = 0xFFFF; - my_white.blue = 0xFFFF; - my_white.gray = 0xFFFF; - } - - png_set_background(image->info.png.png_ptr, &my_white, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + my_white.red = 0xFFFF; + my_white.green = 0xFFFF; + my_white.blue = 0xFFFF; + my_white.gray = 0xFFFF; } - } - /* fetch the actual image data */ - png_read_image(image->info.png.png_ptr, row_pointers); + png_set_background(image->info.png.png_ptr, &my_white, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } } + /* fetch the actual image data */ + png_read_image(image->info.png.png_ptr, row_pointers); + image->in_use = pdc_true; /* mark slot as used */ pdf_put_image(p, imageslot, pdc_true, pdc_true); @@ -787,6 +575,12 @@ pdf_process_PNG_data( pdc_set_errmsg(p->pdc, errcode, "PNG", stemp, 0, 0); break; + case PDF_E_IMAGE_TOO_LARGE: + pdc_set_errmsg(p->pdc, errcode, "PNG", stemp, + pdc_errprintf(p->pdc, "%ld", (long) image->width), + pdc_errprintf(p->pdc, "%ld", (long) image->height)); + break; + case 0: /* error code and message already set */ break; } @@ -800,56 +594,20 @@ pdf_process_PNG_data( pdc_bool pdf_is_PNG_file(PDF *p, pdc_file *fp) { + (void) p; + (void) fp; + return pdc_false; } -/* simple built-in PNG reader without libpng */ - int -pdf_process_PNG_data( - PDF *p, - int imageslot) +pdf_process_PNG_data(PDF *p, int imageslot) { - static const char fn[] = "pdf_process_PNG_data"; - spng_info s_info; - pdf_image *image; - - image = &p->images[imageslot]; - - image->src.init = pdf_data_source_PNG_init; - image->src.fill = pdf_data_source_PNG_fill; - image->src.terminate = pdf_data_source_PNG_terminate; - image->src.private_data = (void *) image; - - if (spng_init(p, image, &s_info) == SPNG_ERR_OK && image->use_raw) - { - image->predictor = pred_png; - image->compression = pdf_comp_flate; /* CDPDF - fixed function name */ - - image->width = (pdc_scalar) s_info.width; - image->height = (pdc_scalar) s_info.height; - image->bpc = s_info.bit_depth; - - image->components = 3; - - /* other types are rejected in spng_init() */ - image->colorspace = - (s_info.color_type == 0 ? DeviceGray : DeviceRGB); + (void) imageslot; + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "PNG", 0, 0, 0); - - } - else - { - pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_IMAGE, "PNG", 0, 0, 0); - return -1; - } - - image->in_use = pdc_true; /* mark slot as used */ - - pdf_put_image(p, imageslot, pdc_true, pdc_true); - - return image->corrupt ? -1 : imageslot; + return -1; } #endif /* !HAVE_LIBPNG */ |