文档章节

点9图 NinePatch chunk解析

shzwork
 shzwork
发布于 09/17 14:44
字数 1037
阅读 8
收藏 0

本文链接:https://blog.csdn.net/u013365670/article/details/25415393
   最近在工作中需要解析点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/article/details/25415393

本文转载自:https://blog.csdn.net/u013365670/article/details/25415393

shzwork
粉丝 15
博文 817
码字总数 10675
作品 0
厦门
私信 提问
Android画布和图形绘制---Canvas and Drawables(五)

Nine-patch NinePatchDrawable图形是可拉伸的位图图片,Android系统会根据View对象中的内容来自动的调整背景图片。使用NinePatch图片的一个例子就是标准Android按钮的背景图片---按钮必须根据...

长平狐
2012/10/16
802
0
Android开发中的NinePatch圖檔

传统UI开发中,如果背景的大小不一样,一般需要为每种大小都 制作一张图片,这在button中尤为明显。当然我们也可以一小块一小块水平重复的画,也可 以垂直的话。在android中专门有一种叫nin...

囧南风囧
2010/11/26
1K
0
android游戏开发框架libgdx的使用(五)--舞台和常用UI类

本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。 常用的UI类包括标签,按钮,勾选框,下拉框,图片,输入框,列表,滑动面板,滑条,分割面板。它们...

长平狐
2013/11/25
321
0
android游戏开发框架libgdx的使用(十八)—简单的AVG游戏效果实现

本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。 好久没有写libgdx的东西了,主要是最近迷上了各种算法… 文章是关于实现简单的AVG游戏效果,可能会...

长平狐
2013/11/25
408
0
android游戏开发框架libgdx的使用(十一)—Skin和UI配置文件的使用

本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。 libgdx的UI改进很大,原来各种稀奇古怪的问题都已经解决了,而且UI的类型也基本上完全了。推荐大家...

长平狐
2013/11/25
221
0

没有更多内容

加载失败,请刷新页面

加载更多

JS实现使用Math.random()函数生成n到m间的随机数字

Math.random()函数返回0和1之间的伪随机数,可能为0,但总是小于1,[0,1) 生成n-m,包含n但不包含m的整数: 第一步算出 m-n的值,假设等于w 第二步Math.random()*w 第三步Math.random()*w+n...

张兴华ZHero
25分钟前
4
0
入门了解Service Mesh + Istio?从本文开始

下周六,深圳,阔别已久的线下技术沙龙要和你见面啦! 现场有Rancher Labs研发经理demo刚刚发布的Rancher 2.3中的Istio、Windows容器、集群模板等功能及使用,还有k3s首次线下workshop,由R...

RancherLabs
26分钟前
4
0
Gradle 发布 Jar 到 Archiva 时提示不能 Overwriting released artifacts is not allowed

系统提示错误信息: Received status code 409 from server: Overwriting released artifacts is not allowed. 这是在 Archiva 默认的配置下如果你不是使用 snapshot 配置的话,是不允许对仓...

honeymoose
27分钟前
4
0
二维码插件之qrcode.min.js

文件链接百度云地址 https://pan.baidu.com/s/1nWiBuT4Z7WOAMoUEFL8PZg 入门 http://www.jq22.com/jquery-info294 使用jquery.qrcode.min.js实现前台二维码生成(带Logo) https://blog.csd......

木九天
37分钟前
3
0
开源 java CMS - FreeCMS2.8 自定义标签 commentPage

项目地址:http://www.freeteam.cn/ commentPage 根据参数提取评论对象。 参数 说明 siteid 站点id objtype 评论对象类型 objid 评论对象id membername 会员名称 isanonymous 是否匿名 1是 ...

freeteam
38分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部