zoukankan      html  css  js  c++  java
  • 点9图 NinePatch chunk解析

    最近在工作中需要解析点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是好帮手。


    ————————————————
    版权声明:本文为CSDN博主「鲁晓宇-Baidu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/u013365670/java/article/details/25415393

  • 相关阅读:
    威胁情报网站
    python3实现telnet查看IP地址段端口开放情况
    python3实现指定IP多线程端口扫描
    安全网址导航
    python3调用exe程序编写cve20190708批量检测工具
    python3爬取网页中的邮箱地址
    黑客马拉松
    Nginx自定义模块编写:根据post参数路由到不同服务器
    Apache HTTP Server 与 Tomcat 的三种连接方式介绍
    Apache HTTP Server 与 Tomcat 的三种连接方式介绍
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/13182801.html
Copyright © 2011-2022 走看看