From e5a37797b4b9bdd5620f8e887e6efbe439064fe3 Mon Sep 17 00:00:00 2001 From: Guy Schalnat Date: Wed, 5 Jun 1996 15:50:50 -0500 Subject: [PATCH] Imported from libpng-0.89.tar --- descrip.mms | 5 +- example.c | 245 +++++++------- libpng.txt | 926 +++++++++++++++++++++++++++++---------------------- makefile | 7 +- makefile.aco | 114 +++++++ makefile.ama | 2 +- makefile.atr | 2 +- makefile.bor | 36 +- makefile.elf | 11 +- makefile.gcc | 5 +- makefile.knr | 7 +- makefile.mip | 7 +- makefile.msc | 7 +- makefile.std | 7 +- makefile.tc | 9 +- makevms.com | 6 +- png.c | 60 ++-- png.h | 547 +++++++++++++++--------------- pngchang.txt | 27 ++ pngconf.h | 7 +- pngerror.c | 39 ++- pngio.c | 318 ------------------ pngmem.c | 136 ++++++-- pngpread.c | 167 ++++++---- pngrcb.c | 10 +- pngread.c | 406 +++++++++++++--------- pngrio.c | 141 ++++++++ pngrtran.c | 271 +++++++++++---- pngrutil.c | 344 ++++++++++++------- pngtest.c | 117 ++++--- pngtest.png | Bin 7147 -> 8907 bytes pngtodo.txt | 2 + pngtrans.c | 10 +- pngwio.c | 174 ++++++++++ pngwrite.c | 327 ++++++++++++------ pngwtran.c | 10 +- pngwutil.c | 679 ++++++++++++++++++++++++------------- readme.txt | 72 ++-- 38 files changed, 3198 insertions(+), 2062 deletions(-) create mode 100644 makefile.aco delete mode 100644 pngio.c create mode 100644 pngrio.c create mode 100644 pngwio.c diff --git a/descrip.mms b/descrip.mms index 200d7606..16c7c9b5 100644 --- a/descrip.mms +++ b/descrip.mms @@ -10,7 +10,7 @@ pref = /prefix=all OBJS = png.obj, pngrcb.obj, pngrutil.obj, pngtrans.obj, pngwutil.obj,\ pngread.obj, pngmem.obj, pngwrite.obj, pngrtran.obj, pngwtran.obj,\ - pngio.obj, pngerror.obj, pngpread.obj + pngrio.obj, pngwio.obj, pngerror.obj, pngpread.obj CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) @@ -41,7 +41,8 @@ pngrtran.obj : png.h, pngconf.h pngrutil.obj : png.h, pngconf.h pngerror.obj : png.h, pngconf.h pngmem.obj : png.h, pngconf.h -pngio.obj : png.h, pngconf.h +pngrio.obj : png.h, pngconf.h +pngwio.obj : png.h, pngconf.h pngtest.obj : png.h, pngconf.h pngtrans.obj : png.h, pngconf.h pngwrite.obj : png.h, pngconf.h diff --git a/example.c b/example.c index 63d7962e..65e615d7 100644 --- a/example.c +++ b/example.c @@ -48,47 +48,45 @@ void read_png(char *file_name) if (!fp) return; - /* allocate the necessary structures */ - png_ptr = malloc(sizeof (png_struct)); + /* Create and initialize the png_struct with the desired error handler + functions. If you want to use the default stderr and longjump method, + you can supply NULL for the last three parameters. We also check that + the header file is compatible with the library version. + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) { fclose(fp); return; } - info_ptr = malloc(sizeof (png_info)); + info_ptr = png_create_info_struct(); if (!info_ptr) { fclose(fp); - free(png_ptr); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return; } - /* set error handling */ + /* set error handling if you are using the setjmp/longjmp method */ if (setjmp(png_ptr->jmpbuf)) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); - free(png_ptr); - free(info_ptr); /* If we get here, we had a problem reading the file */ return; } - /* initialize the structures, info first for error handling */ - png_info_init(info_ptr); - png_read_init(png_ptr); - /* set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); - /* if you are using replacement read functions, here you would call */ - png_set_read_fn(png_ptr, (void *)io_ptr, user_read_fn); - /* where io_ptr is a structure you want available to the callbacks */ - - /* if you are using replacement message functions, here you would call */ - png_set_message_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn); - /* where msg_ptr is a structure you want available to the callbacks */ + /* if you are using replacement read functions, instead of calling + png_init_io() here you would call */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ /* read the file information */ png_read_info(png_ptr, info_ptr); @@ -96,29 +94,31 @@ void read_png(char *file_name) /* set up the transformations you want. Note that these are all optional. Only call them if you want them */ - /* expand paletted colors into true rgb */ + /* expand paletted colors into true RGB triplets */ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); /* expand grayscale images to the full 8 bits */ - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - info_ptr->bit_depth < 8) + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8) png_set_expand(png_ptr); - /* expand images with transparency to full alpha channels */ + /* expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets */ if (info_ptr->valid & PNG_INFO_tRNS) png_set_expand(png_ptr); /* Set the background color to draw transparent and alpha - images over */ + images over. It is possible to set the red, green, and blue + components directly for paletted images. */ + png_color_16 my_background; if (info_ptr->valid & PNG_INFO_bKGD) png_set_background(png_ptr, &(info_ptr->background), - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); /* tell libpng to handle the gamma conversion for you */ if (info_ptr->valid & PNG_INFO_gAMA) @@ -126,18 +126,17 @@ void read_png(char *file_name) else png_set_gamma(png_ptr, screen_gamma, 0.45); - /* tell libpng to strip 16 bit depth files down to 8 bits */ + /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (info_ptr->bit_depth == 16) png_set_strip_16(png_ptr); - /* dither rgb files down to 8 bit palettes & reduce palettes + /* dither rgb files down to 8 bit palette & reduce palettes to the number of colors available on your screen */ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) { if (info_ptr->valid & PNG_INFO_PLTE) - png_set_dither(png_ptr, info_ptr->palette, - info_ptr->num_palette, max_screen_colors, - info_ptr->histogram); + png_set_dither(png_ptr, info_ptr->palette, info_ptr->num_palette, + max_screen_colors, info_ptr->histogram); else { png_color std_color_cube[MAX_SCREEN_COLORS] = @@ -148,9 +147,8 @@ void read_png(char *file_name) } } - /* invert monocrome files */ - if (info_ptr->bit_depth == 1 && - info_ptr->color_type == PNG_COLOR_GRAY) + /* invert monocrome files to have 0 as white and 1 as black */ + if (info_ptr->bit_depth == 1 && info_ptr->color_type == PNG_COLOR_GRAY) png_set_invert(png_ptr); /* shift the pixels down to their true bit depth */ @@ -158,7 +156,8 @@ void read_png(char *file_name) info_ptr->bit_depth > info_ptr->sig_bit) png_set_shift(png_ptr, &(info_ptr->sig_bit)); - /* pack pixels into bytes */ + /* pack multiple pixels with bit depths of 1, 2, and 4 into bytes + (useful only for paletted and grayscale images) */ if (info_ptr->bit_depth < 8) png_set_packing(png_ptr); @@ -171,21 +170,15 @@ void read_png(char *file_name) if (info_ptr->bit_depth == 16) png_set_swap(png_ptr); - /* add a filler byte to rgb files */ - if (info_ptr->bit_depth == 8 && - info_ptr->color_type == PNG_COLOR_TYPE_RGB) + /* add a filler byte to RGB files (before or after each RGB triplet) */ + if (info_ptr->bit_depth == 8 && info_ptr->color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); /* turn on interlace handling if you are not using png_read_image() */ - if (info_ptr->interlace_type) - number_passes = png_set_interlace_handling(png_ptr); - else - number_passes = 1; + number_passes = png_set_interlace_handling(png_ptr); - /* optional call to update palette with transformations */ - png_start_read_image(png_ptr); - - /* optional call to update the info structure */ + /* optional call to gamma correct and add the background to the palette + and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* allocate the memory to hold the image using the fields @@ -193,6 +186,12 @@ void read_png(char *file_name) /* the easiest way to read the image */ png_bytep row_pointers[height]; + + for (row = 0; row < height; row++) + { + row_pointers[row] = malloc(info_ptr->rowbytes); + } + png_read_image(png_ptr, row_pointers); /* the other way to read images - deal with interlacing */ @@ -216,16 +215,11 @@ void read_png(char *file_name) so here */ } - /* read the rest of the file, getting any additional chunks - in info_ptr */ + /* read the rest of the file, getting any additional chunks in info_ptr */ png_read_end(png_ptr, info_ptr); /* clean up after the read, and free any memory allocated */ - png_read_destroy(png_ptr, info_ptr, (png_infop)0); - - /* free the structures */ - free(png_ptr); - free(info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* close the file */ fclose(fp); @@ -236,68 +230,74 @@ void read_png(char *file_name) /* progressively read a file */ -/* these will normally not be global unless you are only - reading in one image at a time */ -png_structp png_ptr; -png_infop info_ptr; - int -initialize_png_reader() +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) { - png_ptr = malloc(sizeof (png_struct)); - if (!png_ptr) - return -1; - info_ptr = malloc(sizeof (png_info)); - if (!info_ptr) + /* Create and initialize the png_struct with the desired error handler + functions. If you want to use the default stderr and longjump method, + you can supply NULL for the last three parameters. We also check that + the library version is compatible in case we are using dynamically + linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); + + if (! *png_ptr) { - free(png_ptr); - return -1; + *info_ptr = NULL; + return ERROR; } - if (setjmp(png_ptr->jmpbuf)) + *info_ptr = png_create_info_struct(png_ptr); + + if (! *info_ptr) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); - /* free pointers before returning, if necessary */ - free(png_ptr); - free(info_ptr); - return -1; + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return ERROR; } - png_info_init(info_ptr); - png_read_init(png_ptr); + if (setjmp((*png_ptr)->jmpbuf)) + { + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return ERROR; + } /* this one's new. You will need to provide all three function callbacks, even if you aren't using them all. - You can put a void pointer in place of the NULL, and - retrieve the pointer from inside the callbacks using - the function png_get_progressive_ptr(png_ptr); */ - png_set_progressive_read_fn(png_ptr, NULL, + These functions shouldn't be dependent on global or + static variables if you are decoding several images + simultaneously. You should store stream specific data + in a separate struct, given as the second parameter, + and retrieve the pointer from inside the callbacks using + the function png_get_progressive_ptr(png_ptr). */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, info_callback, row_callback, end_callback); - return 0; + return OK; } int -process_data(png_bytep buffer, png_uint_32 length) +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) { - if (setjmp(png_ptr->jmpbuf)) + if (setjmp((*png_ptr)->jmpbuf)) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); - free(png_ptr); - free(info_ptr); - return -1; + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return ERROR; } - /* this one's new also. Simply give it a chunk of data - from the file stream (in order, of course). On Segmented - machines, don't give it any more then 64K. The library - seems to run fine with sizes of 4K, although you can give - it much less if necessary (I assume you can give it chunks - of 1 byte, but I haven't tried less then 256 bytes yet). - When this function returns, you may want to display any - rows that were generated in the row callback. */ - png_process_data(png_ptr, info_ptr, buffer, length); - return 0; + /* this one's new also. Simply give it chunks of data as + they arrive from the data stream (in order, of course). + On Segmented machines, don't give it any more than 64K. + The library seems to run fine with sizes of 4K, although + you can give it much less if necessary (I assume you can + give it chunks of 1 byte, but I haven't tried with less + than 256 bytes yet). When this function returns, you may + want to display any rows that were generated in the row + callback, if you aren't already displaying them there. */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return OK; } info_callback(png_structp png_ptr, png_infop info) @@ -363,44 +363,41 @@ void write_png(char *file_name, ... other image information ...) if (!fp) return; - /* allocate the necessary structures */ - png_ptr = malloc(sizeof (png_struct)); + /* Create and initialize the png_struct with the desired error handler + functions. If you want to use the default stderr and longjump method, + you can supply NULL for the last three parameters. We also check that + the library version is compatible in case we are using dynamically + linked libraries. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); + if (!png_ptr) { fclose(fp); return; } - info_ptr = malloc(sizeof (png_info)); + info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fclose(fp); - free(png_ptr); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return; } /* set error handling */ if (setjmp(png_ptr->jmpbuf)) { - png_write_destroy(png_ptr); - fclose(fp); - free(png_ptr); - free(info_ptr); /* If we get here, we had a problem reading the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return; } - /* initialize the structures */ - png_info_init(info_ptr); - png_write_init(png_ptr); - /* set up the output control if you are using standard C streams */ png_init_io(png_ptr, fp); - /* if you are using replacement write functions, here you would call */ - png_set_write_fn(png_ptr, (void *)io_ptr, user_write_fn, user_flush_fn); - /* where io_ptr is a structure you want available to the callbacks */ - /* if you are using replacement message functions, here you would call */ png_set_message_fn(png_ptr, (void *)msg_ptr, user_error_fn, user_warning_fn); /* where msg_ptr is a structure you want available to the callbacks */ @@ -432,9 +429,9 @@ void write_png(char *file_name, ... other image information ...) info_ptr->valid |= PNG_INFO_gAMA; info_ptr->gamma = gamma; - /* other optional chunks */ + /* other optional chunks like cHRM, bKGD, tRNS, tEXt, tIME, oFFs, pHYs, */ - /* write the file information */ + /* write the file header information */ png_write_info(png_ptr, info_ptr); /* set up the transformations you want. Note that these are @@ -466,8 +463,10 @@ void write_png(char *file_name, ... other image information ...) else number_passes = 1; - /* the easiest way to write the image */ - png_bytep row_pointers[height]; + /* the easiest way to write the image (you may choose to allocate the + memory differently, however) */ + png_byte row_pointers[height][width]; + png_write_image(png_ptr, row_pointers); /* the other way to write the image - deal with interlacing */ @@ -485,19 +484,23 @@ void write_png(char *file_name, ... other image information ...) } } + /* You can write optional chunks like tEXt, tIME at the end as well. + * Note that if you wrote tEXt or zTXt chunks before the image, and + * you aren't writing out more at the end, you have to set + * info_ptr->num_text = 0 or they will be written out again. + */ + /* write the rest of the file */ png_write_end(png_ptr, info_ptr); - /* clean up after the write, and free any memory allocated */ - png_write_destroy(png_ptr); - /* if you malloced the palette, free it here */ if (info_ptr->palette) free(info_ptr->palette); - /* free the structures */ - free(png_ptr); - free(info_ptr); + /* if you allocated any text comments, free them here */ + + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); /* close the file */ fclose(fp); diff --git a/libpng.txt b/libpng.txt index 251795a5..0abf51c0 100644 --- a/libpng.txt +++ b/libpng.txt @@ -1,9 +1,13 @@ libpng.txt - a description on how to use and modify libpng - libpng 1.0 beta 2 - version 0.87 + libpng 1.0 beta 3 - version 0.89 + Updated and distributed by Andreas Dilger , + based on: + + libpng 1.0 beta 2 - version 0.88 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 15, 1996 + May 24, 1996 Updated/rewritten per request in the libpng FAQ Copyright (c) 1995 Frank J. T. Wojcik December 18, 1995 && January 20, 1996 @@ -51,8 +55,8 @@ II. Structures There are two main structures that are important to libpng, png_struct and png_info. The first, png_struct, is an internal structure that -will not, for the most part, be used by the general user except as -the first variable passed to every png function call. +will not, for the most part, be used by a user except as the first +variable passed to every png function call. The png_info structure is designed to provide information about the png file. All of its fields are intended to be examined or modified @@ -83,7 +87,10 @@ To use it, pass in the first 1 to 8 bytes of the file, and it will return true or false (1 or 0) depending on whether the bytes could be part of a PNG file. Of course, the more bytes you pass in, the greater the accuracy of the prediction. If you pass in more then -eight bytes, libpng will only look at the first eight bytes. +eight bytes, libpng will only look at the first eight bytes. However, +because libpng automatically checks the file header, this is not often +necessary, and you should pass a newly opened file pointer to libpng +when reading a file. (*): If you are not using the standard I/O functions, you will need to replace them with custom functions. See the discussion under @@ -100,56 +107,55 @@ Customizing libpng. { return; } + fclose(fp); Next, png_struct and png_info need to be allocated and initialized. -As these are both large, you may not want to store these on the stack, -unless you have stack space to spare. Of course, you will want to -check if malloc returns NULL. +In order to ensure that the size of these structures is correct even +with a dynamically linked libpng, there are functions to initialize +and allocate the structures. We also pass the library version, and +optionally pointers to error handling functions (these can be NULL +if the default error handlers are to be used). See the section on +Changes to Libpng below regarding the old initialization functions. - png_structp png_ptr = malloc(sizeof (png_struct)); + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); if (!png_ptr) return; - png_infop info_ptr = malloc(sizeof (png_info)); + png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - free(png_ptr); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return; + } + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return; } -After you have these structures, you will need to set up the -error handling. When libpng encounters an error, it expects to -longjmp back to your routine. Therefore, you will need to call -setjmp and pass the jmpbuf field of your png_struct. If you -read the file from different routines, you will need to update -the jmpbuf field every time you enter a new routine that will -call a png_ function. See your documentation of setjmp/longjmp -for your compiler for more information on setjmp/longjmp. See -the discussion on libpng error handling in the Customizing Libpng -section below for more information on the libpng error handling. -If an error occurs, and libpng longjmp's back to your setjmp, -you will want to call png_read_destroy() to free any memory. +The error handling routines passed to png_create_read_struct() +are only necessary if you are not using the libpng supplied +error handling functions. When libpng encounters an error, +it expects to longjmp back to your routine. Therefore, you +will need to call setjmp and pass the jmpbuf field of your +png_struct. If you read the file from different routines, you +will need to update the jmpbuf field every time you enter a new +routine that will call a png_ function. See your documentation +of setjmp/longjmp for your compiler for more information on +setjmp/longjmp. See the discussion on libpng error handling +in the Customizing Libpng section below for more information on +the libpng error handling. If an error occurs, and libpng +longjmp's back to your setjmp, you will want to call +png_destroy_read_struct() to free any memory. if (setjmp(png_ptr->jmpbuf)) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); - /* free pointers before returning, if necessary */ - free(png_ptr); - free(info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return; } -Next, you will need to call png_info_init() and png_read_init(). -These functions make sure all the fields are initialized to useful -values, and, in the case of png_read_init(), and allocate any memory -needed for internal uses. You must call png_info_init() first, as -png_read_init() could do a longjmp, and, if the info is not initialized, -then png_read_destroy() could try to png_free() random addresses, which -would be bad. - - png_info_init(info_ptr); - png_read_init(png_ptr); - Now you need to set up the input code. The default for libpng is to use the C function fread(). If you use this, you will need to pass a valid FILE * in the function png_init_io(). Be sure that the file is @@ -165,7 +171,7 @@ image data. You do this with a call to png_read_info(). png_read_info(png_ptr, info_ptr); The png_info structure is now filled in with all the data necessary -to read the file. Some of the more important parts of the png_info are: +to read the file. Some of the more important parts of the info_ptr are: width - holds the width of the file height - holds the height of the file @@ -178,30 +184,32 @@ to read the file. Some of the more important parts of the png_info are: rowbytes - number of bytes needed to hold a row interlace_type - currently 0 for none, 1 for interlaced valid - this details which optional chunks were found in the - file to see if a chunk was present, AND valid with + file to see if a chunk was present, AND '&' valid with the appropriate PNG_INFO_ define. These are also important, but their validity depends on whether a corresponding chunk exists. Use valid (see above) to ensure that what you're doing with these values makes sense. - palette - the palette for the file + palette - the palette for the file (PNG_INFO_PLTE) num_palette - number of entries in the palette - gamma - the gamma the file is written at - sig_bit - the number of significant bits + gamma - the gamma the file is written at (PNG_INFO_gAMA) + sig_bit - the number of significant bits (PNG_INFO_sBIT) for the gray, red, green, and blue channels, whichever are appropriate for the given color type. - trans_values - transparent pixel for non-paletted images + trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS) trans - array of transparent entries for paletted images num_trans - number of transparent entries - hist - histogram of palette + hist - histogram of palette (PNG_INFO_hIST) + mod_time - time image was last modified (PNG_VALID_tIME) + background - background color (PNG_VALID_bKGD) text - text comments in the file. num_text - number of comments for more information, see the png_info definition in png.h and the PNG specification for chunk contents. Be careful with trusting rowbytes, as some of the transformations could increase the space -needed to hold a row (expand, rgbx, xrgb, graph_to_rgb, etc.). +needed to hold a row (expand, RGBX, XRGB, gray_to_rgb, etc.). See png_update_info(), below. A quick word about text and num_text. PNG stores comments in @@ -213,10 +221,10 @@ keyword. It is strongly suggested that keywords be sensible to humans specification for more details. There is also no requirement to have text after the keyword. -Keywords are restricted to 80 characters without leading or trailing -spaces, but spaces are allowed within the keyword It is possible to -have the same keyword any number of times. The text field is an -array of png_text structures, each holding pointer to a keyword +Keywords should be limited to 80 characters without leading or trailing +spaces, but non-consecutive spaces are allowed within the keyword. It is +possible to have the same keyword any number of times. The text field +is an array of png_text structures, each holding pointer to a keyword and a pointer to a text string. Only the text string may be null. The keyword/text pairs are put into the array in the order that they are received. However, some or all of the text chunks may be @@ -235,10 +243,22 @@ checks to see if it has data that it can do somthing with, you should make sure to only enable a transformation if it will be valid for the data. For example, don't swap red and blue on grayscale data. -The following code transforms bit depths of less than 8 to 8 bits, -changes paletted images to rgb, and adds an alpha channel if there is -transparency information in a tRNS chunk. This is probably most -useful on grayscale images with bit depths of 2 or 4 and tRNS chunks. +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGBRGBRGB format unless png_set_filler() is called to insert filler +bytes, either before or after each RGB triplet. 16-bit RGB data will +be returned RRGGBBRRGGBB, with the most significant byte of the color +value first, unless png_set_strip_16() is called to transform it to +regular RGBRGB triplets. + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && info_ptr->bit_depth < 8) @@ -251,17 +271,69 @@ useful on grayscale images with bit depths of 2 or 4 and tRNS chunks. if (info_ptr->valid & PNG_INFO_tRNS) png_set_expand(png_ptr); +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (info_ptr->bit_depth == 16) + png_set_strip_16(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (info_ptr->bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. It is then +required that values be "scaled" or "shifted" up to the bit depth used +in the file (ie from 5 bits/sample in the range [0,31] to 8 bits/sample +in the range [0, 255]). However, they also provide a way to describe +the true bit depth of the image. See the PNG specification for details. +This call reduces the pixels back down to the true bit depth: + + if (info_ptr->valid & PNG_INFO_sBIT) + png_set_shift(png_ptr, &(info_ptr->sig_bit)); + +PNG files store 3 color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 bytes. This code expands them +into 4 bytes for windowing systems that need them in this format: + + if (info_ptr->bit_depth == 8 && + info_ptr->color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler_byte, PNG_FILLER_BEFORE); + +where filler_byte is the number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. + +For some uses, you may want a gray-scale image to be represented as +RGB. This code will do that conversion: + + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + The following code handles alpha and transparency by replacing it with -a background value. If there was a valid one in the file, you can use +a background value. If there was a valid bKGD in the file, you can use it if you want. However, you can replace it with your own if you want also. If there wasn't one in the file, you must supply a color. If libpng is doing gamma correction, you will need to tell libpng where the background came from so it can do the appropriate gamma -correction. If you are telling libpong to modify the color data with -png_set_expand(), you must indicate whether the background needs to be -expanded. See the function definition in png.h for more details. +correction. If you have a grayscale and you are using png_set_expand() +to change to a higher bit-depth you must indicate if the background gray +needs to be expanded to the new bit-depth. Similarly, if you are reading +a paletted image, you must indicate if you have supplied the background +index that needs to be expanded to RGB values. You can always specify +RGB color values directly when setting your background for paletted images. - png_color_16 my_background; + png_color_16 my_background; if (info_ptr->valid & PNG_INFO_bKGD) png_set_backgrond(png_ptr, &(info_ptr->background), @@ -279,16 +351,10 @@ strongly recommended that viewers support gamma correction. if (info_ptr->valid & PNG_INFO_gAMA) png_set_gamma(png_ptr, screen_gamma, info_ptr->gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45); + else + png_set_gamma(png_ptr, screen_gamma, 0.45); -PNG can have files with 16 bits per channel. If you only can handle -8 bits per channel, this will strip the pixels down to 8 bit. - - if (info_ptr->bit_depth == 16) - png_set_strip_16(png_ptr); - -If you need to reduce an rgb file to a paletted file, or if a paletted +If you need to reduce an RGB file to a paletted file, or if a paletted file has more entries then will fit on your screen, png_set_dither() will do that. Note that this is a simple match dither that merely finds the closest color available. This should work fairly well with @@ -296,13 +362,9 @@ optimized palettes, and fairly badly with linear color cubes. If you pass a palette that is larger then maximum_colors, the file will reduce the number of colors in the palette so it will fit into maximum_colors. If there is a histogram, it will use it to make -intelligent choices when reducing the palette. If there is no +more intelligent choices when reducing the palette. If there is no histogram, it may not do as good a job. -It should be noted that this function will be rewritten and/or -replaced in libpng 0.9, which will have full two pass dithering with -optimized palettes. - if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) { if (info_ptr->valid & PNG_INFO_PLTE) @@ -329,37 +391,6 @@ zero): info_ptr->color_type == PNG_COLOR_GRAY) png_set_invert_mono(png_ptr); -PNG files have possible bit depths of 1, 2, 4, 8, and 16. However, -they also provide a way to describe the true bit depth of the image. -It is then required that values be "scaled" or "shifted" up to the bit -depth used in the file. See the PNG specification for details. This -code reduces the pixels back down to the true bit depth: - - if (info_ptr->valid & PNG_INFO_sBIT) - png_set_shift(png_ptr, &(info_ptr->sig_bit)); - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit -files. This code expands to 1 pixel per byte without changing the -values of the pixels: - - if (info_ptr->bit_depth < 8) - png_set_packing(png_ptr); - -PNG files store 3 color pixels in red, green, blue order. This code -changes the storage of the pixels to blue, green, red: - - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB || - info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr(png_ptr); - -For some uses, you may want a gray-scale image to be represented as -rgb. This code will do that conversion: - - if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - PNG files store 16 bit pixels in network byte order (big-endian, ie. most significant bits first). This code chages the storage to the other way (little-endian, ie. least significant bits first, eg. the @@ -368,45 +399,28 @@ way PCs store them): if (info_ptr->bit_depth == 16) png_set_swap(png_ptr); -PNG files store rgb pixels packed into 3 bytes. This code packs them -into 4 bytes: - - if (info_ptr->bit_depth == 8 && - info_ptr->color_type == PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr, filler_byte, PNG_FILLER_BEFORE); - -where filler_byte is the number to fill with, and the location is -either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether -you want the filler before the rgb or after. - The last thing to handle is interlacing; this is covered in detail below, but you must call the function here. if (info_ptr->interlace_type) number_passes = png_set_interlace_handling(png_ptr); -After setting the transformations, you can update your palette by -calling png_start_read_image(). This function is provided for those -who need an updated palette before they read the image data. If you -don't call this function, the library will automatically call it -before it reads the first row. - - png_start_read_image(png_ptr); - -libpng can update your png_info structure to reflect any -transformations you've requested with this call. This is most useful -to update the info structures rowbytes field, so you can use it to -allocate your image memory. This function calls -png_start_read_image(), so you don't have to call both of them. +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structures rowbytes +field, so you can use it to allocate your image memory. This function +will also update your palette with the correct display gamma and +background if these have been given with the calls above. png_read_update_info(png_ptr, info_ptr); After you call png_read_update_info(), you can allocate any -memory you need to hold the image. As the actual allocation +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation varies among applications, no example will be given. If you -are allocating one large chunk, you may find it useful to -build an array of pointers to each row, as it will be needed -for some of the functions below. +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. After you've allocated memory, you can read the image data. The simplest way to do this is in one function call. If you are @@ -423,7 +437,7 @@ times, or any of that other stuff necessary with png_read_rows(). where row_pointers is: - png_bytep row_pointers[height]; + png_bytep row_pointers[height]; You can point to void or char or whatever you use for pixels. @@ -439,28 +453,45 @@ If you are doing this just one row at a time, you can do this with row_pointers: png_bytep row_pointers = row; - png_read_rows(png_ptr, &row_pointers, NULL, 1); + png_read_row(png_ptr, &row_pointers, NULL); If the file is interlaced (info_ptr->interlace_type != 0), things get -a good deal harder. The only currently (as of 1/96 -- PNG -Specification version 0.92) defined interlacing scheme for PNG files -(info_ptr->interlace_type == 1) is a complicated interlace scheme, -known as Adam7, that breaks down an image into seven smaller images of -varying size. libpng will fill out those images or it will give them -to you "as is". If you want them filled out, there are two ways to -do that. The one mentioned in the PNG specification is to expand each -pixel to cover those pixels that have not been read yet. This results -in a blocky image for the first pass, which gradually smoothes out as -more pixels are read. The other method is the "sparkle" method, where -pixels are draw only in their final locations, with the rest of the -image remaining whatever colors they were initialized to before the -start of the read. The first method usually looks better, but tends -to be slower, as there are more pixels to put in the rows. +somewhat harder. The only currently (as of 6/96 -- PNG +Specification version 1.0) defined interlacing scheme for PNG files +(info_ptr->interlace_type == 1) is a someewhat complicated 2D interlace +scheme, known as Adam7, that breaks down an image into seven smaller +images of varying size, based on an 8x8 grid. -If you don't want libpng to handle the interlacing details, just -call png_read_rows() the correct number of times to read in all -seven images. See the PNG specification for more details on the -interlacing scheme. +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet. This results in a blocky +image for the first pass, which gradually smoothes out as more pixels +are read. The other method is the "sparkle" method, where pixels are +draw only in their final locations, with the rest of the image remaining +whatever colors they were initialized to before the start of the read. +The first method usually looks better, but tends to be slower, as there +are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images are valid images by themselves, or they can be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in row 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! If you want libpng to expand the images, call this before calling png_start_read_image() or png_read_update_info(): @@ -471,7 +502,7 @@ png_start_read_image() or png_read_update_info(): This will return the number of passes needed. Currently, this is seven, but may change if another interlace type is added. This function can be called even if the file is not interlaced, -when it will return one. +where it will return one pass. If you are not going to display the image after each pass, but are going to wait until the entire image is read in, use the sparkle @@ -496,19 +527,20 @@ the second parameter NULL. png_read_rows(png_ptr, NULL, row_pointers, number_of_rows); After you are finished reading the image, you can finish reading -the file. If you are interested in comments or time, you should -pass the png_info pointer from the png_read_info() call. If you -are not interested, you can pass NULL. +the file. If you are interested in comments or time, which may be +stored either before or after the image data, you should pass the +info_ptr pointer from the png_read_info() call, or you can pass a +separate png_info struct if you want to keep the comments from +before and after the image separate. If you are not interested, you +can pass NULL. - png_read_end(png_ptr, info_ptr); + png_read_end(png_ptr, end_info); -When you are done, you can free all memory used by libpng like this: +When you are done, you can free all memory allocated by libpng like this: - png_read_destroy(png_ptr, info_ptr, (png_info *)0); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); -After that, you can discard the structures, or reuse them another -read or write. For a more compact example of reading a PNG image, -see the file example.c. +For a more compact example of reading a PNG image, see the file example.c. Reading PNG files progressively: @@ -527,125 +559,127 @@ all of the code). png_structp png_ptr; png_infop info_ptr; +/* An example code fragment of how you would initialize the progressive + reader in your application. */ int initialize_png_reader() { - png_ptr = malloc(sizeof (png_struct)); + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); if (!png_ptr) return -1; - info_ptr = malloc(sizeof (png_info)); + info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - free(png_ptr); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return -1; } if (setjmp(png_ptr->jmpbuf)) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); - /* free pointers before returning, if necessary */ - free(png_ptr); - free(info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return -1; } - png_info_init(info_ptr); - png_read_init(png_ptr); - - /* - This one's new. You will need to provide all three - function callbacks, even if you aren't using them all. - You can use any void pointer as the user_ptr, and - retrieve the pointer from inside the callbacks using - the function png_get_progressive_ptr(png_ptr); - */ - png_set_progressive_read_fn(png_ptr, user_ptr, + /* This one's new. You can provide functions to be called + when the header info is valid, when each row is completed, + and when the image is finished. If you aren't using all + functions, you can specify a NULL parameter. You can use + any struct as the user_ptr (cast to a void pointer for the + function call), and retrieve the pointer from inside the + callbacks using the function png_get_progressive_ptr(png_ptr); + which will return a void pointer, which you have to cast + appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, info_callback, row_callback, end_callback); return 0; } +/* A code fragment that you call as you recieve blocks of data */ int process_data(png_bytep buffer, png_uint_32 length) { if (setjmp(png_ptr->jmpbuf)) { - png_read_destroy(png_ptr, info_ptr, (png_info *)0); - free(png_ptr); - free(info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return -1; } - /* - This one's new also. Simply give it a chunk of data - from the file stream (in order, of course). On machines - with segmented memory models machines, don't give it any - more than 64K. The library seems to run fine with sizes - of 4K. Although you can give it much less if necessary - (I assume you can give it chunks of 1 byte, I haven't - tried less then 256 bytes yet). When this function returns, - you may want to display any rows that were generated in the - row callback. - */ + /* This one's new also. Simply give it a chunk of data + from the file stream (in order, of course). On machines + with segmented memory models machines, don't give it any + more than 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if necessary + (I assume you can give it chunks of 1 byte, I haven't + tried less then 256 bytes yet). When this function returns, + you may want to display any rows that were generated in the + row callback if you don't already do so there. + */ png_process_data(png_ptr, info_ptr, buffer, length); return 0; } +/* This function is called (as set by png_set_progressive_fn() above) + when enough data has been supplied so all of the header has been read. + */ +void info_callback(png_structp png_ptr, png_infop info) { - /* - Do any setup here, including setting any of the transformations - mentioned in the Reading PNG files section. For now, you _must_ - call either png_start_read_image() or png_read_update_info() - after all the transformations are set (even if you don't set - any). You may start getting rows before png_process_data() - returns, so this is your last chance to prepare for that. - */ + /* Do any setup here, including setting any of the transformations + mentioned in the Reading PNG files section. For now, you _must_ + call either png_start_read_image() or png_read_update_info() + after all the transformations are set (even if you don't set + any). You may start getting rows before png_process_data() + returns, so this is your last chance to prepare for that. + */ } +/* This function is called when each row of image data is complete */ +void row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { - /* - This function is called for every row in the image. If the - image is interlaced, and you turned on the interlace handler, - this function will be called for every row in every pass. - Some of these rows will not be changed from the previous pass. - When the row is not changed, the new_row variable will be NULL. - The rows and passes are called in order, so you don't really - need the row_num and pass, but I'm supplying them because it - may make your life easier. + /* If the image is interlaced, and you turned on the interlace + handler, this function will be called for every row in every pass. + Some of these rows will not be changed from the previous pass. + When the row is not changed, the new_row variable will be NULL. + The rows and passes are called in order, so you don't really + need the row_num and pass, but I'm supplying them because it + may make your life easier. - For the non-NULL rows of interlaced images, you must call - png_progressive_combine_row() passing in the row and the - old row. You can call this function for NULL rows (it will - just return) and for non-interlaced images (it just does the - memcpy for you) if it will make the code easier. Thus, you - can just do this for all cases: + For the non-NULL rows of interlaced images, you must call + png_progressive_combine_row() passing in the row and the + old row. You can call this function for NULL rows (it will + just return) and for non-interlaced images (it just does the + memcpy for you) if it will make the code easier. Thus, you + can just do this for all cases: + */ png_progressive_combine_row(png_ptr, old_row, new_row); - where old_row is what was displayed for previous rows. Note - that the first pass (pass == 0, really) will completely cover - the old row, so the rows do not have to be initialized. After - the first pass (and only for interlaced images), you will have - to pass the current row, and the function will combine the - old row and the new row. + /* where old_row is what was displayed for previous rows. Note + that the first pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be initialized. After + the first pass (and only for interlaced images), you will have + to pass the current row, and the function will combine the + old row and the new row. */ } +void end_callback(png_structp png_ptr, png_infop info) { - /* - This function is called after the whole image has been read, - including any chunks after the image (up to and including - the IEND). You will usually have the same info chunk as you - had in the header, although some data may have been added - to the comments and time fields. + /* This function is called after the whole image has been read, + including any chunks after the image (up to and including + the IEND). You will usually have the same info chunk as you + had in the header, although some data may have been added + to the comments and time fields. - Most people won't do much here, perhaps setting a flag that - marks the image as finished. - */ + Most people won't do much here, perhaps setting a flag that + marks the image as finished. + */ } @@ -657,34 +691,36 @@ importance is repeated here, so you won't have to constantly look back up in the reading section to understand writing. You will want to do the I/O initialization before you get into libpng, -so if it doesn't work, you don't have much to undo. If you are not +so if it doesn't work, you don't have anything to undo. If you are not using the standard I/O functions, you will need to replace them with -custom functions. See the discussion under Customizing libpng. +custom writing functions. See the discussion under Customizing libpng. FILE *fp = fopen(file_name, "wb"); if (!fp) { - return; + return; } Next, png_struct and png_info need to be allocated and initialized. -As these are both large, you may not want to store these on the stack, -unless you have stack space to spare. Of course, you will want to -check if malloc returns NULL. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. - png_structp png_ptr = malloc(sizeof (png_struct)); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + (void *)user_error_ptr, user_error_fn, user_warning_fn); if (!png_ptr) - return; - png_infop info_ptr = malloc(sizeof (png_info)); + return; + + png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - free(png_ptr); - return; + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return; } After you have these structures, you will need to set up the error handling. When libpng encounters an error, it expects to -longjmp back to your routine. Therefore, you will need to call +longjmp() back to your routine. Therefore, you will need to call setjmp and pass the jmpbuf field of your png_struct. If you write the file from different routines, you will need to update the jmpbuf field every time you enter a new routine that will @@ -695,25 +731,11 @@ section below for more information on the libpng error handling. if (setjmp(png_ptr->jmpbuf)) { - png_write_destroy(png_ptr); - /* free pointers before returning. Make sure you clean up - anything else you've done. */ - free(png_ptr); - free(info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } -Then, you will need to call png_info_init() and png_write_init(). -These functions make sure all the fields are initialized to useful -values, and, in the case of png_write_init(), allocate any memory -needed for internal uses. Do png_info_init() first, so if -png_write_init() longjmps, you know info_ptr is valid, so you -don't free random memory pointers, which would be bad. - - png_info_init(info_ptr); - png_write_init(png_ptr); - Now you need to set up the input code. The default for libpng is to use the C function fwrite(). If you use this, you will need to pass a valid FILE * in the function png_init_io(). Be sure that the file is @@ -723,21 +745,34 @@ Libpng section below. png_init_io(png_ptr, fp); -You now have the option of modifying how the compression library -will run. The following functions are mainly for testing, but -may be useful in certain special cases, like if you need to -write png files extremely fast and are willing to give up some -compression, or if you want to get the maximum possible compression -at the expense of slower writing. If you have no special needs -in this area, let the library do what it wants, as it has been -carefully tuned to deliver the best speed/compression ratio. -See the compression library for more details. - - /* turn on or off filtering (1 or 0) */ - png_set_filtering(png_ptr, 1); +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write png files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid value is '0' (as of the +06/96 PNG specification. The third parameter is a flag that indicates +which filter type(s) are to be tested for each scanline. See the +Compression Library for details on the specific filter types. - /* compression level (0 - none, 6 - default, 9 - maximum) */ - png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + /* turn on or off filtering, and/or choose specific filters */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_PAETH); + +The png_set_compression_???() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + + /* set other zlib parameters */ png_set_compression_mem_level(png_ptr, 8); png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); png_set_compression_window_bits(png_ptr, 15); @@ -746,12 +781,13 @@ See the compression library for more details. You now need to fill in the png_info structure with all the data you wish to write before the actual image. Note that the only thing you are allowed to write after the image is the text chunks and the time -chunk (as of PNG Specification 0.92, anyway). See png_write_end() and +chunk (as of PNG Specification 1.0, anyway). See png_write_end() and the latest PNG specification for more information on that. If you -wish to write them before the image, fill them in now. If you want to -wait until after the data, don't fill them until png_write_end(). For -all the fields in png_info, see png.h. For explanations of what the -fields contain, see the PNG specification. +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. Some of the more important parts of the png_info are: @@ -760,23 +796,25 @@ Some of the more important parts of the png_info are: bit_depth - holds the bit depth of one of the image channels color_type - describes the channels and what they mean see the PNG_COLOR_TYPE_ defines for more information - interlace_type - currently 0 for none, 1 for interlaced + interlace_type - allowed values are 0 for none, 1 for interlaced valid - this describes which optional chunks to write to the file. Note that if you are writing a PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not optional, but must still be marked for writing. To - mark chunks for writing, OR valid with the - appropriate PNG_INFO_ define. - palette - the palette for the file + mark chunks for writing, logical OR '|' valid with + the appropriate PNG_INFO_ define. + palette - the palette for the file (PNG_INFO_PLTE) num_palette - number of entries in the palette - gamma - the gamma the file is written at - sig_bit - the number of significant bits for the gray, red, - green, and blue channels, whichever are appropriate - for the given color type. - trans_values - transparent pixel for non-paletted images + gamma - the gamma the file is written at (PNG_INFO_gAMA) + sig_bit - the number of significant bits (PNG_INFO_sBIT) + for the gray, red, green, and blue channels, whichever + are appropriate for the given color type. + trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS) trans - array of transparent entries for paletted images num_trans - number of transparent entries - hist - histogram of palette + hist - histogram of palette (PNG_INFO_hIST) + mod_time - time image was last modified (PNG_VALID_tIME) + background - background color (PNG_VALID_bKGD) text - text comments in the file. num_text - number of comments @@ -790,7 +828,21 @@ types of the image data. Currently, the only valid number is zero. However, you can store text either compressed or uncompressed, unlike images which always have to be compressed. So if you don't want the text compressed, set the compression type to -1. Until text gets -arount 1000 bytes, it is not worth compressing it. +around 1000 bytes, it is not worth compressing it. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion from other + image format The keyword-text pairs work like this. Keywords should be short simple descriptions of what the comment is about. Some typical @@ -801,9 +853,12 @@ to put a description of the image before the image, but leave the disclaimer until after, so viewers working over modem connections don't have to wait for the disclaimer to go over the modem before they start seeing the image. Finally, keywords should be full -words, not abbreviations. Keywords can not contain NUL characters, -and should not contain control characters. Text in general should -not contain control characters. The keyword must be present, but +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but you can leave off the text string on non-compressed pairs. Compressed pairs must have a text string, as only the text string is compressed anyway, so the compression would be meaningless. @@ -815,36 +870,15 @@ time_t routine uses gmtime(). You don't have to use either of these, but if you wish to fill in the png_time structure directly, you should provide the time in universal time (GMT) if possible instead of your local time. Note that the year number is the full -year (ie 1996, rather than 96). - -It is possible to have libpng flush any pending output, either manually, -or automatically after a certain number of lines have been written. To -flush the output stream a single time call: - - png_write_flush(png_ptr); - -and to have libpng flush the output stream periodically after a certain -number of scanlines have been written, call: - - png_set_flush(png_ptr, nrows); - -Note that the distance between rows is from the last time png_write_flush -was called, or the first row of the image if it has never been called. -So if you write 50 lines, and then png_set_flush 25, it will flush the -output on the next scanline, and on line 75, unless png_write_flush is -called earlier. If nrows is too small (less than about 10 lines) the -image compression may decrease dramatically (although this may be -acceptable for real-time applications). Infrequent flushing will only -degrade the compression performance by a few percent over images that -do not use flushing. +year (ie 1996, rather than 96), and that months start with 1. You are now ready to write all the file information up to the actual image data. You do this with a call to png_write_info(). png_write_info(png_ptr, info_ptr); -After you've read the file information, you can set up the library to -handle any special transformations of the image data. The various +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various ways to transform the data will be described in the order that they should occur. This is important, as some of these change the color type and/or bit depth of the data, and some others only work on @@ -853,33 +887,30 @@ checks to see if it has data that it can do somthing with, you should make sure to only enable a transformation if it will be valid for the data. For example, don't swap red and blue on grayscale data. -PNG files store rgb pixels packed into 3 bytes. This code tells -the library to use 4 bytes per pixel +PNG files store RGB pixels packed into 3 bytes. This code tells +the library to expect input data with 4 bytes per pixel png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -where the 0 is not used for writing, and the location is either -PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether you -want the filler before the rgb or after. +where the 0 is the value that will be put in the 4th byte, and the +location is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending +upon whether the filler byte is stored XRGB or RGBX. PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as they can, resulting in, for example, 8 pixels per byte for 1 bit files. If the data is supplied at 1 pixel per byte, use this code, which will -correctly pack the values: +correctly pack the pixels into a single byte: png_set_packing(png_ptr); PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your -data is of another bit depth, but is packed into the bytes correctly, -this will scale the values to appear to be the correct bit depth. -Make sure you write a sBIT chunk when you do this, so others, if -they want, can reduce the values down to their true depth. +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can get the original data if desired. /* Do this before png_write_info() */ info_ptr->valid |= PNG_INFO_sBIT; - /* Note that you can cheat and set all the values of - sig_bit to true_bit_depth if you want */ + /* Set the true bit depth of the image data */ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) { info_ptr->sig_bit.red = true_bit_depth; @@ -896,6 +927,11 @@ they want, can reduce the values down to their true depth. info_ptr->sig_bit.alpha = true_bit_depth; } +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (ie 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + png_set_shift(png_ptr, &(info_ptr->sig_bit)); PNG files store 16 bit pixels in network byte order (big-endian, @@ -916,6 +952,28 @@ one. This code would be used if the pixels are supplied with this reversed png_set_invert(png_ptr); +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush()ls is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + That's it for the transformations. Now you can write the image data. The simplest way to do this is in one function call. If have the whole image in memory, you can just call png_write_image() and libpng @@ -943,13 +1001,13 @@ row_pointers is the same as in the png_write_image() call. If you are just writing one row at a time, you can do this with row_pointers: - png_bytep row_pointers = row; + png_bytep row_pointer = row; - png_write_rows(png_ptr, &row_pointers, 1); + png_write_row(png_ptr, &row_pointer); When the file is interlaced, things can get a good deal more -complicated. The only currently (as of 1/96 -- PNG Specification -version 0.92) defined interlacing scheme for PNG files is a +complicated. The only currently (as of 6/96 -- PNG Specification +version 1.0) defined interlacing scheme for PNG files is a compilcated interlace scheme, known as Adam7, that breaks down an image into seven smaller images of varying size. libpng will build these images for you, or you can do them yourself. If you want to @@ -957,8 +1015,8 @@ build them yourself, see the PNG specification for details of which pixels to write when. If you don't want libpng to handle the interlacing details, just -call png_write_rows() the correct number of times to write all -seven sub-images. +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. If you want libpng to build the sub-images, call this before you start writing any rows: @@ -968,7 +1026,7 @@ writing any rows: This will return the number of passes needed. Currently, this is seven, but may change if another interlace type is added. -Then write the image number_passes times. +Then write the complete image number_passes times. png_write_rows(png_ptr, row_pointers, number_of_rows); @@ -979,20 +1037,20 @@ and only update the rows that are actually used. After you are finished writing the image, you should finish writing the file. If you are interested in writing comments or time, you should pass the an appropriately filled png_info pointer. If you -are not interested, you can pass NULL. Be careful that you don't -write the same text or time chunks here as you did in png_write_info(). +are not interested, you can pass NULL. If you have written text at +the beginning and are not writing more at the end, you should set +info_ptr->num_text = 0, or the text will be written again here. png_write_end(png_ptr, info_ptr); When you are done, you can free all memory used by libpng like this: - png_write_destroy(png_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); -Any data you allocated for png_info, you must free yourself. +You must free any data you allocated for info_ptr, such as comments, +palette, or histogram, before the call to png_destroy_write_struct(); -After that, you can discard the structures, or reuse them another -read or write. For a more compact example of writing a PNG image, -see the file example.c. +For a more compact example of writing a PNG image, see the file example.c. V. Modifying/Customizing libpng: @@ -1004,18 +1062,17 @@ adding new transformations, and generally changing how libpng works. All of the memory allocation, input/output, and error handling in libpng goes through callbacks which are user setable. The default -routines are in pngmem.c, pngio.c, and pngerror.c respectively. To -change these functions, call the approprate _fn function. +routines are in pngmem.c, pngrio.c, pngwio.c, and pngerror.c respectively. +To change these functions, call the approprate png_set_???_fn() function. Memory allocation is done through the functions png_large_malloc(), -png_malloc(), png_realloc(), png_large_free(), and png_free(). -These currently just call the standard C functions. The large -functions must handle exactly 64K, but they don't have to handle -more then that. If your pointers can't access more then 64K at a -time, you will want to set MAXSEG_64K in zlib.h. Since it is unlikely -that the method of handling memory allocation on a platform will -change between applications, these functions must be modified in the -library at compile time. +png_malloc(), png_realloc(), png_large_free(), and png_free(). These +currently just call the standard C functions. The large functions must +handle exactly 64K, but they don't have to handle more than that. If +your pointers can't access more then 64K at a time, you will want to +set MAXSEG_64K in zlib.h. Since it is unlikely that the method of +handling memory allocation on a platform will change between applications, +these functions must be modified in the library at compile time. Input/Output in libpng is done throught png_read() and png_write(), which currently just call fread() and fwrite(). The FILE * is stored in @@ -1051,16 +1108,22 @@ should never return to it's caller. Currently, this is handled via setjmp() and longjmp(), but you could change this to do things like exit() if you should wish. On non-fatal errors, png_warning() is called to print a warning message, and then control returns to the calling code. -By default png_error() and png_warning() print a message on stderr. If +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_STDIO defined. If you wish to change the behavior of the error functions, you will need to -set up your own message callbacks. You do this like the I/O callbacks above. +set up your own message callbacks. These functions are normally supplied +at the time that the png_struct is created. It is also possible to change +these functions after png_create_???_struct() has been called by calling: - png_set_message_fn(png_structp png_ptr, png_voidp msg_ptr, - png_msg_ptr error_fn, png_msg_ptr warning_fn); + png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn); - png_voidp msg_ptr = png_get_msg_ptr(png_ptr); + png_voidp error_ptr = png_get_error_ptr(png_ptr); -The replacement message functions should have parameters as follows: +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: void user_error_fn(png_struct png_ptr, png_const_charp error_msg); void user_warning_fn(png_struct png_ptr, png_const_charp warning_msg); @@ -1074,29 +1137,30 @@ setjmp returns non zero besides returning itself. Consult your compiler documentation for more details. If you need to read or write custom chunks, you will need to get deeper -into the libpng code. First, read the PNG specification, and have -a first level of understanding of how it works. Pay particular -attention to the sections that describe chunk names, and look -at how other chunks were designed, so you can do things similarly. -Second, check out the sections of libpng that read and write chunks. -Try to find a chunk that is similar to yours and copy off of it. -More details can be found in the comments inside the code. +into the libpng code, as a mechanism has not yet been supplied for user +callbacks with custom chunks. First, read the PNG specification, and have +a first level of understanding of how it works. Pay particular attention +to the sections that describe chunk names, and look at how other chunks +were designed, so you can do things similarly. Second, check out the +sections of libpng that read and write chunks. Try to find a chunk that +is similar to yours and copy off of it. More details can be found in the +comments inside the code. A way of handling unknown chunks in a generic +method, potentially via callback functions, would be best. -If you wish to write your own transformation for the data, look -through the part of the code that does the transformations, and check -out some of the simpler ones to get an idea of how they work. Try to -find a similar transformation to the one you want to add and copy off -of it. More details can be found in the comments inside the code -itself. +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. Configuring for 16 bit platforms: -You may need to change the png_large_malloc() and -png_large_free() routines in pngmem.c, as these are requred -to allocate 64K. Also, you will want to look into zconf.h to tell -zlib (and thus libpng) that it cannot allocate more then 64K at a -time. Even if you can, the memory won't be accessable. So limit zlib -and libpng to 64K by defining MAXSEG_64K. +You may need to change the png_large_malloc() and png_large_free() +routines in pngmem.c, as these are requred to allocate 64K, although +there is already support for many of the common DOS compilers. Also, +you will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessable. So limit zlib and libpng to 64K by defining MAXSEG_64K. Configuring for DOS: @@ -1117,11 +1181,12 @@ unsigned char far * far *. Configuring for gui/windowing platforms: -You will need to change the error message display in png_error() and -png_warning() to display a message instead of fprinting it to stderr. -You may want to write a single function to do this and call it something -like png_message(). On some compliers, you may have to change the -memory allocators (png_malloc, etc.). +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_???_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compliers, +you may also have to change the memory allocators (png_malloc, etc.). Configuring for compiler xxx: @@ -1133,11 +1198,17 @@ files in libpng proper only include png.h, which includes pngconf.h. Configuring zlib: -There are special functions to configure the compression. Perhaps -the most useful one changes the compression level. The library -normally uses the default compression level, but for maximum -compression (9) or maximum speed (1), you may desire to change the -level. You do this by calling: +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6), but if +speed is not critical it is possible to configure it for maximum +compression (Z_BEST_COMPRESSION = 9) to generate smaller PNG files. +For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: png_set_compression_mem_level(png_ptr, level); @@ -1148,34 +1219,83 @@ short on memory (running DOS, for example, where you only have 640K). png_set_compression_mem_level(png_ptr, level); If you want to control whether libpng uses filtering or not, you -can call this function. I recommend not changing the default unless -you are experimenting with compression ratios. +can call this function. Filtering is enabled by default for RGB +and grayscale images (with and without alpha), and for 8-bit +paletted images, but not for paletted images with bit depths less +than 8 bits/pixel. The 'method' parameter sets the main filtering +method, which is currently only '0' in the PNG 1.0 specification. +The 'filters' parameter sets which filter(s), if any, should be +used for each scanline. Possible values are PNG_ALL_FILTERS and +PNG_NO_FILTERS to turn filtering on and off, respectively. +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together '|' to specify one or more filters to use. These +filters are described in more detail in the PNG specification. If +you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. - png_set_filtering(png_ptr, use_filter); + png_set_filter(png_ptr, method, filters); The other functions are for configuring zlib. They are not recommended -for normal use and may result in writing an invalid png file. See +for normal use and may result in writing an invalid PNG file. See zlib.h for more information on what these mean. png_set_compression_strategy(png_ptr, strategy); png_set_compression_window_bits(png_ptr, window_bits); png_set_compression_method(png_ptr, method); -Except for png_set_filtering(), all of these are just controlling -zlib, so see the zlib documentation (zlib.h and zconf.h) for more -information. +Except for png_set_filter(), all of these are just controlling zlib, +so see the zlib documentation (zlib.h and zconf.h) for more information. Removing unwanted object code: There are a bunch of #define's in pngconf.h that control what parts of libpng are compiled. All the defines end in _SUPPORT. If you are -never going to use an ability, you can change the #define to #undef and -save yourself code and data space. All the reading and writing -specific code are in seperate files, so the linker should only grab -the files it needs. However, if you want to make sure, or if you -are building a stand alone library, all the reading files start with -pngr and all the writing files start with pngw. The files that -don't match either (like png.c, pngtrans.c, etc.) are used for -both reading and writing, and always need to be included. The -progressive reader is in pngpread.c +never going to use an ability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space. All +the reading and writing specific code are in seperate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the +library, as this will cause applications linked with different versions +of the library to fail if they call functions not available in your +library. The size of the library itself should not be an issue, because +only those sections which are actually used will be loaded into memory. + +Changes to Libpng from version 0.88 to version 0.89 + +It should be noted that version 0.89 of libpng is not distributed by +the original author, Guy Schalnat, but rather Andreas Dilger, although +all of the copyright messages have been left in Guy's name. + +The old libpng functions png_read_init(), png_write_init() and +png_info_init() still exist in the 0.89 version of the library, as +do png_read_destroy() and png_write_destroy(). The preferred method +of creating and initializing the libpng structures is via the +png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow +the use of custom error handling routines during the initialization, +which the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng allocated +for these structs, but just reset the data structures, so they can be +used instead of png_destroy_read_struct() and png_destroy_write_struct() +if you feel there is too much system overhead allocating and freeing the +png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications which do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a +new name to force compilation errors with the new library. diff --git a/makefile b/makefile index ae3a0bee..b8a12b5d 100644 --- a/makefile +++ b/makefile @@ -13,8 +13,8 @@ RANLIB=echo prefix=/usr/local OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ - pngmem.o pngerror.o pngpread.o + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o + pngwtran.o pngmem.o pngerror.o pngpread.o all: libpng.a pngtest @@ -45,7 +45,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.aco b/makefile.aco new file mode 100644 index 00000000..2d8d408a --- /dev/null +++ b/makefile.aco @@ -0,0 +1,114 @@ +# Project: libpng + + +# Toolflags: +CCflags = -c -depend !Depend -IC:,Zlib: -g -throwback -DRISCOS -fnah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -o $@ +Squeezeflags = -o $@ + + +# Final targets: +@.libpng-lib: @.o.png @.o.pngerror @.o.pngrio @.o.pngwio @.o.pngmem \ + @.o.pngpread @.o.pngrcb @.o.pngread @.o.pngrtran @.o.pngrutil \ + @.o.pngtrans @.o.pngwrite @.o.pngwtran @.o.pngwutil + LibFile $(LibFileflags) @.o.png @.o.pngerror @.o.pngrio @.o.pngwio \ + @.o.pngmem @.o.pngpread @.o.pngrcb @.o.pngread @.o.pngrtran \ + @.o.pngrutil @.o.pngtrans @.o.pngwrite @.o.pngwtran @.o.pngwutil +@.test: @.tests.pngtest + echo Please run "Test" in directory tests +@.tests.pngtest: @.o.pngtest @.libpng-lib C:o.Stubs Zlib:zlib_lib + Link $(Linkflags) @.o.pngtest @.libpng-lib C:o.Stubs Zlib:zlib_lib + + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + + +# Static dependencies: +@.o.example: @.tests.c.example + cc $(ccflags) -o @.o.example @.tests.c.example +@.o.pngtest: @.tests.c.pngtest + cc $(ccflags) -o @.o.pngtest @.tests.c.pngtest + + +# Dynamic dependencies: +o.png: c.png +o.png: h.png +o.png: Zlib:h.zlib +o.png: Zlib:h.zconf +o.png: h.pngconf +o.pngerror: c.pngerror +o.pngerror: h.png +o.pngerror: Zlib:h.zlib +o.pngerror: Zlib:h.zconf +o.pngerror: h.pngconf +o.pngrio: c.pngrio +o.pngrio: h.png +o.pngrio: Zlib:h.zlib +o.pngrio: Zlib:h.zconf +o.pngrio: h.pngconf +o.pngwio: c.pngwio +o.pngwio: h.png +o.pngwio: Zlib:h.zlib +o.pngwio: Zlib:h.zconf +o.pngwio: h.pngconf +o.pngmem: c.pngmem +o.pngmem: h.png +o.pngmem: Zlib:h.zlib +o.pngmem: Zlib:h.zconf +o.pngmem: h.pngconf +o.pngpread: c.pngpread +o.pngpread: h.png +o.pngpread: Zlib:h.zlib +o.pngpread: Zlib:h.zconf +o.pngpread: h.pngconf +o.pngrcb: c.pngrcb +o.pngrcb: h.png +o.pngrcb: Zlib:h.zlib +o.pngrcb: Zlib:h.zconf +o.pngrcb: h.pngconf +o.pngread: c.pngread +o.pngread: h.png +o.pngread: Zlib:h.zlib +o.pngread: Zlib:h.zconf +o.pngread: h.pngconf +o.pngrtran: c.pngrtran +o.pngrtran: h.png +o.pngrtran: Zlib:h.zlib +o.pngrtran: Zlib:h.zconf +o.pngrtran: h.pngconf +o.pngrutil: c.pngrutil +o.pngrutil: h.png +o.pngrutil: Zlib:h.zlib +o.pngrutil: Zlib:h.zconf +o.pngrutil: h.pngconf +o.pngtrans: c.pngtrans +o.pngtrans: h.png +o.pngtrans: Zlib:h.zlib +o.pngtrans: Zlib:h.zconf +o.pngtrans: h.pngconf +o.pngwrite: c.pngwrite +o.pngwrite: h.png +o.pngwrite: Zlib:h.zlib +o.pngwrite: Zlib:h.zconf +o.pngwrite: h.pngconf +o.pngwtran: c.pngwtran +o.pngwtran: h.png +o.pngwtran: Zlib:h.zlib +o.pngwtran: Zlib:h.zconf +o.pngwtran: h.pngconf +o.pngwutil: c.pngwutil +o.pngwutil: h.png +o.pngwutil: Zlib:h.zlib +o.pngwutil: Zlib:h.zconf +o.pngwutil: h.pngconf +o.pngtest: tests.c.pngtest +o.pngtest: h.png +o.pngtest: Zlib:h.zlib +o.pngtest: Zlib:h.zconf +o.pngtest: h.pngconf diff --git a/makefile.ama b/makefile.ama index 367431c1..c56ff257 100644 --- a/makefile.ama +++ b/makefile.ama @@ -23,7 +23,7 @@ AR= oml MKDIR= makedir OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o pngpread.o \ -pngread.o pngerror.o pngwrite.o pngrtran.o pngwtran.o pngio.o pngmem.o +pngread.o pngerror.o pngwrite.o pngrtran.o pngwtran.o pngrio.o pngwio.o pngmem.o all: libpng.lib pngtest diff --git a/makefile.atr b/makefile.atr index 88ba1637..9adc65ac 100644 --- a/makefile.atr +++ b/makefile.atr @@ -14,7 +14,7 @@ OBJS = $(LBR)(png.o) $(LBR)(pngrcb.o) $(LBR)(pngrutil.o)\ $(LBR)(pngtrans.o) $(LBR)(pngwutil.o)\ $(LBR)(pngread.o) $(LBR)(pngerror.o) $(LBR)(pngwrite.o)\ $(LBR)(pngrtran.o) $(LBR)(pngwtran.o)\ - $(LBR)(pngmem.o) $(LBR)(pngio.o) $(LBR)(pngpread.o) + $(LBR)(pngmem.o) $(LBR)(pngrio.o) $(LBR)(pngwio.o) $(LBR)(pngpread.o) all: $(LBR) pngtest.ttp diff --git a/makefile.bor b/makefile.bor index 17160995..3b8cf509 100644 --- a/makefile.bor +++ b/makefile.bor @@ -71,35 +71,35 @@ O=obj ## variables OBJS = \ png.$(O) \ + pngerror.$(O) \ + pngmem.$(O) \ + pngpread.$(O) \ pngrcb.$(O) \ + pngread.$(O) \ + pngrio.$(O) \ + pngrtran.$(O) \ pngrutil.$(O) \ pngtrans.$(O) \ - pngwutil.$(O) \ - pngmem.$(O) \ - pngread.$(O) \ - pngpread.$(O) \ - pngerror.$(O) \ pngwrite.$(O) \ - pngrtran.$(O) \ pngwtran.$(O) \ - pngzlib.$(O) \ - pngio.$(O) + pngwio.$(O) \ + pngwutil.$(O) LIBOBJS = \ +png.$(O) \ - +pngrcb.$(O) \ - +pngrutil.$(O) \ - +pngtrans.$(O) \ - +pngwutil.$(O) \ + +pngerror.$(O) \ +pngmem.$(O) \ +pngpread.$(O) \ +pngread.$(O) \ - +pngerror.$(O) \ - +pngwrite.$(O) \ + +pngrcb.$(O) \ + +pngrio.$(O) \ +pngrtran.$(O) \ + +pngrutil.$(O) \ + +pngtrans.$(O) \ + +pngwrite.$(O) \ +pngwtran.$(O) \ - +pngzlib.$(O) \ - +pngio.$(O) + +pngwio.$(O) + +pngwutil.$(O) LIBNAME=libpng$(MODEL).lib @@ -133,12 +133,12 @@ pngrtran.obj: pngrtran.c pngrutil.obj: pngrutil.c pngerror.obj: pngerror.c pngmem.obj: pngmem.c -pngio.obj: pngio.c +pngrio.obj: pngrio.c +pngwio.obj: pngwio.c pngtrans.obj: pngtrans.c pngwrite.obj: pngwrite.c pngwtran.obj: pngwtran.c pngwutil.obj: pngwutil.c -pngzlib.obj: pngzlib.c $(LIBNAME): $(OBJS) diff --git a/makefile.elf b/makefile.elf index b9ad0701..f61d30de 100644 --- a/makefile.elf +++ b/makefile.elf @@ -4,19 +4,19 @@ CC=gcc CFLAGS=-I../zlib -O2 -Wall -fPIC -LDFLAGS=-L. -L../zlib/ -lpng -lz -lm +LDFLAGS=-L. -Wl,-rpath,. -L../zlib/ -Wl,-rpath,../zlib/ -lpng -lz -lm RANLIB=ranlib #RANLIB=echo -PNGVER = 0.86 +PNGVER = 0.89 # where make install puts libpng.a, libpng.so*, and png.h prefix=/usr/local OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ - pngmem.o pngerror.o pngpread.o + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \ + pngwtran.o pngmem.o pngerror.o pngpread.o all: libpng.so pngtest @@ -59,7 +59,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.gcc b/makefile.gcc index 999a34b1..afc79237 100644 --- a/makefile.gcc +++ b/makefile.gcc @@ -13,7 +13,7 @@ RANLIB=ranlib prefix=. OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o pngwtran.o \ pngmem.o pngerror.o pngpread.o all: libpng.a pngtest @@ -35,7 +35,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.knr b/makefile.knr index 7d742123..b4cc37c2 100644 --- a/makefile.knr +++ b/makefile.knr @@ -15,8 +15,8 @@ RANLIB=ranlib prefix=/usr/local OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ - pngmem.o pngerror.o pngpread.o + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \ + pngwtran.o pngmem.o pngerror.o pngpread.o all: ansi2knr libpng.a pngtest @@ -57,7 +57,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.mip b/makefile.mip index 76e0a0ea..6208d230 100644 --- a/makefile.mip +++ b/makefile.mip @@ -14,8 +14,8 @@ RANLIB=echo prefix=/usr/local OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ - pngmem.o pngerror.o pngpread.o + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \ + pngwtran.o pngmem.o pngerror.o pngpread.o all: libpng.a pngtest @@ -46,7 +46,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.msc b/makefile.msc index d48d9efe..b0c259a7 100644 --- a/makefile.msc +++ b/makefile.msc @@ -17,7 +17,7 @@ ERRFILE= >> pngerrs # variables OBJS1 = png$(O) pngrcb$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O) pngmem$(O) pngpread$(O) -OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngio$(O) +OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O) all: libpng.lib @@ -45,7 +45,10 @@ pngerror$(O): png.h pngconf.h pngmem$(O): png.h pngconf.h $(CC) -c $(CFLAGS) $*.c $(ERRFILE) -pngio$(O): png.h pngconf.h +pngrio$(O): png.h pngconf.h + $(CC) -c $(CFLAGS) $*.c $(ERRFILE) + +pngwio$(O): png.h pngconf.h $(CC) -c $(CFLAGS) $*.c $(ERRFILE) pngtest$(O): png.h pngconf.h diff --git a/makefile.std b/makefile.std index ae3a0bee..9d28c564 100644 --- a/makefile.std +++ b/makefile.std @@ -13,8 +13,8 @@ RANLIB=echo prefix=/usr/local OBJS = png.o pngrcb.o pngrutil.o pngtrans.o pngwutil.o \ - pngread.o pngio.o pngwrite.o pngrtran.o pngwtran.o \ - pngmem.o pngerror.o pngpread.o + pngread.o pngrio.o pngwio.o pngwrite.o pngrtran.o \ + pngwtran.o pngmem.o pngerror.o pngpread.o all: libpng.a pngtest @@ -45,7 +45,8 @@ clean: png.o: png.h pngconf.h pngerror.o: png.h pngconf.h -pngio.o: png.h pngconf.h +pngrio.o: png.h pngconf.h +pngwio.o: png.h pngconf.h pngmem.o: png.h pngconf.h pngrcb.o: png.h pngconf.h pngread.o: png.h pngconf.h diff --git a/makefile.tc b/makefile.tc index 3fb5e423..58d5f55a 100644 --- a/makefile.tc +++ b/makefile.tc @@ -14,9 +14,9 @@ O=.obj # variables OBJS1 = png$(O) pngrcb$(O) pngrutil$(O) pngtrans$(O) pngwutil$(O) pngmem$(O) pngpread$(O) -OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngio$(O) +OBJS2 = pngread$(O) pngerror$(O) pngwrite$(O) pngrtran$(O) pngwtran$(O) pngrio$(O) pngwio$(O) OBJSL1 = +png$(O) +pngrcb$(O) +pngrutil$(O) +pngtrans$(O) +pngwutil$(O) +pngmem$(O) +pngpread$(O) -OBJSL2 = +pngread$(O) +pngerror$(O) +pngwrite$(O) +pngrtran$(O) +pngwtran$(O) pngio$(O) +OBJSL2 = +pngread$(O) +pngerror$(O) +pngwrite$(O) +pngrtran$(O) +pngwtran$(O) +pngrio$(O) +pngwio$(O) all: libpng.lib @@ -44,7 +44,10 @@ pngerror$(O): png.h pngconf.h pngmem$(O): png.h pngconf.h $(CC) -c $(CFLAGS) $*.c -pngio$(O): png.h pngconf.h +pngrio$(O): png.h pngconf.h + $(CC) -c $(CFLAGS) $*.c + +pngwio$(O): png.h pngconf.h $(CC) -c $(CFLAGS) $*.c pngtest$(O): png.h pngconf.h diff --git a/makevms.com b/makevms.com index aa112b11..e2b5088b 100644 --- a/makevms.com +++ b/makevms.com @@ -52,8 +52,10 @@ $ CALL MAKE pngerror.OBJ "cc ''CCOPT' pngerror" - pngerror.c png.h pngconf.h $ CALL MAKE pngmem.OBJ "cc ''CCOPT' pngmem" - pngmem.c png.h pngconf.h -$ CALL MAKE pngio.OBJ "cc ''CCOPT' pngio" - - pngio.c png.h pngconf.h +$ CALL MAKE pngrio.OBJ "cc ''CCOPT' pngrio" - + pngrio.c png.h pngconf.h +$ CALL MAKE pngwio.OBJ "cc ''CCOPT' pngwio" - + pngwio.c png.h pngconf.h $ CALL MAKE pngtrans.OBJ "cc ''CCOPT' pngtrans" - pngtrans.c png.h pngconf.h $ CALL MAKE pngwrite.OBJ "cc ''CCOPT' pngwrite" - diff --git a/png.c b/png.c index facd04c7..d582f423 100644 --- a/png.c +++ b/png.c @@ -1,10 +1,10 @@ /* png.c - location for general purpose png functions - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -13,7 +13,7 @@ /* version information for c files. This better match the version string defined in png.h */ -char png_libpng_ver[] = "0.88"; +char png_libpng_ver[] = "0.89"; /* place to hold the signiture string for a png file. */ png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; @@ -25,39 +25,17 @@ png_byte FARDATA png_IHDR[4] = { 73, 72, 68, 82}; png_byte FARDATA png_IDAT[4] = { 73, 68, 65, 84}; png_byte FARDATA png_IEND[4] = { 73, 69, 78, 68}; png_byte FARDATA png_PLTE[4] = { 80, 76, 84, 69}; -#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED) png_byte FARDATA png_gAMA[4] = {103, 65, 77, 65}; -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED) png_byte FARDATA png_sBIT[4] = {115, 66, 73, 84}; -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED) png_byte FARDATA png_cHRM[4] = { 99, 72, 82, 77}; -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) png_byte FARDATA png_tRNS[4] = {116, 82, 78, 83}; -#endif -#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED) png_byte FARDATA png_bKGD[4] = { 98, 75, 71, 68}; -#endif -#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED) png_byte FARDATA png_hIST[4] = {104, 73, 83, 84}; -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) png_byte FARDATA png_tEXt[4] = {116, 69, 88, 116}; -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) png_byte FARDATA png_zTXt[4] = {122, 84, 88, 116}; -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED) png_byte FARDATA png_pHYs[4] = {112, 72, 89, 115}; -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) png_byte FARDATA png_oFFs[4] = {111, 70, 70, 115}; -#endif -#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) png_byte FARDATA png_tIME[4] = {116, 73, 77, 69}; -#endif /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ @@ -209,6 +187,21 @@ png_calculate_crc(png_structp png_ptr, png_bytep ptr, { png_ptr->crc = update_crc(png_ptr->crc, ptr, length); } + +png_infop +png_create_info_struct(png_structp png_ptr) +{ + png_infop info_ptr; + + if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL) + { + png_memset(info_ptr, 0, sizeof(png_info)); + png_ptr->do_free |= PNG_FREE_INFO; + } + + return info_ptr; +} + void png_info_init(png_infop info) { @@ -216,3 +209,20 @@ png_info_init(png_infop info) png_memset(info, 0, sizeof (png_info)); } +/* This function returns a pointer to the io_ptr associated with the user + functions. The application should free any memory associated with this + pointer before png_write_destroy and png_read_destroy are called. */ +png_voidp +png_get_io_ptr(png_structp png_ptr) +{ + return png_ptr->io_ptr; +} + +/* Initialize the default input/output functions for the png file. If you + change the read, or write routines, you can call either png_set_read_fn() + or png_set_write_fn() instead of png_init_io(). */ +void +png_init_io(png_structp png_ptr, FILE *fp) +{ + png_ptr->io_ptr = (png_voidp)fp; +} diff --git a/png.h b/png.h index 1fe369f1..c17d7863 100644 --- a/png.h +++ b/png.h @@ -1,8 +1,8 @@ /* png.h - header file for png reference library - libpng 1.0 beta 2 - version 0.88 - Jan 25, 1996 + libpng 1.0 beta 3 - version 0.89 + May 25, 1996 Note: This is a beta version. It reads and writes valid files on the platforms I have, but it has had limited portability @@ -74,10 +74,10 @@ /* version information for png.h - this should match the version number in png.c */ -#define PNG_LIBPNG_VER_STRING "0.88" -/* careful here. I wanted to use 088, but that would be octal. Version +#define PNG_LIBPNG_VER_STRING "0.89" +/* careful here. I wanted to use 089, but that would be octal. Version 1.0 will be 100 here, etc. */ -#define PNG_LIBPNG_VER 88 +#define PNG_LIBPNG_VER 89 /* variables defined in png.c - only it needs to define PNG_NO_EXTERN */ #ifndef PNG_NO_EXTERN @@ -88,11 +88,7 @@ extern char png_libpng_ver[]; /* three color definitions. The order of the red, green, and blue, (and the exact size) is not important, although the size of the fields need to - be png_byte or png_uint_16 (as defined below). While png_color_8 and - png_color_16 have more fields then they need, they are never used in - arrays, so the size isn't that important. I thought about using - unions, but it looked too clumsy, so I left it. If you're using C++, - you can union red, index, and gray, if you really want too. */ + be png_byte or png_uint_16 (as defined below). */ typedef struct png_color_struct { png_byte red; @@ -144,7 +140,6 @@ typedef struct png_time_struct { png_uint_16 year; /* full year, as in, 1995 */ png_byte month; /* month of year, 1 - 12 */ - png_byte day; /* day of month, 1 - 31 */ png_byte hour; /* hour of day, 0 - 23 */ png_byte minute; /* minute of hour, 0 - 59 */ @@ -165,18 +160,22 @@ typedef struct png_info_struct /* the following are necessary for every png file */ png_uint_32 width; /* with of file */ png_uint_32 height; /* height of file */ + png_uint_32 valid; /* the PNG_INFO_ defines, OR'd together */ + png_uint_32 rowbytes; /* bytes needed for untransformed row */ + png_colorp palette; /* palette of file */ + png_uint_16 num_palette; /* number of values in palette */ + png_uint_16 num_trans; /* number of trans values */ png_byte bit_depth; /* 1, 2, 4, 8, or 16 */ png_byte color_type; /* use the PNG_COLOR_TYPE_ defines */ png_byte compression_type; /* must be 0 */ png_byte filter_type; /* must be 0 */ png_byte interlace_type; /* 0 for non-interlaced, 1 for interlaced */ - png_uint_32 valid; /* the PNG_INFO_ defines, OR'd together */ /* the following is informational only on read, and not used on writes */ png_byte channels; /* number of channels of data per pixel */ png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* To align the data, and for future use */ - png_uint_32 rowbytes; /* bytes needed for untransformed row */ /* the rest are optional. If you are reading, check the valid field to see if the information in these are valid. If you are writing, set the valid field to those chunks you want @@ -184,9 +183,38 @@ typedef struct png_info_struct #if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED) float gamma; /* gamma value of file, if gAMA chunk is valid */ #endif +#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) + int num_text; /* number of comments */ + int max_text; /* size of text array */ + png_textp text; /* array of comments */ +#endif +#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) + png_time mod_time; /* modification time */ +#endif #if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED) png_color_8 sig_bit; /* significant bits */ #endif +#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) + png_bytep trans; /* tRNS values for palette image */ + png_color_16 trans_values; /* tRNS values for non-palette image */ +#endif +#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED) + png_color_16 background; /* background color of image */ +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) + png_uint_32 x_offset; /* x offset on page */ + png_uint_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED) + png_uint_32 x_pixels_per_unit; /* x resolution */ + png_uint_32 y_pixels_per_unit; /* y resolution */ + png_byte phys_unit_type; /* resolution type */ +#endif +#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED) + png_uint_16p hist; /* histogram of palette usage */ +#endif #if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED) float x_white; /* cHRM chunk values */ float y_white; @@ -196,62 +224,31 @@ typedef struct png_info_struct float y_green; float x_blue; float y_blue; -#endif - png_colorp palette; /* palette of file */ - png_uint_16 num_palette; /* number of values in palette */ - png_uint_16 num_trans; /* number of trans values */ -#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) - png_bytep trans; /* tRNS values for palette image */ - png_color_16 trans_values; /* tRNS values for non-palette image */ -#endif -#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED) - - png_color_16 background; /* background color of image */ -#endif -#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED) - png_uint_16p hist; /* histogram of palette usage */ -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED) - png_uint_32 x_pixels_per_unit; /* x resolution */ - png_uint_32 y_pixels_per_unit; /* y resolution */ - png_byte phys_unit_type; /* resolution type */ -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) - png_uint_32 x_offset; /* x offset on page */ - png_uint_32 y_offset; /* y offset on page */ - png_byte offset_unit_type; /* offset units type */ -#endif -#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) - png_time mod_time; /* modification time */ -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ - defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) - int num_text; /* number of comments */ - int max_text; /* size of text array */ - png_textp text; /* array of comments */ #endif } png_info; typedef png_info FAR * png_infop; typedef png_info FAR * FAR * png_infopp; #define PNG_RESOLUTION_UNKNOWN 0 -#define PNG_RESOLUTION_METER 1 +#define PNG_RESOLUTION_METER 1 +#define PNG_RESOLUTION_LAST 2 -#define PNG_OFFSET_PIXEL 0 -#define PNG_OFFSET_MICROMETER 1 +#define PNG_OFFSET_PIXEL 0 +#define PNG_OFFSET_MICROMETER 1 +#define PNG_OFFSET_LAST 2 /* these describe the color_type field in png_info */ /* color type masks */ #define PNG_COLOR_MASK_PALETTE 1 -#define PNG_COLOR_MASK_COLOR 2 -#define PNG_COLOR_MASK_ALPHA 4 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 /* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 #define PNG_COLOR_TYPE_PALETTE \ (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) -#define PNG_COLOR_TYPE_GRAY 0 #define PNG_COLOR_TYPE_RGB_ALPHA \ (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) @@ -269,11 +266,6 @@ typedef png_info FAR * FAR * png_infopp; #define PNG_INFO_oFFs 0x0100 #define PNG_INFO_tIME 0x0200 -/* these determine if a function in the info needs to be freed */ -#define PNG_FREE_PALETTE 0x0001 -#define PNG_FREE_HIST 0x0002 -#define PNG_FREE_TRANS 0x0004 - /* this is used for the transformation routines, as some of them change these values for the row. It also should enable using the routines for other uses. */ @@ -291,14 +283,14 @@ typedef png_row_info FAR * png_row_infop; typedef png_row_info FAR * FAR * png_row_infopp; /* These are the function types for the I/O functions, and the functions which - * modify the default I/O functions to user I/O functions. The png_msg_ptr + * modify the default I/O functions to user I/O functions. The png_error_ptr * type should match that of user supplied warning and error functions, while * the png_rw_ptr type should match that of the user read/write data functions. */ typedef struct png_struct_def png_struct; typedef png_struct FAR * png_structp; -typedef void (*png_msg_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (*png_error_ptr) PNGARG((png_structp, png_const_charp)); typedef void (*png_rw_ptr) PNGARG((png_structp, png_bytep, png_uint_32)); typedef void (*png_flush_ptr) PNGARG((png_structp)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED @@ -316,55 +308,28 @@ typedef void (*png_progressive_row_ptr) PNGARG((png_structp, png_bytep, struct png_struct_def { jmp_buf jmpbuf; /* used in png_error */ + + png_error_ptr error_fn; /* Function for printing errors and aborting */ + png_error_ptr warning_fn; /* Function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* Function for writing output data */ + png_rw_ptr read_data_fn; /* Function for reading input data */ + png_voidp io_ptr; /* Pointer to user supplied struct for I/O functions */ + png_byte mode; /* used to determine where we are in the png file */ - png_byte read_mode; - png_byte color_type; /* color type of file */ - png_byte bit_depth; /* bit depth of file */ - png_byte interlaced; /* interlace type of file */ - png_byte compession; /* compression type of file */ - png_byte filter; /* filter type */ - png_byte channels; /* number of channels in file */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte usr_bit_depth; /* bit depth of users row */ - png_byte usr_channels; /* channels at start of write */ -#if defined(PNG_READ_GAMMA_SUPPORTED) - png_byte gamma_shift; /* amount of shift for 16 bit gammas */ -#endif - png_byte pass; /* current pass (0 - 6) */ - png_byte row_init; /* 1 if png_read_start_row() has been called */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_byte background_gamma_type; - png_byte background_expand; -#endif - png_byte zlib_finished; - png_byte user_palette; -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) - png_byte filler; - png_byte filler_loc; -#endif - png_byte zlib_custom_level; /* one if custom compression level */ - png_byte zlib_custom_method; /* one if custom compression method */ - png_byte zlib_custom_window_bits; /* one if custom compression window bits */ - png_byte zlib_custom_mem_level; /* one if custom compression memory level */ - png_byte zlib_custom_strategy; /* one if custom compression strategy */ - png_byte do_filter; /* one if filtering, zero if not */ - png_byte do_custom_filter; /* one if filtering, zero if not */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_byte have_chunk_header; -#endif - png_uint_16 num_palette; /* number of entries in palette */ - png_uint_16 num_trans; /* number of transparency values */ + png_uint_32 do_free; /* flags indicating if libpng should free memory */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream * zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_uint_32 zbuf_size; /* size of zbuf */ int zlib_level; /* holds zlib compression level */ int zlib_method; /* holds zlib compression method */ int zlib_window_bits; /* holds zlib compression window bits */ int zlib_mem_level; /* holds zlib compression memory level */ int zlib_strategy; /* holds zlib compression strategy */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - int process_mode; - int cur_palette; -#endif - png_uint_32 transformations; /* which transformations to perform */ - png_uint_32 crc; /* current crc value */ + png_uint_32 width; /* width of file */ png_uint_32 height; /* height of file */ png_uint_32 num_rows; /* number of rows in current pass */ @@ -373,20 +338,87 @@ struct png_struct_def png_uint_32 iwidth; /* interlaced width */ png_uint_32 irowbytes; /* interlaced rowbytes */ png_uint_32 row_number; /* current row in pass */ + png_bytep row_buf; /* row buffer */ + png_bytep prev_row; /* previous row */ + png_bytep sub_row; /* place to save row when filtering */ + png_bytep up_row; /* place to save row when filtering */ + png_bytep avg_row; /* place to save row when filtering */ + png_bytep paeth_row; /* place to save row when filtering */ + png_row_info row_info; /* used for transformation routines */ + png_uint_32 idat_size; /* current idat size for read */ - png_uint_32 zbuf_size; /* size of zbuf */ - png_uint_32 do_free; /* flags indicating if libpng should free memory */ + png_uint_32 crc; /* current crc value */ + png_colorp palette; /* files palette */ + png_uint_16 num_palette; /* number of entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte interlaced; /* interlace type of file */ + png_byte pass; /* current pass (0 - 6) */ + png_byte compression; /* compression type of file */ + png_byte filter; /* filter type */ + png_byte do_filter; /* non-zero if row filtering, zero if not */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_byte filler; /* filler byte to be used for 32-bit frame buffers */ +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + png_byte background_gamma_type; + float background_gamma; + png_color_16 background; /* background color, gamma corrected for screen */ +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif #if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_flush_ptr output_flush_fn;/* Function for flushing output */ png_uint_32 flush_dist; /* how many rows apart to flush, 0 for no flush */ png_uint_32 flush_rows; /* number of rows written since last flush */ #endif /* PNG_WRITE_FLUSH_SUPPORTED */ +#if defined(PNG_READ_GAMMA_SUPPORTED) + int gamma_shift; /* amount of shift for 16 bit gammas */ + float gamma; /* file gamma value */ + float display_gamma; /* display gamma value */ +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table; /* gamma table for 8 bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16 bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined (PNG_READ_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in file */ +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ +#endif +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; + png_progressive_row_ptr row_fn; + png_progressive_end_ptr end_fn; + png_bytep save_buffer_ptr; + png_bytep save_buffer; + png_bytep current_buffer_ptr; + png_bytep current_buffer; png_uint_32 push_length; png_uint_32 skip_length; png_uint_32 save_buffer_size; png_uint_32 save_buffer_max; png_uint_32 buffer_size; png_uint_32 current_buffer_size; + int process_mode; + int cur_palette; + png_byte push_chunk_name[4]; #if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED) png_uint_32 current_text_size; png_uint_32 current_text_left; @@ -401,85 +433,29 @@ struct png_struct_def png_uint_16 offset_table_count; png_uint_16 offset_table_count_free; #endif - png_byte push_chunk_name[4]; - png_bytep save_buffer_ptr; - png_bytep save_buffer; - png_bytep current_buffer_ptr; - png_bytep current_buffer; -#endif - png_colorp palette; /* files palette */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ #if defined(PNG_READ_DITHER_SUPPORTED) png_bytep palette_lookup; /* lookup table for dithering */ -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_table; /* gamma table for 8 bit depth files */ -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_from_1; /* converts from 1.0 to screen */ - png_bytep gamma_to_1; /* converts from file to 1.0 */ -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep trans; /* transparency values for paletted files */ -#endif -#if defined(PNG_READ_DITHER_SUPPORTED) png_bytep dither_index; /* index translation for palette files */ -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_uint_16pp gamma_16_table; /* gamma table for 16 bit depth files */ -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ - png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ -#endif -#if defined(PNG_READ_DITHER_SUPPORTED) png_uint_16p hist; /* histogram */ #endif - png_bytep zbuf; /* buffer for zlib */ - png_bytep row_buf; /* row buffer */ - png_bytep prev_row; /* previous row */ - png_bytep save_row; /* place to save row before filtering */ - z_stream * zstream; /* pointer to decompression structure (below) */ -#if defined(PNG_READ_GAMMA_SUPPORTED) - float gamma; /* file gamma value */ - float display_gamma; /* display gamma value */ -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - float background_gamma; -#endif -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift; /* shift for significant bit tranformation */ -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined (PNG_READ_sBIT_SUPPORTED) - png_color_8 sig_bit; /* significant bits in file */ -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_color_16 trans_values; /* transparency values for non-paletted files */ - png_color_16 background; /* background color, gamma corrected for screen */ -#if defined(PNG_READ_GAMMA_SUPPORTED) - png_color_16 background_1; /* background normalized to gamma 1.0 */ -#endif -#endif - png_row_info row_info; /* used for transformation routines */ - FILE *fp; /* used for default png_read and png_write */ - png_msg_ptr error_fn; /* Function for printing errors and aborting */ - png_msg_ptr warning_fn; /* Function for printing warnings */ - png_rw_ptr write_data_fn; /* Function for writing output data */ - png_rw_ptr read_data_fn; /* Function for reading input data */ -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_flush_ptr output_flush_fn;/* Function for flushing output */ -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn; - png_progressive_row_ptr row_fn; - png_progressive_end_ptr end_fn; - png_voidp push_ptr; -#endif - png_voidp io_ptr; /* Pointer to user supplied struct for I/O functions */ - png_voidp msg_ptr; /* Pointer to user supplied struct for message functions */ }; typedef png_struct FAR * FAR * png_structpp; +/* flags for png_set_filter() to say which filters to use. The flags + are chosen so that they don't conflict with real filter types, in case they + are supplied instead of the #defined constants. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + /* Here are the function definitions most commonly used. This is not the place to find out how to use libpng. See libpng.txt for the full explanation, see example.c for the summary. This just provides @@ -488,13 +464,31 @@ typedef png_struct FAR * FAR * png_structpp; /* check the first 1 - 8 bytes to see if it is a png file */ extern int png_check_sig PNGARG((png_bytep sig, int num)); -/* initialize png structure for reading, and allocate any memory needed */ +/* allocate and initialize png structure for reading, and any other memory */ +extern png_structp png_create_read_struct PNGARG((png_const_charp user_png_ver, + voidp error_ptr, png_error_ptr warn_fn, png_error_ptr error_fn)); + +/* reset the png_struct to read a new image */ +extern void png_reset_read_struct PNGARG((png_structpp png_ptr)); + +/* initialize png structure for reading, and allocate any other memory (old) */ extern void png_read_init PNGARG((png_structp png_ptr)); -/* initialize png structure for writing, and allocate any memory needed */ +/* allocate and initialize png structure for reading, and any other memory */ +extern png_structp png_create_write_struct + PNGARG((png_const_charp user_png_ver, voidp error_ptr, + png_error_ptr warn_fn, png_error_ptr error_fn)); + +/* reset the png_struct to read a new image */ +extern void png_reset_write_struct PNGARG((png_structpp png_ptr)); + +/* initialize png structure for writing, and allocate any other memory (old) */ extern void png_write_init PNGARG((png_structp png_ptr)); -/* initialize the info structure */ +/* allocate and initialize the info structure */ +extern png_infop png_create_info_struct PNGARG((png_structp png_ptr)); + +/* initialize the info structure (old interface) */ extern void png_info_init PNGARG((png_infop info)); /* Writes all the png information before the image. */ @@ -506,7 +500,7 @@ extern void png_read_info PNGARG((png_structp png_ptr, png_infop info)); #if defined(PNG_WRITE_tIME_SUPPORTED) /* convert from a struct tm to png_time */ extern void png_convert_from_struct_tm PNGARG((png_timep ptime, - struct tm FAR * ttime)); /*SJT: struct tm FAR *tttime ??? */ + struct tm FAR * ttime)); /* convert from time_t to png_time. Uses gmtime() */ extern void png_convert_from_time_t PNGARG((png_timep ptime, time_t ttime)); @@ -533,7 +527,7 @@ extern void png_set_gray_to_rgb PNGARG((png_structp png_ptr)); #define PNG_FILLER_AFTER 1 /* Add a filler byte to rgb images. */ extern void png_set_filler PNGARG((png_structp png_ptr, int filler, - int filler_loc)); + int flags)); /* old ways of doing this, still supported through 1.x for backwards compatability, but not suggested */ @@ -574,10 +568,10 @@ extern void png_set_invert_mono PNGARG((png_structp png_ptr)); #if defined(PNG_READ_BACKGROUND_SUPPORTED) /* Handle alpha and tRNS by replacing with a background color. */ -#define PNG_BACKGROUND_GAMMA_SCREEN 0 -#define PNG_BACKGROUND_GAMMA_FILE 1 -#define PNG_BACKGROUND_GAMMA_UNIQUE 2 -#define PNG_BACKGROUND_GAMMA_UNKNOWN 3 +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 extern void png_set_background PNGARG((png_structp png_ptr, png_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)); @@ -653,10 +647,22 @@ extern void png_write_end PNGARG((png_structp png_ptr, png_infop info)); /* read the end of the png file. */ extern void png_read_end PNGARG((png_structp png_ptr, png_infop info)); -/* free all memory used by the read */ +/* free the info structure */ +extern void png_destroy_info_struct PNGARG((png_structp png_ptr, + png_infopp info_ptr)); + +/* free any memory associated with the png_struct and the info_structs */ +extern void png_destroy_read_struct PNGARG((png_structpp png_ptr, + png_infopp info, png_infopp end_info)); + +/* free all memory used by the read (old method) */ extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info, png_infop end_info)); +/* free any memory associated with the png_struct and the info_structs */ +extern void png_destroy_write_struct PNGARG((png_structpp png_ptr, + png_infopp info)); + /* free any memory used in png struct */ extern void png_write_destroy PNGARG((png_structp png_ptr)); @@ -667,7 +673,8 @@ extern void png_write_destroy PNGARG((png_structp png_ptr)); performance at the expense of compression can modify them. See the compression library header file for an explination of these functions */ -extern void png_set_filtering PNGARG((png_structp png_ptr, int filter)); +extern void png_set_filter PNGARG((png_structp png_ptr, int method, + int filters)); extern void png_set_compression_level PNGARG((png_structp png_ptr, int level)); @@ -684,10 +691,12 @@ extern void png_set_compression_window_bits PNGARG((png_structp png_ptr, extern void png_set_compression_method PNGARG((png_structp png_ptr, int method)); -/* These next functions are stubs of typical c functions for input/output, - memory, and error handling. They are in the file pngio.c, and pngerror.c. - These functions can be replaced at run time for those applications that - need to handle I/O in a different manner. See the file libpng.txt for +/* These next functions are called for input/output, memory, and error + handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + and call standard C I/O routines such as fread(), fwrite(), and + fprintf(). These functions can be made to use other I/O routines + at run time for those applications that need to handle I/O in a + different manner by calling png_set_???_fn(). See libpng.txt for more information */ /* Write the data to whatever output you are using. */ @@ -707,11 +716,11 @@ extern void png_init_io PNGARG((png_structp png_ptr, FILE *fp)); still do a longjmp to the last setjmp location if you are using this method of error handling. If error_fn or warning_fn is NULL, the default functions will be used. */ -extern void png_set_message_fn PNGARG((png_structp png_ptr, png_voidp msg_ptr, - png_msg_ptr error_fn, png_msg_ptr warning_fn)); +extern void png_set_error_fn PNGARG((png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn)); -/* Return the user pointer associated with the message functions */ -extern png_voidp png_get_msg_ptr PNGARG((png_structp png_ptr)); +/* Return the user pointer associated with the error functions */ +extern png_voidp png_get_error_ptr PNGARG((png_structp png_ptr)); /* Replace the default data output functions with a user supplied one(s). If buffered output is not used, then output_flush_fn can be set to NULL. @@ -753,6 +762,12 @@ extern void * png_realloc PNGARG((png_structp png_ptr, void * ptr, /* free's a pointer allocated by png_malloc() */ extern void png_free PNGARG((png_structp png_ptr, void * ptr)); +/* allocate memory for an internal libpng struct */ +extern voidp png_create_struct PNGARG((uInt type)); + +/* free memory from internal libpng struct */ +extern void png_destroy_struct PNGARG((voidp struct_ptr)); + /* Fatal error in libpng - can't continue */ extern void png_error PNGARG((png_structp png_ptr, png_const_charp error)); @@ -767,50 +782,74 @@ extern void png_warning PNGARG((png_structp png_ptr, png_const_charp message)); define PNG_INTERNAL inside your code, so everyone who includes png.h won't get yet another definition the compiler has to deal with. */ -#ifdef PNG_INTERNAL +#if defined(PNG_INTERNAL) /* various modes of operation. Note that after an init, mode is set to zero automatically */ -#define PNG_BEFORE_IHDR 0 -#define PNG_HAVE_IHDR 1 -#define PNG_HAVE_PLTE 2 -#define PNG_HAVE_IDAT 3 -#define PNG_AT_LAST_IDAT 4 -#define PNG_AFTER_IDAT 5 -#define PNG_AFTER_IEND 6 +#define PNG_BEFORE_IHDR 0x00 +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AT_LAST_IDAT 0x08 +#define PNG_AFTER_IDAT 0x10 +#define PNG_AFTER_IEND 0x20 /* push model modes */ -#define PNG_READ_SIG_MODE 0 +#define PNG_READ_SIG_MODE 0 #define PNG_READ_CHUNK_MODE 1 -#define PNG_READ_IDAT_MODE 2 -#define PNG_READ_PLTE_MODE 3 -#define PNG_READ_END_MODE 4 -#define PNG_SKIP_MODE 5 -#define PNG_READ_tEXt_MODE 6 -#define PNG_READ_zTXt_MODE 7 -#define PNG_READ_DONE_MODE 8 -#define PNG_ERROR_MODE 9 +#define PNG_READ_IDAT_MODE 2 +#define PNG_READ_PLTE_MODE 3 +#define PNG_READ_END_MODE 4 +#define PNG_SKIP_MODE 5 +#define PNG_READ_tEXt_MODE 6 +#define PNG_READ_zTXt_MODE 7 +#define PNG_READ_DONE_MODE 8 +#define PNG_ERROR_MODE 9 /* read modes */ #define PNG_READ_PULL_MODE 0 #define PNG_READ_PUSH_MODE 1 /* defines for the transformations the png library does on the image data */ -#define PNG_BGR 0x0001 -#define PNG_INTERLACE 0x0002 -#define PNG_PACK 0x0004 -#define PNG_SHIFT 0x0008 -#define PNG_SWAP_BYTES 0x0010 -#define PNG_INVERT_MONO 0x0020 -#define PNG_DITHER 0x0040 -#define PNG_BACKGROUND 0x0080 -#define PNG_XRGB 0x0100 -#define PNG_16_TO_8 0x0200 -#define PNG_RGBA 0x0400 -#define PNG_EXPAND 0x0800 -#define PNG_GAMMA 0x1000 -#define PNG_GRAY_TO_RGB 0x2000 -#define PNG_FILLER 0x4000 +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 +#define PNG_XRGB 0x0200 +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000 + +/* flags for png_ptr->do_free to say if memory in png_info needs to be freed */ +#define PNG_FREE_PALETTE 0x0001 +#define PNG_FREE_HIST 0x0002 +#define PNG_FREE_TRANS 0x0004 +#define PNG_FREE_STRUCT 0x0008 +#define PNG_FREE_INFO 0x0010 + +/* flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* flags for the png_ptr->flags rather than declaring a bye for each one */ +#define PNG_FLAG_WROTE_tIME 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0010 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0020 +#define PNG_FLAG_ZLIB_FINISHED 0x0040 +#define PNG_FLAG_ROW_INIT 0x0080 +#define PNG_FLAG_FILLER_AFTER 0x0100 +#define PNG_FLAG_HAVE_CHUNK_HEADER 0x0200 /* save typing and make code easier to understand */ #define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ @@ -826,44 +865,24 @@ extern png_byte png_sig[]; extern char png_libpng_ver[]; /* constant strings for known chunk types. If you need to add a chunk, - add a string holding the name here. See png.c for more details */ + add a string holding the name here. See png.c for more details. We + can't selectively include these, since we still check for chunk in the + wrong locations with these labels. */ extern png_byte FARDATA png_IHDR[]; extern png_byte FARDATA png_IDAT[]; extern png_byte FARDATA png_IEND[]; extern png_byte FARDATA png_PLTE[]; -#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED) extern png_byte FARDATA png_gAMA[]; -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) || defined(PNG_WRITE_sBIT_SUPPORTED) extern png_byte FARDATA png_sBIT[]; -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED) extern png_byte FARDATA png_cHRM[]; -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) extern png_byte FARDATA png_tRNS[]; -#endif -#if defined(PNG_READ_bKGD_SUPPORTED) || defined(PNG_WRITE_bKGD_SUPPORTED) extern png_byte FARDATA png_bKGD[]; -#endif -#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED) extern png_byte FARDATA png_hIST[]; -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) extern png_byte FARDATA png_tEXt[]; -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) extern png_byte FARDATA png_zTXt[]; -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED) extern png_byte FARDATA png_pHYs[]; -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) extern png_byte FARDATA png_oFFs[]; -#endif -#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) extern png_byte FARDATA png_tIME[]; -#endif /* Structures to facilitate easy interlacing. See png.c for more details */ extern int FARDATA png_pass_start[]; extern int FARDATA png_pass_inc[]; @@ -894,14 +913,8 @@ extern void png_reset_crc PNGARG((png_structp png_ptr)); extern void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, png_uint_32 length)); -/* default error and warning functions if user doesn't supply them */ -extern void png_default_warning PNGARG((png_structp png_ptr, - png_const_charp message)); -extern void png_default_error PNGARG((png_structp png_ptr, - png_const_charp error)); #if defined(PNG_WRITE_FLUSH_SUPPORTED) extern void png_flush PNGARG((png_structp png_ptr)); -extern void png_default_flush PNGARG((png_structp png_ptr)); #endif /* place a 32 bit number into a buffer in png byte order. We work @@ -1105,11 +1118,14 @@ extern void png_do_write_interlace PNGARG((png_row_infop row_info, #endif /* unfilter a row */ -extern void png_read_filter_row PNGARG((png_row_infop row_info, - png_bytep row, png_bytep prev_row, int filter)); -/* filter a row, and place the correct filter byte in the row */ -extern void png_write_filter_row PNGARG((png_row_infop row_info, - png_bytep row, png_bytep prev_row)); +extern void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); +/* choose the best filter to use and filter the row data */ +extern void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); +/* write out the filtered row */ +extern void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); /* finish a row while reading, dealing with interlacing passes, etc. */ extern void png_read_finish_row PNGARG((png_structp png_ptr)); /* initialize the row buffers, etc. */ @@ -1163,6 +1179,11 @@ extern void png_do_dither PNGARG((png_row_infop row_info, png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); #endif +#if defined(PNG_CORRECT_PALETTE_SUPPORTED) +extern void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +#endif + #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) extern void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); #endif @@ -1289,13 +1310,13 @@ extern void png_push_fill_buffer PNGARG((png_structp png_ptr, png_bytep buffer, extern void png_push_save_buffer PNGARG((png_structp png_ptr)); extern void png_push_restore_buffer PNGARG((png_structp png_ptr, png_bytep buffer, png_uint_32 buffer_length)); -extern void png_push_read_idat PNGARG((png_structp png_ptr)); +extern void png_push_read_IDAT PNGARG((png_structp png_ptr)); extern void png_process_IDAT_data PNGARG((png_structp png_ptr, png_bytep buffer, png_uint_32 buffer_length)); extern void png_push_process_row PNGARG((png_structp png_ptr)); extern void png_push_handle_PLTE PNGARG((png_structp png_ptr, png_uint_32 length)); -extern void png_push_read_plte PNGARG((png_structp png_ptr, png_infop info)); +extern void png_push_read_PLTE PNGARG((png_structp png_ptr, png_infop info)); extern void png_push_handle_tRNS PNGARG((png_structp png_ptr, png_infop info, png_uint_32 length)); extern void png_push_handle_hIST PNGARG((png_structp png_ptr, png_infop info, @@ -1310,12 +1331,12 @@ extern void png_read_push_finish_row PNGARG((png_structp png_ptr)); #if defined(PNG_READ_tEXt_SUPPORTED) extern void png_push_handle_tEXt PNGARG((png_structp png_ptr, png_uint_32 length)); -extern void png_push_read_text PNGARG((png_structp png_ptr, png_infop info)); +extern void png_push_read_tEXt PNGARG((png_structp png_ptr, png_infop info)); #endif #if defined(PNG_READ_zTXt_SUPPORTED) extern void png_push_handle_zTXt PNGARG((png_structp png_ptr, png_uint_32 length)); -extern void png_push_read_ztxt PNGARG((png_structp png_ptr, png_infop info)); +extern void png_push_read_zTXt PNGARG((png_structp png_ptr, png_infop info)); #endif #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/pngchang.txt b/pngchang.txt index 54245135..8fc0956f 100644 --- a/pngchang.txt +++ b/pngchang.txt @@ -74,3 +74,30 @@ version 0.88 fixed progressive bugs replaced tabs with spaces cleaned up documentation + added callbacks for read/write and warning/error functions +version 0.89 + added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + optimized filter selection code + fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) + fixed bug with Borland 64K memory allocation (Alexander Lehmann) + fixed bug in interlace handling (Smaraderagd, I think) + added more error checking for writing and image to reduce invalid files + separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + new pngtest image also has interlacing and zTXt + updated dcumentation to reflect new API diff --git a/pngconf.h b/pngconf.h index 60bad864..35b5b967 100644 --- a/pngconf.h +++ b/pngconf.h @@ -1,10 +1,10 @@ /* pngconf.c - machine configurable file for libpng - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ /* Any machine specific code is near the front of this file, so if you @@ -78,7 +78,7 @@ #endif /* PNGARG */ /* enough people need this for various reasons to include it here */ -#ifndef MACOS +#if !defined(MACOS) && !defined(RISCOS) #include #endif /* need the time information for reading tIME chunks */ @@ -179,6 +179,7 @@ #define PNG_READ_FILLER_SUPPORTED #define PNG_READ_GAMMA_SUPPORTED #define PNG_READ_GRAY_TO_RGB_SUPPORTED +#undef PNG_CORRECT_PALETTE_SUPPORTED #define PNG_WRITE_INTERLACING_SUPPORTED #define PNG_WRITE_SHIFT_SUPPORTED diff --git a/pngerror.c b/pngerror.c index bc3f324a..0e286ae4 100644 --- a/pngerror.c +++ b/pngerror.c @@ -1,22 +1,27 @@ /* pngerror.c - stub functions for i/o and memory allocation - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 This file provides a location for all error handling. Users which need special error handling are expected to write replacement functions - and use png_set_message_fn() to use those functions. See the instructions + and use png_set_error_fn() to use those functions. See the instructions at each function. */ #define PNG_INTERNAL #include "png.h" +static void png_default_error PNGARG((png_structp png_ptr, + png_const_charp message)); +static void png_default_warning PNGARG((png_structp png_ptr, + png_const_charp message)); + /* This function is called whenever there is a fatal error. This function should not be changed. If there is a need to handle errors differently, - you should supply a replacement error function and use png_set_message_fn() + you should supply a replacement error function and use png_set_error_fn() to replace the error function at run-time. */ void png_error(png_structp png_ptr, png_const_charp message) @@ -32,7 +37,7 @@ png_error(png_structp png_ptr, png_const_charp message) /* This function is called whenever there is a non-fatal error. This function should not be changed. If there is a need to handle warnings differently, you should supply a replacement warning function and use - png_set_message_fn() to replace the warning function at run-time. */ + png_set_error_fn() to replace the warning function at run-time. */ void png_warning(png_structp png_ptr, png_const_charp message) { @@ -45,8 +50,8 @@ png_warning(png_structp png_ptr, png_const_charp message) /* This is the default error handling function. Note that replacements for this function MUST NOT RETURN, or the program will likely crash. This function is used by default, or if the program supplies NULL for the - error function pointer in png_set_message_fn(). */ -void + error function pointer in png_set_error_fn(). */ +static void png_default_error(png_structp png_ptr, png_const_charp message) { #ifndef PNG_NO_STDIO @@ -68,7 +73,7 @@ png_default_error(png_structp png_ptr, png_const_charp message) it can continue anyway. Replacement functions don't have to do anything here if you don't want to. In the default configuration, png_ptr is not used, but it is passed in case it may be useful. */ -void +static void png_default_warning(png_structp png_ptr, png_const_charp message) { if (!png_ptr) @@ -81,27 +86,25 @@ png_default_warning(png_structp png_ptr, png_const_charp message) /* This function is called when the application wants to use another method of handling errors and warnings. Note that the error function MUST NOT - return to the calling routine or serious problems will occur. The error - return method used in the default routine calls - longjmp(png_ptr->jmpbuf, 1) */ + return to the calling routine or serious problems will occur. The return + method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) */ void -png_set_message_fn(png_structp png_ptr, png_voidp msg_ptr, png_msg_ptr error_fn, - png_msg_ptr warning_fn) +png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) { - png_ptr->msg_ptr = msg_ptr; - + png_ptr->error_ptr = error_ptr; png_ptr->error_fn = error_fn; png_ptr->warning_fn = warning_fn; } -/* This function returns a pointer to the msg_ptr associated with the user +/* This function returns a pointer to the error_ptr associated with the user functions. The application should free any memory associated with this pointer before png_write_destroy and png_read_destroy are called. */ png_voidp -png_get_msg_ptr(png_structp png_ptr) +png_get_error_ptr(png_structp png_ptr) { - return png_ptr->msg_ptr; + return png_ptr->error_ptr; } diff --git a/pngio.c b/pngio.c deleted file mode 100644 index 3dc4451b..00000000 --- a/pngio.c +++ /dev/null @@ -1,318 +0,0 @@ - -/* pngio.c - stub functions for i/o and memory allocation - - libpng 1.0 beta 2 - version 0.88 - For conditions of distribution and use, see copyright notice in png.h - Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 - - This file provides a location for all input/output. Users which need - special handling are expected to write functions which have the same - arguments as these, and perform similar functions, but possibly have - different I/O methods. Note that you shouldn't change these functions, - but rather write replacement functions and then change them at run - time with png_set_write_fn(...) or png_set_read_fn(...), etc */ - -#define PNG_INTERNAL -#include "png.h" - -/* Write the data to whatever output you are using. The default routine - writes to a file pointer. Note that this routine sometimes gets called - with very small lengths, so you should implement some kind of simple - buffering if you are using unbuffered writes. This should never be asked - to write more then 64K on a 16 bit machine. The cast to png_size_t is - there to quiet warnings of certain compilers. */ - -void -png_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - if (png_ptr->write_data_fn) - (*(png_ptr->write_data_fn))(png_ptr, data, length); - else - png_error(png_ptr, "Call to NULL write function"); -} - -/* This is the function which does the actual writing of data. If you are - not writing to a standard C stream, you should create a replacement - write_data function and use it at run time with png_set_write_fn(), rather - than changing the library. */ -#ifndef USE_FAR_KEYWORD -void -png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - png_uint_32 check; - - check = fwrite(data, 1, (png_size_t)length, png_ptr->fp); - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} -#else -/* this is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -#ifdef _MSC_VER -/* for FP_OFF */ -#include -#endif - -void -png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - png_uint_32 check; - png_byte *n_data; - - /* Check if data really is near. If so, use usual code. */ -#ifdef _MSC_VER - /* do it this way just to quiet warning */ - FP_OFF(n_data) = FP_OFF(data); - if (FP_SEG(n_data) == FP_SEG(data)) -#else - /* this works in MSC also but with lost segment warning */ - n_data = (png_byte *)data; - if ((png_bytep)n_data == data) -#endif - { - check = fwrite(n_data, 1, (png_size_t)length, png_ptr->fp); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = (png_size_t)length; - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* copy far buffer to near buffer */ - err = fwrite(buf, 1, written, png_ptr->fp); - if (err != written) - break; - else - check += err; - data += written; - remaining -= written; - } - while (remaining != 0); - } - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} - -#endif - -/* Read the data from whatever input you are using. The default routine - reads from a file pointer. Note that this routine sometimes gets called - with very small lengths, so you should implement some kind of simple - buffering if you are using unbuffered reads. This should never be asked - to read more then 64K on a 16 bit machine. The cast to png_size_t is - there to quiet some compilers */ -void -png_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - if (png_ptr->read_mode == PNG_READ_PUSH_MODE) - { - png_push_fill_buffer(png_ptr, data, length); - } - else -#endif - { - if (png_ptr->read_data_fn) - (*(png_ptr->read_data_fn))(png_ptr, data, length); - else - png_error(png_ptr, "Call to NULL read function"); - } -} - -/* This is the function which does the actual reading of data. If you are - not reading from a standard C stream, you should create a replacement - read_data function and use it at run time with png_set_read_fn(), rather - than changing the library. */ -#ifndef USE_FAR_KEYWORD -void -png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - png_uint_32 check; - - check = fread(data, 1, (size_t)length, png_ptr->fp); - if (check != length) - { - png_error(png_ptr, "Read Error"); - } -} -#else -void -png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - png_uint_32 check; - png_byte *n_data; - - /* Check if data really is near. If so, use usual code. */ -#ifdef _MSC_VER - /* do it this way just to quiet warning */ - FP_OFF(n_data) = FP_OFF(data); - if (FP_SEG(n_data) == FP_SEG(data)) -#else - /* this works in MSC also but with lost segment warning */ - n_data = (png_byte *)data; - if ((png_bytep)n_data == data) -#endif - { - check = fread(n_data, 1, (size_t)length, png_ptr->fp); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = (png_size_t)length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - err = fread(buf, 1, read, png_ptr->fp); - png_memcpy(data, buf, read); /* copy far buffer to near buffer */ - if(err != read) - break; - else - check += err; - data += read; - remaining -= read; - } - while (remaining != 0); - } - if (check != length) - { - png_error(png_ptr, "read Error"); - } -} -#endif - -/* This function is called to output any data pending writing (normally - to disk. After png_flush is called, there should be no data pending - writing in any buffers. */ -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -void -png_flush(png_structp png_ptr) -{ - if (png_ptr->output_flush_fn) - (*(png_ptr->output_flush_fn))(png_ptr); -} - -void -png_default_flush(png_structp png_ptr) -{ - if (png_ptr->fp) - fflush(png_ptr->fp); -} -#endif - -/* This function allows the application to supply new output functions for - libpng if standard C streams aren't being used. - - This function takes as its arguments: - png_ptr - pointer to a png output data structure - io_ptr - pointer to user supplied structure containing info about - the output functions. May be NULL. - write_data_fn - pointer to a new output function which takes as its - arguments a pointer to a png_struct, a pointer to - data to be written, and a 32-bit unsigned int which is - the number of bytes to be written. The new write - function should call png_error(png_ptr, "Error msg") - to exit and output any fatal error messages. - flush_data_fn - pointer to a new flush function which takes as its - arguments a pointer to a png_struct. After a call to - the flush function, there should be no data in any buffers - or pending transmission. If the output method doesn't do - any buffering of ouput, a function prototype must still be - supplied although it doesn't have to do anything. If - PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile - time, output_flush_fn will be ignored, although it must be - supplied for compatibility. */ -void -png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, - png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) -{ - png_ptr->io_ptr = io_ptr; - - if (write_data_fn) - png_ptr->write_data_fn = write_data_fn; - else - png_ptr->write_data_fn = png_default_write_data; - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - if (output_flush_fn) - png_ptr->output_flush_fn = output_flush_fn; - else - png_ptr->output_flush_fn = png_default_flush; -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - - /* It is an error to read while writing a png file */ - png_ptr->read_data_fn = NULL; -} - - -/* This function allows the application to supply a new input function - for libpng if standard C streams aren't being used. - - This function takes as its arguments: - png_ptr - pointer to a png input data structure - io_ptr - pointer to user supplied structure containing info about - the input functions. May be NULL. - read_data_fn - pointer to a new input function which takes as it's - arguments a pointer to a png_struct, a pointer to - a location where input data can be stored, and a 32-bit - unsigned int which is the number of bytes to be read. - To exit and output any fatal error messages the new write - function should call png_error(png_ptr, "Error msg"). */ -void -png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn) -{ - png_ptr->io_ptr = io_ptr; - - if (read_data_fn) - png_ptr->read_data_fn = read_data_fn; - else - png_ptr->read_data_fn = png_default_read_data; - - /* It is an error to write to a read device */ - png_ptr->write_data_fn = NULL; - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_ptr->output_flush_fn = NULL; -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ -} - - -/* This function returns a pointer to the io_ptr associated with the user - functions. The application should free any memory associated with this - pointer before png_write_destroy and png_read_destroy are called. */ -png_voidp -png_get_io_ptr(png_structp png_ptr) -{ - return png_ptr->io_ptr; -} - -/* Initialize the default input/output functions for the png file. If you - change the read, or write routines, you can call either png_set_read_fn() - or png_set_write_fn() instead of png_init_io(). */ -void -png_init_io(png_structp png_ptr, FILE *fp) -{ - png_ptr->fp = fp; - png_ptr->read_data_fn = png_default_read_data; - png_ptr->write_data_fn = png_default_write_data; -#ifdef PNG_WRITE_FLUSH_SUPPORTED - png_ptr->output_flush_fn = png_default_flush; -#endif -} - diff --git a/pngmem.c b/pngmem.c index 63200fd6..d3fc9917 100644 --- a/pngmem.c +++ b/pngmem.c @@ -1,10 +1,10 @@ /* pngmem.c - stub functions for memory allocation - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 This file provides a location for all memory allocation. Users which need special memory handling are expected to modify the code in this file @@ -17,6 +17,39 @@ #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) /* if you change this, be sure to change the one in png.h also */ +/* Allocate memory for a png_struct. The malloc and memset can be replaced + * by a single call to calloc() if this is thought to improve performance. + */ +png_voidp +png_create_struct(uInt type) +{ + png_size_t type; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = sizeof(png_struct); + else + return (png_voidp)NULL; + + if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL) + { + png_memset(struct_ptr, 0, size); + } + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void +png_destroy_struct(png_voidp struct_ptr) +{ + if (struct_ptr) + farfree (struct_ptr); +} + /* Allocate memory. For reasonable files, size should never exceed 64K. However, zlib may allocate more then 64K if you don't tell it not to. See zconf.h and png.h for more information. zlib does @@ -27,7 +60,9 @@ It gives you a segment with an offset of 8 (perhaps to store it's memory stuff). zlib doesn't like this at all, so we have to detect and deal with it. This code should not be needed in - Windows or OS/2 modes, and only in 16 bit mode. + Windows or OS/2 modes, and only in 16 bit mode. This code has + been updated by Alexander Lehmann for version 0.89 to waste less + memory. */ png_voidp @@ -35,7 +70,7 @@ png_large_malloc(png_structp png_ptr, png_uint_32 size) { png_voidp ret; if (!png_ptr || !size) - return ((voidp)0); + return ((voidp)NULL); #ifdef PNG_MAX_MALLOC_64K if (size > (png_uint_32)65536L) @@ -58,7 +93,7 @@ png_large_malloc(png_structp png_ptr, png_uint_32 size) if (ret) farfree(ret); - ret = 0; + ret = NULL; num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); if (num_blocks < 1) @@ -68,7 +103,7 @@ png_large_malloc(png_structp png_ptr, png_uint_32 size) else num_blocks++; - total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks; + total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; table = farmalloc(total_size); @@ -77,27 +112,25 @@ png_large_malloc(png_structp png_ptr, png_uint_32 size) png_error(png_ptr, "Out of Memory"); } - if ((long)table & 0xffff) + if ((long)table & 0xfff0) { - farfree(table); - total_size += (png_uint_32)65536L; - } - - table = farmalloc(total_size); - - if (!table) - { - png_error(png_ptr, "Out of Memory"); + png_error(png_ptr, "Farmalloc didn't return normalized pointer"); } png_ptr->offset_table = table; png_ptr->offset_table_ptr = farmalloc( num_blocks * sizeof (png_bytep)); - hptr = (png_byte huge *)table; - if ((long)hptr & 0xffff) + + if (!png_ptr->offset_table_ptr) { - hptr = (png_byte huge *)((long)(hptr) & 0xffff0000L); - hptr += 65536L; + png_error(png_ptr, "Out of memory"); + } + + hptr = (png_byte huge *)table; + if ((long)hptr & 0xf) + { + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr += 16L; } for (i = 0; i < num_blocks; i++) { @@ -109,12 +142,12 @@ png_large_malloc(png_structp png_ptr, png_uint_32 size) png_ptr->offset_table_count = 0; png_ptr->offset_table_count_free = 0; } - - if (png_ptr->offset_table_count >= png_ptr->offset_table_number) - png_error(png_ptr, "Out of Memory"); - - ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; } + + if (png_ptr->offset_table_count >= png_ptr->offset_table_number) + png_error(png_ptr, "Out of Memory"); + + ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; } else ret = farmalloc(size); @@ -167,13 +200,63 @@ png_large_free(png_structp png_ptr, png_voidp ptr) #else /* Not the Borland DOS special memory handler */ +/* Allocate memory for a png_struct or a png_info. The malloc and + * memset can be replaced by a single call to calloc() if this is thought + * to improve performance noticably. + */ +png_voidp +png_create_struct(uInt type) +{ + size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = sizeof(png_struct); + else + return (png_voidp)NULL; + +#if defined(__TURBOC__) && !defined(__FLAT__) + if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL) +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + if ((struct_ptr = (png_voidp)halloc(size)) != NULL) +# else + if ((struct_ptr = (png_voidp)malloc(size)) != NULL) +# endif +#endif + { + png_memset(struct_ptr, 0, size); + } + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void +png_destroy_struct(png_voidp struct_ptr) +{ + if (struct_ptr) +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(struct_ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(struct_ptr); +# else + free(struct_ptr); +# endif +#endif +} + + /* Allocate memory. For reasonable files, size should never exceed 64K. However, zlib may allocate more then 64K if you don't tell it not to. See zconf.h and png.h for more information. zlib does need to allocate exactly 64K, so whatever you call here must have the ability to do that. */ - png_voidp png_large_malloc(png_structp png_ptr, png_uint_32 size) { @@ -300,4 +383,3 @@ png_free(png_structp png_ptr, void * ptr) free(ptr); } - diff --git a/pngpread.c b/pngpread.c index facea6c7..bcac0eaf 100644 --- a/pngpread.c +++ b/pngpread.c @@ -1,10 +1,10 @@ /* pngpread.c - read a png file in push mode - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -41,25 +41,25 @@ png_process_some_data(png_structp png_ptr, png_infop info) } case PNG_READ_IDAT_MODE: { - png_push_read_idat(png_ptr); + png_push_read_IDAT(png_ptr); break; } case PNG_READ_PLTE_MODE: { - png_push_read_plte(png_ptr, info); + png_push_read_PLTE(png_ptr, info); break; } #if defined(PNG_READ_tEXt_SUPPORTED) case PNG_READ_tEXt_MODE: { - png_push_read_text(png_ptr, info); + png_push_read_tEXt(png_ptr, info); break; } #endif #if defined(PNG_READ_zTXt_SUPPORTED) case PNG_READ_zTXt_MODE: { - png_push_read_ztxt(png_ptr, info); + png_push_read_zTXt(png_ptr, info); break; } #endif @@ -107,7 +107,7 @@ png_push_read_sig(png_structp png_ptr) void png_push_read_chunk(png_structp png_ptr, png_infop info) { - if (!png_ptr->have_chunk_header) + if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER)) { png_byte chunk_start[8]; @@ -120,7 +120,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) png_push_fill_buffer(png_ptr, chunk_start, 8); png_ptr->push_length = png_get_uint_32(chunk_start); png_memcpy(png_ptr->push_chunk_name, (png_voidp)(chunk_start + 4), 4); - png_ptr->have_chunk_header = 1; + png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER; png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_start + 4, 4); } @@ -128,7 +128,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) if (!png_memcmp(png_ptr->push_chunk_name, png_IHDR, 4)) { if (png_ptr->mode != PNG_BEFORE_IHDR) - png_error(png_ptr, "Out of Place IHDR"); + png_error(png_ptr, "Out of place IHDR"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { @@ -168,7 +168,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } else if (!png_memcmp(png_ptr->push_chunk_name, png_IEND, 4)) { - png_error(png_ptr, "No Image in File"); + png_error(png_ptr, "No image in file"); } #if defined(PNG_READ_gAMA_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_gAMA, 4)) @@ -180,7 +180,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place gAMA"); + png_error(png_ptr, "Out of place gAMA"); png_handle_gAMA(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -196,7 +196,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place sBIT"); + png_error(png_ptr, "Out of place sBIT"); png_handle_sBIT(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -212,7 +212,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place cHRM"); + png_error(png_ptr, "Out of place cHRM"); png_handle_cHRM(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -228,7 +228,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } if (png_ptr->mode != PNG_HAVE_IHDR && png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place tRNS"); + png_error(png_ptr, "Out of place tRNS"); png_handle_tRNS(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -245,7 +245,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) if (png_ptr->mode != PNG_HAVE_IHDR && png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place bKGD"); + png_error(png_ptr, "Out of place bKGD"); png_handle_bKGD(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -261,7 +261,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) } if (png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place hIST"); + png_error(png_ptr, "Out of place hIST"); png_handle_hIST(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -278,7 +278,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) if (png_ptr->mode != PNG_HAVE_IHDR && png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place pHYs"); + png_error(png_ptr, "Out of place pHYs"); png_handle_pHYs(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -295,7 +295,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) if (png_ptr->mode != PNG_HAVE_IHDR && png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place oFFs"); + png_error(png_ptr, "Out of place oFFs"); png_handle_oFFs(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -312,7 +312,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tIME"); + png_error(png_ptr, "Out of place tIME"); png_handle_tIME(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -323,7 +323,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) { if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tEXt"); + png_error(png_ptr, "Out of place tEXt"); png_push_handle_tEXt(png_ptr, png_ptr->push_length); } @@ -333,19 +333,43 @@ png_push_read_chunk(png_structp png_ptr, png_infop info) { if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place zTXt"); + png_error(png_ptr, "Out of place zTXt"); png_push_handle_zTXt(png_ptr, png_ptr->push_length); } #endif else { + if (png_ptr->push_chunk_name[0] <41 || png_ptr->push_chunk_name[0]> 122 || + (png_ptr->push_chunk_name[0]>90 && png_ptr->push_chunk_name[0]< 97) || + png_ptr->push_chunk_name[1] <41 || png_ptr->push_chunk_name[1]> 122 || + (png_ptr->push_chunk_name[1]>90 && png_ptr->push_chunk_name[1]< 97) || + png_ptr->push_chunk_name[2] <41 || png_ptr->push_chunk_name[2]> 122 || + (png_ptr->push_chunk_name[2]>90 && png_ptr->push_chunk_name[2]< 97) || + png_ptr->push_chunk_name[3] <41 || png_ptr->push_chunk_name[3]> 122 || + (png_ptr->push_chunk_name[3]>90 && png_ptr->push_chunk_name[3]< 97)) + { + char msg[200]; + + sprintf(msg, "Invalid chunk type 0x%02X 0x%02X 0x%02X 0x%02X", + png_ptr->push_chunk_name[0], png_ptr->push_chunk_name[1], + png_ptr->push_chunk_name[2], png_ptr->push_chunk_name[3]); + png_error(png_ptr, msg); + } + if ((png_ptr->push_chunk_name[0] & 0x20) == 0) - png_error(png_ptr, "Unknown Critical Chunk"); + { + char msg[200]; + + sprintf(msg, "Unknown critical chunk %c%c%c%c", + png_ptr->push_chunk_name[0], png_ptr->push_chunk_name[1], + png_ptr->push_chunk_name[2], png_ptr->push_chunk_name[3]); + png_error(png_ptr, msg); + } png_push_crc_skip(png_ptr, png_ptr->push_length); } - png_ptr->have_chunk_header = 0; + png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER; } void @@ -513,9 +537,9 @@ png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, } void -png_push_read_idat(png_structp png_ptr) +png_push_read_IDAT(png_structp png_ptr) { - if (!png_ptr->have_chunk_header) + if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER)) { png_byte chunk_start[8]; @@ -529,13 +553,13 @@ png_push_read_idat(png_structp png_ptr) png_ptr->push_length = png_get_uint_32(chunk_start); png_memcpy(png_ptr->push_chunk_name, (png_voidp)(chunk_start + 4), 4); - png_ptr->have_chunk_header = 1; + png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER; png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_start + 4, 4); if (png_memcmp(png_ptr->push_chunk_name, png_IDAT, 4)) { png_ptr->process_mode = PNG_READ_END_MODE; - if (!png_ptr->zlib_finished) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) png_error(png_ptr, "Not enough compressed data"); return; } @@ -585,7 +609,7 @@ png_push_read_idat(png_structp png_ptr) } png_push_check_crc(png_ptr); - png_ptr->have_chunk_header = 0; + png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER; } } @@ -595,7 +619,7 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, { int ret; - if (png_ptr->zlib_finished && buffer_length) + if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length) png_error(png_ptr, "Extra compression data"); png_ptr->zstream->next_in = buffer; @@ -612,11 +636,11 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, png_push_process_row(png_ptr); } png_ptr->mode = PNG_AT_LAST_IDAT; - png_ptr->zlib_finished = 1; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; } if (ret != Z_OK) - png_error(png_ptr, "Compression Error"); + png_error(png_ptr, "Decompression Error"); if (!(png_ptr->zstream->avail_out)) { png_push_process_row(png_ptr); @@ -638,10 +662,9 @@ png_push_process_row(png_structp png_ptr) png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); - if (png_ptr->row_buf[0]) - png_read_filter_row(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); png_memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1); @@ -811,7 +834,7 @@ void png_push_handle_PLTE(png_structp png_ptr, png_uint_32 length) { if (length % 3) - png_error(png_ptr, "Invalid Palette Chunk"); + png_error(png_ptr, "Invalid palette chunk"); png_ptr->num_palette = (png_uint_16)(length / 3); png_ptr->cur_palette = 0; @@ -821,7 +844,7 @@ png_push_handle_PLTE(png_structp png_ptr, png_uint_32 length) } void -png_push_read_plte(png_structp png_ptr, png_infop info) +png_push_read_PLTE(png_structp png_ptr, png_infop info) { while (png_ptr->cur_palette < png_ptr->num_palette && png_ptr->buffer_size >= 3) @@ -862,7 +885,7 @@ png_push_handle_tEXt(png_structp png_ptr, png_uint_32 length) } void -png_push_read_text(png_structp png_ptr, png_infop info) +png_push_read_tEXt(png_structp png_ptr, png_infop info) { if (png_ptr->buffer_size && png_ptr->current_text_left) { @@ -931,7 +954,7 @@ png_push_handle_zTXt(png_structp png_ptr, } void -png_push_read_ztxt(png_structp png_ptr, png_infop info) +png_push_read_zTXt(png_structp png_ptr, png_infop info) { if (png_ptr->buffer_size && png_ptr->current_text_left) { @@ -1105,13 +1128,13 @@ png_push_have_row(png_structp png_ptr, png_bytep row) png_voidp png_get_progressive_ptr(png_structp png_ptr) { - return png_ptr->push_ptr; + return png_ptr->io_ptr; } void png_push_read_end(png_structp png_ptr, png_infop info) { - if (!png_ptr->have_chunk_header) + if (!(png_ptr->flags & PNG_FLAG_HAVE_CHUNK_HEADER)) { png_byte chunk_start[8]; @@ -1124,23 +1147,23 @@ png_push_read_end(png_structp png_ptr, png_infop info) png_push_fill_buffer(png_ptr, chunk_start, 8); png_ptr->push_length = png_get_uint_32(chunk_start); png_memcpy(png_ptr->push_chunk_name, (png_voidp)(chunk_start + 4), 4); - png_ptr->have_chunk_header = 1; + png_ptr->flags |= PNG_FLAG_HAVE_CHUNK_HEADER; png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_start + 4, 4); } if (!png_memcmp(png_ptr->push_chunk_name, png_IHDR, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid IHDR after IDAT"); } else if (!png_memcmp(png_ptr->push_chunk_name, png_PLTE, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid PLTE after IDAT"); } else if (!png_memcmp(png_ptr->push_chunk_name, png_IDAT, 4)) { if (png_ptr->push_length > 0 || png_ptr->mode != PNG_AT_LAST_IDAT) - png_error(png_ptr, "too many IDAT's found"); + png_error(png_ptr, "Too many IDAT's found"); } else if (!png_memcmp(png_ptr->push_chunk_name, png_IEND, 4)) { @@ -1159,49 +1182,49 @@ png_push_read_end(png_structp png_ptr, png_infop info) #if defined(PNG_READ_gAMA_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_gAMA, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid gAMA after IDAT"); } #endif #if defined(PNG_READ_sBIT_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_sBIT, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid sBIT after IDAT"); } #endif #if defined(PNG_READ_cHRM_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_cHRM, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid cHRM after IDAT"); } #endif #if defined(PNG_READ_tRNS_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_tRNS, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid tRNS after IDAT"); } #endif #if defined(PNG_READ_bKGD_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_bKGD, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid bKGD after IDAT"); } #endif #if defined(PNG_READ_hIST_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_hIST, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid hIST after IDAT"); } #endif #if defined(PNG_READ_pHYs_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_pHYs, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid pHYs after IDAT"); } #endif #if defined(PNG_READ_oFFs_SUPPORTED) else if (!png_memcmp(png_ptr->push_chunk_name, png_oFFs, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid oFFs after IDAT"); } #endif #if defined(PNG_READ_tIME_SUPPORTED) @@ -1215,7 +1238,7 @@ png_push_read_end(png_structp png_ptr, png_infop info) if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tIME"); + png_error(png_ptr, "Out of place tIME"); png_handle_tIME(png_ptr, info, png_ptr->push_length); png_push_check_crc(png_ptr); @@ -1226,7 +1249,7 @@ png_push_read_end(png_structp png_ptr, png_infop info) { if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tEXt"); + png_error(png_ptr, "Out of place tEXt"); png_push_handle_tEXt(png_ptr, png_ptr->push_length); } @@ -1236,21 +1259,45 @@ png_push_read_end(png_structp png_ptr, png_infop info) { if (png_ptr->mode == PNG_BEFORE_IHDR || png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place zTXt"); + png_error(png_ptr, "Out of place zTXt"); png_push_handle_zTXt(png_ptr, png_ptr->push_length); } #endif else { + if (png_ptr->push_chunk_name[0] <41 || png_ptr->push_chunk_name[0]> 122 || + (png_ptr->push_chunk_name[0]>90 && png_ptr->push_chunk_name[0]< 97) || + png_ptr->push_chunk_name[1] <41 || png_ptr->push_chunk_name[1]> 122 || + (png_ptr->push_chunk_name[1]>90 && png_ptr->push_chunk_name[1]< 97) || + png_ptr->push_chunk_name[2] <41 || png_ptr->push_chunk_name[2]> 122 || + (png_ptr->push_chunk_name[2]>90 && png_ptr->push_chunk_name[2]< 97) || + png_ptr->push_chunk_name[3] <41 || png_ptr->push_chunk_name[3]> 122 || + (png_ptr->push_chunk_name[3]>90 && png_ptr->push_chunk_name[3]< 97)) + { + char msg[45]; + + sprintf(msg, "Invalid chunk type 0x%02X 0x%02X 0x%02X 0x%02X", + png_ptr->push_chunk_name[0], png_ptr->push_chunk_name[1], + png_ptr->push_chunk_name[2], png_ptr->push_chunk_name[3]); + png_error(png_ptr, msg); + } + if ((png_ptr->push_chunk_name[0] & 0x20) == 0) - png_error(png_ptr, "Unknown Critical Chunk"); + { + char msg[40]; + + sprintf(msg, "Unknown critical chunk %c%c%c%c", + png_ptr->push_chunk_name[0], png_ptr->push_chunk_name[1], + png_ptr->push_chunk_name[2], png_ptr->push_chunk_name[3]); + png_error(png_ptr, msg); + } png_push_crc_skip(png_ptr, png_ptr->push_length); } if (png_ptr->mode == PNG_AT_LAST_IDAT) png_ptr->mode = PNG_AFTER_IDAT; - png_ptr->have_chunk_header = 0; + png_ptr->flags &= ~PNG_FLAG_HAVE_CHUNK_HEADER; } void @@ -1260,9 +1307,9 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, { png_ptr->info_fn = info_fn; png_ptr->row_fn = row_fn; - png_ptr->push_ptr = progressive_ptr; png_ptr->end_fn = end_fn; - png_ptr->read_mode = PNG_READ_PUSH_MODE; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); } void diff --git a/pngrcb.c b/pngrcb.c index f2824e49..914a6a1a 100644 --- a/pngrcb.c +++ b/pngrcb.c @@ -1,9 +1,9 @@ /* pngrcb.c - callbacks while reading a png file - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -185,7 +185,7 @@ png_read_tIME(png_structp png_ptr, png_infop info, } #endif -#if defined(PNG_READ_zTXt_SUPPORTED) +#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED) void png_read_zTXt(png_structp png_ptr, png_infop info, png_charp key, png_charp text, png_uint_32 text_len, int compression) @@ -214,10 +214,10 @@ png_read_zTXt(png_structp png_ptr, png_infop info, } else { - info->max_text = info->num_text + 16; + info->max_text = 16; + info->num_text = 0; info->text = (png_textp)png_large_malloc(png_ptr, info->max_text * sizeof (png_text)); - info->num_text = 0; } } diff --git a/pngread.c b/pngread.c index fc618b28..29afd6e2 100644 --- a/pngread.c +++ b/pngread.c @@ -1,45 +1,116 @@ /* pngread.c - read a png file - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL #include "png.h" -/* initialize png structure for reading, and allocate any memory needed */ -void -png_read_init(png_structp png_ptr) +/* Create a png structure for reading, and allocate any memory needed. */ +png_structp +png_create_read_struct(png_const_charp user_png_ver, voidp error_ptr, + png_error_ptr warn_fn, png_error_ptr error_fn) { - jmp_buf tmp_jmp; - png_msg_ptr error_fn; - png_msg_ptr warning_fn; - png_voidp msg_ptr; + png_structp png_ptr; - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); - error_fn = png_ptr->error_fn; - warning_fn = png_ptr->warning_fn; - msg_ptr = png_ptr->msg_ptr; + if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL) + { + return (png_structp)NULL; + } - png_memset(png_ptr, 0, sizeof (png_struct)); + if (setjmp(png_ptr->jmpbuf)) + { + png_large_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->zstream); + png_destroy_struct(png_ptr); + return (png_structp)NULL; + } - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; - png_ptr->msg_ptr = msg_ptr; + png_set_error_fn(png_ptr, error_ptr, warn_fn, error_fn); + if (user_png_ver == NULL || strcmp(user_png_ver, png_libpng_ver)) + { + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0]) + { + png_error(png_ptr, "Incompatible libpng versions"); + } + else + { + png_warning(png_ptr, "Different libpng versions"); + } + } + + /* initialize zbuf - compression buffer */ png_ptr->zbuf_size = PNG_ZBUF_SIZE; png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size); + png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream)); png_ptr->zstream->zalloc = png_zalloc; png_ptr->zstream->zfree = png_zfree; png_ptr->zstream->opaque = (voidpf)png_ptr; - inflateInit(png_ptr->zstream); + + switch (inflateInit(png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + png_ptr->zstream->next_out = png_ptr->zbuf; png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, NULL, NULL); + + png_ptr->do_free |= PNG_FREE_STRUCT; + + return (png_ptr); +} + + +/* initialize png structure for reading, and allocate any memory needed */ +/* This interface is depreciated in favour of the png_create_read_struct() */ +void +png_read_init(png_structp png_ptr) +{ + jmp_buf tmp_jmp; /* to save current jump buffer */ + + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, sizeof (png_struct)); + + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size); + + png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream)); + png_ptr->zstream->zalloc = png_zalloc; + png_ptr->zstream->zfree = png_zfree; + png_ptr->zstream->opaque = (voidpf)png_ptr; + + switch (inflateInit(png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream->next_out = png_ptr->zbuf; + png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, NULL, NULL); } /* read the information before the actual image data. */ @@ -50,8 +121,13 @@ png_read_info(png_structp png_ptr, png_infop info) png_uint_32 length; png_read_data(png_ptr, chunk_start, 8); - if (png_memcmp(chunk_start, png_sig, 8)) - png_error(png_ptr, "Not a Png File"); + if (!png_check_sig(chunk_start, 8)) + { + if (!png_check_sig(chunk_start, 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } while (1) { @@ -62,167 +138,110 @@ png_read_info(png_structp png_ptr, png_infop info) png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_start + 4, 4); if (!png_memcmp(chunk_start + 4, png_IHDR, 4)) - { - if (png_ptr->mode != PNG_BEFORE_IHDR) - png_error(png_ptr, "Out of Place IHDR"); - png_handle_IHDR(png_ptr, info, length); - png_ptr->mode = PNG_HAVE_IHDR; - } else if (!png_memcmp(chunk_start + 4, png_PLTE, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Missing IHDR"); - -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - png_crc_skip(png_ptr, length); - else -#else - { - png_handle_PLTE(png_ptr, info, length); - } -#endif - png_ptr->mode = PNG_HAVE_PLTE; - } + png_handle_PLTE(png_ptr, info, length); else if (!png_memcmp(chunk_start + 4, png_IDAT, 4)) { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + png_ptr->idat_size = length; - png_ptr->mode = PNG_HAVE_IDAT; + png_ptr->mode |= PNG_HAVE_IDAT; break; } else if (!png_memcmp(chunk_start + 4, png_IEND, 4)) - { - png_error(png_ptr, "No Image in File"); - } + png_error(png_ptr, "No image in file"); #if defined(PNG_READ_gAMA_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_gAMA, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place PLTE"); - png_handle_gAMA(png_ptr, info, length); - } #endif #if defined(PNG_READ_sBIT_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_sBIT, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place sBIT"); - png_handle_sBIT(png_ptr, info, length); - } #endif #if defined(PNG_READ_cHRM_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_cHRM, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR) - png_error(png_ptr, "Out of Place cHRM"); - png_handle_cHRM(png_ptr, info, length); - } #endif #if defined(PNG_READ_tRNS_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_tRNS, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR && - png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place tRNS"); - png_handle_tRNS(png_ptr, info, length); - } #endif #if defined(PNG_READ_bKGD_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_bKGD, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR && - png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place bKGD"); - png_handle_bKGD(png_ptr, info, length); - } #endif #if defined(PNG_READ_hIST_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_hIST, 4)) - { - if (png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place hIST"); - png_handle_hIST(png_ptr, info, length); - } #endif #if defined(PNG_READ_pHYs_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_pHYs, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR && - png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place pHYs"); - png_handle_pHYs(png_ptr, info, length); - } #endif #if defined(PNG_READ_oFFs_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_oFFs, 4)) - { - if (png_ptr->mode != PNG_HAVE_IHDR && - png_ptr->mode != PNG_HAVE_PLTE) - png_error(png_ptr, "Out of Place oFFs"); - png_handle_oFFs(png_ptr, info, length); - } #endif #if defined(PNG_READ_tIME_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_tIME, 4)) - { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tIME"); - png_handle_tIME(png_ptr, info, length); - } #endif #if defined(PNG_READ_tEXt_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_tEXt, 4)) - { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tEXt"); - png_handle_tEXt(png_ptr, info, length); - } #endif #if defined(PNG_READ_zTXt_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_zTXt, 4)) - { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place zTXt"); - png_handle_zTXt(png_ptr, info, length); - } #endif else { + if (chunk_start[4] < 41 || chunk_start[4] > 122 || + (chunk_start[4] > 90 && chunk_start[4] < 97) || + chunk_start[5] < 41 || chunk_start[5] > 122 || + (chunk_start[5] > 90 && chunk_start[5] < 97) || + chunk_start[6] < 41 || chunk_start[6] > 122 || + (chunk_start[6] > 90 && chunk_start[6] < 97) || + chunk_start[7] < 41 || chunk_start[7] > 122 || + (chunk_start[7] > 90 && chunk_start[7] < 97)) + { + char msg[45]; + + sprintf(msg, "Invalid chunk type 0x%02X 0x%02X 0x%02X 0x%02X", + chunk_start[4], chunk_start[5], chunk_start[6], chunk_start[7]); + png_error(png_ptr, msg); + } + if ((chunk_start[4] & 0x20) == 0) - png_error(png_ptr, "Unknown Critical Chunk"); + { + char msg[40]; + + sprintf(msg, "Unknown critical chunk %c%c%c%c", + chunk_start[4], chunk_start[5], chunk_start[6], chunk_start[7]); + png_error(png_ptr, msg); + } png_crc_skip(png_ptr, length); } png_read_data(png_ptr, chunk_start, 4); crc = png_get_uint_32(chunk_start); - if (((crc ^ 0xffffffffL) & 0xffffffffL) != - (png_ptr->crc & 0xffffffffL)) + if (((crc ^ 0xffffffffL) & 0xffffffffL) != (png_ptr->crc & 0xffffffffL)) png_error(png_ptr, "Bad CRC value"); } } /* optional call to update the users info structure */ void -png_read_update_info(png_structp png_ptr, png_infop info_ptr) +png_read_update_info(png_structp png_ptr, png_infop info) { - if (!(png_ptr->row_init)) + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); - png_read_transform_info(png_ptr, info_ptr); + png_read_transform_info(png_ptr, info); } /* initialize palette, background, etc, after transformations @@ -232,7 +251,7 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr) void png_start_read_image(png_structp png_ptr) { - if (!(png_ptr->row_init)) + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); } @@ -240,7 +259,7 @@ void png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) { int ret; - if (!(png_ptr->row_init)) + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); #if defined(PNG_READ_INTERLACING_SUPPORTED) @@ -320,8 +339,8 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - if (png_ptr->mode != PNG_HAVE_IDAT) - png_error(png_ptr, "invalid attempt to read row data"); + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); png_ptr->zstream->next_out = png_ptr->row_buf; png_ptr->zstream->avail_out = (uInt)png_ptr->irowbytes; @@ -346,8 +365,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) png_crc_read(png_ptr, buf, 4); if (png_memcmp(buf, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - + png_error(png_ptr, "Not enough IDATs for image"); } png_ptr->zstream->avail_in = (uInt)png_ptr->zbuf_size; png_ptr->zstream->next_in = png_ptr->zbuf; @@ -362,17 +380,15 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) if (png_ptr->zstream->avail_out || png_ptr->zstream->avail_in || png_ptr->idat_size) png_error(png_ptr, "Extra compressed data"); - png_ptr->mode = PNG_AT_LAST_IDAT; + png_ptr->mode |= PNG_AT_LAST_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; } if (ret != Z_OK) - png_error(png_ptr, "Compression Error"); - + png_error(png_ptr, png_ptr->zstream->msg ? png_ptr->zstream->msg : + "Decompression error"); } while (png_ptr->zstream->avail_out); - if (ret == Z_STREAM_END) - png_ptr->zlib_finished = 1; - png_ptr->row_info.color_type = png_ptr->color_type; png_ptr->row_info.width = png_ptr->iwidth; png_ptr->row_info.channels = png_ptr->channels; @@ -381,10 +397,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); - if (png_ptr->row_buf[0]) - png_read_filter_row(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); png_memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1); @@ -471,9 +486,12 @@ png_read_rows(png_structp png_ptr, png_bytepp row, /* read the image. If the image has an alpha channel or a transparency chunk, and you have called png_handle_alpha(), you will need to initialize the image to the current image that png will be overlaying. - Note that png_set_interlace_handling() has no effect on this call. - You only need to call this function once. If you desire to have - an image for each pass of a interlaced image, use png_read_rows() */ + We set the num_rows again here, in case it was incorrectly set in + png_read_start_row() by a call to png_read_update_info() or + png_start_read_image() if png_set_interlace_handling() wasn't called + prior to either of these functions like it should have been. You only + need to call this function once. If you desire to have an image for + each pass of a interlaced image, use png_read_rows() instead */ void png_read_image(png_structp png_ptr, png_bytepp image) { @@ -482,6 +500,9 @@ png_read_image(png_structp png_ptr, png_bytepp image) png_bytepp rp; pass = png_set_interlace_handling(png_ptr); + + png_ptr->num_rows = png_ptr->height; /* Make sure this is set correctly */ + for (j = 0; j < pass; j++) { rp = image; @@ -518,55 +539,53 @@ png_read_end(png_structp png_ptr, png_infop info) if (!png_memcmp(chunk_start + 4, png_IHDR, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid IHDR after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_PLTE, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid PLTE after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_gAMA, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid gAMA after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_sBIT, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid sBIT after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_cHRM, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid cHRM after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_tRNS, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid tRNS after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_bKGD, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid bKGD after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_hIST, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid hIST after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_IDAT, 4)) { - if (length > 0 || png_ptr->mode != PNG_AT_LAST_IDAT) - png_error(png_ptr, "too many IDAT's found"); + if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); } else if (!png_memcmp(chunk_start + 4, png_pHYs, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid pHYs after IDAT"); } else if (!png_memcmp(chunk_start + 4, png_oFFs, 4)) { - png_error(png_ptr, "invalid chunk after IDAT"); + png_error(png_ptr, "Invalid oFFs after IDAT"); } #if defined(PNG_READ_tIME_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_tIME, 4)) { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tIME"); + png_ptr->mode |= PNG_AFTER_IDAT; if (info) png_handle_tIME(png_ptr, info, length); @@ -577,9 +596,7 @@ png_read_end(png_structp png_ptr, png_infop info) #if defined(PNG_READ_tEXt_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_tEXt, 4)) { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place tEXt"); + png_ptr->mode |= PNG_AFTER_IDAT; if (info) png_handle_tEXt(png_ptr, info, length); @@ -590,9 +607,7 @@ png_read_end(png_structp png_ptr, png_infop info) #if defined(PNG_READ_zTXt_SUPPORTED) else if (!png_memcmp(chunk_start + 4, png_zTXt, 4)) { - if (png_ptr->mode == PNG_BEFORE_IHDR || - png_ptr->mode == PNG_AFTER_IEND) - png_error(png_ptr, "Out of Place zTXt"); + png_ptr->mode |= PNG_AFTER_IDAT; if (info) png_handle_zTXt(png_ptr, info, length); @@ -602,31 +617,83 @@ png_read_end(png_structp png_ptr, png_infop info) #endif else if (!png_memcmp(chunk_start + 4, png_IEND, 4)) { - png_ptr->mode = PNG_AFTER_IEND; + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->mode |= PNG_AFTER_IEND; } else { - if ((chunk_start[4] & 0x20) == 0) - png_error(png_ptr, "Unknown Critical Chunk"); + if (chunk_start[4] < 41 || chunk_start[4] > 122 || + (chunk_start[4] > 90 && chunk_start[4] < 97) || + chunk_start[5] < 41 || chunk_start[5] > 122 || + (chunk_start[5] > 90 && chunk_start[5] < 97) || + chunk_start[6] < 41 || chunk_start[6] > 122 || + (chunk_start[6] > 90 && chunk_start[6] < 97) || + chunk_start[7] < 41 || chunk_start[7] > 122 || + (chunk_start[7] > 90 && chunk_start[7] < 97)) + { + png_error(png_ptr, "Invalid chunk type"); + } + if ((chunk_start[4] & 0x20) == 0) + png_error(png_ptr, "Unknown critical chunk"); + + png_ptr->mode |= PNG_AFTER_IDAT; png_crc_skip(png_ptr, length); } png_read_data(png_ptr, chunk_start, 4); crc = png_get_uint_32(chunk_start); - if (((crc ^ 0xffffffffL) & 0xffffffffL) != - (png_ptr->crc & 0xffffffffL)) + if (((crc ^ 0xffffffffL) & 0xffffffffL) != (png_ptr->crc & 0xffffffffL)) png_error(png_ptr, "Bad CRC value"); - if (png_ptr->mode == PNG_AT_LAST_IDAT) - png_ptr->mode = PNG_AFTER_IDAT; - } while (png_ptr->mode != PNG_AFTER_IEND); + } while (!(png_ptr->mode & PNG_AFTER_IEND)); } /* free all memory used by the read */ void +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL, end_info = NULL; + + if (png_ptr_ptr) + png_ptr = *png_ptr_ptr; + + if (info_ptr_ptr) + info_ptr = *info_ptr_ptr; + + if (end_info_ptr) + end_info = *end_info_ptr; + + png_read_destroy(png_ptr, info_ptr, end_info); + + if (info_ptr) + { + png_destroy_struct((voidp)info_ptr); + *info_ptr_ptr = (png_infop)NULL; + } + + if (end_info) + { + png_destroy_struct((voidp)end_info); + *end_info_ptr = (png_infop)NULL; + } + + if (png_ptr) + { + png_destroy_struct((voidp)png_ptr); + *png_ptr_ptr = (png_structp)NULL; + } +} + +/* free all memory used by the read (old) */ +void png_read_destroy(png_structp png_ptr, png_infop info, png_infop end_info) { int i; jmp_buf tmp_jmp; + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; if (info) { @@ -712,8 +779,21 @@ png_read_destroy(png_structp png_ptr, png_infop info, png_infop end_info) #ifdef PNG_PROGRESSIVE_READ_SUPPORTED png_large_free(png_ptr, png_ptr->save_buffer); #endif + + /* Save the important info out of the png_struct, in case it is + * being used again. + */ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; + png_memset(png_ptr, 0, sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); } - diff --git a/pngrio.c b/pngrio.c new file mode 100644 index 00000000..facd4310 --- /dev/null +++ b/pngrio.c @@ -0,0 +1,141 @@ + +/* pngrio.c - functions for data input + + libpng 1.0 beta 3 - version 0.89 + For conditions of distribution and use, see copyright notice in png.h + Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + May 25, 1996 + + This file provides a location for all input. Users which need + special handling are expected to write a function which has the same + arguments as this, and perform a similar function, but possibly has + a different input method. Note that you shouldn't change this + function, but rather write a replacement function and then make + libpng use it at run time with png_set_read_fn(...) */ + +#define PNG_INTERNAL +#include "png.h" + +/* Read the data from whatever input you are using. The default routine + reads from a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered reads. This should never be asked + to read more then 64K on a 16 bit machine. The cast to png_size_t is + there to quiet some compilers */ +void +png_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + if (png_ptr->read_data_fn) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL read function"); +} + +/* This is the function which does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void +png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + png_uint_32 check; + + check = fread(data, 1, (size_t)length, (FILE *)png_ptr->io_ptr); + if (check != length) + { + png_error(png_ptr, "Read Error"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +#ifdef _MSC_VER +/* for FP_OFF */ +#include +#endif + +static void +png_default_read_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + png_uint_32 check; + png_byte *n_data; + + /* Check if data really is near. If so, use usual code. */ +#ifdef _MSC_VER + /* do it this way just to quiet warning */ + FP_OFF(n_data) = FP_OFF(data); + if (FP_SEG(n_data) == FP_SEG(data)) +#else + /* this works in MSC also but with lost segment warning */ + n_data = (png_byte *)data; + if ((png_bytep)n_data == data) +#endif + { + check = fread(n_data, 1, (size_t)length, (FILE *)png_ptr->io_ptr); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = (png_size_t)length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + err = fread(buf, 1, read, (FILE *)png_ptr->io_ptr); + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "read Error"); + } +} +#endif + +/* This function allows the application to supply a new input function + for libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png input data structure + io_ptr - pointer to user supplied structure containing info about + the input functions. May be NULL. + read_data_fn - pointer to a new input function which takes as it's + arguments a pointer to a png_struct, a pointer to + a location where input data can be stored, and a 32-bit + unsigned int which is the number of bytes to be read. + To exit and output any fatal error messages the new write + function should call png_error(png_ptr, "Error msg"). */ +void +png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + png_ptr->io_ptr = io_ptr; + + if (read_data_fn) + png_ptr->read_data_fn = read_data_fn; + else + png_ptr->read_data_fn = png_default_read_data; + + /* It is an error to write to a read device */ + png_ptr->write_data_fn = NULL; + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->output_flush_fn = NULL; +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ +} + diff --git a/pngrtran.c b/pngrtran.c index e829dc3c..0adf311b 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -1,10 +1,10 @@ /* pngrtran.c - transforms the data in a row for png readers - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -22,7 +22,7 @@ png_set_background(png_structp png_ptr, sizeof(png_color_16)); png_ptr->background_gamma = (float)background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - png_ptr->background_expand = (png_byte)need_expand; + png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); } #endif @@ -353,7 +353,6 @@ png_set_dither(png_structp png_ptr, png_colorp palette, if (!(png_ptr->palette)) { png_ptr->palette = palette; - png_ptr->user_palette = 1; } png_ptr->num_palette = (png_uint_16)num_palette; @@ -468,45 +467,44 @@ png_init_read_transformations(png_structp png_ptr) color_type = png_ptr->color_type; -#if defined(PNG_READ_EXPAND_SUPPORTED) && \ - defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->transformations & PNG_EXPAND) +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) { - if (color_type == PNG_COLOR_TYPE_GRAY && - png_ptr->bit_depth < 8 && - (png_ptr->transformations & PNG_BACKGROUND) && - png_ptr->background_expand) -/* (!(png_ptr->transformations & PNG_BACKGROUND) || - png_ptr->background_expand)) */ + if (color_type == PNG_COLOR_TYPE_GRAY) { - /* expand background chunk. While this may not be - the fastest way to do this, it only happens once - per file. */ + /* expand background chunk. */ switch (png_ptr->bit_depth) { case 1: - png_ptr->background.gray *= (png_byte)0xff; + png_ptr->background.gray *= (png_uint_16)0xff; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; break; case 2: - png_ptr->background.gray *= (png_byte)0x55; + png_ptr->background.gray *= (png_uint_16)0x55; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; break; case 4: - png_ptr->background.gray *= (png_byte)0x11; + png_ptr->background.gray *= (png_uint_16)0x11; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; + break; + case 8: + case 16: + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; break; } } - if (color_type == PNG_COLOR_TYPE_PALETTE && - (png_ptr->transformations & PNG_BACKGROUND) && - png_ptr->background_expand) + else if (color_type == PNG_COLOR_TYPE_PALETTE) { - /* expand background chunk */ - png_ptr->background.red = + png_ptr->background.red = png_ptr->palette[png_ptr->background.index].red; png_ptr->background.green = png_ptr->palette[png_ptr->background.index].green; - png_ptr->background.blue = + png_ptr->background.blue = png_ptr->palette[png_ptr->background.index].blue; - color_type = PNG_COLOR_TYPE_RGB; } } #endif @@ -519,10 +517,71 @@ png_init_read_transformations(png_structp png_ptr) { png_build_gamma_table(png_ptr); #if defined(PNG_READ_BACKGROUND_SUPPORTED) - if ((png_ptr->transformations & PNG_BACKGROUND) && - (color_type != PNG_COLOR_TYPE_PALETTE)) + if (png_ptr->transformations & PNG_BACKGROUND) { - if (png_ptr->background_gamma_type != PNG_BACKGROUND_GAMMA_UNKNOWN) + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + int num_palette, i; + png_color back, back_1; + png_colorp palette; + + palette = png_ptr->palette; + num_palette = png_ptr->num_palette; + + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans[i] != 0xff) + { + int v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + w = (int)(((png_uint_32)(v) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back_1.red) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + w = (int)(((png_uint_32)(v) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back_1.green) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + w = (int)(((png_uint_32)(v) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back_1.blue) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + else if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) { double g, gs, m; @@ -571,7 +630,69 @@ png_init_read_transformations(png_structp png_ptr) } } } + else #endif + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + int num_palette, i; + png_colorp palette; + + palette = png_ptr->palette; + num_palette = png_ptr->num_palette; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND && + color_type == PNG_COLOR_TYPE_PALETTE) + { + int i; + png_color back; + png_colorp palette; + + palette = png_ptr->palette; + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < png_ptr->num_trans; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans[i] != 0xff) + { + palette[i].red = (png_byte)(( + (png_uint_32)(palette[i].red) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back.red) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + palette[i].green = (png_byte)(( + (png_uint_32)(palette[i].green) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back.green) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + palette[i].blue = (png_byte)(( + (png_uint_32)(palette[i].blue) * + (png_uint_32)(png_ptr->trans[i]) + + (png_uint_32)(back.blue) * + (png_uint_32)(255 - png_ptr->trans[i]) + + 127) / 255); + } + } } #endif @@ -769,7 +890,7 @@ png_do_read_transformations(png_structp png_ptr) #if defined(PNG_READ_FILLER_SUPPORTED) if (png_ptr->transformations & PNG_FILLER) png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->filler, png_ptr->filler_loc); + png_ptr->filler, png_ptr->flags); #endif } @@ -1002,14 +1123,14 @@ png_do_chop(png_row_infop row_info, png_bytep row) /* add filler byte */ void png_do_read_filler(png_row_infop row_info, png_bytep row, - png_byte filler, png_byte filler_loc) + png_byte filler, png_byte flags) { png_bytep sp, dp; png_uint_32 i; if (row && row_info && row_info->color_type == 2 && row_info->bit_depth == 8) { - if (filler_loc == PNG_FILLER_AFTER) + if (flags & PNG_FLAG_FILLER_AFTER) { for (i = 1, sp = row + (png_size_t)row_info->width * 3, dp = row + (png_size_t)row_info->width * 4; @@ -1183,32 +1304,28 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette) } } -#if defined(PNG_READ_DITHER_SUPPORTED) +/* This function is currently unused? */ +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_CORRECT_PALETTE_SUPPORTED) void png_correct_palette(png_structp png_ptr, png_colorp palette, int num_palette) { +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) if ((png_ptr->transformations & (PNG_GAMMA)) && (png_ptr->transformations & (PNG_BACKGROUND))) { - if (png_ptr->color_type == 3) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int i; png_color back, back_1; - back.red = png_ptr->gamma_table[png_ptr->palette[ - png_ptr->background.index].red]; - back.green = png_ptr->gamma_table[png_ptr->palette[ - png_ptr->background.index].green]; - back.blue = png_ptr->gamma_table[png_ptr->palette[ - png_ptr->background.index].blue]; + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - back_1.red = png_ptr->gamma_to_1[png_ptr->palette[ - png_ptr->background.index].red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->palette[ - png_ptr->background.index].green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->palette[ - png_ptr->background.index].blue]; + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; for (i = 0; i < num_palette; i++) { @@ -1256,17 +1373,18 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, } else { - int i, back; + int i; + png_color back; - back = png_ptr->gamma_table[png_ptr->background.gray]; + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; for (i = 0; i < num_palette; i++) { if (palette[i].red == png_ptr->trans_values.gray) { - palette[i].red = (png_byte)back; - palette[i].green = (png_byte)back; - palette[i].blue = (png_byte)back; + palette[i] = back; } else { @@ -1277,7 +1395,10 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, } } } - else if (png_ptr->transformations & (PNG_GAMMA)) + else +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & (PNG_GAMMA)) { int i; @@ -1288,25 +1409,30 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, palette[i].blue = png_ptr->gamma_table[palette[i].blue]; } } - else if (png_ptr->transformations & (PNG_BACKGROUND)) +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & (PNG_BACKGROUND)) { - if (png_ptr->color_type == 3) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int i; - png_byte br, bg, bb; + png_color back; - br = palette[png_ptr->background.index].red; - bg = palette[png_ptr->background.index].green; - bb = palette[png_ptr->background.index].blue; + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; for (i = 0; i < num_palette; i++) { if (i >= (int)png_ptr->num_trans || png_ptr->trans[i] == 0) { - palette[i].red = br; - palette[i].green = bg; - palette[i].blue = bb; + palette[i].red = back.red; + palette[i].green = back.green; + palette[i].blue = back.blue; } else if (i < (int)png_ptr->num_trans || png_ptr->trans[i] != 0xff) @@ -1314,19 +1440,19 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, palette[i].red = (png_byte)(( (png_uint_32)(png_ptr->palette[i].red) * (png_uint_32)(png_ptr->trans[i]) + - (png_uint_32)(br) * + (png_uint_32)(back.red) * (png_uint_32)(255 - png_ptr->trans[i]) + 127) / 255); palette[i].green = (png_byte)(( (png_uint_32)(png_ptr->palette[i].green) * (png_uint_32)(png_ptr->trans[i]) + - (png_uint_32)(bg) * + (png_uint_32)(back.green) * (png_uint_32)(255 - png_ptr->trans[i]) + 127) / 255); palette[i].blue = (png_byte)(( (png_uint_32)(png_ptr->palette[i].blue) * (png_uint_32)(png_ptr->trans[i]) + - (png_uint_32)(bb) * + (png_uint_32)(back.blue) * (png_uint_32)(255 - png_ptr->trans[i]) + 127) / 255); } @@ -1340,20 +1466,21 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, { if (i == (int)png_ptr->trans_values.gray) { - palette[i].red = (png_byte)png_ptr->background.gray; - palette[i].green = (png_byte)png_ptr->background.gray; - palette[i].blue = (png_byte)png_ptr->background.gray; + palette[i].red = (png_byte)png_ptr->background.red; + palette[i].green = (png_byte)png_ptr->background.green; + palette[i].blue = (png_byte)png_ptr->background.blue; } } } } +#endif } #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) /* replace any alpha or transparency with the supplied background color. - background is the color (in rgb or grey or palette index, as - appropriate). note that paletted files are taken care of elsewhere */ + background is the color. note that paletted files are taken care of + elsewhere */ void png_do_background(png_row_infop row_info, png_bytep row, png_color_16p trans_values, png_color_16p background, @@ -1364,8 +1491,8 @@ png_do_background(png_row_infop row_info, png_bytep row, { png_bytep sp, dp; png_uint_32 i; - int shift; + if (row && row_info && background && (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || (row_info->color_type != PNG_COLOR_TYPE_PALETTE && @@ -1423,7 +1550,7 @@ png_do_background(png_row_infop row_info, png_bytep row, } case 4: { - sp = row + 1; + sp = row; shift = 4; for (i = 0; i < row_info->width; i++) { @@ -2013,7 +2140,7 @@ png_do_background(png_row_infop row_info, png_bytep row, if (row_info->color_type & PNG_COLOR_MASK_ALPHA) { row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; - row_info->channels -= (png_byte)1; + row_info->channels--; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); row_info->rowbytes = ((row_info->width * diff --git a/pngrutil.c b/pngrutil.c index 41d50b9b..0c9e9dfb 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,10 +1,10 @@ /* pngrutil.c - utilities to read a png file - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -71,6 +71,9 @@ png_handle_IHDR(png_structp png_ptr, png_infop info, png_uint_32 length) int bit_depth, color_type, compression_type, filter_type; int interlace_type; + if (png_ptr->mode != PNG_BEFORE_IHDR) + png_error(png_ptr, "Out of place IHDR"); + /* check the length */ if (length != 13) png_error(png_ptr, "Invalid IHDR chunk"); @@ -87,36 +90,36 @@ png_handle_IHDR(png_structp png_ptr, png_infop info, png_uint_32 length) /* check for width and height valid values */ if (width == 0 || height == 0) - png_error(png_ptr, "Invalid Width or Height Found"); + png_error(png_ptr, "Invalid image size in IHDR"); /* check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8 && bit_depth != 16) - png_error(png_ptr, "Invalid Bit Depth Found"); + png_error(png_ptr, "Invalid bit depth in IHDR"); if (color_type < 0 || color_type == 1 || color_type == 5 || color_type > 6) - png_error(png_ptr, "Invalid Color Type Found"); + png_error(png_ptr, "Invalid color type in IHDR"); if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth == 16) - png_error(png_ptr, "Found Invalid Color Type and Bit Depth Combination"); + png_error(png_ptr, "Invalid color type and bit depth combination in IHDR"); if ((color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8) - png_error(png_ptr, "Found Invalid Color Type and Bit Depth Combination"); + png_error(png_ptr, "Invalid color type and bit depth in IHDR"); if (interlace_type > 1) - png_error(png_ptr, "Found Invalid Interlace Value"); + png_error(png_ptr, "Invalid interlace method in IHDR"); if (compression_type > 0) - png_error(png_ptr, "Found Invalid Compression Value"); + png_error(png_ptr, "Invalid compression method in IHDR"); if (filter_type > 0) - png_error(png_ptr, "Found Invalid Filter Value"); + png_error(png_ptr, "Invalid filter method in IHDR"); /* set internal variables */ png_ptr->width = width; @@ -150,6 +153,8 @@ png_handle_IHDR(png_structp png_ptr, png_infop info, png_uint_32 length) /* call the IHDR callback (which should just set up info) */ png_read_IHDR(png_ptr, info, width, height, bit_depth, color_type, compression_type, filter_type, interlace_type); + + png_ptr->mode |= PNG_HAVE_IHDR; } /* read and check the palette */ @@ -159,8 +164,32 @@ png_handle_PLTE(png_structp png_ptr, png_infop info, png_uint_32 length) int num, i; png_colorp palette; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before PLTE"); + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_error(png_ptr, "Multiple PLTE"); + +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_skip(png_ptr, length); + return; + } +#endif + if (length % 3) - png_error(png_ptr, "Invalid Palette Chunk"); + { + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_warning(png_ptr, "Invalid palette chunk"); + png_crc_skip(png_ptr, length); + return; + } + else + { + png_error(png_ptr, "Invalid palette chunk"); + } + } num = (int)length / 3; palette = (png_colorp)png_large_malloc(png_ptr, num * sizeof (png_color)); @@ -178,6 +207,8 @@ png_handle_PLTE(png_structp png_ptr, png_infop info, png_uint_32 length) png_ptr->palette = palette; png_ptr->num_palette = (png_uint_16)num; png_read_PLTE(png_ptr, info, palette, num); + + png_ptr->mode |= PNG_HAVE_PLTE; } #if defined(PNG_READ_gAMA_SUPPORTED) @@ -188,6 +219,12 @@ png_handle_gAMA(png_structp png_ptr, png_infop info, png_uint_32 length) float gamma; png_byte buf[4]; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before gAMA"); + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place gAMA chunk"); + if (length != 4) { png_warning(png_ptr, "Incorrect gAMA chunk length"); @@ -216,6 +253,12 @@ png_handle_sBIT(png_structp png_ptr, png_infop info, png_uint_32 length) buf[0] = buf[1] = buf[2] = buf[3] = 0; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sBIT chunk"); + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) slen = 3; else @@ -253,6 +296,12 @@ png_handle_cHRM(png_structp png_ptr, png_infop info, png_uint_32 length) png_uint_32 v; float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before cHRM"); + if (length != 32) { png_warning(png_ptr, "Incorrect cHRM chunk length"); @@ -301,9 +350,17 @@ png_handle_cHRM(png_structp png_ptr, png_infop info, png_uint_32 length) void png_handle_tRNS(png_structp png_ptr, png_infop info, png_uint_32 length) { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tRNS"); + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (length > png_ptr->num_palette) + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + else if (length > png_ptr->num_palette) { png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_skip(png_ptr, length); @@ -348,7 +405,11 @@ png_handle_tRNS(png_structp png_ptr, png_infop info, png_uint_32 length) png_ptr->trans_values.gray = png_get_uint_16(buf); } else - png_warning(png_ptr, "Invalid tRNS chunk"); + { + png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); + png_crc_skip(png_ptr, length); + return; + } png_read_tRNS(png_ptr, info, png_ptr->trans, png_ptr->num_trans, &(png_ptr->trans_values)); @@ -362,6 +423,16 @@ png_handle_bKGD(png_structp png_ptr, png_infop info, png_uint_32 length) int truelen; png_byte buf[6]; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before bKGD"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before bKGD"); + png_crc_skip(png_ptr, length); + return; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) truelen = 1; else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) @@ -377,10 +448,24 @@ png_handle_bKGD(png_structp png_ptr, png_infop info, png_uint_32 length) } png_crc_read(png_ptr, buf, length); + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr. */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { png_ptr->background.index = buf[0]; + png_ptr->background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; + } else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + { + png_ptr->background.red = + png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray = png_get_uint_16(buf); + } else { png_ptr->background.red = png_get_uint_16(buf); @@ -398,6 +483,15 @@ png_handle_hIST(png_structp png_ptr, png_infop info, png_uint_32 length) { int num, i; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before hIST"); + else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before hIST"); + png_crc_skip(png_ptr, length); + return; + } + if (length != 2 * png_ptr->num_palette) { png_warning(png_ptr, "Incorrect hIST chunk length"); @@ -428,6 +522,9 @@ png_handle_pHYs(png_structp png_ptr, png_infop info, png_uint_32 length) png_uint_32 res_x, res_y; int unit_type; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pHYS"); + if (length != 9) { png_warning(png_ptr, "Incorrect pHYs chunk length"); @@ -452,6 +549,9 @@ png_handle_oFFs(png_structp png_ptr, png_infop info, png_uint_32 length) png_uint_32 offset_x, offset_y; int unit_type; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before oFFs"); + if (length != 9) { png_warning(png_ptr, "Incorrect oFFs chunk length"); @@ -475,6 +575,9 @@ png_handle_tIME(png_structp png_ptr, png_infop info, png_uint_32 length) png_byte buf[7]; png_time mod_time; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tIME"); + if (length != 7) { png_warning(png_ptr, "Incorrect tIME chunk length"); @@ -503,12 +606,15 @@ png_handle_tEXt(png_structp png_ptr, png_infop info, png_uint_32 length) png_charp key; png_charp text; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tEXt"); + key = (png_charp )png_large_malloc(png_ptr, length + 1); png_crc_read(png_ptr, (png_bytep )key, length); key[(png_size_t)length] = '\0'; for (text = key; *text; text++) - /* empty loop */ ; + /* empty loop to check key length */ ; if (text != key + (png_size_t)length) text++; @@ -518,15 +624,19 @@ png_handle_tEXt(png_structp png_ptr, png_infop info, png_uint_32 length) #endif #if defined(PNG_READ_zTXt_SUPPORTED) -/* note: this does not correctly handle chunks that are > 64K compressed */ +/* note: this does not correctly handle chunks that are > 64K compressed + on those systems that can't malloc more than 64KB at a time. */ void png_handle_zTXt(png_structp png_ptr, png_infop info, png_uint_32 length) { + static char msg[] = "Error decoding zTXt chunk"; png_charp key; png_charp text; - int ret; png_uint_32 text_size, key_size; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before zTXt"); + key = png_large_malloc(png_ptr, length + 1); png_crc_read(png_ptr, (png_bytep )key, length); key[(png_size_t)length] = '\0'; @@ -538,103 +648,108 @@ png_handle_zTXt(png_structp png_ptr, png_infop info, png_uint_32 length) if (text == key + (png_size_t)length) { png_warning(png_ptr, "Zero length zTXt chunk"); - png_large_free(png_ptr, key); - return; + text_size = 0; } - - text++; - - if (*text) /* check compression byte */ + else if (*(++text)) /* check compression type byte */ { - png_large_free(png_ptr, key); - return; + png_warning(png_ptr, "Unknown zTXt compression type"); + + /* Copy what we can of the error message into the text chunk */ + text_size = length - (text - key) - 1; + text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + png_memcpy(text, msg, (png_size_t)(text_size + 1)); } - - text++; - - png_ptr->zstream->next_in = (png_bytep )text; - png_ptr->zstream->avail_in = (uInt)(length - (text - key)); - png_ptr->zstream->next_out = png_ptr->zbuf; - png_ptr->zstream->avail_out = (png_size_t)png_ptr->zbuf_size; - - key_size = text - key; - text_size = 0; - text = NULL; - ret = Z_STREAM_END; - - while (png_ptr->zstream->avail_in) + else { - ret = inflate(png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - if (png_ptr->zstream->msg) - png_warning(png_ptr, png_ptr->zstream->msg); - else - png_warning(png_ptr, "zTXt decompression error"); - inflateReset(png_ptr->zstream); - png_ptr->zstream->avail_in = 0; - png_large_free(png_ptr, key); - png_large_free(png_ptr, text); - return; - } - if (!png_ptr->zstream->avail_out || ret == Z_STREAM_END) - { - if (!text) - { - text = (png_charp)png_large_malloc(png_ptr, - png_ptr->zbuf_size - png_ptr->zstream->avail_out + - key_size + 1); - png_memcpy(text + (png_size_t)key_size, png_ptr->zbuf, - (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out)); - png_memcpy(text, key, (png_size_t)key_size); - text_size = key_size + (png_size_t)png_ptr->zbuf_size - - png_ptr->zstream->avail_out; - *(text + (png_size_t)text_size) = '\0'; - } - else - { - png_charp tmp; + text++; - tmp = text; - text = png_large_malloc(png_ptr, text_size + - png_ptr->zbuf_size - png_ptr->zstream->avail_out + 1); - png_memcpy(text, tmp, (png_size_t)text_size); - png_large_free(png_ptr, tmp); - png_memcpy(text + (png_size_t)text_size, png_ptr->zbuf, - (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out)); - text_size += png_ptr->zbuf_size - png_ptr->zstream->avail_out; - *(text + (png_size_t)text_size) = '\0'; - } - if (ret != Z_STREAM_END) + png_ptr->zstream->next_in = (png_bytep )text; + png_ptr->zstream->avail_in = (uInt)(length - (text - key)); + png_ptr->zstream->next_out = png_ptr->zbuf; + png_ptr->zstream->avail_out = (png_size_t)png_ptr->zbuf_size; + + key_size = text - key; + text_size = 0; + text = NULL; + + while (png_ptr->zstream->avail_in) + { + int ret; + + ret = inflate(png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) { - png_ptr->zstream->next_out = png_ptr->zbuf; - png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + if (png_ptr->zstream->msg) + png_warning(png_ptr, png_ptr->zstream->msg); + else + png_warning(png_ptr, "zTXt decompression error"); + inflateReset(png_ptr->zstream); + png_ptr->zstream->avail_in = 0; + + if (!text) + { + text_size = key_size + sizeof(msg) + 1; + text = (png_charp)png_large_malloc(png_ptr, text_size); + png_memcpy(text, key, (png_size_t)key_size); + } + + text[text_size - 1] = '\0'; + + /* Copy what we can of the error message into the text chunk */ + text_size = length - (text - key) - 1; + text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + png_memcpy(text + key_size, msg, (png_size_t)(text_size + 1)); + break; + } + if (!png_ptr->zstream->avail_out || ret == Z_STREAM_END) + { + if (!text) + { + text = (png_charp)png_large_malloc(png_ptr, + png_ptr->zbuf_size - png_ptr->zstream->avail_out + + key_size + 1); + png_memcpy(text + (png_size_t)key_size, png_ptr->zbuf, + (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out)); + png_memcpy(text, key, (png_size_t)key_size); + text_size = key_size + (png_size_t)png_ptr->zbuf_size - + png_ptr->zstream->avail_out; + *(text + (png_size_t)text_size) = '\0'; + } + else + { + png_charp tmp; + + tmp = text; + text = png_large_malloc(png_ptr, text_size + + png_ptr->zbuf_size - png_ptr->zstream->avail_out + 1); + png_memcpy(text, tmp, (png_size_t)text_size); + png_large_free(png_ptr, tmp); + png_memcpy(text + (png_size_t)text_size, png_ptr->zbuf, + (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream->avail_out)); + text_size += png_ptr->zbuf_size - png_ptr->zstream->avail_out; + *(text + (png_size_t)text_size) = '\0'; + } + if (ret != Z_STREAM_END) + { + png_ptr->zstream->next_out = png_ptr->zbuf; + png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + } + else + { + break; + } } } - else - { - break; - } - if (ret == Z_STREAM_END) - break; - } + inflateReset(png_ptr->zstream); + png_ptr->zstream->avail_in = 0; - inflateReset(png_ptr->zstream); - png_ptr->zstream->avail_in = 0; - - if (ret != Z_STREAM_END) - { png_large_free(png_ptr, key); - png_large_free(png_ptr, text); - return; + key = text; + text += (png_size_t)key_size; + text_size -= key_size; } - png_large_free(png_ptr, key); - key = text; - text += (png_size_t)key_size; - text_size -= key_size; - png_read_zTXt(png_ptr, info, key, text, text_size, 0); } #endif @@ -964,7 +1079,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass) #endif void -png_read_filter_row(png_row_infop row_info, png_bytep row, +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter) { switch (filter) @@ -1064,6 +1179,7 @@ png_read_filter_row(png_row_infop row_info, png_bytep row, break; } default: + png_error(png_ptr, "Bad adaptive filter type"); break; } } @@ -1107,7 +1223,7 @@ png_read_finish_row(png_structp png_ptr) return; } - if (!png_ptr->zlib_finished) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) { char extra; int ret; @@ -1127,7 +1243,7 @@ png_read_finish_row(png_structp png_ptr) crc = png_get_uint_32(buf); if (((crc ^ 0xffffffffL) & 0xffffffffL) != (png_ptr->crc & 0xffffffffL)) - png_error(png_ptr, "Bad CRC value"); + png_warning(png_ptr, "Bad CRC value"); png_read_data(png_ptr, buf, 4); png_ptr->idat_size = png_get_uint_32(buf); @@ -1151,11 +1267,12 @@ png_read_finish_row(png_structp png_ptr) if (!(png_ptr->zstream->avail_out) || png_ptr->zstream->avail_in || png_ptr->idat_size) png_error(png_ptr, "Extra compressed data"); - png_ptr->mode = PNG_AT_LAST_IDAT; + png_ptr->mode |= PNG_AT_LAST_IDAT; break; } if (ret != Z_OK) - png_error(png_ptr, "Compression Error"); + png_error(png_ptr, png_ptr->zstream->msg ? png_ptr->zstream->msg : + "Decompression Error"); if (!(png_ptr->zstream->avail_out)) png_error(png_ptr, "Extra compressed data"); @@ -1169,7 +1286,7 @@ png_read_finish_row(png_structp png_ptr) inflateReset(png_ptr->zstream); - png_ptr->mode = PNG_AT_LAST_IDAT; + png_ptr->mode |= PNG_AT_LAST_IDAT; } void @@ -1206,13 +1323,11 @@ png_read_start_row(png_structp png_ptr) #if defined(PNG_READ_PACK_SUPPORTED) if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) - { max_pixel_depth = 8; - } #endif -#if defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & (PNG_EXPAND | PNG_PACK)) +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -1277,19 +1392,18 @@ png_read_start_row(png_structp png_ptr) 1 + ((max_pixel_depth + 7) >> 3); #ifdef PNG_MAX_MALLOC_64K if (rowbytes > 65536L) - png_error(png_ptr, "This image requires a row greater then 64KB"); + png_error(png_ptr, "This image requires a row greater than 64KB"); #endif png_ptr->row_buf = (png_bytep )png_large_malloc(png_ptr, rowbytes); #ifdef PNG_MAX_MALLOC_64K if (png_ptr->rowbytes + 1 > 65536L) - png_error(png_ptr, "This image requires a row greater then 64KB"); + png_error(png_ptr, "This image requires a row greater than 64KB"); #endif - png_ptr->prev_row = png_large_malloc(png_ptr, - png_ptr->rowbytes + 1); + png_ptr->prev_row = png_large_malloc(png_ptr, png_ptr->rowbytes + 1); png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1); - png_ptr->row_init = 1; + png_ptr->flags |= PNG_FLAG_ROW_INIT; } diff --git a/pngtest.c b/pngtest.c index 5b6715cb..18fc07ab 100644 --- a/pngtest.c +++ b/pngtest.c @@ -1,9 +1,9 @@ /* pngtest.c - a simple test program to test libpng - libpng 1.0 beta 2 - version 0.87 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 15, 1996 + May 25, 1996 */ #include @@ -19,27 +19,31 @@ #define STDERR stdout /* for DOS */ /* input and output filenames */ -char inname[] = "pngtest.png"; -char outname[] = "pngout.png"; - -png_struct read_ptr; -png_struct write_ptr; -png_info info_ptr; -png_info end_info; +#ifdef RISCOS +char *inname = "pngtest_pn"; +char *outname = "pngout_png"; +#else +char *inname = "pngtest.png"; +char *outname = "pngout.png"; +#endif char inbuf[256], outbuf[256]; -int main() +int main(int argc, char *argv[]) { FILE *fpin, *fpout; + png_structp read_ptr; + png_structp write_ptr; + png_infop info_ptr; + png_infop end_info; png_bytep row_buf; - png_byte * near_row_buf; + png_byte *near_row_buf; png_uint_32 rowbytes; png_uint_32 y; int channels, num_pass, pass; - row_buf = (png_bytep)0; - near_row_buf = (png_byte *)0; + row_buf = (png_bytep)NULL; + near_row_buf = (png_byte *)NULL; fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); @@ -51,6 +55,18 @@ int main() fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); } + if (argc > 1) + inname = argv[1]; + + if (argc > 2) + outname = argv[2]; + + if (argc > 3) + { + fprintf(stderr, "usage: %s [infile.png] [outfile.png]\n", argv[0]); + exit(1); + } + fpin = fopen(inname, "rb"); if (!fpin) { @@ -61,62 +77,68 @@ int main() fpout = fopen(outname, "wb"); if (!fpout) { - fprintf(STDERR, "could not open output file %s\n", outname); + fprintf(STDERR, "Could not open output file %s\n", outname); fclose(fpin); return 1; } - if (setjmp(read_ptr.jmpbuf)) + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL); + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL); + info_ptr = png_create_info_struct(read_ptr); + end_info = png_create_info_struct(read_ptr); + + if (setjmp(read_ptr->jmpbuf)) { fprintf(STDERR, "libpng read error\n"); + png_destroy_read_struct(&read_ptr, &info_ptr, &end_info); + png_destroy_write_struct(&write_ptr, (png_infopp)NULL); fclose(fpin); fclose(fpout); return 1; } - if (setjmp(write_ptr.jmpbuf)) + if (setjmp(write_ptr->jmpbuf)) { fprintf(STDERR, "libpng write error\n"); + png_destroy_read_struct(&read_ptr, &info_ptr, &end_info); + png_destroy_write_struct(&write_ptr, (png_infopp)NULL); fclose(fpin); fclose(fpout); return 1; } - png_read_init(&read_ptr); - png_write_init(&write_ptr); - png_info_init(&info_ptr); - png_info_init(&end_info); + png_init_io(read_ptr, fpin); + png_init_io(write_ptr, fpout); - png_init_io(&read_ptr, fpin); - png_init_io(&write_ptr, fpout); + png_read_info(read_ptr, info_ptr); + png_write_info(write_ptr, info_ptr); - png_read_info(&read_ptr, &info_ptr); - png_write_info(&write_ptr, &info_ptr); - - if ((info_ptr.color_type & 3) == 2) - channels = 3; - else + if ((info_ptr->color_type & PNG_COLOR_TYPE_PALETTE)==PNG_COLOR_TYPE_PALETTE) channels = 1; - if (info_ptr.color_type & 4) + else + channels = 3; + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) channels++; - rowbytes = ((info_ptr.width * info_ptr.bit_depth * channels + 7) >> 3); + rowbytes = ((info_ptr->width * info_ptr->bit_depth * channels + 7) >> 3); near_row_buf = (png_byte *)malloc((size_t)rowbytes); row_buf = (png_bytep)near_row_buf; if (!row_buf) { - fprintf(STDERR, "no memory to allocate row buffer\n"); - png_read_destroy(&read_ptr, &info_ptr, (png_infop )0); - png_write_destroy(&write_ptr); + fprintf(STDERR, "No memory to allocate row buffer\n"); + png_destroy_read_struct(&read_ptr, &info_ptr, &end_info); + png_destroy_write_struct(&write_ptr, (png_infopp)NULL); fclose(fpin); fclose(fpout); return 1; } - if (info_ptr.interlace_type) + if (info_ptr->interlace_type) { - num_pass = png_set_interlace_handling(&read_ptr); - num_pass = png_set_interlace_handling(&write_ptr); + num_pass = png_set_interlace_handling(read_ptr); + num_pass = png_set_interlace_handling(write_ptr); } else { @@ -125,21 +147,21 @@ int main() for (pass = 0; pass < num_pass; pass++) { - for (y = 0; y < info_ptr.height; y++) + for (y = 0; y < info_ptr->height; y++) { #ifdef TESTING fprintf(STDERR, "Processing line #%ld\n", y); #endif - png_read_rows(&read_ptr, (png_bytepp)&row_buf, (png_bytepp)0, 1); - png_write_rows(&write_ptr, (png_bytepp)&row_buf, 1); + png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)0, 1); + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); } } - png_read_end(&read_ptr, &end_info); - png_write_end(&write_ptr, &end_info); + png_read_end(read_ptr, end_info); + png_write_end(write_ptr, end_info); - png_read_destroy(&read_ptr, &info_ptr, &end_info); - png_write_destroy(&write_ptr); + png_destroy_read_struct(&read_ptr, &info_ptr, &end_info); + png_destroy_write_struct(&write_ptr, (png_infopp)NULL); fclose(fpin); fclose(fpout); @@ -150,14 +172,14 @@ int main() if (!fpin) { - fprintf(STDERR, "could not find file %s\n", inname); + fprintf(STDERR, "Could not find file %s\n", inname); return 1; } fpout = fopen(outname, "rb"); if (!fpout) { - fprintf(STDERR, "could not find file %s\n", outname); + fprintf(STDERR, "Could not find file %s\n", outname); fclose(fpin); return 1; } @@ -171,7 +193,8 @@ int main() if (num_in != num_out) { - fprintf(STDERR, "files are of a different size\n"); + fprintf(STDERR, "Files %s and %s are of a different size\n", + inname, outname); fclose(fpin); fclose(fpout); return 1; @@ -182,7 +205,7 @@ int main() if (memcmp(inbuf, outbuf, num_in)) { - fprintf(STDERR, "files are different\n"); + fprintf(STDERR, "Files %s and %s are different\n", inname, outname); fclose(fpin); fclose(fpout); return 1; diff --git a/pngtest.png b/pngtest.png index 43485ec29c9179e36791fddff4a0406a78709a2f..fc40f5ff8e0b67d2bba925df173e9ec295b9f36f 100644 GIT binary patch literal 8907 zcmV;+A~fBJP)Rn^({z1E)h8IyA| zCnOO_<1GTY zSbmO?N}@;4i)W-X1D9NM0gg6Mi)Xa|iKc&l&mGKQGS+``aCLe2tgC;1{`uO0y@zn% z$gzF?G`W;-HRJ>tGiN?R0N~?K064$F{Dpra5C8rVR$qVYADy}B#%b)(p%5&?8Ft|X z#Zw-9^wAMNRFNM6S6wlc{o=A;F#zDN8ZqjDieW=%Shj{G%ifzlVqlM1>pt7D)Fsl1 zy~?xk{-*~30Q8NO%O8v-Oe}eB{rs+_>8q2PgTg%5_F%w|b2=7-Fb91u8rq!#K%)5w z^74dfi)%ArsgmhR}BDDr{2Wwz3(p4 zr_cGDpMPzQRoAEi0C)hXZa5lDPxDy-a6$JXECg`VuYY~Ufcfz;bm%otUef29T_-4> z377W0`ZJ$b?Y-*l=gH4|4=F5aS5RG4kb~{JzPYQY$TeHx)3JT;(e(~Uzrx}y;G>fs zgqL4h!6d=KTW`JByIc7=8;Nb>j(hGPQzzfSC>&TOu;}@D;4(7?8)`lUq5p0 zf=9`Oag!HU3>z>dmWa=KZN#Hj!u-krf z6B~Tl)q7jZ=FED8wO#vLlgZ_S$Fkx=FC0+RH`aH4gVNU7t|K!XQ8^L5yUwWEdL0bZ=-+zQ8y3hcMY33b{YeK0ewe4 zH+kHz*_&^_e0R4F?P@RTS%d|P9wVBigNgqb3i{X|W=kVSjH$c#?)%tB@4wGhE`ODc zA9DkH|NZ3)3JUX4oEO9mlW!gM-iFsF9j;3P0MdL4T&f!Y;8=XT=~xnfd~BW%`1>f| zJoU~SFTLb~h3~HY1fPGkvwZTTE35YGIE?B;4H$9RIrwDjAw2iO0y5;X>sfxjdt5=T z=f#rzJdB-s`V2w=V8OyU&oo8i$jESE>(;efo9kO}VUI%C#2WTd)!vGXKpJM=`w){w zicTF%XK{?c<4eP!fg=M0FCBAu(52(qp#EbIo}yu>sS!TE9~Hw#1r!O8MPSXlFTP`# zZ03RLqxHNX;b%Qck(m+5Z*0~fC@!pB_jXvpsV2gGHw}jJAX|VkAI`(B$(< z`1Ff!ngF2xg`LV)ta>&ll8hiTJ011)b#N>V0!Q)G`~@Ydz$0ZO(W_hV)KPAXwzz8= zBIw?w0LQ{{`SFGGG5}!fo(2HGqq83-DP2d0(gGx5$l;bI^z7DYUw&RXTABJW~` z@y*`w30fIJ6=h{vCv4t&=ao(0c5*UKVW_1v7#fEzozpje{PFR!S6;9DH?CIy4fvPK zbM5HKTy=HiW4BA_Ey)yqj~6zT(0nWmUeMq;9{ly)#V2^3_4N9ExMJ9K52!Mo!Eqw8 z)BQ;Ey3rI%;fbdnAtQ#3VzXz`{oJ1}Y^{4~-wCF` zF}|#8F&=;N_vGp;#xs|P!t3KvnB5Msh>iyzKfV{fwC@~HU%C zSRw(pg!*f5xGCrRLgus>+_v@WSsgpJpB`#*ke8E%z2Wn+pra;L6MW4HL(70Jz`NC zE{_jhj|YnAWLFHG!UUc}B#{KqG1#^RRh6OJfXCy)^5qN2XS-Sq1 zSWg;A**XUF>xGh{EOhH$R1r$W@a3j0uwjGeIILc|`e~0BOT%FcmH~uXLJ&CzN!>hi z47TFFJEyaF(tvK-@TfpzC^_x97Z)#R%XaLjo0#ghS1(?&=!%oe$6q_SuJ;AqvokaN z&{O*Mag%@5?fOYKxE!6thYY(Irs-hKyC31u;S}5oh1cst$M${*62b2tdWd`{!BG`s zZ|v5!U}0LCA1%>lY}?s{S64jOrv2rE$FZWK0KVQ<56Xw+^&hT1u|3GnDB^CJHp%k1 z{rJtDx1Lge=#ZkJ4HNsT{;nwvGRP5xn`=x6GA9;%9`LJ$LTh z9Y03nKjA0f->@J2Hb#vaAJCH4XpSQljUj7bzdk>6KlJe3iPro7=lj9$!^Ia~eIw!c zh3S3{vZ6v2+(;pXWFiW;%H#0iqrCuZ_?Hm;<;aO$HC-E+O2yW!d+(h+SC5!#Vr9Kf=FnqY_0o+TL>1-H3Wc_NtO&df+d zGNBJ%xq9il0Kjor$bnSosZ_Q@2sBNfzi`pq`>z`{i79Rgk|-hIA!xFleIIoqG0 zN#LMLDySf$YTGvK-``+)yl%d{yaYM9necktkY&-@v1=27ZA|w{?pZA@A$07R4IXKj zF#3iq&%d(hJOGdd9xk^GpGz4m@?y5vEkhP~D1r)?D&x*+w?zQp?bWX}E~M)Mq(PGnvGy~9vtQX0QT;w>FsDS5KBYQBOyDOwea1wZ#7fX zLe;i9$SQ}rW*xHRMc0!2%JE~a_kr50OxuCQOz=DfWfcBk0N_LjymY3}KMkimB+a3^ z>6TeCHEtz9DTN?XTz}oKOP*c!)R#Sfb}r8Aln$3FAvY^f4gd!ZH{-${1*mI?THsaQ zPz<=JgyNjsaC7s%s~x6{woMz9a?nk{)^w=;AOMQ_bN=Xhb4^u0SY!%gq=FIx$01wGzdB997hifdVwpO$WCE#V3~nzEucF)s0P#pObjyY)awy6_o)Q%WS{qB5 zSh#Gy5Kly)3IgIu8@wc;bBBUT0Tj_h460iSo0bFJG@%m_f-K`uO=5Sutl(;g&^3+BurNJdh;5lHxrK3jK4vJtJIB=*Q z)wPZL0KnttD>ci+v>R^e`M0&Jk9a)JG>2n|CX%3_=+o~4z#-^zPRVXU9mL~0h(JMk zKoI1?r5*Cu=#~MuD5514fy?88?Z~*WXUXnXKBp1v(4lCSZCGHY1((P}k{krnj z9gbmxV}Fk|p6~bA>_?iL!zKvfAW8s(gjkN57{4dz&ggk!j2 z@?8up4wG>ZRTZ{rBN~apX6A|YxJ`o5sD2-11kF($iIj=zx-cG@JNuosY#CUkB%D64 zt^MG`Y}?dfm^zZF;|Z&mUS87Ya45cF=QlL~fWCb?qiR zwe1QrhHH)uMOG_!?A#ICzJ1GUIeG1CMV=1VEQVm33rFgr&~yvAc|J5WwN%Z0V$RRL zQ$YaG3uL6NGU@HGt?G^XX`dn@01Y00|xHgD7tDRk`E zd01=tbITSksa*OzUsbhhoucyST9$?OCI0n?Ypeb97tA~FWFKeTZY7d-eNGOSeIyhE z0Rtt{LIBH8wwZSGZLXSw$3EV=y#^)4B0}Mmf9#kk+)FQ4+O0OPt$Oi7ug`537iJCy z@Jws@j-6HZj-6G5&eVP@&ZywwW8oQx8=9fTQi!K4fWUug-(Q}RK%T!~UV?HQI<$AA zC1SuMD~LuDv%l?Y$+Cq)eN*#&-$&-G23nUG}>4UH)zQ#?9!Xn%?wCq(>r z-@oif$;$v|I2RA-KR8R31NH6N`4NjJp{fc9VCj}U|Ji4sx&6l?b5^)*+O50px%X;V1lr|6JU1%RN3t$vDG@LC5iL&kp`8apR45_`dpTUuRhqJ1Yt;W6UXy$1K0a zxL&-#xn;qIBy&)d<7=kv0EQ+Zo(va#^wFD#+Vc4?&tCp3(d)cRvI+`HRwq+tFNZle zQqzbup9`uiASW{erpXX$i9_`$&~+P@WkNRrJ>`Hf8=OF($|Ag8sSLn>uYiLF3=hb% zw^u5mcNRphT%fc}5NR1>Ocr99-#kz^DQENG?$5I~kB7`hEc0WbpQ0FGlp6og&?+C1+3+XNgs_?p6a zOe>?5FB1i^v!u|CZ@=^BXTELMx6jB?mZ7}DD;x^j`4RAEf&oZVW$-+OZaHX-B;uh+ z(~JWLkF4p}=NG<=Kz20;+b?@5RF4Q|Gq@BtIKhp0JPFfqpj(Mvwr!O~quNrA=KxB; zb0#=NfRLT)q3VSfo;Ljd;{~By;Q2B_n9Nb(_*W6C3|SQ5z(gb* zM^h*Y-LzqwoF<55mdk^g(WpLO*GYLa8ZS%t2Rb|8VNe1|;J|SrI7VPH6Zr)h!FIW6 zwZ#R+^PXPvr_;9VYuCNrf;Sikt1u%Xjx)ylBB`hr&}F-G0lRTXfyADCMoPZk>7s(tJF?z>5^Tz=LCe z<2cy#*(TK1B|#h~?(lJcLxWi^Ny>@=gU&0GLrNgove6#lmY{Ra4_NC+5 zj4OsrxICV+R`(t9KZHcm!M>X2r7Ko0nbgX0%%~|P zp+63&jx?7a+Fw`Ya>;P1A_8d=L=Gq}Xb-|M7`6#f zMMEpzT)J}io-I$bggm8wpK`7u^3YOA@B+XXLuRHIUYC@eo7>61ZTseTzuC8SZ+ThI zDW-0E4U1uabv=Rs0hBSsGz+`-9Yg&w4LqkHH#5DwOQ#;w3){C}y=(W^4cm8o)zY!F zdxgLY*#b`?h=9)@fMFO&MdQ6VK|;VUBO}`n#p{9FUVteBaK_E>+#K*gws$Ak8gndk!3H3IzS``o<{0 z5%~NHs6fE;1X&qgKHcq`TGr*<@-Mc0zP#%>J+lc&Kb{vLiadNC1t8Q4H%0PQRRQ66 zs60b3-2>H|4xSf4IUbV0ffrQ&tE*PFnczIXSHD16m)`vg3(Br7Ea-Yyhmv!LcPKg6 z-@bjv(1C-y+RW*E?<#!voezGNpP$(qe^0jAwhhVyv1l_IYD2Iz2ZAC@d~(s_%K+fg zORl=IsIX*Jw=UU`Wd>EE04Kxk;t-FdP+uRam_GCOZ}#gmJiwT%>D;mmcw`wzn_C99 zG{-x)FUp_q^UH879wu{;OzPk$ph_ZKiiAWwZZ*c@w>33t^99Po;5Z7)b|6p( zg22IXY$OdEmIH_a50U3VVD0O4PJY=_PyJE<&IoKpAT75xH#cXT(IyD6{85^S5nB{E1n4^7h$3dh%c@X5zpt84b8 zI+S!R=c&*c90$#?=&Nrmy*Ib8!>oP#8V3{3$#tnbGJ|d?ya>wk;AIJUS?Sc{_6!X* zhd~Jkj^p6KK|#BAYC}UqJ#$PqAsi@o{E-dj=7KQ_RTerN z)W$jNb|XSV`$EKUb6^01jzo0;vdsH~iKVw-iwoN6oH{>z`= zJy2b}Uei+`wgp|+VL3Jc3Plj%a#3)EbiQWf^;ZJGWrK!t@kA;d^eYI5qo{8TBauj= zw!RrH(KzZtP3u~HtE#lLC6a>Ir$7{?(T_enM|xw$GJWlPFaJ#BoqmaE(xMQM5pW?l zONGGOa2SEC%DCvF^N^FD1~?8Z!-8q($ZeOsJ(jdV9ScUvMq^71hGoI+mO(%u2s~_y zA;XvEfAx)pS6E1vH#A4#Q78f)7434p$jNjeFUy0T~O?@ zZCH?a4o90}NTyP#J<>Ac>BWmrjNV)CJpZO?lcq$%Kygkwuf>|jwccB}&hRsiRi;b>Hq+r41V?M? zKnVlK5fDP4dQ@a&r;i4J6|XNG|`=Mz`IF19y2BI+yn#ugH zzxvvB0H7$`Mve#wg;M}HBw_}V@e~}#g5M>=qsrhoAR5zQ*`(|={y#)O0C2f8zX_&$ zrclmCG-aYWszJ9b2)qPU5mA(%fy{s(evccXAcImG2C?RE+Wf`vCl)Tack`An_qOG? zLuu!42ovt``P`5N+OGR~Jzm+kabxqzHV3N@B)+Qpa!zi3yIPMb5BGU}h-(HUiNL2y z5I7Dlw+ccjT#CAT=Bx*AEjzbIFqJaTcdHbkP#6V;*`RPB$r9?DqVRcKy^b~NZ^h%r zg#27zHYdo4v?L+P5(pC{JZN%fr+RrwAcFN1$A1vU(Lwk+{GCTAV zc&VdH=8;I5NF;S=hK{6RAR14hrXhh)B33@<$vHRu?SuFK@ZS0jYxnNkoBA%l`}XaK zbtviDOA>^RNz+6kp=n#TY+l=z?bq9@wrt=2%}kfuds$wVKOdBX$Z@b82Zm)sB!Fd^ z#>%(fer?;ful`!lu3*0DaF^)1o*!-wAtxsY2LPiK0=2vzulk$n0}a_;j|^Fn5!ZC2 zbRCosNQw-%M+KOHbhirL0SM2m4?q57@joRX0JJYG-dUUO zml6)(1qqrBXu971t<`To3;=ug?n!;UqiV^QRhu8o$Z0Qc-(7Ptco94$Xlx3DF&n|4 z7d!XVpt>f6WI{(WX~8mWm^Oo|Ql$G8Xtsu^rqyrVwyXdC{d;34^EvBm%*~T;TA7on zRyg1w3L+c=sG^9Zk;I`R5rjf1IMgnBeZ>oHCLr6w!l#!=@2%UUDY5{~2qPotAC{Ju zvr$nM?YH;cnfR`{qklPRadBbRl>Gc`*gAs_8+G+{10SC|=e;)VM@{If$V%n8Wu>Jp zF&zYeEDDIkk^qh;Rbw#&fCEvYVP<3Yma4C2ee&rByDfibE#Qz}T-oXT^SbPIDFkW0 zbQsJ)I2uPXWg#4nARIPvtSMHxcHN3!eV?!Xmk#y`B>hFok%5NE?Lx|L<1s;UNi z_O~G2$3s$t+g@M!;&&ds`u81@m7SGUbzYCo*@`5fB^sH1{{z3j`-k>v&YU^E&p!Ly z@Adfc>~qij;DHDJ$$a2%rr!2)hmx$(hLM74Gei;&Yi$K zv3t+lp1>y-ZR;Ufmf5|6qG(`870HoUwK0aKAo#(Z8uHjU;OkUmw_AYh3PPt8 z?kIlW8vj7=R2g|}jPuv$$2(r3mfRZ^wfZuHVjA2UD3GFo-^+KR$Zoe8L$nAq?3CzC ztsQ7?6>Pp&K{^(mhWC^q+IYsY=f9!>Ur~JT!Jy}0MmPpT=)p)wa^#evR%6E1?UWe& Z_6HdhTAl6V_{IPL002ovPDHLkV1jaS3t#{M literal 7147 zcmVU555EN|` z&|@cRQV0neAPKpgBB9dRhNI^_#!>2LnkmT0N4D_+bU}qpS-r{FUK6FDJbflclvQ<4~`()=ti~{kZUK z{n?*+_3A(Vli%yTP}~1d0N?YT-x>JUx3;Z}!*FGi$Vuhz$tRvP@z6v3#{;xKT1#@{ zD2lQ>*Pi*np1r$oJL^BcVL%E0he|`7XexD$x1Pa96%|0Y>oBFGH0fo71IgsVLUv2( zply2e(mpB(2qTG! zpo5FgKkwr0pSkCj2cFy3l>Mn%wQ}P^ryD29z`47#1LNK~=Hig!myJ=B4(Hr0x81(( zYJj)A@t5CMiDc6QaYYhn2}(0GIEX0?!h%w4TX*A)-vqvS-p{||V()Q_n;EENeUE~~Bj0_E+w5FB>RO1*Y1STtJG%JKEV5jxBo%{MX zt-AjUpWA(~?ITm4-vRsvz&U4M^!BpQw@D$1B7+R(sZ}auS^C&P`#6j)^Ejl0Fcf(2 zsmC>xlo%(GQXwhtIcVSMb^lPwcq)!GoxTC-!3E6sbMo9WI$B37ey}5O?VI1aqR8x| z3ZqrFbd%n)yq9J*tpmIl+u|r%pJttP>mRynAAqrb!$70Pi4(_A6oM>IA<)DUj9Q$m zlYx+9mJN+0iMsQZD}VgVN4IXW&wua8NOIToUTg4ZYb@=B9`#xSX-(Sq9GK}+ ztE!g<@cgwG4x55i9x z=aWx8{p3ZPw|wK50ABN&xBh{W!IdYSG)6cOArVLcq10qX(yZ68LR|jq@BXc+kACd0 zKKcBB!%#lf@B7srh1Ouof+!9Tc5sdN0_P-g6c7iBM!iN51UM@(HbZK`$k_1q=lZNR z>|I{Q*LG7=)5-16hj)^tOUGyqH+f?74(8kW1uITH z{o2i2zVVv?k390JKR@$7U3B)`Oz-T$TFk&uomQ*G^06gYA=$NOA4Byjy-clp{p;Se z;R|2-+>_4@SYRL1QUMTz0fF{Jfm#mWonIvaMHB=mB?+~ro-`1I1fhj2B&umH`-9*8 zXCOXz&)?1d!douB*n2MOruoVx!?oqZgK<39%28-cnQi^tFxcvoUy# zNzqcHl&8!LB^ntl?yk$yuzAbl?Abd<+Aoduex^B4A763WaU@X)QsJy6Pywf$vXrNu zKEUj}zwB)nzUQ9XKY7yw022FPS)^yzD^+@(43ipWX4?#n)KNZQpx#6)S(}^f-g*98 z-gf3^?!NumN{G^I)k@*LCkz!r3gR$a4iJUWL=Z^gNE2v{6i`j7I4|)+5f6BJy=>PD zf%yBoZ}~Lv>4U$2^&Rgyxu4E2tJcbG_uTh)yI-iyKLdEvy6ZPpl6YgDJ0qnwldoK{ zdU$X^gC}Ucg`6TQJ7#H2mwM!PB>wd zyeP1Ry%Kl;U|=A5teYBSV5ulcBW^I#tg&O)ehQ};9@5OrcQ|&exoX=^dmZr3gK^gD zm92AG4npCazzc!Y;rQ?T)*t@(jwkmLtC%2^1VMll5XcarJcTU@wZ>OMb2u2!)&IWj zrYC_Xzn`6a?vHCeeDxVOeDs=EUw7k&e)`czw_N6|$9PGW7395wEG;RFA+99oKmxLc zi&uaCf!n|N^p2ftr@r=t>2$g{2gX?t9;IOE(qWQHwCWenf7?$16s9#*2}5>G&oh0X zO%OS>w%{O5`#iCI4^QptP*}%My?*iA-ufHwJ{aR2pIrB35CoZ05^um;gAM{Zo&IDX zB_OHP0>Vl}rB(x}P%0n_Lxd27f#e6N!+P7g^|5u^cRVv)n1b9wW<90%6h>034xj^p z$Ae)Fz@|-K-1OvA`#&*rU;$g?gAd7Xdu*#m~+LA-jB0qLkwQ zZrsJ(LWfEs(LuoWogIoyQ05^c!%b>Qa@{YS|Mnk07@KwFRwV`2dvas29tNAuGnEnu zDbYx3)r6p$puzwr6xJz}P~d)`{04?Y8gkL%4!ad3;e2;0Zh&e{7RRJ$}~Km~w*>0#g|Et9{9}8z4uQ{oN%cS3hzoxX|PTslqOV*`$ehrnFsCv@mqI)Gp@d4 zTdOy|e5fMvQlX_JiY4`0K&28*{?Gq$MfAZxet+KW=Nr;2UpqeDq>%*KGt+aeB_qx8 zvM^Zhsa0coc}n6nQ8nP$B_qpc=jUz#&R0rq^$tMcoLnp&dun)rQj3KHS9$_r2;&f} zXFzKLX;CU1KU{x*a`jomg9GDh%97R2`PD%nyHbh=9r=S_{L-h7zMxvEvA*By5(G^| z0LD0M&mfc_N)nVdIOj&*^=t1v`Q}@1coM)Gd;j#l{4zHfvUEv8wGsk?PS?<^*Yu8^ zyOsl+<0Rg=_du7G%g4y_B91ER(&_2>J5N4tsopcwA_+sB1Y<4UIl@pg+#Fc@o_AjQ zzGrr~9*e>n&N~DW>pTMk^<`2?z~h|5c*s)A@QA{CLl7&xb4cg8?&`m&-u?M+#E583 zncG!?(yKjgHC`?A9<&m81>OmaaTg&H&Ux+Iw z1^vuZmIi?bN>WqM$qUlLPjpi*3B%@{?|tv@M=uH>K)XG+-a9BwL0OgK0BNdJvuhD3Pgt25~ zY;buL%hfL$;NCq4*5`SFcMfB7l2D@YcmaVH=s-{!yXK(%{SSU-cOXSJJKseqP|{<{ z6z45vY4FZJ>$@=JhA;>ytw(FU3ZOX@U%KzW!iFbzPE**7p`n0!Ra0+7MAZbX1;;HN zZ&s4U-3AWI+z=-TQtM0#i}0S@c=F65lq66Z9W1WED$q<$F1;;`^*z0`V0b8@QLijc zQBELKNTpgMsWfN~*I6}r9A}(<4C6~0M3LMT$9~l{e|hC2FB)L8Ir#AG+^i|f0^vMm zks)!5Wg)2u0uacRYu|j~@WD2{et%l4fYw5fZm)}!5>q+?tq?&leb7!xy)iFK8ucp1 z*i`_3f9I{ake#&)?R0wIz8=%lJ?fR1KnB#J0Ph7+60u^%2{;Tm@YbRwgi$nuU)(X} zxuKWlXcbUPLfqo}5K?g5_(>8MmHEC1|Iu8sh{@Wp#} zj|@i_)e>Qj9d8mRiqX-4+-7({2*L315KEVh0uF0EX_hlGHaOi$4N^FSTTF@ic?wFR z5J&~4aAc{S08pC8W?Ov+os>`Q%N*ZEB4LhbTY?KGvU+|$F@G7&x=aS zd)@we;T>9m#$fXtYYMd1M1ep`K^Vp7z3%5Oys*sc>z()Gy>1_@MLN%cxh?^ke!tlE zk-zzyXZMw1EH+3b$qGxeQPsP5Y@a;%?8c9Mp#T9wYwC^aN`MnjT(-+ujrRhCq{zSv zNnVt++8IewAxsh~VTBWy4l+D+=;`K*0@!NJuP+LVG3I-VNQtnHBos*HQOeV9^)4w& zJ`pG3nFDo2X*Je*f>2XBPdn`}H{ZMMxqk2b^sT$|!q3>!GFXim9;&Z;?(@IC;kxUe znLcpKz5^}t++nQ8If)1~QiGPB(@#GcsXWdaqCiaqvA!!S3Y;+DB<;Bl!h0kFfgnjj z;!3m%;6qpa>Fm%*E$j9zQYfSnXa$v8KwjpQ&XRcM1%m?(UUAyVF98wCrlVtr2Q|FU;i!d_wt9mU7Q1zmPC57;-ZD7$V!BF2ukV|O`~3;m*$ADf|Mc0j1QZBkzV|f zo37t?2%x&&`1CV#w6Yv8+#vw3yW!e=*Pfl{&CDK{4z;4!PsxfB=RFSpy#i^Ik>Mtl zYSbJWtnN};tncPIPFQ9S%+Sxec;^rv(!wExWNgWjGXbJV@2W%*Gjn}}6j&=Mazl}q z)RKt7Mimg`xg&}W-Nn4<(!|_+`$6k0LO4p3lRHo0N@gb9ce$Om!`BjT?*$hPLXByrHw#re}Jzx&=;XUU~X4y!wpe zId-gxa29Ex+sRt9bFHiX;gPQ|zw$3Xbob#syA49P@6`{f{r2UTuXrJ=+wQpak^OV? zm+qgNW1wCk%Sy^JMPTtPjz+EEn6c57xBTr#AMwIp*X|Z*Y1q4G8YN({e&pG|e~vJe z=e^;a3r=n=WUG`ijEpuYjlfz@SgDfr45lb43P-<}Gv7<;_WLg#;EAUkvtjpvR=2f~ zq7)RR#TziLzzIt~FX?9`2(DY`cFyaS#rS{!zz2Wt-uv&HJ(Azg-~XxIffh5}Zb~Q5 zX)i2H9?tgmJ8t>do_+h*wOVsjB2AhZ9FS%OrLlz46Ge;V{V0~d>x6rFzMIo+w`k9` zaLyuxAPNHpYT>dIj-S}3Rk+HUjAh5vKuHSY08bcK5JHkf0%Hn_Zl5Fxmc3+vA6s{$ zZFkD`rBO(~xT3XsDRb?V*>=iYtHbua3w&qS{&jzP%~kjQ(I0;>f3d!eDW=NY(Cr!o z;hH1ae)jIqUHaW8cTN>q4<$W$mgDghWl33-NH3NHtXp?e-fGXR&5B~Gofd4~{2i>b zqrv%Y&vqDJGDveM;@g{dvuX2A zOp#-X9OoTbX0WBD8YLvv03UdYl0%LIjtXF&ch-YN;}~p2EFG=WY{XO|O&BSJ5Ey&( z0P~_ZwXl#8M-i1uW%c*7f8=Xl-gjVTe(jbmPaAIqrFB@RNv$9&{qpD9-u&^8_U`z^ z&A-$uvMc}b+fT6LnHgH`dAi*mGjnZDJ>>+32SdEG%(pVy9n1V&pMF-56*)SDnRbi$ zZf|k{eH1lngcpaL(fVVt=HPEE%mZI8>wE?vmwp z?{8ez-MMqm`^&=7>9$!iI{MW&y#6h7Z+OFhkzfAu7s|u6+xo<#-#+QY)0YW& zRT3u@-IBB@5K`Xv^{KBv{e1h4n>Kv=)Kgb}b#A_WW}}e|&9!Weg-Q|=1cH9nC(SbY zsiWQQOg;6~md!8Lr+3vgWntfS@`+0c0>yy?owsd%Z1?X^@7ep_Wy_AacKeQ}4!I|D zP%{Tw_tk67*Ea{N%aUq@5}MMOuYL8QuYB``>>t~_X-8Sw8)oNwPdP^|4ud61i_if@ zQDUq$&bhA!T3$6fci>$gyZNJEeCC-Q{)K$OOSoLLkapJ#6%dAkY8+Acg1Ln*X#w7Q z0u6Y1HgL$bjOXjMKX>jxAck&pMx0%gj@h|+UO72RzuUujgHpOVJUn(OaM&qf`oMNO zJAc~R&71YcGhVfFJc$CrkmZN72iW}hM!Wg(jkf}~0$hFd)dTP>F`_)RZ( z_Hj5J^&#o!AGrI8ZYP^IMq!+x%nfNN5MuErKp23O!3FPn=dTZZKVPSxzS7hi`n(|U zF&=j9>G1Tj`*MQ<*$5xU$>X7-MVGF$@3gxj|}kndf)rr z*S_=4PwqHcc<>Sc0+g2Z^+uI`nvxX;TM7y*F_1Swr@r}7w`;sT0+Ktlc zh^f#IQZEVM^lWSW_C3?gF7)ZAIc3&IlaXZwQ791-@~jw9+D-&fc*M>-$3`g>)tcg% z@dza~MJZ5PBMAvrOqLZ#Os)^=Gk4!{>s)(oJ8!3yk{fQg@gpzzf%3mM9rYY|;zaYVK+1Ea_ES1g4;MyEefY1h`Jtr^FY9H! hte5q&Ue>=G{Xd+9e9h)^&uRbw002ovPDHLkV1lK?3PS(@ diff --git a/pngtodo.txt b/pngtodo.txt index 8b8089b7..3423f527 100644 --- a/pngtodo.txt +++ b/pngtodo.txt @@ -8,6 +8,8 @@ for 0.9 after 1.0 overlaying one image on top of another + make pull reader use push reader internally to reduce code, and + increase amount of image read in an error situation optional palette creation histogram creation text conversion between different code types diff --git a/pngtrans.c b/pngtrans.c index bbab3505..759ccb58 100644 --- a/pngtrans.c +++ b/pngtrans.c @@ -2,10 +2,10 @@ /* pngtrans.c - transforms the data in a row routines used by both readers and writers - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -72,7 +72,11 @@ png_set_filler(png_structp png_ptr, int filler, int filler_loc) { png_ptr->transformations |= PNG_FILLER; png_ptr->filler = (png_byte)filler; - png_ptr->filler_loc = (png_byte)filler_loc; + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB && png_ptr->bit_depth == 8) png_ptr->usr_channels = 4; diff --git a/pngwio.c b/pngwio.c new file mode 100644 index 00000000..904c3196 --- /dev/null +++ b/pngwio.c @@ -0,0 +1,174 @@ + +/* pngwio.c - functions for data output + + libpng 1.0 beta 3 - version 0.89 + For conditions of distribution and use, see copyright notice in png.h + Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + May 25, 1996 + + This file provides a location for all output. Users which need + special handling are expected to write functions which have the same + arguments as these, and perform similar functions, but possibly use + different output methods. Note that you shouldn't change these + functions, but rather write replacement functions and then change + them at run time with png_set_write_fn(...) */ + +#define PNG_INTERNAL +#include "png.h" + +/* Write the data to whatever output you are using. The default routine + writes to a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered writes. This should never be asked + to write more then 64K on a 16 bit machine. The cast to png_size_t is + there to quiet warnings of certain compilers. */ + +void +png_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + if (png_ptr->write_data_fn) + (*(png_ptr->write_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL write function"); +} + +/* This is the function which does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void +png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + png_uint_32 check; + + check = fwrite(data, 1, (png_size_t)length, (FILE *)(png_ptr->io_ptr)); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +#ifdef _MSC_VER +/* for FP_OFF */ +#include +#endif + +static void +png_default_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) +{ + png_uint_32 check; + png_byte *n_data; + + /* Check if data really is near. If so, use usual code. */ +#ifdef _MSC_VER + /* do it this way just to quiet warning */ + FP_OFF(n_data) = FP_OFF(data); + if (FP_SEG(n_data) == FP_SEG(data)) +#else + /* this works in MSC also but with lost segment warning */ + n_data = (png_byte *)data; + if ((png_bytep)n_data == data) +#endif + { + check = fwrite(n_data, 1, (png_size_t)length, (FILE *)(png_ptr->io_ptr)); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = (png_size_t)length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ + err = fwrite(buf, 1, written, (FILE *)(png_ptr->io_ptr)); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +#endif + +/* This function is called to output any data pending writing (normally + to disk). After png_flush is called, there should be no data pending + writing in any buffers. */ +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +void +png_flush(png_structp png_ptr) +{ + if (png_ptr->output_flush_fn) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +static void +png_default_flush(png_structp png_ptr) +{ + if ((FILE *)(png_ptr->io_ptr)) + fflush((FILE *)(png_ptr->io_ptr)); +} +#endif + +/* This function allows the application to supply new output functions for + libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png output data structure + io_ptr - pointer to user supplied structure containing info about + the output functions. May be NULL. + write_data_fn - pointer to a new output function which takes as its + arguments a pointer to a png_struct, a pointer to + data to be written, and a 32-bit unsigned int which is + the number of bytes to be written. The new write + function should call png_error(png_ptr, "Error msg") + to exit and output any fatal error messages. + flush_data_fn - pointer to a new flush function which takes as its + arguments a pointer to a png_struct. After a call to + the flush function, there should be no data in any buffers + or pending transmission. If the output method doesn't do + any buffering of ouput, a function prototype must still be + supplied although it doesn't have to do anything. If + PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + time, output_flush_fn will be ignored, although it must be + supplied for compatibility. */ +void +png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + png_ptr->io_ptr = io_ptr; + + if (write_data_fn) + png_ptr->write_data_fn = write_data_fn; + else + png_ptr->write_data_fn = png_default_write_data; + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + if (output_flush_fn) + png_ptr->output_flush_fn = output_flush_fn; + else + png_ptr->output_flush_fn = png_default_flush; +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + png_ptr->read_data_fn = NULL; +} + diff --git a/pngwrite.c b/pngwrite.c index 58070b67..fd68e7a2 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1,10 +1,10 @@ /* pngwrite.c - general routines to write a png file - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ /* get internal access to png.h */ @@ -48,6 +48,8 @@ png_write_info(png_structp png_ptr, png_infop info) #endif if (info->valid & PNG_INFO_PLTE) png_write_PLTE(png_ptr, info->palette, info->num_palette); + else if (info->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images\n"); #if defined(PNG_WRITE_tRNS_SUPPORTED) if (info->valid & PNG_INFO_tRNS) png_write_tRNS(png_ptr, info->trans, &(info->trans_values), @@ -73,10 +75,13 @@ png_write_info(png_structp png_ptr, png_infop info) #endif #if defined(PNG_WRITE_tIME_SUPPORTED) if (info->valid & PNG_INFO_tIME) + { png_write_tIME(png_ptr, &(info->mod_time)); - /* Check to see if we need to write text chunks */ + png_ptr->flags |= PNG_FLAG_WROTE_tIME; + } #endif #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) + /* Check to see if we need to write text chunks */ if (info->num_text) { int i; /* local counter */ @@ -92,6 +97,8 @@ png_write_info(png_structp png_ptr, png_infop info) png_write_zTXt(png_ptr, info->text[i].key, info->text[i].text, info->text[i].text_length, info->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text\n"); #endif } else @@ -100,6 +107,8 @@ png_write_info(png_structp png_ptr, png_infop info) /* write uncompressed chunk */ png_write_tEXt(png_ptr, info->text[i].key, info->text[i].text, info->text[i].text_length); +#else + png_warning(png_ptr, "Unable to write uncompressed text\n"); #endif } } @@ -114,12 +123,16 @@ png_write_info(png_structp png_ptr, png_infop info) void png_write_end(png_structp png_ptr, png_infop info) { + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + /* see if user wants us to write information chunks */ if (info) { #if defined(PNG_WRITE_tIME_SUPPORTED) /* check to see if user has supplied a time chunk */ - if (info->valid & PNG_INFO_tIME) + if (info->valid & PNG_INFO_tIME && + !(png_ptr->flags & PNG_FLAG_WROTE_tIME)) png_write_tIME(png_ptr, &(info->mod_time)); #endif #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) @@ -131,28 +144,33 @@ png_write_end(png_structp png_ptr, png_infop info) /* loop through comment chunks */ for (i = 0; i < info->num_text; i++) { +#if defined(PNG_WRITE_zTXt_SUPPORTED) /* check to see if comment is to be compressed */ if (info->text[i].compression >= 0) { -#if defined(PNG_WRITE_zTXt_SUPPORTED) /* write compressed chunk */ png_write_zTXt(png_ptr, info->text[i].key, info->text[i].text, info->text[i].text_length, info->text[i].compression); -#endif } - else - { #if defined(PNG_WRITE_tEXt_SUPPORTED) + else +#endif +#endif +#if defined(PNG_WRITE_tEXt_SUPPORTED) + { /* write uncompressed chunk */ png_write_tEXt(png_ptr, info->text[i].key, info->text[i].text, info->text[i].text_length); -#endif } +#endif } } #endif } + + png_ptr->mode |= PNG_AFTER_IDAT; + /* write end of png file */ png_write_IEND(png_ptr); } @@ -180,31 +198,70 @@ png_convert_from_time_t(png_timep ptime, time_t ttime) #endif /* initialize png structure, and allocate any memory needed */ -void -png_write_init(png_structp png_ptr) +png_structp +png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr, + png_error_ptr warn_fn, png_error_ptr error_fn) { - jmp_buf tmp_jmp; /* to save current jump buffer */ - png_msg_ptr error_fn; - png_msg_ptr warning_fn; - png_voidp msg_ptr; + png_structp png_ptr; - /* save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); - error_fn = png_ptr->error_fn; - warning_fn = png_ptr->warning_fn; - msg_ptr = png_ptr->msg_ptr; + if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL) + { + return (png_structp)NULL; + } - /* reset all variables to 0 */ - png_memset(png_ptr, 0, sizeof (png_struct)); - /* restore jump buffer and error functions */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; - png_ptr->msg_ptr = msg_ptr; + if (setjmp(png_ptr->jmpbuf)) + { + png_large_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->zstream); + png_destroy_struct(png_ptr); + return (png_structp)NULL; + } + + png_set_error_fn(png_ptr, error_ptr, warn_fn, error_fn); + + if (user_png_ver == NULL || strcmp(user_png_ver, png_libpng_ver)) + { + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0]) + { + png_error(png_ptr, "Incompatible libpng versions"); + } + else + { + png_warning(png_ptr, "Different libpng versions"); + } + } /* initialize zbuf - compression buffer */ png_ptr->zbuf_size = PNG_ZBUF_SIZE; png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size); + + png_set_write_fn(png_ptr, NULL, NULL, NULL); + + png_ptr->do_free |= PNG_FREE_STRUCT; + + return (png_ptr); +} + + +/* initialize png structure, and allocate any memory needed */ +void +png_write_init(png_structp png_ptr) +{ + jmp_buf tmp_jmp; /* to save current jump buffer */ + + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, sizeof (png_struct)); + + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size); + png_set_write_fn(png_ptr, NULL, NULL, NULL); } /* write a few rows of image data. If the image is interlaced, @@ -248,7 +305,7 @@ png_write_image(png_structp png_ptr, png_bytepp image) } } -/* write a row of image data */ +/* called by user to write a row of image data */ void png_write_row(png_structp png_ptr, png_bytep row) { @@ -350,72 +407,18 @@ png_write_row(png_structp png_ptr, png_bytep row) if (png_ptr->transformations) png_do_write_transformations(png_ptr); - /* filter rows that have been proved to help */ - if (png_ptr->do_filter) + /* find a filter if necessary, filter the row and write it out */ + png_write_find_filter(png_ptr, &(png_ptr->row_info)); + + /* trade current and prev rows so next filter references are correct */ + if (png_ptr->prev_row) { - /* save row to previous row */ - png_memcpy(png_ptr->save_row, png_ptr->row_buf, - (png_size_t)png_ptr->row_info.rowbytes + 1); + png_bytep tptr; - /* filter row */ - png_write_filter_row(&(png_ptr->row_info), png_ptr->row_buf, - png_ptr->prev_row); - - /* trade saved pointer and prev pointer so next row references are correctly */ - { /* scope limiter */ - png_bytep tptr; - - tptr = png_ptr->prev_row; - png_ptr->prev_row = png_ptr->save_row; - png_ptr->save_row = tptr; - } + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; } - else - /* set filter row to "none" */ - png_ptr->row_buf[0] = 0; - - /* set up the zlib input buffer */ - png_ptr->zstream->next_in = png_ptr->row_buf; - png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1; - /* repeat until we have compressed all the data */ - do - { - int ret; /* return of zlib */ - - /* compress the data */ - ret = deflate(png_ptr->zstream, Z_NO_FLUSH); - /* check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream->msg) - png_error(png_ptr, png_ptr->zstream->msg); - else - png_error(png_ptr, "zlib error"); - } - - /* see if it is time to write another IDAT */ - if (!png_ptr->zstream->avail_out) - { - /* write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream->next_out = png_ptr->zbuf; - png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; - } - /* repeat until all data has been compressed */ - } while (png_ptr->zstream->avail_in); - - /* finish row - updates counters and flushes zlib if last row */ - png_write_finish_row(png_ptr); - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_ptr->flush_rows++; - - if (png_ptr->flush_dist > 0 && - png_ptr->flush_rows >= png_ptr->flush_dist) - { - png_write_flush(png_ptr); - } -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ } #if defined(PNG_WRITE_FLUSH_SUPPORTED) @@ -432,7 +435,8 @@ png_write_flush(png_structp png_ptr) { int wrote_IDAT; - if (png_ptr->mode != PNG_HAVE_IDAT) + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) return; do @@ -477,65 +481,184 @@ png_write_flush(png_structp png_ptr) } #endif /* PNG_WRITE_FLUSH_SUPPORTED */ +/* free all memory used by the write */ +void +png_destroy_write_struct(png_structpp png_ptr, png_infopp info_ptr) +{ + if (info_ptr && *info_ptr) + { + png_destroy_struct((voidp)*info_ptr); + *info_ptr = (png_infop)NULL; + } -/* free any memory used in png struct */ + if (png_ptr && *png_ptr) + { + png_write_destroy(*png_ptr); + png_destroy_struct((voidp)*png_ptr); + *png_ptr = (png_structp)NULL; + } +} + + +/* free any memory used in png struct (old) */ void png_write_destroy(png_structp png_ptr) { jmp_buf tmp_jmp; /* save jump buffer */ + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; /* free any memory zlib uses */ deflateEnd(png_ptr->zstream); png_free(png_ptr, png_ptr->zstream); + /* free our memory. png_free checks NULL for us. */ png_large_free(png_ptr, png_ptr->zbuf); png_large_free(png_ptr, png_ptr->row_buf); png_large_free(png_ptr, png_ptr->prev_row); - png_large_free(png_ptr, png_ptr->save_row); + png_large_free(png_ptr, png_ptr->sub_row); + png_large_free(png_ptr, png_ptr->up_row); + png_large_free(png_ptr, png_ptr->avg_row); + png_large_free(png_ptr, png_ptr->paeth_row); + /* reset structure */ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; + png_memset(png_ptr, 0, sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); } + +/* Allow the application to select one or more filters to use */ void -png_set_filtering(png_structp png_ptr, int filter) +png_set_filter(png_structp png_ptr, int method, int filters) { - png_ptr->do_custom_filter = 1; - png_ptr->do_filter = (png_byte)filter; + /* We allow 'method' only for future expansion of the base filter method */ + if (method == 0) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { + case 5: + case 6: + case 7: png_warning(png_ptr, "Unknown custom row filter for method 0"); + case 0: png_ptr->do_filter = PNG_FILTER_NONE; break; + case 1: png_ptr->do_filter = PNG_FILTER_SUB; break; + case 2: png_ptr->do_filter = PNG_FILTER_UP; break; + case 3: png_ptr->do_filter = PNG_FILTER_AVG; break; + case 4: png_ptr->do_filter = PNG_FILTER_PAETH; break; + default: png_ptr->do_filter = (png_byte)filters; break; + } + + /* If we have allocated the row_buf, then we should have also allocated + * all of the filter buffers that have been selected. + */ + if (png_ptr->row_buf) + { + if (png_ptr->do_filter & PNG_FILTER_SUB && !(png_ptr->sub_row)) + { + png_ptr->sub_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->sub_row[0] = 1; /* Set the row filter type */ + } + + if (png_ptr->do_filter & PNG_FILTER_UP && !(png_ptr->up_row)) + { + if (!(png_ptr->prev_row)) + { + png_warning(png_ptr, "Can't to add up filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_UP; + } + else + { + png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->up_row[0] = 2; /* Set the row filter type */ + } + } + + if (png_ptr->do_filter & PNG_FILTER_AVG && !(png_ptr->avg_row)) + { + if (!(png_ptr->prev_row)) + { + png_warning(png_ptr, "Can't add average filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_AVG; + } + else + { + png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->up_row[0] = 3; /* Set the row filter type */ + } + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH && !(png_ptr->paeth_row)) + { + if (!(png_ptr->prev_row)) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_PAETH; + } + else + { + png_ptr->paeth_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->paeth_row[0] = 4; /* Set the row filter type */ + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); } void png_set_compression_level(png_structp png_ptr, int level) { - png_ptr->zlib_custom_level = 1; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; png_ptr->zlib_level = level; } void png_set_compression_mem_level(png_structp png_ptr, int mem_level) { - png_ptr->zlib_custom_mem_level = 1; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; png_ptr->zlib_mem_level = mem_level; } void png_set_compression_strategy(png_structp png_ptr, int strategy) { - png_ptr->zlib_custom_strategy = 1; + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; } void png_set_compression_window_bits(png_structp png_ptr, int window_bits) { - png_ptr->zlib_custom_window_bits = 1; + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; png_ptr->zlib_window_bits = window_bits; } void png_set_compression_method(png_structp png_ptr, int method) { - png_ptr->zlib_custom_method = 1; + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; png_ptr->zlib_method = method; } diff --git a/pngwtran.c b/pngwtran.c index 757af61b..cea52a29 100644 --- a/pngwtran.c +++ b/pngwtran.c @@ -1,10 +1,10 @@ /* pngwtran.c - transforms the data in a row for png writers - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL @@ -18,7 +18,7 @@ png_do_write_transformations(png_structp png_ptr) #if defined(PNG_WRITE_FILLER_SUPPORTED) if (png_ptr->transformations & PNG_FILLER) png_do_write_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->filler_loc); + png_ptr->flags); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) if (png_ptr->transformations & PNG_PACK) @@ -299,12 +299,12 @@ png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) /* remove filler byte */ void png_do_write_filler(png_row_infop row_info, png_bytep row, - png_byte filler_loc) + png_byte flags) { if (row && row_info && row_info->color_type == PNG_COLOR_TYPE_RGB && row_info->bit_depth == 8) { - if (filler_loc == PNG_FILLER_AFTER) + if (flags & PNG_FLAG_FILLER_AFTER) { png_bytep sp, dp; diff --git a/pngwutil.c b/pngwutil.c index cde6ab51..5ca26ef8 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1,10 +1,10 @@ /* pngwutil.c - utilities to write a png file - libpng 1.0 beta 2 - version 0.88 + libpng 1.0 beta 3 - version 0.89 For conditions of distribution and use, see copyright notice in png.h Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - January 25, 1996 + May 25, 1996 */ #define PNG_INTERNAL #include "png.h" @@ -139,6 +139,81 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, { png_byte buf[13]; /* buffer to store the IHDR info */ + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case 0: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + case 16: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for grayscale image"); + } + break; + case 2: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGB image"); + png_ptr->channels = 3; + break; + case 3: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + case 4: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + png_ptr->channels = 2; + break; + case 6: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + png_ptr->channels = 4; + break; + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != 0) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = 0; + } + + if (filter_type != 0) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = 0; + } + + if (interlace_type != 0 && interlace_type != 1) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = 1; + } + + /* save off the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3); + /* set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + /* pack the header information into the buffer */ png_save_uint_32(buf, width); png_save_uint_32(buf + 4, height); @@ -147,65 +222,36 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, buf[10] = (png_byte)compression_type; buf[11] = (png_byte)filter_type; buf[12] = (png_byte)interlace_type; - /* save off the relevent information */ - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->color_type = (png_byte)color_type; - png_ptr->interlaced = (png_byte)interlace_type; - png_ptr->width = width; - png_ptr->height = height; - - switch (color_type) - { - case 0: - case 3: - png_ptr->channels = 1; - break; - case 2: - png_ptr->channels = 3; - break; - case 4: - png_ptr->channels = 2; - break; - case 6: - png_ptr->channels = 4; - break; - } - png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); - png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3); - /* set the usr info, so any transformations can modify it */ - png_ptr->usr_width = png_ptr->width; - png_ptr->usr_bit_depth = png_ptr->bit_depth; - png_ptr->usr_channels = png_ptr->channels; /* write the chunk */ - png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13); + png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13); /* initialize zlib with png info */ png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream)); png_ptr->zstream->zalloc = png_zalloc; png_ptr->zstream->zfree = png_zfree; png_ptr->zstream->opaque = (voidpf)png_ptr; - if (!png_ptr->do_custom_filter) + if (!(png_ptr->do_filter)) { if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8) - png_ptr->do_filter = 0; + png_ptr->do_filter = PNG_FILTER_NONE; else - png_ptr->do_filter = 1; + png_ptr->do_filter = PNG_ALL_FILTERS; } - if (!png_ptr->zlib_custom_strategy) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) { - if (png_ptr->do_filter) + if (png_ptr->do_filter != PNG_FILTER_NONE) png_ptr->zlib_strategy = Z_FILTERED; else png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; } - if (!png_ptr->zlib_custom_level) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; - if (!png_ptr->zlib_custom_mem_level) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) png_ptr->zlib_mem_level = 8; - if (!png_ptr->zlib_custom_window_bits) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) png_ptr->zlib_window_bits = 15; - if (!png_ptr->zlib_custom_method) + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) png_ptr->zlib_method = 8; deflateInit2(png_ptr->zstream, png_ptr->zlib_level, png_ptr->zlib_method, @@ -215,6 +261,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, png_ptr->zstream->next_out = png_ptr->zbuf; png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->mode = PNG_HAVE_IHDR; } /* write the palette. We are careful not to trust png_color to be in the @@ -227,6 +274,21 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, int number) png_colorp pal_ptr; png_byte buf[3]; + if (number == 0 || number > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + png_ptr->num_palette = number; + png_write_chunk_start(png_ptr, png_PLTE, number * 3); for (i = 0, pal_ptr = palette; i < number; @@ -238,6 +300,7 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, int number) png_write_chunk_data(png_ptr, buf, (png_uint_32)3); } png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; } /* write an IDAT chunk */ @@ -245,6 +308,7 @@ void png_write_IDAT(png_structp png_ptr, png_bytep data, png_uint_32 length) { png_write_chunk(png_ptr, png_IDAT, data, length); + png_ptr->mode |= PNG_HAVE_IDAT; } /* write an IEND chunk */ @@ -252,6 +316,7 @@ void png_write_IEND(png_structp png_ptr) { png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0); + png_ptr->mode |= PNG_AFTER_IEND; } #if defined(PNG_WRITE_gAMA_SUPPORTED) @@ -280,6 +345,16 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) /* make sure we don't depend upon the order of PNG_COLOR_8 */ if (color_type & PNG_COLOR_MASK_COLOR) { + int maxbits; + + maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth; + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } buf[0] = sbit->red; buf[1] = sbit->green; buf[2] = sbit->blue; @@ -287,12 +362,22 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) } else { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } buf[0] = sbit->gray; size = 1; } if (color_type & PNG_COLOR_MASK_ALPHA) { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } buf[size++] = sbit->alpha; } @@ -311,22 +396,50 @@ png_write_cHRM ( png_structp png_ptr, double white_x, double white_y, png_byte buf[32]; /* each value is saved int 1/100,000ths */ + if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || + white_x + white_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM white point specified"); + return; + } itemp = (png_uint_32)(white_x * 100000.0 + 0.5); png_save_uint_32(buf, itemp); itemp = (png_uint_32)(white_y * 100000.0 + 0.5); png_save_uint_32(buf + 4, itemp); + + if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 || + red_x + red_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM red point specified"); + return; + } itemp = (png_uint_32)(red_x * 100000.0 + 0.5); png_save_uint_32(buf + 8, itemp); itemp = (png_uint_32)(red_y * 100000.0 + 0.5); png_save_uint_32(buf + 12, itemp); + + if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 || + green_x + green_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM green point specified"); + return; + } itemp = (png_uint_32)(green_x * 100000.0 + 0.5); png_save_uint_32(buf + 16, itemp); itemp = (png_uint_32)(green_y * 100000.0 + 0.5); png_save_uint_32(buf + 20, itemp); + + if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 || + blue_x + blue_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM blue point specified"); + return; + } itemp = (png_uint_32)(blue_x * 100000.0 + 0.5); png_save_uint_32(buf + 24, itemp); itemp = (png_uint_32)(blue_y * 100000.0 + 0.5); png_save_uint_32(buf + 28, itemp); + png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32); } #endif @@ -341,6 +454,11 @@ png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, if (color_type == PNG_COLOR_TYPE_PALETTE) { + if (num_trans <= 0 || num_trans > png_ptr->num_palette) + { + png_warning(png_ptr,"Invalid number of transparent colors specified"); + return; + } /* write the chunk out as it is */ png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)num_trans); } @@ -358,6 +476,10 @@ png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, png_save_uint_16(buf + 4, tran->blue); png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)6); } + else + { + png_warning(png_ptr, "Can't write tRNS with and alpha channel"); + } } #endif @@ -370,6 +492,11 @@ png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) if (color_type == PNG_COLOR_TYPE_PALETTE) { + if (back->index > png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } buf[0] = back->index; png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)1); } @@ -396,6 +523,12 @@ png_write_hIST(png_structp png_ptr, png_uint_16p hist, int number) int i; png_byte buf[3]; + if (number <= 0 || number > png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2)); for (i = 0; i < number; i++) { @@ -415,6 +548,19 @@ png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, int key_len; key_len = png_strlen(key); + + if (key_len == 0) + { + png_warning(png_ptr, "Invalid text keyword length"); + return; + } + else if (key_len > 80) + { + png_warning(png_ptr, "Text keyword length restricted to 80 characters\n"); + key[80] = '\0'; + key_len = 80; + } + /* make sure we count the 0 after the key */ png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)(key_len + text_len + 1)); @@ -441,6 +587,24 @@ png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, key_len = png_strlen(key); + if (key_len == 0) + { + png_warning(png_ptr, "Invalid text keyword length"); + return; + } + else if (key_len > 80) + { + png_warning(png_ptr, "Text keyword length restricted to 80 characters\n"); + key[80] = '\0'; + key_len = 80; + } + + if (compression != 0) + { + png_warning(png_ptr, "Only type 0 compression allowed for text\n"); + compression = 0; + } + /* we can't write the chunk until we find out how much data we have, which means we need to run the compresser first, and save the output. This shouldn't be a problem, as the vast majority of @@ -603,6 +767,9 @@ png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, { png_byte buf[9]; + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + png_save_uint_32(buf, x_pixels_per_unit); png_save_uint_32(buf + 4, y_pixels_per_unit); buf[8] = (png_byte)unit_type; @@ -620,6 +787,9 @@ png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset, { png_byte buf[9]; + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + png_save_uint_32(buf, x_offset); png_save_uint_32(buf + 4, y_offset); buf[8] = (png_byte)unit_type; @@ -636,6 +806,14 @@ png_write_tIME(png_structp png_ptr, png_timep mod_time) { png_byte buf[7]; + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + png_save_uint_16(buf, mod_time->year); buf[2] = mod_time->month; buf[3] = mod_time->day; @@ -656,15 +834,47 @@ png_write_start_row(png_structp png_ptr) (((png_uint_32)png_ptr->usr_channels * (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1); - /* set up filtering buffers, if filtering */ - if (png_ptr->do_filter) + png_ptr->row_buf[0] = 0; + + /* set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) { + png_ptr->sub_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->sub_row[0] = 1; /* Set the row filter type */ + } + + /* We only need to keep the previous row if we are using one of these */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* set up previous row buffer */ png_ptr->prev_row = (png_bytep )png_large_malloc(png_ptr, - png_ptr->rowbytes + 1); - png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1); - png_ptr->save_row = (png_bytep )png_large_malloc(png_ptr, - png_ptr->rowbytes + 1); - png_memset(png_ptr->save_row, 0, (png_size_t)png_ptr->rowbytes + 1); + (((png_uint_32)png_ptr->usr_channels * + (png_uint_32)png_ptr->usr_bit_depth * + png_ptr->width + 7) >> 3) + 1); + png_memset(png_ptr->prev_row, 0, (((png_uint_32)png_ptr->usr_channels * + (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->up_row[0] = 2; /* Set the row filter type */ + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->avg_row[0] = 3; /* Set the row filter type */ + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep )png_large_malloc(png_ptr, + png_ptr->rowbytes + 1); + png_ptr->paeth_row[0] = 4; /* Set the row filter type */ + } } /* if interlaced, we need to set up width and height of pass */ @@ -736,9 +946,11 @@ png_write_finish_row(png_structp png_ptr) } - /* reset filter row */ + /* reset the row above the image for the next pass */ if (png_ptr->prev_row) - png_memset(png_ptr->prev_row, 0, (png_size_t)png_ptr->rowbytes + 1); + png_memset(png_ptr->prev_row, 0, (((png_uint_32)png_ptr->usr_channels * + (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1); + /* if we have more data to get, go get it */ if (png_ptr->pass < 7) return; @@ -935,220 +1147,215 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) } #endif -/* this filters the row. Both row and prev_row have space at the - first byte for the filter byte. */ +/* this filters the row, chooses which filter to use, if it has not already + * been given by the application, and then writes the row out with the + * chosen filter */ void -png_write_filter_row(png_row_infop row_info, png_bytep row, - png_bytep prev_row) +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) { - int minf, bpp; - png_uint_32 i, v; - png_uint_32 s0, s1, s2, s3, s4, mins; - png_bytep rp, pp, cp, lp; + png_bytep prev_row, best_row, row_buf; + png_uint_32 mins; + int bpp; /* find out how many bytes offset each pixel is */ bpp = (row_info->pixel_depth + 7) / 8; - if (bpp < 1) - bpp = 1; + + prev_row = png_ptr->prev_row; + best_row = row_buf = png_ptr->row_buf; + mins = 0xffffffff; /* the prediction method we use is to find which method provides the smallest value when summing the abs of the distances from zero using anything >= 128 as negitive numbers. */ - s0 = s1 = s2 = s3 = s4 = 0; - for (i = 0, rp = row + 1, pp = prev_row + 1, lp = row + 1 - bpp, - cp = prev_row + 1 - bpp; - i < bpp; i++, rp++, pp++, lp++, cp++) + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. */ + if (png_ptr->do_filter & PNG_FILTER_NONE && + png_ptr->do_filter != PNG_FILTER_NONE) { - /* check none filter */ - v = *rp; - if (v < 128) - s0 += v; - else - s0 += 256 - v; + png_bytep rp; + png_uint_32 sum = 0; + int i, v; - /* check up filter */ - v = (png_byte)(((int)*rp - (int)*pp) & 0xff); - - if (v < 128) - s2 += v; - else - s2 += 256 - v; - - /* check avg filter */ - v = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff); - - if (v < 128) - s3 += v; - else - s3 += 256 - v; + for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + mins = sum; } - /* some filters are same until we get past bpp */ - s1 = s0; - s4 = s2; - - for (; i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++) + /* sub filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) { - int a, b, c, pa, pb, pc, p; + png_bytep rp, dp, lp; + png_uint_32 sum = 0; + int i, v; - /* check none filter */ - v = *rp; - if (v < 128) - s0 += v; - else - s0 += 256 - v; + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; - /* check sub filter */ - v = (png_byte)(((int)*rp - (int)*lp) & 0xff); + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - if (v < 128) - s1 += v; - else - s1 += 256 - v; - - /* check up filter */ - v = (png_byte)(((int)*rp - (int)*pp) & 0xff); - - if (v < 128) - s2 += v; - else - s2 += 256 - v; - - /* check avg filter */ - v = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff); - - if (v < 128) - s3 += v; - else - s3 += 256 - v; - - /* check paeth filter */ - b = *pp; - c = *cp; - a = *lp; - p = a + b - c; - pa = abs(p - a); - pb = abs(p - b); - pc = abs(p - c); - - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; - - v = (png_byte)(((int)*rp - p) & 0xff); - - if (v < 128) - s4 += v; - else - s4 += 256 - v; + sum += (v < 128) ? v : 256 - v; + } + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } } - mins = s0; - minf = 0; - - if (s1 < mins) + /* up filter */ + if (png_ptr->do_filter & PNG_FILTER_UP) { - mins = s1; - minf = 1; + png_bytep rp, dp, pp; + png_uint_32 sum = 0; + int i, v; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } } - if (s2 < mins) + /* avg filter */ + if (png_ptr->do_filter & PNG_FILTER_AVG) { - mins = s2; - minf = 2; + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0; + int i, v; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_info->rowbytes; + i++, rp++, pp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } } - if (s3 < mins) + /* paeth filter */ + if (png_ptr->do_filter & PNG_FILTER_PAETH) { - mins = s3; - minf = 3; + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0; + int i, v; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes; + i++, rp++, pp++, lp++, dp++, cp++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp; + c = *cp; + a = *lp; + + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + + v = *dp = (png_byte)(((int)*rp - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } } - if (s4 < mins) - { - minf = 4; - } - - /* set filter byte */ - row[0] = (png_byte)minf; - - /* do filter */ - switch (minf) - { - /* sub filter */ - case 1: - for (i = bpp, rp = row + (png_size_t)row_info->rowbytes, - lp = row + (png_size_t)row_info->rowbytes - bpp; - i < row_info->rowbytes; i++, rp--, lp--) - { - *rp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - } - break; - /* up filter */ - case 2: - for (i = 0, rp = row + (png_size_t)row_info->rowbytes, - pp = prev_row + (png_size_t)row_info->rowbytes; - i < row_info->rowbytes; i++, rp--, pp--) - { - *rp = (png_byte)(((int)*rp - (int)*pp) & 0xff); - } - break; - /* avg filter */ - case 3: - for (i = row_info->rowbytes, - rp = row + (png_size_t)row_info->rowbytes, - pp = prev_row + (png_size_t)row_info->rowbytes, - lp = row + (png_size_t)row_info->rowbytes - bpp; - i > bpp; i--, rp--, lp--, pp--) - { - *rp = (png_byte)(((int)*rp - (((int)*lp + (int)*pp) / - 2)) & 0xff); - } - for (; i > 0; i--, rp--, pp--) - { - *rp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff); - } - break; - /* paeth filter */ - case 4: - for (i = row_info->rowbytes, - rp = row + (png_size_t)row_info->rowbytes, - pp = prev_row + (png_size_t)row_info->rowbytes, - lp = row + (png_size_t)row_info->rowbytes - bpp, - cp = prev_row + (png_size_t)row_info->rowbytes - bpp; - i > 0; i--, rp--, lp--, pp--, cp--) - { - int a, b, c, pa, pb, pc, p; - - b = *pp; - if (i > bpp) - { - c = *cp; - a = *lp; - } - else - { - a = c = 0; - } - p = a + b - c; - pa = abs(p - a); - pb = abs(p - b); - pc = abs(p - c); - - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; - - *rp = (png_byte)(((int)*rp - p) & 0xff); - } - break; - } + /* Do the actual writing of the filtered row data from the chosen filter */ + png_write_filtered_row(png_ptr, best_row); +} + + +/* do the actual writing of a filtered row */ +void +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +{ + /* set up the zlib input buffer */ + png_ptr->zstream->next_in = filtered_row; + png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1; + /* repeat until we have compressed all the data */ + do + { + int ret; /* return of zlib */ + + /* compress the data */ + ret = deflate(png_ptr->zstream, Z_NO_FLUSH); + /* check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream->msg) + png_error(png_ptr, png_ptr->zstream->msg); + else + png_error(png_ptr, "zlib error"); + } + + /* see if it is time to write another IDAT */ + if (!png_ptr->zstream->avail_out) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream->next_out = png_ptr->zbuf; + png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size; + } + /* repeat until all data has been compressed */ + } while (png_ptr->zstream->avail_in); + + /* finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ } diff --git a/readme.txt b/readme.txt index b1c64cef..9da76ce7 100644 --- a/readme.txt +++ b/readme.txt @@ -1,41 +1,56 @@ -readme.txt - for libpng 0.88 +readme.txt - for libpng 0.89 -This is a bug fix for the second beta version of libpng 1.0, and -a more secure progressive (push) reader. The progressive reader -hasn't been tested as much as the pull reader, but seems to work ok. +This is a bug fix for the third beta version of libpng 1.0. The +changes from libpng-0.88 are bug fixes and some changes to the +API itself to increase robustness with shared libraries. This +release is based on libpng-0.88, but has been modified from that +version by Andreas Dilger because the +original author, Guy Schalnat, has not been able to keep up with +the time demands of maintaining this library. -I've implemented the callback functions for the error/warning -messages and the input/output. See the libpng.txt -for details. I've also added defines to support medium memory -models, so every type now has pointer defines. For example, -a pointer to the png_struct is now png_structp, while a double -pointer is now png_structpp. The old way should work, but I'll -be using the new way from now on in all my examples. Those of -you doing medium memory model or changing the error/warning -or input/output functions should try these and report back to -me any problems. +The callback functions for the error/warning messages have changed +since the last release because their implementation was broken, +and it was thought best to change the API itself (which was only +introduced in libpng-0.88 itself) to alert the user to the change, +rather than mislead the user into thinking their application was +OK after re-compiling. This means that calls to png_set_message_fn() +no longer exist, because the previously suggested method of calling +them before png_read_init() or png_write_init() is now ineffective. -I've tried to incorporate all the changes and makefiles everyone -sent me. However, I may of lost some in the flood. If you sent -me a change and I didn't put it in, send it again. Sorry. +The preferred method of setting the error and warning callbacks +has been incorporated into the allocation of the png_struct and +info_struct itself, which allow them to be safely used during the +initialization of the structure, as well as to keep the size of +the png_struct internal to the library, rather than at compile time +of the application. This will hopefully remove any problems with +dynamically linked libraries, and should be considered the preferred +method of creating these structures, although the previous +initialization API is still available for compatibility. See libpng.txt +for more information on the new API. + +The changes made to the library, and bugs fixed are based on discussions +on the PNG implementation mailing list +and not on material submitted to Guy. For a detailed description on using libpng, read libpng.txt. For usage information and restrictions (what little they are) on libpng, see png.h. For a description on using zlib (the compression library used by libpng) and zlib's restrictions, see zlib.h -I have included a general makefile, but you may have to modify it -for your own needs. +I have included a general makefile, as well as several machine and compiler +specific ones, but you may have to modify one for your own needs. You will need zlib 0.95 or later to run this. zlib is a compression library that is useful for more things then just png files. If -you need a compression library, check out zlib.h +you need a compression library, check out zlib.h. There was a bug in +zlib <= 0.99 which caused it to generate invalid compression streams +on some occasions. Later versions of zlib do not have this problem. zlib should be available at the same place that libpng is. If not, it should be at ftp.uu.net in /graphics/png Eventually, it will be at ftp.uu.net in /pub/archiving/zip/zlib -You will also want a copy of the PNG specification. It should +You may also want a copy of the PNG specification. It should be available at the same place you picked up libpng. If it is not there, try ftp.uu.net in the /graphics/png directory. @@ -55,17 +70,18 @@ Finally, if you get any warning messages when compiling libpng (note: not zlib), and they are easy to fix, I'd appreciate the fix. Please mention "libpng" somewhere in the subject line. Thanks. -You can reach me at: +This release was created and will be supported by myself, and the +PNG group. + +adilger@enel.ucalgary.ca +png-implement@dworkin.wustl.edu + +You can reach Guy, the original libpng author, at (internet preferred): internet: schalnat@group42.com CompuServe: 75501,1625 -I tend to check my CompuServe account very infrequently, so you may -want to use the internet account. If I don't answer your email -immediately, please be patient. If you don't receive a reply within -a week, you may want to write and ask if I got the first email. - -Please do not send me general questions about PNG. Send them to +Please do not send general questions about PNG. Send them to the address in the specification. At the same time, please do not send libpng questions to that address, send them to me. I'll get them in the end anyway. If you have a question about something