diff options
Diffstat (limited to 'gs/libpng/libpng.txt')
-rw-r--r-- | gs/libpng/libpng.txt | 1519 |
1 files changed, 1519 insertions, 0 deletions
diff --git a/gs/libpng/libpng.txt b/gs/libpng/libpng.txt new file mode 100644 index 000000000..a603c3a4c --- /dev/null +++ b/gs/libpng/libpng.txt @@ -0,0 +1,1519 @@ +libpng.txt - a description on how to use and modify libpng + + libpng 1.0 beta 5 - version 0.95 + Updated and distributed by Andreas Dilger <adilger@enel.ucalgary.ca>, + Copyright (c) 1996, 1997 Andreas Dilger + March 15, 1997 + 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 26, 1996 + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995 Frank J. T. Wojcik + December 18, 1995 && January 20, 1996 + +I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. + +Libpng was written as a companion to the PNG specification, as a way +to reduce the amount of time and effort it takes to support the PNG +file format in application programs. Most users will not have to +modify the library significantly; advanced users may want to modify it +more. All attempts were made to make it as complete as possible, +while keeping the code easy to understand. Currently, this library +only supports C. Support for other languages is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of it's users. + +Libpng uses zlib for its compression and decompression of PNG files. +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + + + +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 a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info were delevoped. The fields +of png_info are still available for older applications, but it is +suggested that applications use the new interfaces if at all possible. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include <png.h> + + + +III. Reading + +Reading PNG files: + +We'll now walk you through the possible functions to call when reading +in a PNG file, briefly explaining the syntax and purpose of each one. +See example.c and png.h for more detail. While Progressive reading +is covered in the next section, you will still need some of the +functions discussed in this section to read a PNG file. + +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. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +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 are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): 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. + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return; + } + fread(header, 1, number, fp); + is_png = png_check_sig(header, 0, number); + if (!is_png) + { + return; + } + +Next, png_struct and png_info need to be allocated and initialized. 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, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions 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 = 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 = png_create_info_struct(png_ptr); + if (!info_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; + } + +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_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + return; + } + +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 +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +You are now ready to read all the file information up to the actual +image data. You do this with a call to png_read_info(). + + png_read_info(png_ptr, info_ptr); + +Functions are used to get the information from the info_ptr: + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, &compression_type, &filter_type); + + width - holds the width of the image in pixels (up to 2^31). + height - holds the height of the image in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the image channels. + (valid values are 1, 2, 4, 8, 16 and depend also on the + color_type. See also significant bits (sBIT) below). + color_type - describes which color/alpha channels are present. + PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTERLACE_TYPE_ADAM7 + compression_type - (must be PNG_COMPRESSION_TYPE_BASE for PNG 1.0) + filter_type - (must be PNG_FILTER_TYPE_BASE for PNG 1.0) + + channels = png_get_channels(png_ptr, info_ptr); + channels - number of channels of info for the color type + (valid values are 1 (GRAY, PALETTE), 2 (GRAY_ALPHA), + 3 (RGB), 4 (RGB_ALPHA or RGB + filler byte)) + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + rowbytes - number of bytes needed to hold a row + + signature = png_get_signature(png_ptr, info_ptr); + signature - holds the signature read from the file (if any). The + data is kept in the same offset it would be if the + whole signature were read (ie if an application had + already read in 4 bytes of signature before staring + libpng, the remaining 4 bytes would be in signature[4] + through signature[7] (see png_set_sig_bytes())). + +These are also important, but their validity depends on whether the chunk +has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and +png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_<chunk> are set directly if they are simple data types, or a pointer +into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); + palette - the palette for the file (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written at (PNG_INFO_gAMA) + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for (PNG_INFO_sBIT) + the gray, red, green, and blue channels, whichever + are appropriate for the given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); + trans - array of transparent entries for palette (PNG_INFO_tRNS) + trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); (PNG_INFO_hIST) + hist - histogram of palette (array of png_color_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + + num_text = png_get_text(png_ptr, info_ptr, &text_ptr); + text_ptr - array of png_text holding image comments + text_ptr[i]->key - keyword for comment. + text_ptr[i]->text - text comments for current keyword. + text_ptr[i]->compression - type of compression used on "text" + PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt + num_text - number of comments + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type); + offset_x - positive offset from the left edge of the screen + offset_y - positive offset from the top edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type); + res_x - pixels/unit physical resolution in x direction + res_y - pixels/unit physical resolution in x direction + unit_type - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER + +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, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations or non-printing +symbols. See the PNG specification for more details. There is also +no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 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_ptr 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 +after the image, so, to make sure you have read all the text chunks, +don't mess with these until after you read the stuff after the image. +This will be mentioned again below in the discussion that goes with +png_read_end(). + +After you've read the header 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 +certain color types and bit depths. Even though each transformation +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 colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +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 (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth < 8) + png_set_expand(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, 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 (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background: + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(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 (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image whave been "scaled" or "shifted" up to the next +higher possible bit depth (eg from 5 bits/sample in the range [0,31] to +8 bits/sample in the range [0, 255]). However, it is also possible to +convert the PNG pixel data back to the original bit depth of the image. +This call reduces the pixels back down to the original bit depth: + + png_color_16p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_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 (color_type == PNG_COLOR_TYPE_RGB || + 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 (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" 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. This transformation +does not affect images that already have full alpha channels. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +dispay (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +If you have a grayscale and you are using png_set_expand() to change to +a higher bit-depth you must indicate if the supplied background gray +is supplied in the original file bit depth (need_expand = 1) or in the +expanded bit depth (need_expand = 0). Similarly, if you are reading +a paletted image, you must indicate if you have supplied the background +as a palette index that needs to be expanded (need_expand = 1). You can +also specify an RGB triplet that isn't in the palette when setting your +background for a paletted image. + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background), + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for the +DISPLAY_GAMMA environment variable, which will hopefully be correctly set. + + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same screen gamma value */ + else if ((gamma_str = getenv("DISPLAY_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for PC monitors */ + screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45); + +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 +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 +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) + { + png_color_16p histogram; + + png_get_hIST(png_ptr, info_ptr, &histogram); + png_set_dither(png_ptr, palette, num_palette, max_screen_colors, + histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_GRAY) + png_set_invert_mono(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 +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here. + + number_passes = png_set_interlace_handling(png_ptr); + +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 structure's 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. 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 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 +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read int the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_TYPE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +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_row(png_ptr, &row_pointers, NULL); + +If the file is interlaced (info_ptr->interlace_type != 0), things get +somewhat harder. The only current (PNG Specification version 1.0) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_TYPE_ADAM7) +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. + +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(): + + if (interlace_type == PNG_INTERLACE_TYPE_ADAM7) + number_passes = png_set_interlace_handling(png_ptr); + +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, +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 +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the rectangle effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +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, 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, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + +For a more compact example of reading a PNG image, see the file example.c. + + +Reading PNG files progressively: + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +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 = 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 = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return -1; + } + + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return -1; + } + + /* 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_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 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. + */ +} + +/* 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) +{ + /* 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: + */ + + 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. + */ +} + +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. + + Most people won't do much here, perhaps setting a flag that + marks the image as finished. + */ +} + + + +IV. Writing + +Much of this is very similar to reading. However, everything of +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 anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return; + } + +Next, png_struct and png_info need to be allocated and initialized. +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 = 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 = png_create_info_struct(png_ptr); + if (!info_ptr) + { + 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 +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 +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 (setjmp(png_ptr->jmpbuf)) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return; + } + +Now you need to set up the output 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 +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +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 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. + + + /* 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); + png_set_compression_method(png_ptr, 8); + +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 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, 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: + + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, + interlace_type, + width - holds the width of the image in pixels (up to 2^31). + height - holds the height of the image in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the image channels. + (valid values are 1, 2, 4, 8, 16 and depend also on the + color_type. See also significant bits (sBIT) below). + color_type - describes which color/alpha channels are present. + PNG_COLOR_TYPE_GRAY (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_TYPE_NONE or PNG_INTER_LACE_TYPE_ADAM7 + compression_type - (must be PNG_COMPRESSION_TYPE_DEFAULT for PNG 1.0) + filter_type - (must be PNG_FILTER_TYPE_DEFAULT for PNG 1.0) + Any or all of interlace_type, compression_type, of filter_type can be + NULL if you are not interested in their values. + + png_set_PLTE(png_ptr, info_ptr, palette, num_palette); + palette - the palette for the file (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created at (PNG_INFO_gAMA) + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for (PNG_INFO_sBIT) + the gray, red, green, and blue channels, whichever + are appropriate for the given color type (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, trans_values); + trans - array of transparent entries for palette (PNG_INFO_tRNS) + trans_values - transparent pixel for non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); (PNG_INFO_hIST) + hist - histogram of palette (array of png_color_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image comments + text_ptr[i]->key - keyword for comment. + text_ptr[i]->text - text comments for current keyword. + text_ptr[i]->compression - type of compression used on "text" + PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt + num_text - number of comments in text_ptr + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); + offset_x - positive offset from the left edge of the screen + offset_y - positive offset from the top edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); + res_x - pixels/unit physical resolution in x direction + res_y - pixels/unit physical resolution in x direction + unit_type - PNG_RESOLUTION_UNKOWN, PNG_RESOLUTION_METER + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +If you want, you can use max_text to hold the size of the array, but +libpng ignores it for writing (it does use it for reading). Each +png_text structure holds a keyword-text value, and a compression type. +The compression types have the same valid numbers as the compression +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 PNG_TEXT_COMPRESSION_NONE. +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +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 +keywords are found in the PNG specification, as is some recomendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +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 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. + +PNG supports modification time via the png_time structure. Two +conversion routines are proved, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +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 - PNG is year 2000 compliant!), 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 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 +certain color types and bit depths. Even though each transformation +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 expect input data with 4 bytes per pixel + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +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 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, you can write an sBIT chunk into the +file so that decoders can get the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +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, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, ie. least significant bits +first, eg. the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + 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 +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytef *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you can't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, number_of_rows); + +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_pointer = row; + + 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 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 +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 +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: + + number_passes = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. + +Then write the complete image number_passes times. + + png_write_rows(png_ptr, row_pointers, number_of_rows); + +As some of these rows are not used, and thus return immediately, +you may want to read about interlacing in the PNG specification, +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. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +You must free any data you allocated for info_ptr, such as comments, +palette, or histogram, before the call to png_destroy_write_struct(); + +For a more compact example of writing a PNG image, see the file example.c. + + +V. Modifying/Customizing libpng: + +There are two issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +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, 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 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 +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp png_ptr, voidp io_ptr, + png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp png_ptr, voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn); + + voidp io_ptr = png_get_io_ptr(png_ptr); + +The replacement I/O functions should have prototypes as follows: + + void user_read_data(png_structp png_ptr, png_bytep data, + png_uint_32 length); + void user_write_data(png_structp png_ptr, png_bytep data, + png_uint_32 length); + void user_flush_data(png_structp png_ptr); + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions. It is an error to read from +a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its 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 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. 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_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +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); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything after +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, 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. + +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, 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: + +For DOS users which only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +Configuring for Medium Model: + +Libpng's support for medium model has been tested on most of the popular +complers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the row's of data are defined as png_bytepp which is a +unsigned char far * far *. + +Configuring for gui/windowing platforms: + +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: + +All includes for libpng are in pngconf.h. If you need to add/change/delete +an include, this is the place to do it. The includes that are not +needed outside libpng are protected by the PNG_INTERNAL definition, +which is only defined for those routines inside libpng itself. The +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, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress as well as higher levels, and do so much faster. +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_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +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); + +Controlling row filtering: + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. 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. + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP; + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); + +It is also possible to influence how libpng chooses from among the +available filters. This is done in two ways - by telling it how +important it is to keep the same filter for successive rows, and +by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_selection(png_ptr, PNG_FILTER_SELECTION_WEIGHTED, + 3, weights, costs); + +The weights are multiplying factors which indicate to libpng that row +should be the same for successive rows unless another row filter is that +many times better than the previous filter. In the above example, if +the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduely influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +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 _SUPPORTED. If you are +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 + +It should be noted that versions of libpng later than 0.88 are not +distributed by the original libpng author, Guy Schalnat, but rather +another member of the original PNG Group, Andreas Dilger. Guy is still +alive and well, but he has moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destory() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. 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 applications that try to use +the old method. |