Article directory
PNG Picture Format
PNG(Portable Network Graphics) is a rasterized, lossless compressed image file format. The purpose of the design is to replace GIF, which is the most widely used lossless compressed image format in the network. We can use tools to convert the previous Bitmap to PNG.
Below is the PNG image of png_4x2_32bit.png converted from the BMP mentioned in the previous chapter. The picture is relatively small. Look carefully:
(https://img-blog.csdn.net/20180403180016486? Watermark/2/text/aHR0cHM6Ly9ibG9nLmNzG4ubmV0L2YW9qaWFuZ2x1bw=/font/5a6L5L2T/fontsize/400/I0JBQFCMA=/dissolve/70) Characteristics of PNG Refer to [Baidu Encyclopedia PNG Picture Features] (https://baike.baidu.com/item/png/174154?fr=aladdin#2)- Small volume
Due to bandwidth constraints in network communication, under the premise of ensuring clear and realistic pictures, it is impossible to use large-scale bmp format files in Web pages. - Lossless compressed PNG files are compressed by the derivative algorithm of LZ77 algorithm. As a result, high compression ratio is obtained without losing data. It uses special coding method to mark the repeated data, so it has no effect on the color of the image and can not produce color loss, so it can be saved repeatedly without reducing the quality of the image.
- Index color mode
PNG-8 format is similar to GIF image, and RGB color image is converted to index color image by using 8-bit palette. The color information of each pixel is no longer preserved in the image, but the representative color numbers selected from the image. Each number corresponds to a color, so the amount of data of the image is reduced, which is very beneficial to the transmission of color images. - Optimized Network Transport Display
PNG images are browsed in streaming mode on browsers, even though the interleaved images will provide the viewer with a basic image content before downloading completely, and then gradually become clear. It allows continuous reading and writing of image data. This feature is suitable for displaying and generating images in the communication process. - Supporting transparency
PNG can define 256 transparent layers for the original image, so that the edges of the color image can be smoothly fused with any background, thus eliminating the jagged edges completely. This function is not available in GIF and JPEG. - PNG also supports Alpha channel transparency of true color and gray level images.
- Up to 24 bits of true color image and 8 bits of gray image are supported.
- Supports transparency/translucency of Alpha channels.
- Gamma calibration information supporting image brightness.
- Supports the storage of additional text information to preserve image name, author, copyright, creation time, annotations and other information.
- Asymptotic display and streaming read-write are suitable for displaying the preview effect quickly in network transmission before displaying the panorama.
- Use CRC to prevent file errors.
- The latest PNG standard allows multiple images to be stored in one file.
PNG file structure
PNG image format file (or data stream) consists of an 8-byte PNG file signature domain and more than three chunk s organized according to a specific structure.
We open the PNG graph png_4x2_32bit.png in binary form:
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 00000010: 0000 0004 0000 0002 0806 0000 007f a87d ...............} 00000020: 6300 0000 0173 5247 4200 aece 1ce9 0000 c....sRGB....... 00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a... 00000040: 0009 7048 5973 0000 0ec3 0000 0ec3 01c7 ..pHYs.......... 00000050: 6fa8 6400 0000 1849 4441 5418 5763 0082 o.d....IDAT.Wc.. 00000060: ffff 8118 4c81 2110 8029 b0e0 ffff 0005 ....L.!..)...... 00000070: 2b10 f0fa b027 6800 0000 0049 454e 44ae +....'h....IEND. 00000080: 4260 82 B`.
- File header
The PNG file contains an 8-byte signature:
8950 4e47 0d0a 1a0a
Value Value | Acting Purpose |
---|---|
89 | Beyond the scope of ASCII characters, avoid some software processing pictures as text |
50 4E 47 | ASCII Value of'PNG', Identification of PNG File |
0D 0A | Dos-style carriage return to detect DOS-Unix line end data conversion |
1A | Dos-style line breaks |
0A | Unix-style carriage return |
- data block
PNG file contains more than three data blocks, which are composed in a specific order. Data blocks are divided into key data blocks and auxiliary data blocks. Basically, each data block is described in the following structure:
Name | Bytes | Explain |
---|---|---|
Length | 4 byte | Specifies the length of a data field in a data block that does not exceed (231-1) bytes |
Chunk Type Code | 4 byte | Data block type codes consist of ASCII letters (A-Z and a-z) |
Chunk Data | Variable length | Store data specified by Chunk Type Code |
CRC (Cyclic Redundancy Detection) | 4 byte | Storage of cyclic redundant codes used to detect errors |
- Key data blocks include
Data block symbol | Data block name | Multiple data blocks | Optional | Position restriction |
---|---|---|---|---|
IHDR | File Header Data Block | no | no | First block |
IDAT | Image data block | yes | no | Continuous with other IDAT s |
IEND | Image End Data | no | no | The last data block |
Compared with Bitmap, the key data block has one more IEND block.
- IHDR data block
IHDR, also known as file header data block, contains the basic information of image data stored in PNG file, and it should appear in PNG data stream as the first data block, and only one file header data block can be found in a PNG data stream (file).
IHDR header block consists of 13 bytes
00000000: ---- ---- ---- ---- 0000 000d 4948 4452 .PNG........IHDR 00000010: 0000 0004 0000 0002 0806 0000 007f a87d ...............} 00000020: 63-- ---- ---- ---- ---- ---- ---- ---- c....sRGB.......
Its format is shown in the following table:
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
0000 000d | 13 | size | 4 | Data block size |
4948 4452 | IHDR | type | ASCII of IHDR | Types of data blocks |
0000 0004 | 4 | Width | 4 bytes | Image width, in pixels |
0000 0002 | 2 | Height | 4 bytes | Image height, in pixels |
08 | 8 | Bit depth | 1 byte | Image depth: Indexed color images: 1, 2, 4 or 8 Grayscale images: 1, 2, 4, 8 or 16 True color image: 8 or 16 |
06 | 6 | ColorType | 1 byte | Color type: 0: Grayscale image, 1, 2, 4, 8 or 16 2: True color image, 8 or 16 3: Index color images, 1, 2, 4 or 8 4: Gray-scale images with alpha-channel data, 8 or 16 6: True color image with alpha channel data, 8 or 16 |
00 | 0 | Compression method | 1 byte | Compression Method (LZ77 Derivative Algorithms) |
00 | 0 | Filter method | 1 byte | Filter method |
00 | 0 | Interlace method | 1 byte | Interlaced scanning method: 0: Non-interlaced scanning 1: Adam 7 (7-pass interlaced scanning method developed by Adam M. Costello) |
7fa8 7d63 | CRC | 4 | CRC check code |
According to our documents
- sRGB data block
00000020: --00 0000 0173 5247 4200 aece 1ce9 ---- c....sRGB.......
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
00 0000 01 | 1 | size | 4 | Data block size |
73 5247 42 | sRGB | type | ASCII of sRGB | Types of data blocks |
00 | 0 | sRGB mode | 1 bytes | There are 0.123 four modes available for reference. Introduction of W3 to sRGB |
aece 1ce9 | CRC | 4 | CRC check code |
Not all decoders support sRGB, so if there are sRGB data blocks, there must be gAMA data blocks or cHRM data blocks to be compatible with decoders that do not support sRGB.
- gAMA data block
00000020: ---- ---- ---- ---- ---- ---- ---- 0000 c....sRGB....... 00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a...
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
0000 0004 | 4 | size | 4 | Data block size |
6741 4d41 | gAMA | type | ASCII of gAMA | Types of data blocks |
0000 b18f | 0 | gama check | 1 bytes | gama check |
0bfc 6105 | CRC | 4 | CRC check code |
If there are sRGB data blocks or iCCP data blocks, gAMA data blocks are not needed and override.
- pHYs data block
Expected physical pixel size or scale when displaying pictures.
00000030: ---- ---- ---- ---- ---- ---- ---- 0000 ..gAMA......a... 00000040: 0009 7048 5973 0000 0ec3 0000 0ec3 01c7 ..pHYs.......... 00000050: 6fa8 64-- ---- ---- ---- ---- ---- ---- o.d....IDAT.Wc..
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
0000 0009 | 9 | size | 4 | Data block size |
7048 5973 | pHYs | type | ASCII of pHYs | Types of data blocks |
0000 0ec3 | 3779 | x axis | 4 bytes | gama check |
0000 0ec3 | 3779 | y axis | 4 bytes | gama check |
01 | 1 | Unit specifier | 1 | Unit description |
c76f a8 64 | CRC | 4 | CRC check code |
Unit specifier, with the following defined values:
0: unit is unknown; just the scaling ratio is defined
1: unit is the metre
Then finally we got to our data block.
- IDAT data block
The key data block, the data here is the data of png pictures
00000050: ---- --00 0000 1849 4441 5418 5763 0082 o.d....IDAT.Wc.. 00000060: ffff 8118 4c81 2110 8029 b0e0 ffff 0005 ....L.!..)...... 00000070: 2b10 f0fa b027 6800 0000 0049 454e 44ae +....'h....IEND. 00000080: 4260 82 B`.
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
00 0000 18 | 24 | size | 4 | Data block size |
49 4441 54 | IDAT | type | ASCII of IDAT | Types of data blocks |
1857 6300 82ff ff81 184c 8121 1080 29b0 e0ff ff00 052b 10f0 |
png coded data | 24 | png coded data | |
fab0 2768 | CRC | 4 | CRC check code |
- IEND data block
Key data blocks
00000070: ---- ---- ---- --00 0000 0049 454e 44ae +....'h....IEND. 00000080: 4260 82 B`.
offset | Value Value | Domain name | Bytes | Explain |
---|---|---|---|---|
00 0000 00 | 4 | size | 4 | Data block size |
49 454e 44 | IEND | type | ASCII of IEND | Types of data blocks |
ae 4260 82 | CRC | 4 | CRC check code |
The above is the description of PNG file structure ~~~
PNG Compression Principle
For this section, please refer to the original blog: Principle of PNG Format Pictures
PNG compression process is completely lossless, compressed files can accurately restore the original map, which needs to be completed in two stages: inference (also known as filtering) and compression.
filter
Delta encoding is one of the most powerful digital compression methods. The principle is to replace the following values with other values based on the value of the previous data, such as:
[2,3,4,5,6,7,8] can be transformed into [2,1,1,1,1,1,1,1]. The algorithm is
[2, 3-2=1, 4-3=1, 5-4=1, 6-5=1, 7-6=1, 8-7=1]
It's obvious that if your data is linearly correlated (meaning that there is little difference or correlation between the front and back values in a set of data), you can convert your data set into a set of repetitive, low values, which are easier to compress.
The PNG format uses filtering in Delta encoding. The principle is that for each row of pixels, a current pixel is related to its left, upper and upper left corner pixels.
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwNTIyMjAzNjU0MzE2)For example, if we want to code a given pixel by its difference from the average of A and B (X-(A+B)/2), then we will get:
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwNTIyMjAzNjI3MDM0)We used ABC to infer the value of X, and then we replaced X with a smaller value.
It should be noted that the pixels in each row may be different. PNG allows five different inference algorithms. They are:
- No filtration
- X-A
- X-B
- X-(A+B)/2 (also known as average)
Paeth Inference (Linear Method of A,B,C, This Complicated See W3C Provisions)
It is explained here that the most suitable filtering algorithm should be selected for each row of pixels so that the minimum number of special values can be obtained. Here are our examples of different models:
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwNTIyMjAzNzEyMjg0)It should be noted that these filters work on each row of pixels rather than on a single pixel. That is to say, the filter will work on the red pixels in each row, and then on the blue pixels separately. (Although the pixels in the same row will use the same filter)
Now PNG format has some good methods in selecting filters. Developers have found some good rules based on the experience of using different types of pictures. For example, for palette images and 8-bit gray images, do not filter. For other pictures, choose a filter that minimizes the sum of absolute differences: add up the absolute values of all values, then compare the values of different filters, and choose the filter that adds up to get the minimum value.
compress
After a row of pixels is filtered, DEFLATE compression is performed, which is an extension of LZ77. This algorithm combines LZ77 coding and Huffman coding. It is almost the same as PKWARE, PKZIP, GZIP and so on. Although this method is available, there are still some points needing attention when it is used to compress image data:
- Deflate algorithm can only match between 3 and 258 symbols, so the maximum compression ratio can only reach 1035:1.
- If the matched symbols are less than 3, you will incur some additional overhead to represent these symbols.
These two points above mean that the size of your image will be affected by the matching degree of each row of pixels.
You can see these two pictures. The 270x90 on the left is only 20k, while the 270x92 on the right is twice as big as the one on the left.
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwNTIyMjAzNzI3NjI4)This seems illogical. A picture with 540 pixels is half as compressed. But if we look at it carefully, we can see why. The following chart shows how the compressor compresses a given pixel. Dark blue represents areas with high compression rates, and yellow/red represents areas with little compression.
How does this happen? The reason is that each row of pixels in a small image has a higher degree of matching, so its compression rate is higher. If you adjust the size and change the matching degree, this may happen. Some potential matching objects are not in the compressed region, they are not matched, which may lead to a large image.
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTYwNTIyMjAzNzM3Nzg4)If you want to know the compression rate of your PNG image, you can do the following PNGThermal To glance at.
PNG picture codec libpng
There are many open source projects for encoding and decoding PNG pictures. Libpng is a relatively mature official png codec, which is provided in the form of dynamic libraries. libpng libraries can be used when using libpng libraries. LodePNG It is an integrated codec with no dependence and can be used directly without loading zlib or libpng, https://github.com/lvandeve/lodepng. LodePNG suggests that you go to understand, through LodePNG can understand the implementation of PNG codec very well. Here we focus on using libpng.
On Android platform, the source code of libpng is in the external/libpng directory; the current version should be 16.34.
https://sourceforge.net/projects/libpng/files/libpng16/1.6.34/libpng-1.6.34.tar.gz
The compression algorithm used by png is separated:
git clone https://github.com/madler/zlib.git
We use Android Studio to create a pure Native application that is directly compiled in Native, using libpng and zlib.
Refer to github for sample code Codec-PngCodec This is our PngCodec file structure:
├── build.gradle ├── CMakeLists.txt ├── libs ├── png │ └── libpng-1.6.34 ├── src │ ├── AndroidManifest.xml │ ├── cpp │ │ └── PngCodecNativeActivity.cpp │ ├── java │ └── res └── zlib └── zlib-1.2.11
Put libpng and zlib in the project catalogue. Connect the project to CMakeLists.txt.
CMake of zlib
add_library( zlib STATIC zlib/zlib-1.2.11/adler32.c zlib/zlib-1.2.11/compress.c zlib/zlib-1.2.11/crc32.c zlib/zlib-1.2.11/deflate.c zlib/zlib-1.2.11/gzclose.c zlib/zlib-1.2.11/gzlib.c zlib/zlib-1.2.11/gzread.c zlib/zlib-1.2.11/gzwrite.c zlib/zlib-1.2.11/infback.c zlib/zlib-1.2.11/inflate.c zlib/zlib-1.2.11/inftrees.c zlib/zlib-1.2.11/inffast.c zlib/zlib-1.2.11/trees.c zlib/zlib-1.2.11/uncompr.c zlib/zlib-1.2.11/zutil.c ) target_include_directories(zlib PRIVATE zlib/zlib-1.2.11 )
The Make of libpng
add_library( png STATIC png/libpng-1.6.34/png.c png/libpng-1.6.34/pngerror.c png/libpng-1.6.34/pngget.c png/libpng-1.6.34/pngmem.c png/libpng-1.6.34/pngpread.c png/libpng-1.6.34/pngread.c png/libpng-1.6.34/pngrio.c png/libpng-1.6.34/pngrtran.c png/libpng-1.6.34/pngrutil.c png/libpng-1.6.34/pngset.c png/libpng-1.6.34/pngtrans.c png/libpng-1.6.34/pngwio.c png/libpng-1.6.34/pngwrite.c png/libpng-1.6.34/pngwtran.c png/libpng-1.6.34/pngwutil.c ) target_include_directories(png PRIVATE png/libpng-1.6.34 zlib/zlib-1.2.11 )
CMake for native Applications
add_library( png_codec SHARED src/main/cpp/PngCodecNativeActivity.cpp ) target_include_directories(png_codec PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue png/libpng-1.6.34 zlib/zlib-1.2.11 ) target_link_libraries( png_codec native_activity_glue android zlib png log )
Native applications are compiled into libpng_codec.so and used in Android Manifest:
<application ... android:hasCode="false"> <activity android:name="android.app.NativeActivity"> <meta-data android:name="android.app.lib_name" android:value="png_codec" />
At compilation time, pnglibconf.h needs to be placed in the png/libpng-1.6.34 directory and copied from scripts/pnglibconf.h.prebuilt. We commented out NEON's support here.
The following is a simple implementation of reading png pictures:
void readPngFile(char *name) { ALOGE("readPngFile %s\n", name); // The first few sentences are bullshit. Initialize all kinds of structures. FILE *file = fopen(name, "rb"); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop info_ptr = png_create_info_struct(png_ptr); setjmp(png_jmpbuf(png_ptr)); // This sentence is very important. png_init_io(png_ptr, file); // Read the file. png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0); // Get the width, height and color of the document int m_width = png_get_image_width(png_ptr, info_ptr); int m_height = png_get_image_height(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); // Apply for a memory to play with, here is the c + + grammar, do not want to be compiled on c. int size = m_height * m_width * 4; char* head = static_cast<char*>(malloc(size)); int pos = 0; // In row_pointers is the legendary rgba data. png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); // Copy!! Note that if you read png without channel A, you need 3-bit, 3-bit read. Another thing is to pay attention to the problem of bytes. The simplest thing is not to use the width that can not be divided by 4. Read what you really want to use, you need to add the relevant alignment processing here. ALOGE("png file %s size(%dx%d) pixles:", name, m_width, m_height); for (int i = 0; i < m_height; i++) { for (int j = 0; j < (4 * m_width); j += 4) { head[pos] = row_pointers[i][j + 2]; // blue pos++; head[pos] = row_pointers[i][j + 1]; // green pos++; head[pos] = row_pointers[i][j]; // red pos++; head[pos] = row_pointers[i][j + 3]; // alpha pos++; ALOGE("%02x %02x %02x %02x", head[pos-4], head[pos-3], head[pos-2], head[pos-1]); } } free(head); // Well, you can do anything with this data... You can either display it or print it out. png_destroy_read_struct(&png_ptr, &info_ptr, 0); fclose(file); return; }
We read our png_4x2_32bit.png, pixels are:
0000 00 ff 0000 ffff ff00 00ff 00ff 00ff ffff ffff 00ff 00ff 0000 ffff ff00 00ff
Do you remember what pixels were like before you switched to png when you were working on bmp?
ffff ff7f 00ff 007f 0000 ff7f ff00 007f 0000 0000 0000 ff00 ff00 0000 00ff 0000
Compare:
- Alpha was removed and set to opaque during the conversion.
- The scanning mode of png is the same as that of bmp bar. png starts from the top left, while bmp starts from the bottom left.
Look back at the test code:
The PNG information is described by the structure png_inforp, and the ontology is png_info_def, which is defined in pnginfo.h.
struct png_info_def { /* The following are necessary for every PNG file */ png_uint_32 width; /* width of image in pixels (from IHDR) */ png_uint_32 height; /* height of image in pixels (from IHDR) */ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ png_size_t rowbytes; /* bytes needed to hold an untransformed row */ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ /* The following three should have been named *_method not *_type */ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ ... ... };
The PNG file is described by the structure png_structp, and the ontology is png_struct_def, which is defined in pngstruct.h.
struct png_struct_def { #ifdef PNG_SETJMP_SUPPORTED jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ size_t jmp_buf_size; /* size of the above, if allocated */ #endif png_error_ptr error_fn; /* function for printing errors and aborting */ #ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; /* function for printing warnings */ #endif 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; /* ptr to application struct for I/O functions */ ... ...
libpng is written in c, using the structure, so that it can be used in C/C++.
The reading of PNG information, using the png_read_png interface, is defined in pngread.c. In the png_read_info function, all data blocks of PNG are read out by using the cyclic mode. For example, IHDR data block is processed by png_handle_IHDR.
/* Read and check the IDHR chunk */ void /* PRIVATE */ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; png_uint_32 width, height; int bit_depth, color_type, compression_type, filter_type; int interlace_type; png_debug(1, "in png_handle_IHDR"); if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) png_chunk_error(png_ptr, "out of place"); /* Check the length */ if (length != 13) png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; png_crc_read(png_ptr, buf, 13); png_crc_finish(png_ptr, 0); width = png_get_uint_31(png_ptr, buf); height = png_get_uint_31(png_ptr, buf + 4); bit_depth = buf[8]; color_type = buf[9]; compression_type = buf[10]; filter_type = buf[11]; interlace_type = buf[12]; /* Set internal variables */ png_ptr->width = width; png_ptr->height = height; png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->interlaced = (png_byte)interlace_type; png_ptr->color_type = (png_byte)color_type; #ifdef PNG_MNG_FEATURES_SUPPORTED png_ptr->filter_type = (png_byte)filter_type; #endif png_ptr->compression_type = (png_byte)compression_type; /* Find number of channels */ switch (png_ptr->color_type) { default: /* invalid, png_set_IHDR calls png_error */ case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: png_ptr->channels = 1; break; case PNG_COLOR_TYPE_RGB: png_ptr->channels = 3; break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: png_ptr->channels = 4; break; } /* Set up other useful info */ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); }
IHDR is 13 in size, so apply directly for 13 byte buf. The information is saved in info_ptr.
Picture data is obtained by png_read_image.
void PNGAPI png_read_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i, image_height; int pass, j; png_bytepp rp; png_debug(1, "in png_read_image"); if (png_ptr == NULL) return; #ifdef PNG_READ_INTERLACING_SUPPORTED if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) { pass = png_set_interlace_handling(png_ptr); /* And make sure transforms are initialized. */ png_start_read_image(png_ptr); } else { if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) == 0) { /* Caller called png_start_read_image or png_read_update_info without * first turning on the PNG_INTERLACE transform. We can fix this here, * but the caller should do it! */ png_warning(png_ptr, "Interlace handling should be turned on when " "using png_read_image"); /* Make sure this is set correctly */ png_ptr->num_rows = png_ptr->height; } /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in * the above error case. */ pass = png_set_interlace_handling(png_ptr); } #else if (png_ptr->interlaced) png_error(png_ptr, "Cannot read interlaced image -- interlace handler disabled"); pass = 1; #endif image_height=png_ptr->height; for (j = 0; j < pass; j++) { rp = image; for (i = 0; i < image_height; i++) { png_read_row(png_ptr, *rp, NULL); rp++; } } }
In png_read_row, the pixels data is obtained by png_read_IDAT_data. The data here is compressed and need to be decompressed with zlib. The inflateInit() + inflate() + inflateEnd() and other functions of zlib are decompressed.
The decompression is applied to the z_stream_s structure to read and write the input and output data of zlib.
typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text for deflate, or the decoding state for inflate */ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream;
We can add our own log to print out the pixel data of the decompressed PNG picture.
PngCodec: png_show_byte bnext_in 1857630082FFFF81184C8121108029B0E0FFFF00052B10F0
Is this the same file as when we edit png pictures with a binary editor?
- libpng encoding
Similar to encoding and decoding, it provides png_write_info and png_write_image, one writing Png file information and one writing pixel. Let's take an example. When we used the PNG transcoding tool to convert bmp to png, we lost the Alpha information. Now we add the Alpha information.
void writePngFile(char *fileName, png_byte* src , int width, int height) { png_structp png_ptr; png_infop info_ptr; png_colorp palette; FILE *fp = fopen(fileName, "wb"); if (fp == NULL) return ; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return ; } /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, NULL); return ; } if (setjmp(png_jmpbuf(png_ptr))) { /* If we get here, we had a problem writing the file */ fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return ; } /* Next, tell libpng to write the PNG file in fwrite and pass it to FILE* fp, which has been opened in binary mode. */ png_init_io(png_ptr, fp); /* Setting properties of png files */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Allocate palette space. The value of constant PNG_MAX_PALETTE_LENGTH is 256. */ palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); /* The easiest way to write the image (you may have a different memory * layout, however, so choose what fits your needs best). You need to * use the first method if you aren't handling interlacing yourself. */ png_uint_32 k; png_byte *image; png_bytep row_pointers[height]; image = src; if (height > PNG_UINT_32_MAX/sizeof(png_bytep)) png_error (png_ptr, "Image is too tall to process in memory"); for (k = 0; k < height; k++) row_pointers[k] = image + k*width*3; /* One of the following output methods is REQUIRED */ png_write_image(png_ptr, row_pointers); //end, do the necessary sweeping work: png_write_end(png_ptr, info_ptr); png_free(png_ptr, palette); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); ALOGE("success write png file %s\n", fileName); return ; }
Keep in mind that PNG images are scanned from the top left and cut in RGBA format, so pixel is the data to be adjusted accordingly.
void buildPngFile(char *fileName) { int width = 4; int height = 2; png_byte src[] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x7f }; writePngFile(fileName,src,width, height, PNG_COLOR_TYPE_RGBA); readPngFile(fileName); }
log data:
~ E/PngCodec: 00 00 00 ff ~ E/PngCodec: 00 00 ff ff ~ E/PngCodec: ff 00 00 ff ~ E/PngCodec: 00 ff 00 ff ~ E/PngCodec: ff ff ff 7f ~ E/PngCodec: 00 ff 00 7f ~ E/PngCodec: 00 00 ff 7f ~ E/PngCodec: ff 00 00 7f
The PNG image after Alpha is retained as follows:
(https://img-blog.csdn.net/2018040318184773? Watermark/2/text/aHR0cHM6Ly9ibG9nLmNzG4ubmV0L2YW9qaWZ2x1bw=/font/5a6L5L2T/fontsize/400/fill/I0JBQFCMA=/dissolve/70)The magnified effect:
[Enlarged effect] (https://img-blog.csdn.net/20180403181934551? Watermark/2/text/aHR0cHM6Ly9ibG9nLmNzG4ubmV0L2NoYW9qaWFuZ2x1bw=/font/5a6L5L2T/fonize/400/I0JBQkFCMA=/disso/70)The top row is opaque and the bottom row is translucent.
On Android platform, libpng libraries are not directly invoked. Android provides a unified management of encoding and decoding. This role is skia. Besides png, skia can also use other technologies, such as jpg, gif and so on.
This is where Png is introduced. The format of PNG file and the encoding and decoding of Png pictures with libpng are briefly introduced. Further, we continue to explore.
Instance code can be downloaded in high github.
Codec-PngCodec