Android: Resizing Bitmaps without losing quality
Asked Answered
E

4

8

i've really searched through over the entire web before posting. My problem is that i cannot resize bitmap without losing the quality of the image (the quality is really bad and pixelated).

I take the bitmap from camera and then i have to downscale it, so i can upload it to the server much faster.

This is the function that does the sampling

public Bitmap resizeBitmap(Bitmap bitmap){
         Canvas canvas = new Canvas();
         Bitmap resizedBitmap = null;
         if (bitmap !=null) {
                int h = bitmap.getHeight();
                int w = bitmap.getWidth();
                int newWidth=0;
                int newHeight=0;

                if(h>w){
                    newWidth = 600;
                    newHeight = 800;
                }

                if(w>h){
                    newWidth = 800;
                    newHeight = 600;
                    }

                float scaleWidth = ((float) newWidth) / w;
                float scaleHeight = ((float) newHeight) / h;



                Matrix matrix = new Matrix();
                // resize the bit map
                matrix.preScale(scaleWidth, scaleHeight);

                resizedBitmap  = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);



                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setFilterBitmap(true);
                paint.setDither(true);

                canvas.drawBitmap(resizedBitmap, matrix, paint);



            }


        return resizedBitmap;   

and this is how i get the image from activity result

 protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if(resultCode != RESULT_CANCELED){

         if (requestCode == 0) {
             if (resultCode == RESULT_OK) {


                    getContentResolver().notifyChange(mImageUri, null);
                    ContentResolver cr = this.getContentResolver();

                    try
                    {
                        b = android.provider.MediaStore.Images.Media.getBitmap(cr, mImageUri);
                        Log.d("foto", Integer.toString(b.getWidth()));
                        Log.d("foto", Integer.toString(b.getHeight()));
                        addPhoto.setImageBitmap(b);

                    }
                    catch (Exception e)
                    {
                        Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT).show();
                        Log.d("TAG", "Failed to load", e);
                    }



             }
         }

I'm starting to think that the best way to get a small picture size is to set the camera resolution. Anyone else can help?

Endoderm answered 9/5, 2013 at 15:40 Comment(0)
D
1

Try Bitmap.createScaledBitmap. It also has an option to filter the source.

Disincline answered 9/5, 2013 at 15:42 Comment(5)
thanks...but i've tried: resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); But it was the same...still blocky and pixelatedEndoderm
I see. Last hint I have in mind is that you check the BitmapFactory.Options class, initialize and use the quality-relevant options when decoding your Bitmap. Here's the API link: developer.android.com/reference/android/graphics/…Disincline
i've reached something at least acceptable by decoding the bitmap from uri with the bitmap.factory options. But it's still not the quality i thought. How facebook and g+ handle the photo upload? I see that they resize all the images that you upload. How they do that without losing a single pixel of quality?Endoderm
I'd explore more of the BitmapFactory.Options - just in case you missed out something. I know it's not a very useful answer but I don't know how to help you further :(Disincline
@Endoderm can you update with what you actually ended up going with?Theodolite
C
10

A good downscaling algorithm (not nearest neighbor like) consists of just 2 steps (plus calculation of the exact Rect for input/output images crop):

  1. downscale using BitmapFactory.Options::inSampleSize->BitmapFactory.decodeResource() as close as possible to the resolution that you need but not less than it
  2. get to the exact resolution by downscaling a little bit using Canvas::drawBitmap()

Here is a detailed explanation how SonyMobile resolved this task

Here is the source code of the SonyMobile scale utils

Contraception answered 21/4, 2014 at 1:59 Comment(3)
This should be the accepted answer. Just implemented what's described in the linked article and the result is significantly better than using simply createScaledBitmap, and also uses much less when downscaling. The result is still not as good as when downscaling e.g. in Photoshop though.Solent
i have tried that FIT method and it was exactly the same quality as using default Bitmap.createScaledBitmap. Might be faster/less memory consumed but the quality is the same.Hermia
upd - just checked time, both methods use the same amount of time, in my case those were 2-3 ms. And i didnt use their decode methods, as i had a ready Bitmap as an input, so no changes in memory usage also.Hermia
D
1

Try Bitmap.createScaledBitmap. It also has an option to filter the source.

Disincline answered 9/5, 2013 at 15:42 Comment(5)
thanks...but i've tried: resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); But it was the same...still blocky and pixelatedEndoderm
I see. Last hint I have in mind is that you check the BitmapFactory.Options class, initialize and use the quality-relevant options when decoding your Bitmap. Here's the API link: developer.android.com/reference/android/graphics/…Disincline
i've reached something at least acceptable by decoding the bitmap from uri with the bitmap.factory options. But it's still not the quality i thought. How facebook and g+ handle the photo upload? I see that they resize all the images that you upload. How they do that without losing a single pixel of quality?Endoderm
I'd explore more of the BitmapFactory.Options - just in case you missed out something. I know it's not a very useful answer but I don't know how to help you further :(Disincline
@Endoderm can you update with what you actually ended up going with?Theodolite
G
0

the best rescaling method I have come across the method uses createScaledBitmap whereby the height and width are calculated based on the bitmap height and width and a scale ratio hence quality is not lost

 public Bitmap resize(Bitmap imaged, int maxWidth, int maxHeight) {
        Bitmap image = imaged;

        if (maxHeight > 0 && maxWidth > 0) {
            int width = image.getWidth();
            int height = image.getHeight();
            float ratioBitmap = (float) width / (float) height;
            float ratioMax = (float) maxWidth / (float) maxHeight;
            int finalWidth = maxWidth;
            int finalHeight = maxHeight;
            if (ratioMax > 1) {
                finalWidth = Math.round(((float) maxHeight * ratioBitmap));
            } else {
                finalHeight = Math.round(((float) maxWidth / ratioBitmap));
            }
            return image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, false);
        }
        return image;
    }

how to use:

Bitmap resizedBitmap = resize(scrBitMap,640,640);
Germanophile answered 12/11, 2020 at 9:44 Comment(0)
R
0

Use BitmapCompat.createScaledBitmap() in androidx core library. The result is much smoother and softer than Bitmap.createScaledBitmap()

Reinertson answered 10/3, 2024 at 15:29 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.