如何在Android中调整位图大小?

398

我有一个位图,是从我的远程数据库中取出的Base64字符串生成的(encodedImage表示使用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是我的ImageView

好的,但在将其显示在我的布局ImageView之前,我必须调整此图像的大小。我需要将其调整为120x120。

有人可以告诉我如何调整大小的代码吗?

我找到的示例无法应用于基于base64字符串获取的位图。


可能是在Android中调整位图大小的重复问题。 - Sagar Pilkhwal
@SagarPilkhwal 这个问题先被问到了。 - 김선달
21个回答

624

更改:

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

收件人:

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

5
在我的Galaxy Tab2上,createScaledBitmap方法抛出了一个内存不足的异常,这对我来说非常奇怪,因为有很多可用内存,而且没有其他特定的应用正在运行。Matrix解决方案有效。 - Ludovic
41
如果我们想要保持宽高比怎么办? - Bugs Happen
将过滤器标志设置为真可以提高质量。 - Ehsan Jelodar
4
这个需要进行 DPI 缩放吗?我认为缩放后的位图应该根据设备屏幕的高度和宽度来确定。 - Doug Ray
2
使用Bitmap.createScaledBitmap()对图像进行超过原始大小一半的缩小操作,可能会产生锯齿伪影。您可以查看我写的一篇文章,在其中提出了一些替代方案并比较了质量和性能。 - Petrakeas
显示剩余6条评论

329
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;
}

编辑:根据@aveschini的建议,我添加了bm.recycle();以避免内存泄漏。请注意,如果您将先前的对象用于其他目的,则需要相应处理。


8
我尝试了bitmap.createscaledbitmap和使用矩阵的方法。 我发现,与bitmap.createscaledbitmap相比,使用矩阵的方法可以使图像更加清晰。 我不知道这是否常见,或者仅因为我在模拟器中使用而不是手机上。 这只是给遇到类似问题的人一些提示。 - Anson Yao
2
在这里,您也需要添加bm.recycle()以获得更好的内存性能。 - aveschini
2
谢谢你的解决方案,但如果参数重新排序一下会更好; public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight)。我花了很长时间才搞明白。;P - Attacktive
2
请注意,Matrix的正确导入方式是android.graphics.Matrix。 - Lev
16
这与调用Bitmap.createScaledBitmap()方法是相同的。请参见https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/Bitmap.java#645。 - BamsBamx
显示剩余4条评论

135

如果您已经有一个位图,您可以使用以下代码来调整大小:

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

1
如果你调整图像大小,可能会基于不同的尺寸进行缩放,这会使位图失去正确的比例或删除一些位图信息。 - ZenBalance
我尝试根据比例调整位图的大小,但是我遇到了这个错误。原因是:java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@2291dd13。 - beginner
@初学者 每次调整位图大小时,根据您的操作,通常需要创建一个新尺寸的副本,而不是调整现有的位图大小(因为在这种情况下,位图的引用已经被回收在内存中)。 - ZenBalance
1
正确...我试过了,现在它可以正常工作。谢谢。 - beginner

49

根据宽高比缩放:

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

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

若要以高度作为基础而非宽度,请更改为:

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

27

在保持纵横比的同时,将位图缩放到目标最大尺寸和宽度:

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);

7

有人问如何在这种情况下保持宽高比:

计算您用于缩放的因子,并将其用于两个维度。 例如,如果您希望图像在高度上占屏幕的20%,则可以使用相同的因子来缩放图像的宽度。

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);

获取屏幕分辨率的解决方案如下: 获取像素屏幕尺寸


7

试试这段代码:

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

我希望你能够有所帮助。


5
虽然接受的答案是正确的,但它不会通过保持相同的纵横比来调整位图的大小。如果您要寻找一种方法来通过保持相同的纵横比来调整位图的大小,则可以使用以下实用程序函数。该函数的使用详细信息和说明可在此链接中找到。
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;
       }
   }

4
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;
    }

4
  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;
    }

经过重新输入,它对我起作用了。float excessSizeRatio = width > height ? (float)((float)width / (float)ScaleSize) : (float)((float)height / (float)ScaleSize); - Csabi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接