The intricacies of 9-patch resources
In this note, we will talk about non-obvious features of the 9-patch structures used in Android to create "stretchable" graphic design elements.
I will not dwell on what it is, since there are already articles on this subject . A key element for creating stretch images is the so-called chunk, a structure like byte []. This chunk is used in the NinePatch constructor, but the documentation of what it is is not too verbose: Where does chunk come from?
9-patch resources can reside in one of two types. The first is the same picture with black single-pixel marker lines that define stretch areas. The second type is compiled. The externally compiled image looks exactly the same as the original, but the marker lines are not visually presented, but converted to a binary format and sewn in under the code name “npTc”. The conversion from the first type to the second is performed by the aapt utility, at the stage of preparing the resources.
For clarity, we take a picture consisting of one red pixel and make it a 9-patch resource using the appropriate utility. Compare it in the hex editor with the compiled version:
9 pixels of the original image (1 + 8 pixel markers)
1 pixel + binary data after the npTc label
Each of these forms of being has pros and cons: on the one hand, the compiled form is optimized for use in runtime, but you cannot change it in a graphical editor - chunk will inevitably be overwritten when re-saved.
What exactly is this structure and what is contained in it can be read in the sources (see structure Res_png_9patch)
Why do we need to know this?
The documentation for the 9-patch resources reads: "It must be saved with the extension .9.png, and saved into the res / drawable / directory of your project." So this is the only place where aapt compiles resources from. But what if we want to take pictures from another place, for example, from the assets folder or even download them in runtime? Let's try this:
An attempt to create a NinePatch directly from raw resources in this way leads to a native cache somewhere in the wilds of a virtual machine, specifically on the line raw.getNinePatchChunk (), which is quite logical - instead of the expected npTc, there is a mishmash from the original image and lines - markers.
The solution is to palm out already compiled resources to the system. The easiest way to do this is as follows: you take an empty android project, put your resources in res / drawable, compile, export apk, open apk as an archive, pull the same resources from the same place, but already compiled. Copy them into the assets of your application (or somewhere else) and from now on you can construct valid NinePath objects from bitmaps using the above code.
So it goes.
I will not dwell on what it is, since there are already articles on this subject . A key element for creating stretch images is the so-called chunk, a structure like byte []. This chunk is used in the NinePatch constructor, but the documentation of what it is is not too verbose: Where does chunk come from?
public NinePatch (Bitmap bitmap, byte[] chunk, String srcName)
chunk The 9-patch data chunk describing how the underlying bitmap is split apart and drawn.
Bitmap.getNinePatchChunk()
Returns an optional array of private data, used by the UI system for some bitmaps. Not intended to be called by applications.
9-patch resources can reside in one of two types. The first is the same picture with black single-pixel marker lines that define stretch areas. The second type is compiled. The externally compiled image looks exactly the same as the original, but the marker lines are not visually presented, but converted to a binary format and sewn in under the code name “npTc”. The conversion from the first type to the second is performed by the aapt utility, at the stage of preparing the resources.
For clarity, we take a picture consisting of one red pixel and make it a 9-patch resource using the appropriate utility. Compare it in the hex editor with the compiled version:
9 pixels of the original image (1 + 8 pixel markers)
1 pixel + binary data after the npTc label
Each of these forms of being has pros and cons: on the one hand, the compiled form is optimized for use in runtime, but you cannot change it in a graphical editor - chunk will inevitably be overwritten when re-saved.
What exactly is this structure and what is contained in it can be read in the sources (see structure Res_png_9patch)
Why do we need to know this?
The documentation for the 9-patch resources reads: "It must be saved with the extension .9.png, and saved into the res / drawable / directory of your project." So this is the only place where aapt compiles resources from. But what if we want to take pictures from another place, for example, from the assets folder or even download them in runtime? Let's try this:
public NinePatchDrawable create9Patch() {
Bitmap raw = BitmapFactory.decodeStream(...);
byte[] chunk = raw.getNinePatchChunk();
NinePatch patch = new NinePatch(raw, chunk, null);
return new NinePatchDrawable(patch);
}
* This source code was highlighted with Source Code Highlighter.
An attempt to create a NinePatch directly from raw resources in this way leads to a native cache somewhere in the wilds of a virtual machine, specifically on the line raw.getNinePatchChunk (), which is quite logical - instead of the expected npTc, there is a mishmash from the original image and lines - markers.
I/DEBUG ( 4694): signal 11 (SIGSEGV), fault addr 00000008
I/DEBUG ( 4694): r0 0000bd00 r1 00000007 r2 ad03db59 r3 00000000
I/DEBUG ( 4694): r4 0000bd00 r5 00000000 r6 ad3431b1 r7 41049cf8
I/DEBUG ( 4694): r8 beb484b8 r9 41049cf0 10 41049ce0 fp 00000000
I/DEBUG ( 4694): ip ad3431b1 sp beb48498 lr ad046f05 pc ad03db6c cpsr 00000030
I/DEBUG ( 4694): #00 pc 0003db6c /system/lib/libdvm.so
I/DEBUG ( 4694): #01 pc 000431c6 /system/lib/libandroid_runtime.so
I/DEBUG ( 4694): #02 pc 0000e434 /system/lib/libdvm.so
I/DEBUG ( 4694): #03 pc 00040b0a /system/lib/libdvm.so
I/DEBUG ( 4694): #04 pc 00013198 /system/lib/libdvm.so
I/DEBUG ( 4694): #05 pc 00017b9c /system/lib/libdvm.so
...
The solution is to palm out already compiled resources to the system. The easiest way to do this is as follows: you take an empty android project, put your resources in res / drawable, compile, export apk, open apk as an archive, pull the same resources from the same place, but already compiled. Copy them into the assets of your application (or somewhere else) and from now on you can construct valid NinePath objects from bitmaps using the above code.
So it goes.