Packaging and Encoding of [Image_Codec] Common Picture Formats-Android Platform PNG

Keywords: zlib Android ascii codec

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

Posted by cafrow on Mon, 16 Sep 2019 22:45:46 -0700