Android - Bitmap quality loss? - android

I use transparent png image for my app, but when app runs the image loses its quality and it is not exactly same, its kind of distorted also blurred. Is there something that i can do, like bitmap options?
mBitmap = BitmapFactory.decodeResource(res,R.drawable.img1);

I had this problem too. I did solve it using another format than png (in my case jpg was enough). If you still want to use an alpha channel your only remaining choice is gif, even if this wouldn't be the best choice normally.

Could it be the screen pixel density does not match that of your Bitmap? Unless you specify otherwise, your Bitmap is assumed to be at 160dpi, so it will be rescaled as necessary, depending on the device, when you load it.
You can have different versions of your Bitmap, designed for different pixel densities. Just like app icons, these go into the appropriate res/drawable-*dpi/ subdirectories.

I had the same issue when trying to process pictures from android camera.
I solved using this code:
Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inDensity = 96;
Bitmap originalPicture = BitmapFactory.decodeFile(pictureFile.getPath(), options );
It seems this problem is related to the RGB format of your image and the dither option.

Related

Faster image processing

Can someone suggest me a library that can do simplest operations like scale, crop, rotate without loading image fully into memory?
The situation: I need to scale image down from a very large size, but the scaled down image is still too large to be allocated in memory (if we use standard android tools). Since I only need to upload scaled down version, I thought of scaling it through native library and upload it through FileInputStream.
I've tried to use ImageMagic and it does the job, but performance is very poor (maybe there is a way to speed things up?)
Might want to check out OpenCV for Android
You can use the original Android Bitmap functionality by pulling the image into memory but allowing Android to sample the image before it is loaded.
For example:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap myBitmap = BitmapFactory.decodeStream(inputstream,null,options);
This will load your bitmap into memory with half the memory footprint of the full image. You can experiment with changing the inSampleSize to get a good fit for your application.
You can also calculate the sample size on the fly, if you know the final image size you are aiming for, you can get the current file size of the image before you load it into memory and calculate the sample size using the equation inSampleSize = OriginalSize/RequiredSize. Though sample size is best used when it is a power of 2, so you can make adjustments for this.
Edit:
A great example here https://stackoverflow.com/a/823966/637545

How to decode bitmap with sample size not equals power of 2?

Simple example:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = scale;
Bitmap bmp = BitmapFactory.decodeStream(is, null, opts);
When I'm passing scale value not equal to power of two, bitmap is still scaled by closest power of 2 value. For example, if scale = 3 then actual scale become 2 for some reason. Maybe it's because I'm using hardware acceleration?
Anyway, how can I scale bitmap by non power-of-2 value without allocation memory for full bitmap?
P.S. I know, that using power of two is much faster, but in my case time isn't such critical and I need image scaled exactly by provided scale (otherway it's become too big or too small) - I'm woking with image processing, so big image itself not such a problem (ImageView scales it to required size), but it takes extra time to apply some filter for example.
If you read the documentation for inSampleSize:
Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.
You are not guaranteed exact dimensions. Since memory sounds like it is a concern, I would use your current method to get the image to larger than what you need but something that fits better with your memory requirements than the source image. Then use a different method like Bitmap.createScaledBitmap to get it to your exact dimensions.

Resource to bitmap conversion results in poor quality

I never really noticed it before but when I change the image of an imageview using setImageBitmap, using a bitmap which is decoded from resources using BitmapFactory, then the quality of image deteriorates and I don't know why.
I even played around with BitmapFactoryOptions like options.inPreferredConfig, options.inJustDecodeBounds, options.inDither, but the results were pretty much the same; a poor quality image.
On the other if I just use setImageResource, the image doesn't deteriorates and is in best quality possible.
So basically these two codes
Bitmap b=BitmapFactory.decodeResource(getResources(), R.drawable.keypad,options); iv.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.keypad))
iv.setImageResource(R.drawable.messages);
results in different image quality.
Can anybody explain why? And how to solve this quality issue using code 1.
If you have blurry images using the BitmapFactory.decodeResource method, you can use this code:
Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap b = BitmapFactory.decodeResource(getResources(), path, options);
iv.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.keypad));
Setting the inScaled parameter of BitmapFactory.Options class to false, will prevent blurry images on low screen resolutions since it will prevent scalling as mentioned in the answer of this previous SO question. Maybe you have already tried this but i thought worth mentioning.

Android, Canvas and Screens

I think I've got quiet a common problem in regards to Android development, but cant seem to find the answer I'm looking for.
If I make a canvas on Photoshop 800x480px (240ppi) and make a logo within that canvas that is 282 x 121px, I cant understand why when I display the image it takes up 3/4 of the screen in my emulator with the same 800x480px.
The code I use to display the logo is the following
Bitmap logo = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
//in the onDraw
canvas.drawBitmap(logo, 0, 0, null);
Thanks in advance!
Possible Solution
Not sure if this is the best way to do things and would appriciate any feedback, I came across this solution (typically when you've already posted a question :D ) was to code the image as follows:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
//Load images
logo = BitmapFactory.decodeResource(getResources(), R.drawable.logo, options);
The image was probably only taking up 3/4 of the screen in the emulator because of the pre-scaling android sometimes does.
Check out this article on how to handle multiple resolutions and screen sizes.
You could try placing the drawable into a 'res/drawable-mdpi/' directory or a 'res/drawable-ldpi/' to differentiate between medium density and low density screens. Another option is to place it in a 'res/drawable-nodpi/' directory to prevent any pre-scaling. I've even placed some images in the 'res/raw' folder to get the same effect.
However, if your current method works, go for it!

Background Image in RelativeLayout has artifacts

I created a background .png for my application in GIMP. It's resolution is 640x480, which from googling, seems to be the resolution for a default emulator. My problem is when I apply the background to the RelativeLayout with android:background=#drawable/bg and run it, there are lots of artifacts in the image. As if the emulator could not provide enough colors to display the .png correctly. What is going on here?
P.S. This image is nothing to fancy, just simple lines and radial gradients.
It's resolution is 640x480, which from
googling, seems to be the resolution
for a default emulator
640x480 is not even an officially-supported resolution in Android, let alone a "default" one. Here is the list of supported resolutions.
Also, you want to watch your color depth. I forget the details, but not everything can necessarily handle 24-bit color, due to LCD limitations.
i've gathered 3 possible solutions:
for each problematic image that you have, create and use a bitmap drawable in the xml.
the disadvantage is that you create multiple files. i've tested the other special flags (including the code changes), and haven't noticed any difference.
res/drawable/image_file.xml
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/problematic_image" />
put the problematic image in the drawable-nodpi folder. the disadvantage is that it will use more RAM this way, as it doesn't downscale according to the density. a similar approach can be done in code:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 1;
options.inSampleSize = 1;
options.inTargetDensity = 1;
options.inJustDecodeBounds = false;
final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.problematic_image, options);
imageView.setImageBitmap(bitmap);
if the file is a png file, take a pixel that is least noticable (for example the bottom-left), and change its opacity to 254 instead of 255.
the disadvantage of this method is that it makes the image to take more space , and change the image itself.
all methods worked on galaxy s and galaxy s2 , with android 2.3.x .

Categories

Resources