缩放位图保持宽高比

Ril*_*eyE 52 scaling android bitmap

我想将a缩放Bitmap到与运行时相关的宽度和高度,其中保持纵横比并Bitmap填充整个宽度并使图像垂直居中,裁剪多余部分或用0像素填充间隙.

我目前正在通过创建Bitmap所有0像素像素并在其Bitmap上绘制图像,缩放到指定的宽度并保持纵横比来自己重绘位图,但是,它最终会丢失/搞砸像素数据.

我是这样做的:

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888);
float originalWidth = originalImage.getWidth(), originalHeight = originalImage.getHeight();
Canvas canvas = new Canvas(background);
float scale = width/originalWidth;
float xTranslation = 0.0f, yTranslation = (height - originalHeight * scale)/2.0f;
Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
canvas.drawBitmap(originalImage, transformation, null);
return background;
Run Code Online (Sandbox Code Playgroud)

是否有一个库或一些更好的代码可以做得更好?我希望图像看起来尽可能清晰,但我知道我的功能不会提供很好的结果.

我知道我可以通过使用整数缩放而不是浮动缩放来保持图像保持良好,但我需要宽度为100%填充.

此外,我知道一个ImageView人的Gravity.CENTER_CROP能力,但也使用整数缩放,因此当它不应该时,它会切断图像的宽度.

joa*_*gcd 90

这将尊重maxWidth和maxHeight,这意味着生成的位图的尺寸永远不会大于:

 private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
    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 > ratioBitmap) {
            finalWidth = (int) ((float)maxHeight * ratioBitmap);
        } else {
            finalHeight = (int) ((float)maxWidth / ratioBitmap);
        }
        image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
        return image;
    } else {
        return image;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @JoshPinter"这个问题的接受答案引起了裁剪.这个答案对我来说非常合适,因为它不会造成裁剪." (5认同)

Str*_*ton 68

那这个呢:

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888);

float originalWidth = originalImage.getWidth(); 
float originalHeight = originalImage.getHeight();

Canvas canvas = new Canvas(background);

float scale = width / originalWidth;

float xTranslation = 0.0f;
float yTranslation = (height - originalHeight * scale) / 2.0f;

Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);

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

canvas.drawBitmap(originalImage, transformation, paint);

return background;
Run Code Online (Sandbox Code Playgroud)

我添加了一个paint来过滤缩放的位图.

  • 但它是裁剪图像 (5认同)

Gal*_*Rom 24

这是我的Utils类的一个方法,它完成了这项工作:

public static Bitmap scaleBitmapAndKeepRation(Bitmap targetBmp,int reqHeightInPixels,int reqWidthInPixels)
    {
        Matrix matrix = new Matrix();
        matrix .setRectToRect(new RectF(0, 0, targetBmp.getWidth(), targetBmp.getHeight()), new RectF(0, 0, reqWidthInPixels, reqHeightInPixels), Matrix.ScaleToFit.CENTER);
        Bitmap scaledBitmap = Bitmap.createBitmap(targetBmp, 0, 0, targetBmp.getWidth(), targetBmp.getHeight(), matrix, true);
        return scaledBitmap;
    }
Run Code Online (Sandbox Code Playgroud)

  • **注意**这只是API 17(Jellybean)或更高版本 (4认同)
  • 干净!。那很简单。除了变量命名约定。最好更改TargetBmp-> targetBmp。适用于“人像”和“风景”图像 (2认同)

小智 22

在这里,我有一个经过测试的解决方案,我在一个位图文件中创建一个缩放的Bitmap:

    int scaleSize =1024;

    public Bitmap resizeImageForImageView(Bitmap bitmap) {
        Bitmap resizedBitmap = null;
        int originalWidth = bitmap.getWidth();
        int originalHeight = bitmap.getHeight();
        int newWidth = -1;
        int newHeight = -1;
        float multFactor = -1.0F;
        if(originalHeight > originalWidth) {
            newHeight = scaleSize ;
            multFactor = (float) originalWidth/(float) originalHeight;
            newWidth = (int) (newHeight*multFactor);
        } else if(originalWidth > originalHeight) {
            newWidth = scaleSize ;
            multFactor = (float) originalHeight/ (float)originalWidth;
            newHeight = (int) (newWidth*multFactor);
        } else if(originalHeight == originalWidth) {
            newHeight = scaleSize ;
            newWidth = scaleSize ;
        }
        resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
        return resizedBitmap;
    }
Run Code Online (Sandbox Code Playgroud)

请注意,我需要缩放的位图,其最大尺寸为4096x4096像素,但在调整大小时需要保持纵横比.如果您需要宽度或高度的其他值,只需替换值"4096".

这只是Coen答案的补充,但他的代码中的问题是他计算比率的线.除以两个整数得到一个整数,如果结果为<1,它将被舍入为0.所以这会抛出"除以零"异常.


Bah*_*mir 8

以上答案都不适合我,我只是创建了一种方法,该方法将所有尺寸设置为所需的尺寸,并将空白区域涂成黑色。这是我的方法:

/**
 * Scale the image preserving the ratio
 * @param imageToScale Image to be scaled
 * @param destinationWidth Destination width after scaling
 * @param destinationHeight Destination height after scaling
 * @return New scaled bitmap preserving the ratio
 */
public static Bitmap scalePreserveRatio(Bitmap imageToScale, int destinationWidth,
        int destinationHeight) {
    if (destinationHeight > 0 && destinationWidth > 0 && imageToScale != null) {
        int width = imageToScale.getWidth();
        int height = imageToScale.getHeight();

        //Calculate the max changing amount and decide which dimension to use
        float widthRatio = (float) destinationWidth / (float) width;
        float heightRatio = (float) destinationHeight / (float) height;

        //Use the ratio that will fit the image into the desired sizes
        int finalWidth = (int)Math.floor(width * widthRatio);
        int finalHeight = (int)Math.floor(height * widthRatio);
        if (finalWidth > destinationWidth || finalHeight > destinationHeight) {
            finalWidth = (int)Math.floor(width * heightRatio);
            finalHeight = (int)Math.floor(height * heightRatio);
        }

        //Scale given bitmap to fit into the desired area
        imageToScale = Bitmap.createScaledBitmap(imageToScale, finalWidth, finalHeight, true);

        //Created a bitmap with desired sizes
        Bitmap scaledImage = Bitmap.createBitmap(destinationWidth, destinationHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(scaledImage);

        //Draw background color
        Paint paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);

        //Calculate the ratios and decide which part will have empty areas (width or height)
        float ratioBitmap = (float)finalWidth / (float)finalHeight;
        float destinationRatio = (float) destinationWidth / (float) destinationHeight;
        float left = ratioBitmap >= destinationRatio ? 0 : (float)(destinationWidth - finalWidth) / 2;
        float top = ratioBitmap < destinationRatio ? 0: (float)(destinationHeight - finalHeight) / 2;
        canvas.drawBitmap(imageToScale, left, top, null);

        return scaledImage;
    } else {
        return imageToScale;
    }
}
Run Code Online (Sandbox Code Playgroud)

例如;

假设您有一个 100 x 100 的图像,但所需的大小是 300x50,那么此方法会将您的图像转换为 50 x 50 并将其绘制为尺寸为 300 x 50 的新图像(空字段将为黑色) .

另一个例子:假设您有一个 600 x 1000 的图像,并且所需的尺寸再次为 300 x 50,那么您的图像将被转换为 30 x 50 并绘制成一个新创建的图像,其尺寸为 300 x 50。

我认为这是必须的,卢比。


Coe*_*men 6

也可以这样计算自己的比例来完成。

private Bitmap scaleBitmap(Bitmap bm) {
    int width = bm.getWidth();
    int height = bm.getHeight();

    Log.v("Pictures", "Width and height are " + width + "--" + height);

    if (width > height) {
        // landscape
        int ratio = width / maxWidth;
        width = maxWidth;
        height = height / ratio;
    } else if (height > width) {
        // portrait
        int ratio = height / maxHeight;
        height = maxHeight;
        width = width / ratio;
    } else {
        // square
        height = maxHeight;
        width = maxWidth;
    }

    Log.v("Pictures", "after scaling Width and height are " + width + "--" + height);

    bm = Bitmap.createScaledBitmap(bm, width, height, true);
    return bm;
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,它的解决方案很重要?秃鹰随时准备在这里投票否定想法。 (6认同)

yeh*_*att 6

更简单的解决方案:请注意我们将宽度设置为500像素

 public void scaleImageKeepAspectRatio()
    {
        int imageWidth = scaledGalleryBitmap.getWidth();
        int imageHeight = scaledGalleryBitmap.getHeight();
        int newHeight = (imageHeight * 500)/imageWidth;
        scaledGalleryBitmap = Bitmap.createScaledBitmap(scaledGalleryBitmap, 500, newHeight, false);

    }
Run Code Online (Sandbox Code Playgroud)


v.d*_*v.d 5

基于 joaomgcd 的回答的 Kotlin 扩展功能版本

private fun Bitmap.resize(maxWidth: Int, maxHeight: Int): Bitmap {
    return if (maxHeight > 0 && maxWidth > 0) {
        val width = this.width
        val height = this.height
        val ratioBitmap = width.toFloat() / height.toFloat()
        val ratioMax = maxWidth.toFloat() / maxHeight.toFloat()
        var finalWidth = maxWidth
        var finalHeight = maxHeight
        if (ratioMax > ratioBitmap) {
            finalWidth = (maxHeight.toFloat() * ratioBitmap).toInt()
        } else {
            finalHeight = (maxWidth.toFloat() / ratioBitmap).toInt()
        }
        Bitmap.createScaledBitmap(this, finalWidth, finalHeight, true)
    } else this
}
Run Code Online (Sandbox Code Playgroud)