In the previous article introduces stb_image image library, also helping to talk about the libpng and libjpeg, this article is to introduce how to compile on the Android platform using CMake libpng and libpng use of dynamic link library practice.

【 Simple and easy to use image decoding library introduction — STB_image 】

Glumes.com/post/androi…

Libpng introduction

Libpng’s official website is as follows:

www.libpng.org/pub/png/lib…

Download address:

Sourceforge.net/projects/li…

The version used in the blog is 1.6.37, which is the latest version.

Libpng is available on many blogs, but some are based on Linux and others are based on Android.mk. This article will show you how to build the Android dynamic library using CMake in Android Studio.

CMake builds the libpng dynamic library

Neon related compilation

The cmakelists. TXT file is provided in the libpng source code to explain how to compile, but it is not directly available on the Android platform, but you can use the source code as a reference.

Due to the cross-platform compilation feature of CMake, generally large project code compilation will be adapted to the platform. The common code structure is as follows:

    if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" OR
            CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
        setC arm/filter_neon_intrinsics. C arm/palette_neon_intrinsics. C arm/palette_neon_intrinsicsadd_definitions(-DPNG_ARM_NEON_OPT=2)
    endif(a)Copy the code

This code is to determine the system processor platform, different platforms need to compile different code. Libpng does this mainly because it uses neon related optimizations, which are mostly used for filter operations.

// libpng Use neon optimization acceleration method void png_read_filter_row_up_neon(png_ROW_infop row_info, png_bytep row, png_const_bytep prev_row) { png_bytep rp = row; png_bytep rp_stop = row + row_info->rowbytes; png_const_bytep pp = prev_row; png_debug(1."in png_read_filter_row_up_neon");

   for (; rp < rp_stop; rp += 16, pp += 16) { uint8x16_t qrp, qpp; qrp = vld1q_u8(rp); qpp = vld1q_u8(pp); qrp = vaddq_u8(qrp, qpp); vst1q_u8(rp, qrp); }}Copy the code

Looking at the libpng source code, to enable neon optimization, you must also define the DPNG_ARM_NEON_OPT macro with a value of 2 through the add_definitions method, otherwise neon will not be considered necessary in the source code.

To compile with neon, you also need to specify compiler parameters:

set_property(SOURCE ${libpng_arm_sources}
        APPEND_STRING PROPERTY COMPILE_FLAGS " -mfpu=neon")
Copy the code

However, there are some articles on libpng compilation online that don’t mention neon at all, so I don’t think this optimization acceleration feature will work.

However, you can see how to enable neon to compile in my Demo, and I will write a special article on neon in the future

Zlip library dependencies

Libpng dynamic library compilation also relies on the Zlip library, which is a separate download on other platforms, but not on Android, because the Android build environment provides the library itself, just as we did with the Log library.

// Specify which other SOS to compile. Z is the zlib librarytarget_link_libraries(png z log )
Copy the code

Z is the Zlip library for Android compilation.

The source code to compile

The rest is source code compilation, mainly the use of the add_library method, to specify the source file to compile.

Specific source files need to be added to the compilation, or please refer to the following links, not to post specific code, to reduce the length of the article.

Github.com/glumes/Inst…

After completing the above three procedures, you should be able to compile libpng’s dynamic library. The actual compilation process should be referred to the project code.

The use of libpng

Compiling is a small matter, the key is to use ~~~

Take decoding PNG images to obtain pixel content as an example:

Linpng initialization

The first step is to initialize libpng to get the png_structp structure. It literally represents the libpng context and is passed in as the first argument in method calls.

    // Nullptr arguments are handled with custom errors, which are not required here
    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr.nullptr.nullptr);
Copy the code

Png_create_write_struct (png_create_write_struct, png_create_write_struct)

Set the error return point

Since nullPTR was passed the parameters for the custom error handling when the PNG variable was created, we need to set the error return point so that when libpng fails, the program will return to this call point and we can do some cleanup:

    if (setjmp(png_jmpbuf(png))) {
        png_destroy_read_struct(&png, nullptr.nullptr);
        fclose(fp);
        return;
    }
Copy the code

Check whether the file is in PNG format

Libpng provides the png_SIG_cMP method to check if a file is PNG.

    #define PNG_BYTES_TO_CHECK 4
    char buf[PNG_BYTES_TO_CHECK];
    / / read buffer
    if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) ! = PNG_BYTES_TO_CHECK) {return;
    }
    / / determine
    if(! png_sig_cmp(reinterpret_cast<png_const_bytep>(buf), 0, PNG_BYTES_TO_CHECK)) {
        // If the return value is not 0, the PNG file format is used
    } 
Copy the code

If this method is called, you need to either tell libpng to skip the data or get a black screen with the png_set_SIG_bytes method, or reset the file pointer with the rewind method.

Obtaining image information

First create a pNG_INFop structure to represent the image information:

    png_infop infop = png_create_info_struct(png);
Copy the code

Then set the image data source, the premise is to get the file path:

    // Open the file according to the file path
    FILE *fp = fopen(mFileName.c_str(), "rb");
    // Set the image data source
    png_init_io(png, fp);
Copy the code

Next is to read the message:

    png_read_png(png, infop,
                 (PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND),
Copy the code

Specific information of a certain aspect of the image can be obtained by the following methods:

    mWidth = png_get_image_width(png, info);
    mHeight = png_get_image_height(png, info);
    mColorType = png_get_color_type(png, info);
    mBitDepth = png_get_bit_depth(png, info);
Copy the code

The png_get_IHDR method can also be used to obtain information

    png_get_IHDR(png, infop, &mWidth, &mHeight, &mBitDepth, &mColorType, &mInterlaceType,
                 &mCompressionType, &mFilterType);
Copy the code

Get pixel content

The pNG_get_ROWS method retrieves all data by row and assigns values to the pixel pointer.

	// A pointer to the pixel content
    unsigned char *mPixelData;
    // Get the number of bytes per line
    unsigned int row_bytes = png_get_rowbytes(png, infop);
    mPixelData = new unsigned char[row_bytes * mHeight];
    png_bytepp rows = png_get_rows(png, infop);
    // Read it line by line and fill it into the pixel pointer
    for (int i = 0; i < mHeight; ++i) {
        memcpy(mPixelData + (row_bytes * i), rows[i], row_bytes);
    }
Copy the code

In the png_read_png method, all pixel content is stored in the infop variable row_pointers as follows:

Png_read_image:

    // Row_pointers are used as a one-dimensional pointer array
    png_bytep *row_pointers;
    row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * mHeight);
    for (int y = 0; y < mHeight; y++) {
        row_pointers[y] = (png_byte *) malloc(png_get_rowbytes(png, info));
    }
    png_read_image(png, row_pointers);
Copy the code

Finally, don’t forget to call the png_read_end method to end the reading.

With the pixel content, you can do a common render operation, which is to render the pixel content onto a texture.

Save the picture

Libpng provides a method call to save an image based on its pixel content. The process is as follows:

    png = png_create_write_struct()
    infop = png_create_info_struct()
    // Associate the data source, PNG, and file to write to
    png_init_io(png,fp)
    // Set infop parameters, representing the best image file information to be generated
    png_set_IHDR()
    // Write the image information
    png_write_info(png, infop);
    // Write the image pixel content
    png_write_image(png, row_pointers);
    // Finish writing
    png_write_end(png, NULL);
Copy the code

The process is the opposite of reading pixel content.

The PNG variable is created with png_create_write_struct.

The infop variable is also created using the png_create_info_struct method.

Next is to set the picture information, write the picture information, write the pixel content, the specific code practice can refer to my code example.

reference

Finally, the libpng source code provides rich examples. The open source library usually provides the corresponding test code, and the corresponding function call can be found in the test code.

The following is an example of the libpng official website:

www.libpng.org/pub/png/lib…

If you have any questions, you can find the answer on this.

Related articles:

Simple and easy to use image decoding library introduction – STB_image

Introduction and practice of CameraX, a new component of Google Jetpack

[Douyin internal push] School recruitment advance approval, R & D post special!

AD time

There is a new knowledge planet [graphics/images/audio/video communication] recently, if you have any questions, welcome to discuss in knowledge Planet.

In addition to discussion, the planet is more important to play the role of knowledge precipitation, I will [OpenGLES technology exchange group] in the discussion of the corresponding synchronization to the planet, as content precipitation.

In addition, the TWO-DIMENSIONAL code promoted by wechat public account has also been updated, “Notes on Paper · Multimedia Development”, which will focus more on sharing the accumulation of technology learning and practice in multimedia development.