Document directory
- Libpng Data Structure
- Use of libpng
- Summary:
The above section describes how to use libjpeg to decode JPEG images. PNG images are also widely used. This article will briefly introduce how to use the open-source libpng library to decode PNG images.
Libpng Data Structure
The png_structp variable is created during libpng initialization and used internally by the libpng library. It indicates that libpng is the call context and the library user should not access this variable. When calling the libpng API, you need to pass this parameter as the first parameter.
Png_infop variable. After libpng is initialized, you can obtain this type of variable pointer from LibPNG. This variable stores information about PNG image data, which can be repaired by users of the library.
Modify and view the variable, for example, view the image information and modify the image decoding parameters. In earlier versions, members who directly access the variable are recommended to access these members through APIS.
Use libpng 0 to determine whether it is libpng data
This step is optional. Before using libpng to continue data processing, you can call the png_sig_cmp function to check whether the data is PNG. See the libpng manual for details.
1. initialize libpng
1: /* Create and initialize the png_struct with the desired error handler
2: * functions. If you want to use the default stderr and longjump method,
3: * you can supply NULL for the last three parameters. We also supply the
4: * the compiler header file version, so that we know if the application
5: * was compiled with a compatible version of the library. REQUIRED
6: */
7: png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
8: png_voidp user_error_ptr, user_error_fn, user_warning_fn);
When initializing LibPNG, you can specify a custom error handler. If you do not need to specify a custom error handler, pass null.
The png_create_read_struct function returns a variable png_structp. As mentioned earlier, this variable should not be accessed by users and should be called later.
The libpng function is passed to the libpng library.
To provide a custom memory management module, call png_create_read_struct_2 to initialize libpng:
1: png_structp png_ptr = png_create_read_struct_2
2: (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
3: user_error_fn, user_warning_fn, (png_voidp)
4: user_mem_ptr, user_malloc_fn, user_free_fn)
2. Create an image -- png_infop variable
1: /* Allocate/initialize the memory for image information. REQUIRED. */
2: info_ptr = png_create_info_struct(png_ptr);
3: if (info_ptr == NULL)
4: {
5: png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
6: return (ERROR);
7: }
As mentioned above, you will use the png_infop variable to obtain image information and set image decoding parameters.
3. Set error return points
As mentioned in the above libjpeg decoding JPEG image, the setjmp/longjmp function is used to handle exceptions. Libpng library integrates this mechanism by default to complete exception handling. The following code initialization error return points:
1: /* Set error handling if you are using the setjmp/longjmp method (this is
2: * the normal method of doing things with libpng). REQUIRED unless you
3: * set up your own error handlers in the png_create_read_struct() earlier.
4: */
5: if (setjmp(png_jmpbuf(png_ptr)))
6: {
7: /* Free all of the memory associated with the png_ptr and info_ptr */
8: png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
9: /* If we get here, we had a problem reading the file */
10: return (ERROR);
11: }
As mentioned in the preceding annotations, you must set the error return point only when the custom error processing function is not specified during libpng initialization. If a user-defined error processing function is set, libpng will call the User-Defined error processing function without returning the call point.
When an error occurs in the libpng library, libpng will automatically call the longjmp function to return to this point. At this point, we can perform necessary cleanup work.
4. Set the libpng Data Source
As mentioned in image decoding-using libjpeg to decode JPEG images, a good code library should be able to run various types of user input data, rather than sticky input data. Libpng is doing very well in this regard. It provides support for the default file input stream, and provides a user-defined callback function to complete the input of PNG data.
The code for setting file stream data is as follows:
1: /* One of the following I/O initialization methods is REQUIRED */
2: def streams /* PNG file I/O method 1 */
3: /* Set up the input control if you are using standard C streams */
4: png_init_io(png_ptr, fp);
The user-defined callback function sets the libpng Data Source Code as follows:
1: /* If you are using replacement read functions, instead of calling
2: * png_init_io() here you would call:
3: */
4: png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
5: /* where user_io_ptr is a structure you want available to the callbacks */
If you have used the png_sig_cmp function to check PNG data, you need to call the png_set_sig_bytes function to inform the libpng library. In this way, the library will skip the corresponding data when processing data. For details, refer to the libpng manual.
5. PNG Image Processing
In this step, there are two options: High-level processing and underlying processing.
High-level Processing
When the user's memory is large enough to read all the PNG data at a time and the output data format is as follows, the predefined libpng data type is as follows:
Png_transform_identity no transformation
Png_transform_strip_16 strip 16-bit samples
8 bits
Png_transform_strip_alpha discard the alpha channel
Png_transform_packing expand 1, 2 and 4-bit
Samples to bytes
Png_transform_packswap change order of packed
Pixels to LSB first
Png_transform_expand perform set_expand ()
Png_transform_invert_mono invert monochrome images
Png_transform_shift normalize pixels to
Sbit depth
Png_transform_bgr flip RGB to BGR, rgba
To bgra
Png_transform_swap_alpha flip rgba to argb or GA
To AG
Png_transform_invert_alpha change Alpha from opacity
To transparency
Png_transform_swap_endian byte-swap 16-bit Samples
Png_transform_gray_to_rgb expand grayscale Samples
To RGB (or GA to rgba)
The high-level READ function is as follows:
1: /*
2: * If you have enough memory to read in the entire image at once,
3: * and you need to specify only transforms that can be controlled
4: * with one of the PNG_TRANSFORM_* bits (this presently excludes
5: * dithering, filling, setting background, and doing gamma
6: * adjustment), then you can read the entire image (including
7: * pixels) into the info structure with this call:
8: */
9: png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
This function will decode all the image data to the info_ptr data structure. Png_transforms is an integer parameter, which is obtained by performing the or operation on the predefined data type of LibPNG. If this function is called, you cannot call the png_set_transform function to set the output data.
This function is equivalent to calling underlying functions (as described below) in the following call sequence:
A) call the png_read_info function to obtain image information.
B) According to png_transforms, call png_set_transform to set the output format conversion function.
C) Call png_read_image to decode the data of the entire image to the memory.
D) Call png_read_end to end image decoding.
After you call png_read_png, you can call the following function to obtain PNG data:
1: row_pointers = png_get_rows(png_ptr, info_ptr);
Underlying Processing
A) read the image information of the input PNG data:
1: /* The call to png_read_info() gives us all of the information from the
2: * PNG file before the first IDAT (image data chunk). REQUIRED
3: */
4: png_read_info(png_ptr, info_ptr);
This function will read the information of the input PNG data into the info_ptr data structure.
B) query Image Information
As mentioned above, png_read_info will read the information of the input PNG data into the info_ptr data structure. Next, you need to call the API to query this information.
1: png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
2: &interlace_type, int_p_NULL, int_p_NULL);
C) Set PNG output parameters (Conversion parameters)
This step is very important. You can specify the output data format, such as rgb888 and argb8888. Implemented through the png_set_xxxxx function, for example, the following code:
1: // expand images of all color-type and bit-depth to 3x8 bit RGB images
2: // let the library process things like alpha, transparency, background
3: if (bit_depth == 16)
4: png_set_strip_16(png_ptr);
5: if (color_type == PNG_COLOR_TYPE_PALETTE)
6: png_set_expand(png_ptr);
7: if (bit_depth<8)
8: png_set_expand(png_ptr);
9: if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
10: png_set_expand(png_ptr);
11: if (color_type == PNG_COLOR_TYPE_GRAY ||
12: color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
13: png_set_gray_to_rgb(png_ptr);
The code above will convert the image into the rgb888 data format. There are still many such conversion functions. Refer to the libpng manual to learn about their functions.
Although many functions that can set output parameters can be called, user requirements are unlimited. Many output formats libpng are not supported by native systems, such as yuv565, rgb565, and yuyv.
And so on. Fortunately, libpng provides a custom conversion function that allows you to register a conversion callback function to the libpng library. When libpng converts the output data
The parameters set by the png_set_xxxxx function are converted. Finally, the User-Defined conversion function is called for conversion.
1: png_set_read_user_transform_fn(png_ptr,
2: read_transform_fn);
Read_transform_fn is a user-defined data conversion function. For specific implementation, refer to the implementation in pngtest. C.
In addition, you can use png_set_user_transform_info to tell libpng about the user-defined data structure and output data of your conversion function, such as Yan
Color depth, channel, and so on. Why do you want to tell libpng? Libpng will update the PNG image details based on the information, which will be described later.
Definition:
1: png_set_user_transform_info(png_ptr, user_ptr,
2: user_depth, user_channels);
Usr_ptr is a user-defined data structure. In the User-Defined Conversion Function read_transform_fn, you can use the png_get_user_transform_ptr function to obtain the data structure. For example:
1: voidp read_user_transform_ptr =
2: png_get_user_transform_ptr(png_ptr);
D) Update the details of PNG data.
If the image information of the PNG data is changed, you need to call the png_read_update_info function to update the image details:
1: png_read_update_info(png_ptr, info_ptr);
This function will update the image data information stored in the info_ptr variable, and then call png_get_ihdr to query the image information again.
E) read PNG data
You can use the png_read_image function to read all the data into the memory at a time. For example:
1: png_read_image(png_ptr, row_pointers);
You can also call png_read_rows to read one or more rows into the memory at a time, for example:
1: for (y = 0; y < height; y++)
2: {
3: png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1);
4: }
F) end Data Reading
Use png_read_end to read PNG data. The Code is as follows:
1: /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
2: png_read_end(png_ptr, info_ptr);
6. Release libpng memory
Call png_destroy_read_struct to release the libpng memory. The Code is as follows:
1: /* Clean up after the read, and free any memory allocated - REQUIRED */
2: png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
So far, PNG data decoding is complete.
Summary:
Based on the above introduction, we can find that libpng has excellent scalability compared with libjpeg. Basically, we do not need to modify the libpng library. Its external interfaces provide sufficient flexibility and allow us to expand. From this perspective, the libpng library is worth learning its definition of external interfaces.
Original