解析点9图(请从Demo.java看起)
private void testNinePatch() {
// String pngName = "addto_bookmarks_bg_complied.9.png";
String pngName = "barcode_actionbar_pressed_background_complied.9.png";
try {
InputStream is = getResources().getAssets().open(pngName);
// Bitmap bitmap = BitmapFactory.decodeStream(is);
// byte[] chunkData1 = bitmap.getNinePatchChunk();
byte[] chunkData2 = loadNinePatchChunk(is);
NinePatchChunk mChunk = chunkData2 == null ? null : NinePatchChunk
.deserialize(chunkData2);
if (mChunk == null) {
throw new RuntimeException("invalid nine-patch image: " + pngName);
}
printArray(mChunk.mDivX);
printArray(mChunk.mDivY);
System.out.println(mChunk.mPaddings.toShortString());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 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);
}
}
package com.baidu.luxiaoyu;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import android.graphics.Rect;
/**
*
* See "frameworks/base/include/androidfw/ResourceTypes.h"
* for the format of struct Res_png_9patch
*
* @author luxiaoyu01@baidu.com
* @since 2014-5-6
* @todo
*/
class NinePatchChunk {
public Rect mPaddings = new Rect();
public int mDivX[];
public int mDivY[];
public int mColor[];
private static void readIntArray(int[] data, ByteBuffer buffer) {
for (int i = 0, n = data.length; i < n; ++i) {
data[i] = buffer.getInt();
}
}
private static void checkDivCount(int length) {
if (length == 0 || (length & 0x01) != 0) {
throw new RuntimeException("invalid nine-patch: " + length);
}
}
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;
}
}
package com.baidu.luxiaoyu;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
/**
*
* Simple helper class that allows reading of integers.
*
* TODO: * implement buffering
*
*/
public final class IntReader {
public IntReader() {
}
public IntReader(InputStream stream, boolean bigEndian) {
reset(stream, bigEndian);
}
public final void reset(InputStream stream, boolean bigEndian) {
m_stream = stream;
m_bigEndian = bigEndian;
m_position = 0;
}
public final void close() {
if (m_stream == null) {
return;
}
try {
m_stream.close();
} catch (IOException e) {
}
reset(null, false);
}
public final InputStream getStream() {
return m_stream;
}
public final boolean isBigEndian() {
return m_bigEndian;
}
public final void setBigEndian(boolean bigEndian) {
m_bigEndian = bigEndian;
}
public final int readByte() throws IOException {
return readInt(1);
}
public final int readShort() throws IOException {
return readInt(2);
}
public final int readInt() throws IOException {
return readInt(4);
}
public final int readInt(int length) throws IOException {
if (length < 0 || length > 4) {
throw new IllegalArgumentException();
}
int result = 0;
if (m_bigEndian) {
for (int i = (length - 1) * 8; i >= 0; i -= 8) {
int b = m_stream.read();
if (b == -1) {
throw new EOFException();
}
m_position += 1;
result |= (b << i);
}
} else {
length *= 8;
for (int i = 0; i != length; i += 8) {
int b = m_stream.read();
if (b == -1) {
throw new EOFException();
}
m_position += 1;
result |= (b << i);
}
}
return result;
}
public final int[] readIntArray(int length) throws IOException {
int[] array = new int[length];
readIntArray(array, 0, length);
return array;
}
public final void readIntArray(int[] array, int offset, int length) throws IOException {
for (; length > 0; length -= 1) {
array[offset++] = readInt();
}
}
public final byte[] readByteArray(int length) throws IOException {
byte[] array = new byte[length];
int read = m_stream.read(array);
m_position += read;
if (read != length) {
throw new EOFException();
}
return array;
}
public final void skip(int bytes) throws IOException {
if (bytes <= 0) {
return;
}
long skipped = m_stream.skip(bytes);
m_position += skipped;
if (skipped != bytes) {
throw new EOFException();
}
}
public final void skipInt() throws IOException {
skip(4);
}
public final int available() throws IOException {
return m_stream.available();
}
public final int getPosition() {
return m_position;
}
/////////////////////////////////// data
private InputStream m_stream;
private boolean m_bigEndian;
private int m_position;
}