I am having a rather annoying scenario where I work with a lot of drawable shapes, many of which are slightly changed variants of others. The annoying thing is, when I paste the drawable, it automatically defaults to a random resource folder. See bellow photo. I want it to go directly to the standard drawable folder, not some other density drawable folders without having to manually change the folder every single time.
Is this even possible?
You can change the View from Android to Project if you are copying & pasting multiple images in a row. You can simply paste it to the drawable folder.
In the process of altering the images found in Launcher2.apk, I found some files that are obviously nine-patches, but have a height or width of 1px only:
$ file **/*.9.png G "\( 1 x\|x 1,\)"
Launcher2/res/drawable-land-xhdpi/workspace_bg.9.png: PNG image, 400 x 1, 8-bit gray+alpha, non-interlaced
Launcher2/res/drawable-sw720dp-xhdpi/workspace_bg.9.png: PNG image, 1 x 400, 8-bit gray+alpha, non-interlaced
Launcher2/res/drawable-xhdpi/workspace_bg.9.png: PNG image, 1 x 400, 8-bit gray+alpha, non-interlaced
Are these files that are messed up somehow by their creators or are they special cases, i. e. fixed width but variable height or vice versa?
Is there any formal definition of the format of nine-patch files? Of course I googled, which took me quite some time, without finding any information that would help me here. Would be best if it'd also cover other aspects, because I found many other
suspicious images in several packages that contain none-binary information in there left-/top-/right-/bottom-most pixels; hence I'd also like to know exactly which values encode repeat/stretch/as-is, and which are ignored.
This section in Googles Canvas and Drawables document doesn't give many details (actually none). and the distributed draw9patch.jar doesn't help much either.
Just in case it is of interest: The device I took Launcher2.apk and other packages from is a Moto G, stock 4.3 firmware.
Thanks in advance
Okay, what I learned since I investigated more on nine-patch images:
The main error is probably to think that the repeat/stretch/keep meta data of nine-patches are always encoded in the border pixels of the image files. This is not true.
As a matter of fact, there are two nine-patch formats, apparently called source form and compiled form, the former having the well-known special borders in which pixels specify the patches (of which you can have more than nine, indeed). This is most likely called source form, because the pixels show off in image editors (however, under some circumstances they may not; see below).
According to the apktool wiki the second — compiled — form has this meta information encoded in a special (private) PNG chunk; the same page claims those chunks are called npTc, and my attempt to verify this with basic Linux utilities could confirm this:
$ strings search_frame.9.png
IHDR
TnpTc
yIDATX
[...]
Also TweakPNG shows this chunk.
So, the answer to my actual question is: I thought those 1 pixel high/wide images were nine-patches in source form, while they actually were in the compiled crunched format.
Since there doesn't seem to be an official specification, and this was part of the question, I'm just starting a collection of information here.
Tools that convert from one form to the other
aapt (coming with the Android sdk) has, among others, two subcommands,
s[inglecrunch] compiles a single bordered nine-patch image to the chunked/crunched format (use command line options -i and -o for input and output file, respectively),
c[runch] takes a resource directory (option -S) and the name of an output directory (option -C), traverses the whole source directory and creates target subdirectories as appropriate.
(Be warned: if you forget to create the root of the target directory tree beforehand, aapt doesn't error out, but is busy with $whatever, taking a whole CPU core/thread's attention and power, so effectively showing that it's busy, while it does at least not what the user expects. (Just for the sake of completeness: I'm running SDK 19.0.1))
apktool is a custom java application that is able to unpack whole *.apk files, converting *.xml files to plain text files and *.9.png files to their source format.
To put everything (potentially modified) back into an *.apk archive, you'd need to manually extract some files from the original package, which most zip/unzip utilities should be able to do, but without conversion. For the process of repackaging, apktool apparently makes use of aapt, of which it has a version bundled.
This bundled aapt is probably extracted from an older SDK (pre 19), as it shows off the same flaws (the above mentioned tight busy loop, and several segfaults where a simple if would prevent such nasty behaviour (e. g. it segfaults when you don't give the -C option to the c[runch] subcommand)), while it lacks support for the s[ingleCrunch] subcommand.
xUltimate-d9pc (this seems to be a source-to-crunched-format converter, but I didn't really test it.)
WebLaF (also untested; it seems to have sources, where one could get more info.)
Formats of nine-patches
source form
Most people will already know that the source form of a nine-patch does include the normal pixel data of the image, plus an extra border. I will try to illustrate with a simple ASCII representation (and hope your font allows to recognize what it means):
-------##--#####--##-------
-......XXXXXXXXXXXXX......-
-...XXX.............XXX...-
-..X...................X..-
-.X.....................X.- Legend
-.X.....................X.-
#X.......................X- (top and left borders)
#X.......................X- # denotes a "stretch"/"repeat" mark
-X.......XXXXXXXXX.......X- - denotes a "keep" mark
-X.......X.......X.......X#
#X.......X.......X.......X# (bottom and right borders)
#X.......X.......X.......X# # marks the content area (aka fill area)
-X.......X.......X.......X# - marks ... umm... what is it called?
-X.......XXXXXXXXX.......X-
#X.......................X- (image area)
#X.......................X- . pixel in "background" color
-.X.....................X.- X pixel in foreground color
-.X.....................X.-
-..X...................X..-
-...XXX.............XXX...-
-......XXXXXXXXXXXXX......-
----------#######----------
This is some kind of double box, the outer of which has rounded corners. The size of this form of nine-patch is 27x22px, but the actual image size is 25x20px only — this is also the minimum size at which it can be shown in an app, but it can be stretched to an arbitrary size.
The repeat marks tell the framework which lines to repeat when the image is stretched, e. g. when the image is shown at an actual height of 26 pixels, lines 7, 8, 11, 12, 15, and 16 and repeat, each once, making up for the extra lines on the screen. This way it is ensured that the borders of both boxes will always remain 1 pixel thin and the rounded corners of the outer one will always have the same size/radius. while the marked regions will be adequately stretched (well if the difference of the stretched size to the original size is not a multiple of the marked lines, there will be irregularities, but on today's 160+ dpi display that doesn't probably matter much; however, less repeat/stretch markers will probably be more performant, but then again... on today's 1.6+ GHz quad core phones that doesn't matter either...)
Values for the repeat/stretch markers
When I posted the question, I wasn't sure whether there is any semantic difference between stretching and repeating, and I still am not.
According to A simple guide to 9-patch for Android UI the markers must be solid black for repetition of the row/column in question, otherwise the result will be wrong without any notice to the user except when incorrectly displaying on the screen; this may be correct for previous SDK versions (the article being from May 2011).
However, both aapt versions (in SDK 19 and the one coming with apktool 1.5.2) complain about arbitrary colors in the borders, for example:
ERROR: 9-patch image test/search_frame_.9.png malformed.
Ticks in transparent frame must be black or red.
Found at pixel #21 along top edge.
ERROR: 9-patch image test/tab_unselected_pressed_focused_holo.9.png malformed.
Must have one-pixel frame that is either transparent or white.
where the second file is a compiled/crunched nine-patch already, while the first is not.
What I read from the "black or red" message is that the border may not contain pixel values other than #00000000 (solid black, for repeat/stretch marks), #00ff0000 (solid red, maybe for the same), and #xx000000 (black with arbitrary transparancy (xx>0) for "keep" marks, maybe also #xxFF0000, but I didn't test that).
What I'm still not sure about is whether red and black have distinct semantics, or if red is just an alternative for image editors that use a black background, where it's not easy to visually distinguish between #00000000 and #01000000, for example).
compiled/crunched form
The SDK contains two classes android.graphics.NinePatch and android.graphics.NinePatch_Delegate, which make use of calls to native libraries, so the sources don't give us much. I don't have the NDK installed and I even don't know if it supplies sources for the relevant libraries.
The best that I've found was the answer to Android: compiling 9-patch files to be used outside of the drawable folder?
I need to get same images with same name, but in different resolution. So i created different drawable folder for every resolution and having images with same name in all folder. But when i am running this aap at that time some images coming dynamically at diff resolution. I have to bound images, should comes from related resolution folder at which device it is running at that moment. I used some images as theme, these are making trouble for me. :( :(
I created drawable folder in this way.
drawable-sw600dp-land-mdpi.
drawable-sw600dp-port-mdpi.
Please help me, I am indeed.
If your folders are named correctly, android will take care of that by hisself. If the device is rotated, the activity is destroyed and recreated again. Depending on on current state (landscape or portrait), android loads the drawable from the corresponding folder and you only have to say "load a drawable" :)
If the corresponding folder doesnt exist, android falls back to a default one.
Try to change
"drawable-sw600dp-land-mdpi" to "drawable-sw600dp-land"
"drawable-sw600dp-port-mdpi" to "drawable-sw600dp-port".
Remove "mdpi" from directory names.
create drawable folder like this
drwable-land-mdpi
drawable-port-mdpi
drwable-land-hdpi
drawable-port-hdpi
and also see this link google resources
Images in apps come in many shapes or sizes, but to save space and editing time is there a way to use scaleable vector images?
Ideally I would have one vector image at middle resolution, I could then detect the screen size and scale the vector how I need and add the background using some custom gradients.
I'm using titanium for this.
Titanium doesn't yet support vector graphics, though it is available in native Android code via Shape Drawables. There is a third-party SVG library available for Android SDK.
For Titanium, branch the code based on the device screen size (Titanium.Platform.DisplayCaps), and find an image that works with decent performance on the device.
You can use PNGs with transparency and apply a background color to your view object.
I've found away round making different sized drawable:
Basically just one have folder called drawable within the res folder.
Make your artwork in what ever you use but make it large (at least 1080p for future devices).
Save the image's as PNG within the drawable folder but save them large. (IE at least 1000x1000)
Write a function that loads in the PNG but scales it (according to screen size & percentage of what size you want the drawable to be. So 20% of 800px width is 120px). I've managed to do this bit with 30ish lines of code, can't paste my code since I'm not on my working machine.
For me this has worked across all my apps for all devices, I've not had a single crash yet (1000's of installs, including Live Wallpapers).
The docs say to put XML state files for buttons in "the" "drawable" folder - which one of at least three?! (Putting it in res/drawable gives an out of sync filesystem error and putting it in each of the drawable-*dpi where * is l, m, h is an error too.)
res/drawable is ok and default.
The "fs out of sync" is probably from your IDE when you put the files e.g. via command line or into the folder. IDEs usually try to remember the state of files and report external changes this way. Try issuing a "refresh" command in the IDE.
res/drawable is a fallback that is taken if you do not provide more specific images in res/drawable-*dpi or also some orientation counterparts.
Have a look at the docs:
http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources
drawable-nodpi is a special directory for files you don't want scaled, which makes no sense at all for buttons, as you want buttons to scale according to screen size/dpi.
You should use res/drawable for your XML state list drawables. If you get the "out of sync filesystem" error just refresh the Eclipse project (select it in the projects pane and hit F5).
XML state lists are (in most cases) not DPI-independent. However, their content will not change across different DPI environments. Basically, this means that if you reference a raw drawable called, for example, #drawable/btn_pressed, from within a state list, Android will look for the appropriate file for that drawable, according to the environment (drawable-*dpi/btn_pressed.png).
As you can see, although the state list is the same on LDPI, MDPI and HDPI, the drawables referenced within it could change.
I propose drawable-nodpi because it works.
However this is not made obvious in the docs when it needs to be.
How to make something trivial complicated? Make it ambiguous.