📜 ⬆️ ⬇️

Subtleties 9-patch resources

In this article we will talk about the unobvious features of the work of 9-patch structures used in Android to create "stretching" elements of graphic design.


I will not dwell on what it is, since there are already articles on this topic. The key element for creating stretchable images is the so-called chunk, a byte [] structure. This chunk is used in the NinePatch constructor, but the documentation about what it is is not too verbose:

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.

')
Where does chunk come from?
9-patch resources can be in one of two types. The first is the same picture with black single-pixel marker lines defining the stretch areas. The second view is compiled. Externally, the compiled image looks exactly the same as the original, but the marker lines are not represented visually, but are converted into a binary format and protected inside with the code name “npTc”. The aapt utility performs the conversion from the first type to the second, at the resource preparation stage.

For clarity, take a picture consisting of one pixel of red and make it a 9-patch resource using the appropriate utility. Compare it in the hex editor with the compiled version:

9 pixels of source image (1 + 8 pixels markers)
image

1 pixel + binary data after the npTc tag
image

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 the graphic editor - chunk will inevitably be overwritten when it is retained.

What exactly this structure is and what it contains can be read in the source code (see the Res_png_9patch structure)

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 to do 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 .

Attempting to create a NinePatch in the forehead from “raw” resources in this way leads to a native crash somewhere in the wilds of the virtual machine, specifically on the raw.getNinePatchChunk () line, which is quite logical - instead of the expected npTc, it turns out there is a mess 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 slip the system already compiled resources. The easiest way to do this is the following: you take an empty android project, add your resources to res / drawable, compile, export apk, open apk as an archive, pull out the same resources from the same place, but already compiled. Copy them into the assets of your application (or somewhere else) and from this point on you can construct valid NinePath objects from bitmaps using the above code.

So it goes.

Source: https://habr.com/ru/post/119547/


All Articles