I am working with a team on an Android game. There was a graphics spritesheet resource that was created with an initial tile width of 96 pixels and later reduced to 64 pixels. On the author's computer the project runs correctly at the new dimensions but on my machine, even though the image has been updated to the new resolution, when I go into debug and call getHeight() on the BMP resource, it returns 96 and the animation displays incorrectly (gets clipped).
I have tried:
refreshing eclipse filesystem
re-cloning the project and creating a clean project in eclipse
starting eclipse with -clean
cleaning the build
The problem persists and I have run out of ideas. Please, how do I get get eclipse to uncache whatever crud its keeping somewhere and use the new image that's plainly sitting in the /res/ folder??
I am testing the project on the emulator. Running android api 2.1, level 7.
Bitmap bmp;
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.blah);
You need to set the "inScaled" flag when loading the Bitmap if you want to force the original size. I found this out the hard way when my Open GL textures weren't showing up on larger screen devices.
Something like this should do it:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.my_image, opts);
Android automatically scales images in the resources folder for the screen resolution of the device. So even if the source image has a height of 64 pixels, there's no guarantee the .getHeight() will return 64.
Moral of the story: don't hard-code values for the sizes of images - use the accessor methods.
Related
I would be very grateful if someone could confirm that I have solved the below problem correctly or if there is an alternative solution?
I have an app that loads a large image (e.g. 800*1720 pixels) into memory and displays it in a scrollview. The image is a floor plans for a museum and I wanted a simple map like experience of scrolling and zooming. The image loaded fine on older devices, but caused an out of memory error on a Samsung Galaxy S3.
Looking at the LogCat messages it turned out that in creaing the bitmap 22MB was being allocated for the bitmap instead of 800*1720*4 = 5.5MB. Essentially 4x as much memory was being allocated as required by other devices and pushing the memory usage over the 50MB heap size.
The recommended solution to this problem is to use the BitmapFactory.Options.inSampleSize option to reduce the resolution of the image loaded and have it require less memory. However, this reduces the quality of the image, and I actually want to display it at it's full size in the original quality as works fine on older devices.
After much head scratching I concluded that the issue was that the pixel density on the S3's WXGA screens is 2.0 and thus for each pixel in the image, the bitmap was actually allocating 4 pixels. With a bit of trial and error I discovered I could prevent this happening by setting options.inScaled = false;
http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled
On the way, I also realised that I could cut my memory usage in half to 2.7MB by using a lower fidelity colour depth of 2 pixels instead of 4 pixels by setting options.inPreferredConfig = Bitmap.Config.RGB_565;. For my floorpans this didn't effect the visible image quality.
The final code was thus:
String uri = "drawable/floorplan";
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled = false;
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options);
IVfloorplan.setImageBitmap(bm);
When displaying this bitmap you need to scale it back up. To work out the scaling you can obtain the pixel density from:
float density = getResources().getDisplayMetrics().density;
I reduced memory usage for the bitmap from 22MB to 2.7MB, which in a 50MB heap is significant.
The screen of the S3 has a really high res, so it's quite understandable. Also, if the image is in the drawable folder, it could be getting upscaled automatically. There might be ways to turn that off. Even if your image size doesn't chance, the OS has to allocate a buffer to accommodate the image, also possibly one to accommodate showing it on the screen.
An alternative is using tiling, which is used in games like SNES games. This is also how they handled lots of graphics without running out of RAM. Evidence shows that this is how Google Maps has a map of Planet Earth. You basically chop up the large image into tiles and show the tiles on the screen as you are panned to them (of course, maybe 1 extra tile on each side).
Even though this is post-Honeycomb, where Google put in code to better manage Bitmap allocations, be careful with Bitmap allocation. It's more like a C program than a Java program, and it's a good idea to manage it like one. It's very easy to run out of heap space when using Bitmap objects in Android
Bitmap icon = BitmapFactory.decodeResource(this.getResources(),R.raw.book11);
Canvas c = new Canvas(icon);
using this line of code for making canvas actually increases the size of the canvas(150x177) from the bitmap(100x118). If I use predefining the size of canvas, the bitmap gets cropped. Help please.
thanks.
I solved mine with this equation:
event.getX()*3/2;
event.getY()*3/2;
the system will automatically up-scale your image asset when you use it for a 'larger/higher' screen resolution/density if that particular asset is missing for that particular configuration (i.e. you're referencing an image on a hdpi device while that image is not present in the drawable-hdpi but only in raw drawable directory).
Note that scaling factor depends on device's screen density. In your case that seems to be 1.5.
EDIT: If not done yet, please check the link.
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.
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?
Did you try this?
From Google:
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.
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.