I have some .png files in my app. I need to load these during runtime, and get the exact colors of certain pixels from them. It's important, that I do not want to scale these pictures. I don't show them on the UI directly, they serve as maps.
Now, on Android 1.5, there's no problem with this. I put these images in the '/res/drawable' dir, load them with BitmapFactory into a Bitmap object, and use it to get the color of the desired pixels. E.g. pixel (100, 50) has the color RGB(100, 1, 100).
On Android 2.2 tho, the same procedure results varying colors (for the same pixel), so I get RGB(99, 3, 102) / RGB(101, 2, 99) / etc. for the same (100, 50) pixel. I checked the resolution of the Bitmap object, it seems that is didn't get scaled.
Could somebody explain, why I get distorted colour values?
Solved: It appears, that on Android 2.2, I have to set the correct bitmap configuration. Somehow, versions below 2.2 managed to do this (or maybe fewer configs are supported on those, and the system guessed the config correctly, don't know).
Anyways, here's the code I use now:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither=false;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap mask = BitmapFactory.decodeResource(getResources(), R.drawable.picture, opt);
Go make yourself a bitmap thats entirely the same color of the pixel in question. Make the size of this bitmap the same resolution of the one your currrently using. Load it up and check the RGB values of the same pixel (or any pixel) you are having problems with.
This should tell you whether your problem is either scaling, which is what I think it is, or possibly a problem in the color translation.
If you don't find an answer quickly, my pragmatist streak would ask how hard it is to parse the .png yourself, to get completely deterministic results independent of any changes in the platform.
My 2.3 devices (Nexus One and S) worked fine without setting "opt.inPreferredConfig", but it appears that 2.2 requires it for accurate RGBs.
Related
I've been having problems with large images being resized for UI use in Android.
Look at this image, it's an ImageView:
The original image (That arc is a progressbar) is around 10 times bigger than what you see here. In UWP (Windows Platform) we had no problem using a very large image, but here in Android, I beleive it's the Nearest Neighbour method used for fitting images into UI elements, which as you see, causes sharp edges.
Is there any way to switch it into another method? Like Bicubic? It happens in all Android versions I've tested (4.1, 5.0, 6.0).
Just to mention, I'm using Xamarin 4, which I don't beleive as a contributing factor here.
No luck searching through the internet, I'm afraid I'm the only one having this problem.
Thanks.
As mentioned above, you should prefer to use vector image instead of pixel image.
But if you have to use pixel image, maybe you could use BitmapRegionDecoder to decode lines of image and write your own resample algorithm(like Bilinear Interpolation, it's much better than the Near Neighbor) to resize the image, typically in JNI side.
Another possible way is to use "filter" parameter while calling Bitmap.createBitmap method as your original image would not cause OOM issue, just set it to true, it works to reduce the artifacts.
You should use Vector Images instead of Bitmap Images.
Bitmap x Vector
A bitmap represents an image by a series of colored pixels. Whereas a vector image is represented by geometric shapes (lines, curves) using colors.
The main utility of a vector image is allowing to scale without losing definition.
I'm currently facing several performance issues (out-of-memory) when handling a vast amount of bitmaps. As this is just a problem that can be fixed I'm wondering if anybody can explain me the difference in using the following methods.
If I only want to load an image into an ImageView I usually use:
imageView.setImageDrawable(getResources.getDrawable(R.drawable.id));
If I want to sample the drawable beforehand I usually use (here without sampling):
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.id);
imageView.setImageBitmap(bm);
My question is related to performance optimisation. I'm wondering whether it is better to provide as many drawables as possible using the different drawable folders (so these drawables nearly fit the required resolution for the different devices) or if it is better to sample high-quality drawables? What is setImageDrawable doing internally? Does it decode the resources using the BitmapFactory, just without sampling? There seems to be a trade-off between the actual size of the app and the cpu- and memory-load during runtime.
if you're concerned about apk size, then having as many drawables as possible is not the ideal way to go. but dont forget, when you decode a bitmap, you can pass a sample size so it will scale down to the screen size and only give you the pixels you need, so older phones with smaller screens wont need to decode 8mp images.
check BitmapFactory.Options and here
I have 270 x 2693 pixel image in drawable folder . When i try to set that image in imagview i got Bitmap too large to be uploaded into a texture warning.
Image sets perfectly in android device < 4.0 but not sets > 4.0 device.
Please help me to resolve this issue.
Code
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:contentDescription="#string/name"
android:src="#drawable/hindi" />
Here hindi is a image in drawable folder and its size is 270 x 2693 pixel.
Problem
This problem is usually related either to OpenGL maximum texture size or the Device Memory. The full error you are getting is probably something like
W/OpenGLRenderer(12681): Bitmap too large to be uploaded into a texture (270x2693, max=2048x2048)
Memory is generally the problem with a large scale image but in your case 270x2693 is 727110 pixels. If you are in RGBA, it's 4 bytes per pixel so 727110 * 4 = 2908440 bytes, which is approximately 2,7 megabytes. That should fit on any devices.
Thus, your problem is probably related to OpenGL. What might happen is that the Android device > 4.0 you are testing on detect that your image is too large for OpenGL and resize it for you, while older devices don't.
Edit:
In my case, the problem is that my 640x1136 splash image seems to get rezised automatically to a 1280x2272 image size to fit my device huge screen. Which also triggers the error message you are having.
If you get this error further on, it is related to the dpi that is used to load the image. As you will find on Android reference, device will load image regarding their dpi which can alter the size of image that is loaded in memory.
Solution
You don't have much choice other than detecting the device size to
load the image properly.
See how to load large bitmap in memory.
You can also use different image size for different device dpi which
can be automatically selected from the Drawable folder by Android.
See the How to support screens which tells you how to setup your
folder.
As other stated, use a smaller image or reduce its size.
Related informations
I suggest you have a look there if you need to support multiples screens.
Android also collect data which are updated every 7 days on Screens size among their users.
Also have a look to this interesting answer which points out a good website to understand Image Size in memory.
Finally, if you are already using OpenGL in your app, have a look to this answer which shows how to detect the max OpenGL texture size.
Why not reduce the size of the image? If you don't want to do that, then rather than specify the bitmap in the XML, load it from program code, and scale it to fit the display. See this guide for more information on loading large bitmaps.
try use this code
int[] maxTextureSize = new int[1];
GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
maxTextureSize stores the size limit for decoded image such as 4096x4096, 8192x8192 . Remember to run this piece of code in the MainThread or you will get Zero.
I have an application that displays lots of images, and images can be of varying size up to full screen dimensions of device. The images are all downloaded, and I use imagemagick to reduce colors of image to compress the file size, while keeping dimensions the same, to reduce download time. The reduced color space is fine for my application.
The problem is that when I load the image into a Bitmap in android the file size is much larger because of androids Bitmap config of ARGB_8888, I do need the ALPHA channel. Since ARGB_4444 is deprecated and had performance issues I am not using that. I am wondering if there is any other way to reduce the memory footprint of the loaded Bitmap while keeping the dimensions the same as the original?
---- Update ---
After discussions here and lots of other searching/reading it does not appear that there is a straight forward way do this. I could use ARGB_4444 which stores each pixel as 2 bytes, rather than 4 bytes per pixel. The problem there is that ARGB_4444 is deprecated, and I try not to use deprecated parts of the API for obvious reasons. Android recommends use of ARGB_8888 which is the default, since I need alpha I have to use that. Since there are many applications that do not need such a complex color space it would be nice to see ARGB_4444 or something similar become part of the supported API.
If you don't need alfa (transparency) you can use:
Bitmap.Config.RGB_565
which uses 2 bytes per pixel, instead of 4, reducing size by half.
You should also look at BitmapFactory.Options:
inSampleSize
inScaled
These values correctly set for your requirements, may have a very positive effect on Bitmap memory requirements.
Regards.
Read a similar answer I posted here
Basically, bitmap recycle is required for Pre honeycomb devices to reduce memory usage
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Android app loading images from /drawables-nodpi/ with scaling
I recently rebuilt my Android project to target 2.2 from 2.1.
In the old project, I did not specify a target SDK (the manifest did not contain something like: android:minSdkVersion="8"). This gave me an error in the console when running, but everything worked fine so I didn't fool with it.
The new project now uses android:minSdkVersion="8" in the manifest.
But now my drawables from the /drawable-nodpi/ folder are loading with scaling, making them much smaller and significantly changing the desired visuals.
If I cut out the tag from my manifest, they load properly without scaling.
Even when loading my images like so:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
Bitmap bm = BitmapFactory.decodeResource(_resources, resId, opts);
They are still scaled when I declare the minimum SDK in the manifest, but not scaled if I remove that tag.
Why is this happening? How can I load them without scaling while still declaring the minimum SDK?
There is another explanation given here:
"If you don't specify <supports-screens> or minSdk, then your app will run in compatibility mode, meaning that it's given an HVGA (240x320) "virtual screen", which is then scaled as a whole. So your images will be scaled."
The original poster was therefore running their app in this compatibility mode before and the images were automatically scaled up from HVGA to the actual screen resolution; by adding minSdkVersion the images were no longer scaled and therefore appeared smaller.
When you set minsdkversion you are telling Android that the app can work from API level 8, which is Android 2.2. Previously since you didn't specify that, Android knew how to handle assets, but now with minsdkversion line in manifest you are providing guidelines.
Read up on how all assets and assets hierarchy is implemented in Android here and here. This may be not the quick fix answer you want, but it will help you understand Android platform better.
I know this is an ancient question and the answer probably means little to you today, but because I just wrestled with this for a day and a half, I figured I'd throw out the answer for anyone else.
No matter what I did my images would be loaded from resources with a strange scale. I tried all manner of methods, from using Options.inScaled=false to setting inDensity = 160, to even using an InputStream and decoding the bitmap from the stream. Nothing worked... Images that have a raw size of 340x480 always loaded with some weird dimensions like 321x481 no matter what.
I went to look at the source image itself and see what dpi/ppi it was saved at. The image was created at the correct dimensions but its internal ppi was 72. I changed the image to render at 160ppi (which blew up the dimensions) and then scaled the dimensions back down to their origial pixels. Using this new source image, at a 160ppi that matched the 160dpi of the display, it rendered just as expected without any weird scaling.
So remember, if your source images are not intended to scale at all, you should make sure either they are set at a ppi that matches your density or that when you decode the bitmap from the bitmapfactory that the options specifies the ppi that the image itself was created to fill.