I try to read an image from sdcard (in emulator) and then create a Bitmap image with the
BitmapFactory.decodeByteArray
method. I set the options:
options.inPrefferedConfig = Bitmap.Config.ARGB_8888
options.inDither = false
Then I extract the pixels into a ByteBuffer.
ByteBuffer buffer = ByteBuffer.allocateDirect(width*height*4)
bitmap.copyPixelsToBuffer(buffer)
I use this ByteBuffer then in the JNI to convert it into RGB format and want to calculate on it.
But always I get false data - I test without modifying the ByteBuffer. Only thing I do is to put it into the native method into JNI. Then cast it into a unsigned char*
and convert it back into a ByteBuffer
before returning it back to Java.
unsigned char* buffer = (unsinged char*)(env->GetDirectBufferAddress(byteBuffer))
jobject returnByteBuffer = env->NewDirectByteBuffer(buffer, length)
Before displaying the image I get data back with
bitmap.copyPixelsFromBuffer( buffer )
But then it has wrong data in it.
My Question is if this is because the image is internally converted into RGB 565 or what is wrong here?
.....
Have an answer for it:
->>> yes, it is converted internally to RGB565.
Does anybody know how to create such an bitmap image from PNG with ARGB8888 pixel format?
If anybody has an idea, it would be great!
An ARGB_8888 Bitmap (on pre Honeycomb versions) is natively stored in the RGBA format. So the alpha channel is moved at the end. You should take this into account when accessing a Bitmap's pixels natively.
I assume you are writing code for a version of Android lower than 3.2 (API level < 12), because since then the behavior of the methods
has changed.
On older platforms (API level < 12) the BitmapFactory.decodeFile(..) methods try to return a Bitmap with RGB_565 config by default, if they can't find any alpha, which lowers the quality of an iamge. This is still ok, because you can enforce an ARGB_8888 bitmap using
The real problem comes when each pixel of your image has an alpha value of 255 (i.e. completely opaque). In that case the Bitmap's flag 'hasAlpha' is set to false, even though your Bitmap has ARGB_8888 config. If your *.png-file had at least one real transparent pixel, this flag would have been set to true and you wouldn't have to worry about anything.
So when you want to create a scaled Bitmap using
the method checks whether the 'hasAlpha' flag is set to true or false, and in your case it is set to false, which results in obtaining a scaled Bitmap, which was automatically converted to the RGB_565 format.
Therefore on API level >= 12 there is a public method called
which would have solved this issue. So far this was just an explanation of the problem. I did some research and noticed that the setHasAlpha method has existed for a long time and it's public, but has been hidden (@hide annotation). Here is how it is defined on Android 2.3:
Now here is my solution proposal. It does not involve any copying of bitmap data:
Checked at runtime using java.lang.Reflect if the current Bitmap implementation has a public 'setHasAplha' method. (According to my tests it works perfectly since API level 3, and i haven't tested lower versions, because JNI wouldn't work). You may have problems if a manufacturer has explicitly made it private, protected or deleted it.
Call the 'setHasAlpha' method for a given Bitmap object using JNI. This works perfectly, even for private methods or fields. It is official that JNI does not check whether you are violating the access control rules or not. Source: http://java.sun.com/docs/books/jni/html/pitfalls.html (10.9) This gives us great power, which should be used wisely. I wouldn't try modifying a final field, even if it would work (just to give an example). And please note this is just a workaround...
Here is my implementation of all necessary methods:
JAVA PART:
Load your lib and declare the native method:
Native section ('jni' folder)
Android.mk:
bitmapUtils.c:
That's it. We are done. I've posted the whole code for copy-and-paste purposes. The actual code isn't that big, but making all these paranoid error checks makes it a lot bigger. I hope this could be helpful to anyone.