点9图 NinePatch chunk解析
来源:互联网 发布:win7引导ubuntu双系统 编辑:程序博客网 时间:2024/05/19 05:33
最近在工作中需要解析点9图的头信息(chunk)的格式,读取拉伸坐标片段、padding信息,在网上找了一下没有相关信息,下面详解一下解析过程。
点9图科普
点9图的定义见官方文档:http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
简单来说就是左边的点代表垂直拉伸的区域,上边的点代表水平拉伸的区域;右边的点代表文字等的垂直可可显示区域,下边的点代表文字等的水平可显示区域。所以,左上重合的区域就是拉伸区域;右下重合的区域就是显示区域。
Android的编译工具aapt会把标记了拉伸区域的点9图处理成一个普通的png,并把相关的信息放入png头部的meta-data区域,即chunk。这个过程详见frameworks/base/tools/aapt/Images.cpp的static status_t do_9patch(const char* imageName, image_info* image)
PNG文件结构
官方文档参见右边的链接:The Metadata in PNG files,摘抄部分如下
A PNG always starts with an 8-byte signature: 137 80 78 71 13 10 26 10 (decimal values). The remainder of the file consists a series of chunks beginning with an IHDR chunk and ending with an IEND chunk.
好了,了解了PNG的文件结构我们就可以取出chunk了,只需要按照文档的说明,按顺序取出Chunk data对应的信息即可。特别需要注意的是,读取字节流的时候需要采取大端方式。下面上代码
/** * PNG Chunk struct * <a href="http://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files">The Metadata in PNG files</a> * * +--------+---------+ * | Length | 4 bytes | * +--------+---------+ * | Chunk | 4 bytes | * | type | | * +--------+---------+ * | Chunk | Length | * | data | bytes | * +--------+---------+ * | CRC | 4 bytes | * +--------+---------+ * * @param pngName * @return chunk * @throws IOException */ private byte[] loadNinePatchChunk(InputStream is) throws IOException { IntReader reader = new IntReader(is, true); // check PNG signature // A PNG always starts with an 8-byte signature: 137 80 78 71 13 10 26 10 (decimal values). if (reader.readInt() != 0x89504e47 || reader.readInt() != 0x0D0A1A0A) { return null; } while (true) { int length = reader.readInt(); int type = reader.readInt(); // check for nine patch chunk type (npTc) if (type != 0x6E705463) { reader.skip(length + 4/*crc*/); continue; } return reader.readByteArray(length); } }
解析Chunk
点9图的Chunk是按照struct Res_png_9patch的结构组织的,详见frameworks/base/include/androidfw/ResourceTypes.h。struct Res_png_9patch{ Res_png_9patch() : wasDeserialized(false), xDivs(NULL), yDivs(NULL), colors(NULL) { } int8_t wasDeserialized; int8_t numXDivs; int8_t numYDivs; int8_t numColors; // These tell where the next section of a patch starts. // For example, the first patch includes the pixels from // 0 to xDivs[0]-1 and the second patch includes the pixels // from xDivs[0] to xDivs[1]-1. // Note: allocation/free of these pointers is left to the caller. int32_t* xDivs; int32_t* yDivs; int32_t paddingLeft, paddingRight; int32_t paddingTop, paddingBottom; enum { // The 9 patch segment is not a solid color. NO_COLOR = 0x00000001, // The 9 patch segment is completely transparent. TRANSPARENT_COLOR = 0x00000000 }; // Note: allocation/free of this pointer is left to the caller. uint32_t* colors; // Convert data from device representation to PNG file representation. void deviceToFile(); // Convert data from PNG file representation to device representation. void fileToDevice(); // Serialize/Marshall the patch data into a newly malloc-ed block void* serialize(); // Serialize/Marshall the patch data void serialize(void* outData); // Deserialize/Unmarshall the patch data static Res_png_9patch* deserialize(const void* data); // Compute the size of the serialized data structure size_t serializedSize();};了解了struct Res_png_9patch,我们只需根据struct Res_png_9patch的结构解析上面步骤得到的chunk data即可。代码如下:
public static NinePatchChunk deserialize(byte[] data) { ByteBuffer byteBuffer = ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN); byte wasSerialized = byteBuffer.get(); // if (wasSerialized == 0) return null; NinePatchChunk chunk = new NinePatchChunk(); chunk.mDivX = new int[byteBuffer.get()]; chunk.mDivY = new int[byteBuffer.get()]; chunk.mColor = new int[byteBuffer.get()]; checkDivCount(chunk.mDivX.length); checkDivCount(chunk.mDivY.length); // skip 8 bytes byteBuffer.getInt(); byteBuffer.getInt(); chunk.mPaddings.left = byteBuffer.getInt(); chunk.mPaddings.right = byteBuffer.getInt(); chunk.mPaddings.top = byteBuffer.getInt(); chunk.mPaddings.bottom = byteBuffer.getInt(); // skip 4 bytes byteBuffer.getInt(); readIntArray(chunk.mDivX, byteBuffer); readIntArray(chunk.mDivY, byteBuffer); readIntArray(chunk.mColor, byteBuffer); return chunk; }NinePatchChunk.mDivX和NinePatchChunk.mDivY就是点9图的拉伸区域标识信息,NinePatchChunk.mPaddings是点9图的pading信息,这样点9图的Chunk信息就解析完毕了。
总结
全部代码见https://gist.github.com/luxiaoyu/085135ff88d7c57a18c5 调研这种SDK文档上没有详细信息的数据结构,需要从Android源码入手,耐心查看相关代码和注释,grep和find是好帮手。
- 点9图 NinePatch chunk解析
- iOS处理.9.png (点9图,NinePatch),类似Android
- NinePatch 9Patch 绘制
- ninepatch
- NinePatch
- SDK使用NinePatch(.9)资源
- chunk
- Android基础——NinePatch点九图片
- http多chunk报文C++解析
- Ninepatch为什么要叫9宫图
- tcpip数据包编码解析(chunk and gzip)
- tcpip数据包编码解析(chunk and gzip)
- webpack的commonchunkplugin深度解析以及chunk和module内部结构
- Android 学习笔记(十一):9妹(NinePatch )
- NinePatch圖檔
- Android NinePatch
- NinePatch.java
- ninepatch 分析
- usb otg thinking
- 复数类--重载运算符+,-,*,/
- C# 之 委托
- WEB第三方打印控件[ASP.NET常用工具]
- gdb调试器常用指令
- 点9图 NinePatch chunk解析
- html5本地存储localstorage
- C#中获取路径的几种方法
- VC创建文件夹
- 黑马程序员---学习笔记(第一天)
- 2013ACM-ICPC杭州赛区全国邀请赛——Random Walk
- Java的位运算符详解实例——与(&)、非(~)、或(|)、异或(^)
- getContentLength()为-1 解决方法
- linux网卡驱动分析之驱动加载