Create a NinePatch/NinePatchDrawable in runtime

getNinePatchChunk works just fine. It returned null because you were giving Bitmap a “source” ninepatch. It needs a “compiled” ninepatch image.

There are two types of ninepatch file formats in the Android world (“source” and “compiled”). The source version is where you add the 1px transparency border everywhere– when you compile your app into a .apk later, aapt will convert your *.9.png files to the binary format that Android expects. This is where the png file gets its “chunk” metadata. (read more)

Okay, now down to business (you’re listening to DJ kanzure).

  1. Client code, something like this:

    InputStream stream = .. //whatever
    Bitmap bitmap = BitmapFactory.decodeStream(stream);
    byte[] chunk = bitmap.getNinePatchChunk();
    boolean result = NinePatch.isNinePatchChunk(chunk);
    NinePatchDrawable patchy = new NinePatchDrawable(bitmap, chunk, new Rect(), null);
    
  2. Server-side, you need to prepare your images. You can use the Android Binary Resource Compiler. This automates some of the pain away from creating a new Android project just to compile some *.9.png files into the Android native format. If you were to do this manually, you would essentially make a project and throw in some *.9.png files (“source” files), compile everything into the .apk format, unzip the .apk file, then find the *.9.png file, and that’s the one you send to your clients.

Also: I don’t know if BitmapFactory.decodeStream knows about the npTc chunk in these png files, so it may or may not be treating the image stream correctly. The existence of Bitmap.getNinePatchChunk suggests that BitmapFactory might– you could go look it up in the upstream codebase.

In the event that it does not know about the npTc chunk and your images are being screwed up significantly, then my answer changes a little.

Instead of sending the compiled ninepatch images to the client, you write a quick Android app to load compiled images and spit out the byte[] chunk. Then, you transmit this byte array to your clients along with a regular image– no transparent borders, not the “source” ninepatch image, not the “compiled” ninepatch image. You can directly use the chunk to create your object.

Another alternative is to use object serialization to send ninepatch images (NinePatch) to your clients, such as with JSON or the built-in serializer.

Edit If you really, really need to construct your own chunk byte array, I would start by looking at do_9patch, isNinePatchChunk, Res_png_9patch and Res_png_9patch::serialize() in ResourceTypes.cpp. There’s also a home-made npTc chunk reader from Dmitry Skiba. I can’t post links, so if someone can edit my answer that would be cool.

do_9patch:
https://android.googlesource.com/platform/frameworks/base/+/gingerbread/tools/aapt/Images.cpp

isNinePatchChunk: http://netmite.com/android/mydroid/1.6/frameworks/base/core/jni/android/graphics/NinePatch.cpp

struct Res_png_9patch: https://scm.sipfoundry.org/rep/sipX/main/sipXmediaLib/contrib/android/android_2_0_headers/frameworks/base/include/utils/ResourceTypes.h

Dmitry Skiba stuff: http://code.google.com/p/android4me/source/browse/src/android/graphics/Bitmap.java

Leave a Comment