I'm having trouble with loading textures regarding their resolution on openGL for Android. If the texture is 256x256 everything works perfectly, but if it's other resolution, the program throws this exception on start:
android.content.res.Resources$NotFoundException: Resource ID #0x........
I found a code on the internet that changes the density of the bitmap this way:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 240;
and by doing this, I can load 512x512 textures. But I'm not able to load for example 128x128 bitmaps, because I don't know which density I have to use. I'm not sure either that this is the normal procedure to load textures, because I don't found many information on the internet.
Thank you for reading!
You dont need to specify the density, you just have to make sure the image is a power of 2, which you seem to have done. I would leave out the density option and just specify Config.ARGB_8888;
If this doesnt fix the problem can you show your code for loading the texture
If anyone has this problem, or the textures show up messed up (like ones being another, or other weird things) I was able to solve it by deleting all the items on the "drawable" folder and putting them in again. It seems the pointers to the images were corrupted or something.
Related
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.
Firstly I am aware of the recommended approach of using inJustDecodeBounds and inSample size to load bitmaps at a size close to the desired size. This is however a fairly broad approach that only gets an image approximate to the target.
I have though of utilising options.inDensity and options.inTargetDensity to trick the native loader into scaling an image more precisely to the desired target size. Basically I set options.inDensity to the actual width of the image and options.inTargetDensity to the desired width and I do indeed get an image at the desired size (aspect ration happens to remain the same in this case). I then set image.setDensity(DENSITY_NONE) on the resulting image and all appears to work OK.
Anyone know of anything wrong with this approach? Any thoughts on memory efficiency and image quality?
I have always got better image management with Opengl 2.0 and surface views.
Sounds brilliant to me! (Can't believe android devs wrote the code but didn't expose the functionality in a sane and sensible way).
I do have one concern. I have good reason to believe that Android is unable to deal with instantiated bitmaps that are larger than 2048x2048 pixels in either dimension. If the internal code to do the rescaling isn't sufficiently intelligent, it may fail when loading bitmaps larger than 2048x2048.
I was thinking about this my self, using inDensity and inTargetDensity to scale up/down bitmap on decode. It works well, but unfortunately it yields very bad performance (animation) results. I was hoping I could use this as a "universal" aproach to scale up/down on decode, similar to inSampleSize which is unfortunately only for down sampling. Seems like there is different native implementation: inSampleSize performs well, no obvious performance impact, where inDensity/inTargetDensity introduced noticable performance impact (like slow motion).
Or am I missing something?
What's the best image file format for Android in terms of memory? PNG is recommended for iOS as xCode does some magic with it.. Is it the same for Android?
I'm currently developing a big app with multiple animations going on (sliding in screens, fading etc etc). All works well so far! However I have noticed the view animation where the view contains an ImageView with a (quite large) PNG as the source is a bit laggy.
Obviously I can make the PNG smaller, but is there anything extra I can do to reduce the amount of memory the ImageView takes up/makes the animation smooth? I know PNG has a much larger file size than JPEG, but I can't see this being a problem, the JPEG or PNG (I assume) is eventually stored as an array of colours, so they would both take up the same memory. PNG is probably better for loading due to less cycles uncompressing. Again I only assume, my knowledge of image file formats is null.
Alternatively is there anything else causing the lag? Is the bitmap scaled to fit the view each onDraw() during the animation so should I scale the bitmap in code before giving it to the ImageView?
Thanks,
The formats supported by Android are: PNG, JPG and GIF (also 9.png).
The recomendated is PNG as said in dev guide
All of them are stored in memory as a Bitmap, so the most important thing is the color deph, like this:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon, options);
More info: stackoverflow
and add (after honeycomb):
<application
android:largeHeap="true"
...
to your manifest file :=)
thanks to my dear friend :)
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.