ChatGPT解决这个技术问题 Extra ChatGPT

How to Resize a Bitmap in Android?

I have a bitmap taken of a Base64 String from my remote database, (encodedImage is the string representing the image with Base64):

profileImage = (ImageView)findViewById(R.id.profileImage);

byte[] imageAsBytes=null;
try {
    imageAsBytes = Base64.decode(encodedImage.getBytes());
} catch (IOException e) {e.printStackTrace();}

profileImage.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
);

profileImage is my ImageView

Ok, but I have to resize this image before showing it on my ImageView of my layout. I have to resize it to 120x120.

Can someone tell me the code to resize it?

The examples I found could not be applied to a base64 string obtained bitmap.

Possible duplicate of Resize Bitmap in Android
@SagarPilkhwal this one was asked first

J
JJD

Change:

profileImage.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)

To:

Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));

suppose you have large resolution image say 1200x1200 and when you display this, it will be full in the imageview. If i scale it down say 75% and the screen is so that it displays scaled image also fully in imageview, what should be done for such screens?
The createScaledBitmap throw a Out of Memory Exception on my Galaxy Tab2 which is very odd to me since there is a lot of memory and no other particular app are running. The Matrix solution work though.
what if we want to save aspect ratio ??
What about dpi scaling for this ? I think the scaled bitmap should be based on the device screen height and width ?
Using Bitmap.createScaledBitmap() to downscale an image more than half the original size, can produce aliasing artifacts. You can take a look at a post I wrote where I propose some alternatives and compare quality and performance.
L
Leonid Ustenko
import android.graphics.Matrix
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
    int width = bm.getWidth();
    int height = bm.getHeight();
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // CREATE A MATRIX FOR THE MANIPULATION
    Matrix matrix = new Matrix();
    // RESIZE THE BIT MAP
    matrix.postScale(scaleWidth, scaleHeight);

    // "RECREATE" THE NEW BITMAP
    Bitmap resizedBitmap = Bitmap.createBitmap(
        bm, 0, 0, width, height, matrix, false);
    bm.recycle();
    return resizedBitmap;
}

EDIT: as suggested by by @aveschini, I have added bm.recycle(); in order to avoid the memory leaks. Please note that in case if you are using the previous object for some other purposes, then handle accordingly.


I tried both bitmap.createscaledbitmap and this matrix approach. I find the image is much more clear with matrix approach. I do not know if it is common or just because I am using a simulator instead of a phone. Just a hint for someone who encouters the same trouble like me.
here too you have to add bm.recycle() for much better memory performances
Thanks for the solution, but it would be better if the parameters were reordered; public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight). I spent a hell of time figuring it out. ;P
Note that the correct import for Matrix is android.graphics.Matrix.
This is the same as calling Bitmap.createScaledBitmap(). See android.googlesource.com/platform/frameworks/base/+/refs/heads/…
J
JJD

If you already have a bitmap, you could use the following code to resize:

Bitmap originalBitmap = <original initialization>;
Bitmap resizedBitmap = Bitmap.createScaledBitmap(
    originalBitmap, newWidth, newHeight, false);

@beginner if you resize the image, you may be scaling based on different dimensions that either transform the bitmap to incorrect proportions or remove some of the bitmap information.
I tried resizing the bitmap based on the proportions , but then I was getting this error. Caused by: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@2291dd13
@beginner each time your resize the bitmap, depending on what you are doing, you usually will need to create a copy which is a new size, rather than resizing the existing bitmap (since in this case it looks like the reference to the bitmap was already recycled in memory).
correct ..i tried it and it works proper now. thanks
J
JJD

Scale based on aspect ratio:

float aspectRatio = yourSelectedImage.getWidth() / 
    (float) yourSelectedImage.getHeight();
int width = 480;
int height = Math.round(width / aspectRatio);

yourSelectedImage = Bitmap.createScaledBitmap(
    yourSelectedImage, width, height, false);

To use height as base intead of width change to:

int height = 480;
int width = Math.round(height * aspectRatio);

K
Kevin

Scale a bitmap with a target maximum size and width, while maintaining aspect ratio:

int maxHeight = 2000;
int maxWidth = 2000;    
float scale = Math.min(((float)maxHeight / bitmap.getWidth()), ((float)maxWidth / bitmap.getHeight()));

Matrix matrix = new Matrix();
matrix.postScale(scale, scale);

bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

R
Ravi Makvana

try this this code :

BitmapDrawable drawable = (BitmapDrawable) imgview.getDrawable();
Bitmap bmp = drawable.getBitmap();
Bitmap b = Bitmap.createScaledBitmap(bmp, 120, 120, false);

I hope it's useful.


C
Community

Someone asked how to keep aspect ratio in this situation:

Calculate the factor you are using for scaling and use it for both dimensions. Let´s say you want an image to be 20% of the screen in height

int scaleToUse = 20; // this will be our percentage
Bitmap bmp = BitmapFactory.decodeResource(
    context.getResources(), R.drawable.mypng);
int sizeY = screenResolution.y * scaleToUse / 100;
int sizeX = bmp.getWidth() * sizeY / bmp.getHeight();
Bitmap scaled = Bitmap.createScaledBitmap(bmp, sizeX, sizeY, false);

for getting the screen resolution you have this solution: Get screen dimensions in pixels


S
Sandeep P
  public Bitmap scaleBitmap(Bitmap mBitmap) {
        int ScaleSize = 250;//max Height or width to Scale
        int width = mBitmap.getWidth();
        int height = mBitmap.getHeight();
        float excessSizeRatio = width > height ? width / ScaleSize : height / ScaleSize;
         Bitmap bitmap = Bitmap.createBitmap(
                mBitmap, 0, 0,(int) (width/excessSizeRatio),(int) (height/excessSizeRatio));
        //mBitmap.recycle(); if you are not using mBitmap Obj
        return bitmap;
    }

for me it worked after a bit retyping float excessSizeRatio = width > height ? (float)( (float)width / (float)ScaleSize) : (float)((float)height / (float)ScaleSize);
A
Asad Ali Choudhry

Although the accepted answer is correct, it doesn't resize Bitmap by keeping the same Aspect Ratio. If you are looking for a method to resize Bitmap by keeping the same aspect ratio you can use the following utility function. The usage details and explanation of the function are present at this link.

public static Bitmap resizeBitmap(Bitmap source, int maxLength) {
       try {
           if (source.getHeight() >= source.getWidth()) {
               int targetHeight = maxLength;
               if (source.getHeight() <= targetHeight) { // if image already smaller than the required height
                   return source;
               }

               double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
               int targetWidth = (int) (targetHeight * aspectRatio);

               Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
               if (result != source) {
               }
               return result;
           } else {
               int targetWidth = maxLength;

               if (source.getWidth() <= targetWidth) { // if image already smaller than the required height
                   return source;
               }

               double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
               int targetHeight = (int) (targetWidth * aspectRatio);

               Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
               if (result != source) {
               }
               return result;

           }
       }
       catch (Exception e)
       {
           return source;
       }
   }

J
JJD

Try this: This function resizes a bitmap proportionally. When the last parameter is set to "X" the newDimensionXorY is treated as s new width and when set to "Y" a new height.

public Bitmap getProportionalBitmap(Bitmap bitmap, 
                                    int newDimensionXorY, 
                                    String XorY) {
    if (bitmap == null) {
        return null;
    }

    float xyRatio = 0;
    int newWidth = 0;
    int newHeight = 0;

    if (XorY.toLowerCase().equals("x")) {
        xyRatio = (float) newDimensionXorY / bitmap.getWidth();
        newHeight = (int) (bitmap.getHeight() * xyRatio);
        bitmap = Bitmap.createScaledBitmap(
            bitmap, newDimensionXorY, newHeight, true);
    } else if (XorY.toLowerCase().equals("y")) {
        xyRatio = (float) newDimensionXorY / bitmap.getHeight();
        newWidth = (int) (bitmap.getWidth() * xyRatio);
        bitmap = Bitmap.createScaledBitmap(
            bitmap, newWidth, newDimensionXorY, true);
    }
    return bitmap;
}

J
JJD
profileImage.setImageBitmap(
    Bitmap.createScaledBitmap(
        BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length), 
        80, 80, false
    )
);

k
kakopappa
public static Bitmap resizeBitmapByScale(
            Bitmap bitmap, float scale, boolean recycle) {
        int width = Math.round(bitmap.getWidth() * scale);
        int height = Math.round(bitmap.getHeight() * scale);
        if (width == bitmap.getWidth()
                && height == bitmap.getHeight()) return bitmap;
        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
        Canvas canvas = new Canvas(target);
        canvas.scale(scale, scale);
        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        if (recycle) bitmap.recycle();
        return target;
    }
    private static Bitmap.Config getConfig(Bitmap bitmap) {
        Bitmap.Config config = bitmap.getConfig();
        if (config == null) {
            config = Bitmap.Config.ARGB_8888;
        }
        return config;
    }

D
Dat Nguyen Thanh

Bitmap Resize based on Any Display size

public Bitmap bitmapResize(Bitmap imageBitmap) {

    Bitmap bitmap = imageBitmap;
    float heightbmp = bitmap.getHeight();
    float widthbmp = bitmap.getWidth();

    // Get Screen width
    DisplayMetrics displaymetrics = new DisplayMetrics();
    this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    float height = displaymetrics.heightPixels / 3;
    float width = displaymetrics.widthPixels / 3;

    int convertHeight = (int) hight, convertWidth = (int) width;

    // higher
    if (heightbmp > height) {
        convertHeight = (int) height - 20;
        bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
                convertHighet, true);
    }

    // wider
    if (widthbmp > width) {
        convertWidth = (int) width - 20;
        bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
                convertHeight, true);
    }

    return bitmap;
}

a
afathman

As of API 19, Bitmap setWidth(int width) and setHeight(int height) exist. http://developer.android.com/reference/android/graphics/Bitmap.html


F
Faakhir
/**
 * Kotlin method for Bitmap scaling
 * @param bitmap the bitmap to be scaled
 * @param pixel  the target pixel size
 * @param width  the width
 * @param height the height
 * @param max    the max(height, width)
 * @return the scaled bitmap
 */
fun scaleBitmap(bitmap:Bitmap, pixel:Float, width:Int, height:Int, max:Int):Bitmap {
    val scale = px / max
    val h = Math.round(scale * height)
    val w = Math.round(scale * width)
    return Bitmap.createScaledBitmap(bitmap, w, h, true)
  }

T
Tarasantan

Keeping the aspect ratio,

  public Bitmap resizeBitmap(Bitmap source, int width,int height) {
    if(source.getHeight() == height && source.getWidth() == width) return source;
    int maxLength=Math.min(width,height);
    try {
        source=source.copy(source.getConfig(),true);
        if (source.getHeight() <= source.getWidth()) {
            if (source.getHeight() <= maxLength) { // if image already smaller than the required height
                return source;
            }

            double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
            int targetWidth = (int) (maxLength * aspectRatio);

            return Bitmap.createScaledBitmap(source, targetWidth, maxLength, false);
        } else {

            if (source.getWidth() <= maxLength) { // if image already smaller than the required height
                return source;
            }

            double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
            int targetHeight = (int) (maxLength * aspectRatio);

            return Bitmap.createScaledBitmap(source, maxLength, targetHeight, false);

        }
    }
    catch (Exception e)
    {
        return source;
    }
}

f
fazal ur Rehman
      Try this kotlin code for resize....Where Max size any size you 
      want

      fun getResizedBitmap(image: Bitmap?, maxSize: Int): Bitmap {
    var width = image!!.width
    var height = image.height
    val bitmapRatio = width.toFloat() / height.toFloat()
     if (bitmapRatio > 0) {
        width = maxSize
        height = (width / bitmapRatio).toInt()
     } else {
        height = maxSize
         width = (height * bitmapRatio).toInt()
     }
         return Bitmap.createScaledBitmap(image, width, height, true)
     }

A
Ashutosh Gupta

While the previous answers do scale the image and take care of the aspect ratio, the resampling itself should be done so that there is no aliasing. Taking care of scale is a matter of fixing arguments correctly. There are many comments about the quality of the output images from standard scaling call. to maintain quality of the image one should use the standard call:

Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);

with the last argument set to true because it will do the bilinear filtering for resampling to prevent aliasing. Read more about aliasing here: https://en.wikipedia.org/wiki/Aliasing

From android documentation:

https://developer.android.com/reference/android/graphics/Bitmap#createScaledBitmap(android.graphics.Bitmap,%20int,%20int,%20boolean)


public static Bitmap createScaledBitmap (Bitmap src, 
                int dstWidth, 
                int dstHeight, 
                boolean filter)

filter : boolean, Whether or not bilinear filtering should be used when scaling the bitmap. If this is true then bilinear filtering will be used when scaling which has better image quality at the cost of worse performance. If this is false then nearest-neighbor scaling is used instead which will have worse image quality but is faster. Recommended default is to set filter to 'true' as the cost of bilinear filtering is typically minimal and the improved image quality is significant.


P
Praful Parmar
* For resize bitmap with width and height ratio.    

public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
            int width = image.getWidth();
            int height = image.getHeight();
    
            float bitmapRatio = (float) width / (float) height;
            if (bitmapRatio > 1) {
                width = maxSize;
                height = (int) (width / bitmapRatio);
            } else {
                height = maxSize;
                width = (int) (height * bitmapRatio);
            }
            return Bitmap.createScaledBitmap(image, width, height, true);
        }

l
lannyf

apply Matrix.ScaleToFit.CENTER) for getting a new bitmap keeps aspect ratio.

public static Bitmap getScaledwonBitmap(Bitmap srcBmp, int deisredWidth, int desiredHeight) {
        
            Matrix matrix = new Matrix();
            matrix.setRectToRect(new RectF(0, 0, srcBmp.getWidth(), srcBmp.getHeight()),
                    new RectF(0, 0, deisredWidth, desiredHeight),
                    Matrix.ScaleToFit.CENTER);
           return Bitmap.createBitmap(srcBmp, 0, 0, srcBmp.getWidth(), srcBmp.getHeight(), matrix, true);
        
    }