在NDK中使用libpng读取pixel数据
来源:互联网 发布:北京公交线路优化 编辑:程序博客网 时间:2024/05/18 10:09
libpng的详细使用方法在于它的官方文档libpng-manual.txt,下载文件夹下含有。使用openGL生成纹理的时候需要图片的像素数据。使用libpng可以帮助我们解析PNG标准格式的结构,获得pixel数据。
在NDK中读取assets文件夹内容的方法在头文件#include <android/asset_manager.h>中定义。直接看代码:
/** * Read png pixel data from file, caller must be free it */static void* readPng(const char* filePath, Texture* texture) { void* pixelData = NULL; AAsset* asset = NULL; do { off_t size; asset = getAAsset(filePath, &size); if(!asset) { break; } unsigned char head[8]; AAsset_read(asset, head, 8); if(png_sig_cmp(head, 0, 8)) { LOGE("File %s, is not PNG", filePath); break; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) { LOGE("Unable to create PNG structure: %s", filePath); break; } // Allocate/initialize the memory for image information. REQUIRED png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { png_destroy_read_struct(&pngPtr, NULL, NULL); LOGE("Unable to create PNG info : %s", filePath); break; } png_infop endInfo = png_create_info_struct(pngPtr); if (!endInfo) { png_destroy_read_struct(&pngPtr, &infoPtr, NULL); LOGE("Unable to create PNG end info : %s", filePath); break; } // Set error handling if you are using the setjmp/longjmp method (this is // the normal method of doing things with libpng). REQUIRED unless you // set up your own error handlers in the png_create_read_struct() earlier. if (setjmp(png_jmpbuf(pngPtr))) { // Free all of the memory associated with the png_ptr and info_ptr png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo); LOGE("Error during setjmp : %s", filePath); break; } /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: * where user_io_ptr is a structure you want available to the callbacks */ png_set_read_fn(pngPtr, (void*)asset, readPngData); // If we have already read some of the signature png_set_sig_bytes(pngPtr, 8); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(pngPtr, infoPtr); int bitDepth; int colorType; int interlaceype; png_uint_32 width; png_uint_32 height; png_get_IHDR(pngPtr, infoPtr, &width, &height, &bitDepth,&colorType, &interlaceype, NULL, NULL); texture->width = (float) width; texture->height = (float) height; LOGD("PNG width = %f, height = %f", texture->width, texture->height); // Update the png info struct. png_read_update_info(pngPtr, infoPtr); // Allocate the memory to hold the image using the fields of info_ptr unsigned int rowBytes = png_get_rowbytes(pngPtr, infoPtr); LOGD("Row size: %d bytes", rowBytes); // Allocate the pixel data as a big block, to be given to openGL pixelData = png_malloc(pngPtr, rowBytes * height); if(!pixelData) { png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo); LOGE("Unable to allocate PNG pixel data while loading %s", filePath); break; } /* Turn on interlace handling. REQUIRED if you are not using * png_read_image(). To see how to handle interlacing passes, * see the png_read_row() method below: */ int numberPasses = png_set_interlace_handling(pngPtr); LOGD("interlacing passes = %d", numberPasses); for (int pass = 0; pass < numberPasses; pass++) { for (int row = 0; row < height; row++) { png_read_row(pngPtr, ((unsigned char*)pixelData + (row * rowBytes)), NULL); } } // Read rest of file, and get additional chunks in info_ptr - REQUIRED png_read_end(pngPtr, infoPtr); // At this point you have read the entire image // Clean up after the read, and free any memory allocated - REQUIRE png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo); } while(0); AAsset_close(asset); return pixelData;}这里我参考了libpng官方教程,使用最简单和最直接的方法获得PNG的像素数据。libpng的API可以对PNG进行复杂的操作和设置,我一概没有使用,直接定位到pixel数据,读取到内存。
这里需要解释两个地方。第一,libpng使用了FILE对象的文件操作体系。当然在NDK中无法直接使用,我们需要使用assets来代替。libpng提供了设置读取数据的回调函数。
第二个参数带入了asset指针,第三个参数设置了回调读取函数。实现如下:
/** * Callback for libpng read data */static void readPngData(png_structp pngPtr, png_bytep data, png_size_t length) { AAsset* asset = (AAsset*)png_get_io_ptr(pngPtr); AAsset_read(asset, data, length);}最后一点, libpng读取pixel数据的时候,有2中方法。一种是一次性读取数据到一个指针数组,一个指针持有一行数据。但是openGL需要的是一维数组。所以,通常做法会构建一个一维数组,以后构建一个指针数组,以后把一维数组折叠到指针数组。意思就是,指针数组的每个指针,指向一维数组特定的位置,表示一行数据。
我这里使用了png_read_row方法,每次读取一行,直接就放到一维数组里面去了。省去了构建指针数组的空间,也更简洁直观。
获得assets的方法是NDK提供的函数:
- 在NDK中使用libpng读取pixel数据
- 在NDK中使用libpng读取pixel数据
- 使用libpng读取PNG图片像素数据 .
- bak 9.NDK 下面 编译 libpng.已经如何在opengl es 里面读取png图片.
- bak 9.NDK 下面 编译 libpng.已经如何在opengl es 里面读取png图片.
- 使用libpng读取png图像
- NDK在windows下编译libpng
- 使用libpng,libjpeg从文件读取和从内存读取2中方式的实现
- 使用libpng,libjpeg从文件读取和从内存读取2中方式的实现
- 在Android中通过ndk读取本地文件
- OpenGL使用libPng读取png图片
- OpenGL使用libPng读取png图片
- 在NDK中使用gtest
- 在NDK中使用shared_ptr
- 在NDK中使用STL
- 在 Eclipse 中使用 NDK
- 使用NDK移植/编译开源库(3)libpng的编译
- 在AngularJS中使用$q同步读取服务器数据
- PropertyPlaceholderConfigurer类的使用注意
- stat函数
- 设计--数据库设计
- 大数据发展史
- 一些可以查询IP地理位置、身份证所在地、手机归属地的接口
- 在NDK中使用libpng读取pixel数据
- LUA Metamethods
- SilkTest Q&A 2
- Android EXIF
- SilkTest Q&A 3
- C#中的delegate
- 使用jconsole查看Tomcat运行情况的配置方法
- java 小程序
- SilkTest Q&A 4