android: quality of the images resized in runtime
Asked Answered
M

6

13

I want to show images using drawBitmap() method. But before I want to resize it according screen dimensions. I have a problem with quality of result image. You can see screenshots and test code below. How can I resize images in runtime with a good quality?

Thank you for solutions.

Original image: alt text http://dl.dropbox.com/u/709109/gradient.png

Result screenshot on device: alt text http://dl.dropbox.com/u/709109/device.png

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;

import java.io.IOException;
import java.io.InputStream;

public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LinearLayout container = (LinearLayout) findViewById(R.id.container);
        container.addView(new View(this) {
            @Override
            protected void onDraw(Canvas canvas) {
                Bitmap unscaledBitmap;
                try {
                    InputStream in = getAssets().open("images/gradient.png");
                    unscaledBitmap = BitmapFactory.decodeStream(in);
                    in.close();
                    canvas.drawBitmap(unscaledBitmap, null, new Rect(0, 0, 320, 480), null);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
Maurer answered 11/1, 2010 at 10:36 Comment(0)
O
10

Please refer to Romain's answer below.

I would like to delete this answer, but I am unable to since it's marked as accepted.


Note that Android [when this answer was originally written, without explicitly requesting 32-bit colour] would only do 16-bit colour, so there may be times when you get unwanted artifacts.

You can also try using the dither options to tell Android to automatically apply dithering which, while not perfect, can help make things look a bit better.

Offbeat answered 11/1, 2010 at 11:25 Comment(6)
Thank you, it's helpful answer! But I have no reputation to vote it.Maurer
Now I'm using the "565 dither photoshop plugin" to prepare my graphic. Because dithering is hi-cost operation and it doesn't work with decodeStream and drawBitmap methods.Maurer
Android can do 32 bits just fine. Just make sure both your bitmap and your window use the ARGB8888 format.Johnnie
@RomainGuy Has that always been the case? Just wondering if that was true two years ago when I wrote this.. :) In any case, I shall delete my answer in preference of yours, which I apparently also upvoted two years ago!Offbeat
That was true 2 years ago, it just had to be requested by the app. 32 bits is now the default.Johnnie
@Roces dont worry, I did that for youTrafficator
J
15

Instead of resizing at drawing time (which is going to be very costly), try to resize in an offscreen bitmap and make sure that Bitmap is 32 bits (ARGB888).

Johnnie answered 11/1, 2010 at 16:50 Comment(1)
As I figured out, Android is applying good downscaling algorithm (not nearest neighbor like) only while using BitmapFactory.Options::inSampleSize->BitmapFactory.decodeResource() but this allows to downscale only in exactly integer times smaller than the original. Is there a way to downscale in Android to an exact resolution that I need using something better than nearest neighbor algorithm (which is used every time I call createScaledBitmap(), createBitmap+matrix and e.t.c.)?Alard
O
10

Please refer to Romain's answer below.

I would like to delete this answer, but I am unable to since it's marked as accepted.


Note that Android [when this answer was originally written, without explicitly requesting 32-bit colour] would only do 16-bit colour, so there may be times when you get unwanted artifacts.

You can also try using the dither options to tell Android to automatically apply dithering which, while not perfect, can help make things look a bit better.

Offbeat answered 11/1, 2010 at 11:25 Comment(6)
Thank you, it's helpful answer! But I have no reputation to vote it.Maurer
Now I'm using the "565 dither photoshop plugin" to prepare my graphic. Because dithering is hi-cost operation and it doesn't work with decodeStream and drawBitmap methods.Maurer
Android can do 32 bits just fine. Just make sure both your bitmap and your window use the ARGB8888 format.Johnnie
@RomainGuy Has that always been the case? Just wondering if that was true two years ago when I wrote this.. :) In any case, I shall delete my answer in preference of yours, which I apparently also upvoted two years ago!Offbeat
That was true 2 years ago, it just had to be requested by the app. 32 bits is now the default.Johnnie
@Roces dont worry, I did that for youTrafficator
S
2

Check out http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html (To be used with unscaledBitmap = BitmapFactory.decodeStream(in);

You can add quality settings to the image. I'm guessing that the quality is being degraded as you are not passing any settings for how the image should be processed.

Sled answered 11/1, 2010 at 10:47 Comment(2)
what are the "quality settings" in BitmapFactory.Options? I can't see any, and the word "quality" does not appear once in the documentation.Jointer
There's developer.android.com/reference/android/graphics/…, but the docs say it only refers to JPEG decode and your file is PNG.Lacour
S
1

Implementations of the createScaledBitmap(..) method on older platforms (API level < 12) cause problems when you try to scale an ARGB_8888 Bitmap that has no actual alpha value (i.e. each pixel has alpha = 255), because their hasAlpha flag is set to false. In that case the scaled Bitmap is automatically converted to the RGB_565 format.

Therefore since API level 12 there is a method (in class Bitmap)

setHasAlpha(boolean value);

Which helps to prevent a conversion when using createScaledBitmap(..).

There is a way to use the very same method on API level > 3. It has been present for a very long time, just hidden. All necessary steps including the source code are described here:

https://mcmap.net/q/261782/-bad-image-quality-after-resizing-scaling-bitmap

Hope this helps.

Stoop answered 30/8, 2012 at 18:7 Comment(0)
S
0

I had a similar problem and here is what I ended up doing: Quality problems when resizing an image at runtime

Sniper answered 22/11, 2010 at 23:34 Comment(0)
T
-1

Also, if your resizing function does not respect the aspect ratio of the image, the quality gets affected. You can find some resizing algorithm on the web, for instance check this out

Terracotta answered 11/1, 2010 at 11:11 Comment(2)
No, the both images have the same ratio. original image: 600x900 ratio 1.5 new image size: 320x480 ratio 1.5Maurer
Didn't find any resizing algorithm at the link you provided. Just discussion regarding correct scale value calculation...Alard

© 2022 - 2024 — McMap. All rights reserved.