I've got a bunch of small two colour png images and I'd like to effectively change one of the two colours to another one. Say RED => BLUE.
I know I can either loop over each pixel or use Bitmap.setXfermode to do this but it feels like a big waste on such a simple problem. What I want to do is to access the header of the file and change it in the colour table directly. This hints that png:s are indexed http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap :
Note: Bitmap files may be automatically optimized with lossless image compression by the aapt tool. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in the res/raw/ folder instead, where they will not be optimized.
The files I put in the "project" are indexed png images so I know for sure they are in fact indexed and does have a colour table. Will I have to read the files as binary data and manipulate before I make a Bitmap object? I would really prefer if that wasn't the case but there instead is some hidden Bitmap.switchColor (Col1, Col2); which would do just that since I want to be able to switch back or to a third colour.
Please only android related answers and not general ones since I'm only looking for how to do it in android, using android classes.
Thanks in advance
Related
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'm using the code outlined in the following post:
Draw text in OpenGL ES
I thought I could use this technique in order to dynamically display text (say an FPS counter). I realised that calls to resources to get the drawable slows down this process quite a lot, and I didn't need a bitmap background, so I removed it.
The technique works, but after a while (~2000 frames) the whole phone locks up. I suspect there's some memory which is not being freed in this code but I don't know where. I tried offloading the Canvas, Paint and Bitmap object creations which worked (so they aren't created every single frame) but the same problem still occurs.
I suspect therefore, that the generated GL texture is to blame, but I'm unsure how to remove it, or if this is even the case.
Any help would be appreciated.
EDIT: As an alternative, can someone please point out an easy way to render text to the screen dynamically (e.g. should be able to render the # of frames since starting for example, continually being updated and increasing). All the ways I can think of are either extremely tedious (make individual quads for each digit, store the textures for 0-9 in memory, parse the number and render each digit onto each quad), cannot be updated in good time (overlay Views) or can't get the required positioning in the glSurfaceView.
CBFG - http://www.codehead.co.uk/cbfg
This really is exactly what I've been wanting. You build a bitmap file from a font file using CBFG which can then be loaded and displayed with only a few lines of code (after importing his packages). It's literally as easy as fnt.PrintAt(gl,"Hello world!", 50, 160); in onDraw and more importantly, it handles dynamic text really well. I strongly advise anyone who is the same situation to try this.
two things I can guess you'll want to try:
1) dont' recreate the number of your frs every frame, generate number 1 to 60 and always reuse those.
2) there is an issue I found when generating text for my textures is that the font loader code of android never frees the memory space so avoid loading the font all the time, do it once and store a reference to it
I just wrote an entire tutorial on creating exactly what you are looking for.
The idea is basically to use font files and then generate a font bitmap (or atlas) at run-time instead of using a tool like CBFG to generate it offline. The benefit of this is that you can ship a small font file instead of multiple large bitmaps with your app, and never have to sacrifice font quality by using scaling.
The tutorial includes full working source (that can be dropped into any project). If you are interested go have a look here.
I've run into issues with banding of my PNG files. Digging into the problem has yielded two solutions. Both make sense individually, but together they don't. The solutions I've discovered:
1) Move the PNG file into the "raw" folder. This prevents AAPT from "optimizing" the image which results in banding.
2) Change the pixel format of your Activity's window to RGBA_8888 (i.e. in onCreate add this line "getWindow().setFormat(PixelFormat.RGBA_8888)"). On Android 2.2 and lower the default pixel format is 16-bit (565).
I have tried both of these and they correct the banding effect in my images, however now I am even more confused as to what Android is doing.
On the one hand, if I leave my PNG in the drawable folder it is "optimized" which results in a banding effect in the image. It magically goes away when I change the pixel format to 32-bit. If the image was "optimized" though, I would have expected the banding to remain.
On the other hand, if I move the PNG to the raw folder it will retain the nice gradient and display nicely even though the pixelFormat is supposedly 16-bit.
If anyone has any insight into what is going on I would appreciate it.
Thanks,
-Dan
I believe its quite simple :
You have to think of the pixel format of your Activity(RGBA_8888) as a DEFAULT optimization for your bitmaps.
If it is not set, then prior to 2.2, by default it will compress your bitmap to RGB_565.
But if you were to create programmatically a bitmap and set it to RGBA_8888, then it would be used as such by the app.
Same applies when you put your bitmap in the raw folder : Even though the default PixelFormat is set to RGB_565, the activity will use it as it is without "optimizing" it.
When you put your bitmap in the raw folder it will not be compressed at all and used as is even though the default PixelFormat is still RGB_565.
I'm having trouble making my texture rendered correctly in my applications.
the artwork I use is precise and already scaled and the right size but when I render it on phone suddenly my texture are not as clear/precise as the original artwork and I can't figure out why.
has anybody had this issue before?
This is because android will compress all resources that are not placed inside /res/raw/
http://developer.android.com/guide/topics/graphics/2d-graphics.html
Note: Image resources placed in res/drawable/ may be automatically optimized with lossless image compression by the aapt tool. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in the res/raw/ folder instead, where they will not be optimized.
This might also happen if you use linear filtering in your texture, make sure that texture filters are GL_NEAREST for GL_MIN_FILTER and GL_MAG_FILTER.
Ok I finally figured it out
the problem I was having was coming from the default compatibility mode of android
I had to add this to my manifest
I am trying to port some code from a regular Java program into the Android platform. Unfortunately, a significant part of the program involves manipulating images, and Java's AWT was taken away from me. I am trying to replace awt.BufferedImage with Bitmap, and was hoping that the only differences between the two classes would be their interfaces. I read some of the documentation, and it looked like that is true, but after wrapping all of the image stuff into a nice little class and testing almost-the-same code on both my development machine and an actual phone, one program works and the other does not. So:
The encoding for color does not change - right? It is still 0xAARRGGBB - right?
The images themselves are not changed - right? When I put an image into res/drawable, it is exactly the same image. Most notably, they don't alter the resolution in any way - right?
Accessing the pixels is essentially the same - right? I essentially replaced all of my get/setRGB(x,y,RGB) with get/setPixel(x,y,color). There are no changes to the method of indexing into the grid - is there?
Solved: when opening the image, I failed to create a BitmapFactory.Options() with inDither set to false. The BitmapFactory then failed to produce an exact copy, putting some alterations in the resulting Bitmap in order to make it more pleasing for display.