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

Posted

技术标签:

【中文标题】如何在 Android 中调整位图的大小?【英文标题】:How to Resize a Bitmap in Android? 【发布时间】:2011-06-17 18:52:34 【问题描述】:

我有一个从远程数据库中获取的 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字符串获取的位图。

【问题讨论】:

Resize Bitmap in android的可能重复 @SagarPilkhwal 这个是第一个被问到的 【参考方案1】:

变化:

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

收件人:

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

【讨论】:

假设您有大分辨率图像,例如 1200x1200,当您显示此图像时,图像视图中将充满。如果我把它缩小说 75% 并且屏幕是这样它在 imageview 中也完全显示缩放的图像,对于这样的屏幕应该怎么做? createScaledBitmap 在我的 Galaxy Tab2 上抛出内存不足异常,这对我来说很奇怪,因为内存很大,并且没有其他特定的应用程序正在运行。 Matrix 解决方案虽然有效。 如果我们想保存纵横比怎么办?? 这个 dpi 缩放怎么样?我认为缩放的位图应该基于设备屏幕的高度和宽度? 使用 Bitmap.createScaledBitmap() 将图像缩小到原始大小的一半以上,会产生锯齿伪影。您可以查看我写的post,我在其中提出了一些替代方案并比较了质量和性能。【参考方案2】:
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;

编辑:正如@a​​veschini 所建议的,我添加了bm.recycle(); 以避免内存泄漏。请注意,如果您将前一个对象用于其他目的,请进行相应处理。

【讨论】:

我尝试了 bitmap.createscaledbitmap 和这种矩阵方法。我发现使用矩阵方法的图像更加清晰。我不知道这是否很常见,或者仅仅是因为我使用的是模拟器而不是手机。只是对像我一样遇到同样麻烦的人的提示。 这里你也必须添加 bm.recycle() 以获得更好的内存性能 感谢您的解决方案,但如果重新排序参数会更好; public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight)。我花了很长时间才弄清楚。 ;P 请注意,Matrix 的正确导入是 android.graphics.Matrix。 这与调用 Bitmap.createScaledBitmap() 相同。见android.googlesource.com/platform/frameworks/base/+/refs/heads/…【参考方案3】:

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

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

【讨论】:

@beginner 如果您调整图像大小,您可能会根据不同的尺寸进行缩放,从而将位图转换为不正确的比例或删除一些位图信息。 我尝试根据比例调整位图大小,但随后出现此错误。引起:java.lang.RuntimeException:Canvas:试图使用回收的位图android.graphics.Bitmap@2291dd13 @beginner 每次调整位图大小时,根据您的操作,您通常需要创建一个新大小的副本,而不是调整现有位图的大小(因为在这种情况下它看起来对位图的引用已经在内存中回收了)。 正确..我试过了,现在可以正常工作了。谢谢【参考方案4】:
profileImage.setImageBitmap(
    Bitmap.createScaledBitmap(
        BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length), 
        80, 80, false
    )
);

【讨论】:

【参考方案5】:

试试这个代码:

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

希望对你有用。

【讨论】:

【参考方案6】:

有人问这种情况下如何保持纵横比:

计算用于缩放的因子并将其用于两个维度。 假设您希望图像的高度为屏幕的 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);

要获得屏幕分辨率,您有以下解决方案: Get screen dimensions in pixels

【讨论】:

【参考方案7】:

基于纵横比的比例:

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

【讨论】:

【参考方案8】:

试试这个: 此函数按比例调整位图大小。当最后一个参数设置为“X”时,newDimensionXorY 被视为新宽度,而当设置为“Y”时,新高度。

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;

【讨论】:

【参考方案9】:

使用目标最大尺寸和宽度缩放位图,同时保持纵横比:

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

【讨论】:

【参考方案10】:

从 API 19 开始,存在位图 setWidth(int width) 和 setHeight(int height)。 http://developer.android.com/reference/android/graphics/Bitmap.html

【讨论】:

【参考方案11】:
  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 extraSizeRatio = width > height 后工作了? (float)( (float)width / (float)ScaleSize) : (float)((float)height / (float)ScaleSize);【参考方案12】:

根据任何显示尺寸调整位图大小

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;

【讨论】:

【参考方案13】:
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;
    

【讨论】:

【参考方案14】:

虽然接受的答案是正确的,但它不会通过保持相同的纵横比来调整Bitmap 的大小。如果您正在寻找一种通过保持相同纵横比来调整 Bitmap 大小的方法,您可以使用以下实用程序函数。函数的使用细节和解释见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;
       
   

【讨论】:

【参考方案15】:
/**
 * 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)
  

【讨论】:

【参考方案16】:

保持纵横比,

  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;
    

【讨论】:

【参考方案17】:

虽然前面的答案确实会缩放图像并注意纵横比,但应该重新采样本身,以免出现锯齿。照顾规模是正确解决论点的问题。有许多关于标准缩放调用的输出图像质量的 cmets。为了保持图像质量,应该使用标准调用:

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

将最后一个参数设置为true,因为它会对重采样进行双线性过滤以防止混叠。在此处阅读有关别名的更多信息:https://en.wikipedia.org/wiki/Aliasing

来自安卓文档:

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:布尔值,缩放位图时是否应使用双线性过滤。如果这是真的,那么在缩放时将使用双线性滤波,这会以更差的性能为代价获得更好的图像质量。如果这是错误的,则使用最近邻缩放代替,这将具有更差的图像质量但更快。推荐的默认设置是将过滤器设置为“真”,因为双线性过滤的成本通常是最小的,并且图像质量的提高是显着的。

【讨论】:

【参考方案18】:
* 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);
        

【讨论】:

【参考方案19】:

应用 Matrix.ScaleToFit.CENTER) 获取新的位图保持纵横比。

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

【讨论】:

以上是关于如何在 Android 中调整位图的大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 上调整位图大小

调整可绘制图层列表内的位图大小 2

在android上调整位图大小的最节省内存的方法?

我如何正确调整位图的大小?

在 Android 上将大型位图文件调整为缩放的输出文件

如何在不损失 Android 分辨率的情况下减小位图的大小?