3

I want to scale a bitmap maintaining the aspect ratio, but fitting the required dimensions. This answer scales the bitmap and maintains the aspect ratio, but leaves some blank space unless the image is a perfect square. I need to fill both width and height, just like the FIT_XY ScaleType property of an ImageView.

Community
  • 1
  • 1
Pablo Quemé
  • 1,414
  • 4
  • 16
  • 29

3 Answers3

6

Based on Streets of Boston's answer, I made this method that scales and returns any Bitmap to a desired width and height, fitting both dimensions (no blank space!). It automatically adapts to more horizontal or more vertical images.

public Bitmap resizeBitmapFitXY(int width, int height, Bitmap bitmap){
    Bitmap background = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    float originalWidth = bitmap.getWidth(), originalHeight = bitmap.getHeight();
    Canvas canvas = new Canvas(background);
    float scale, xTranslation = 0.0f, yTranslation = 0.0f;
    if (originalWidth > originalHeight) {
        scale = height/originalHeight;
        xTranslation = (width - originalWidth * scale)/2.0f;
    }
    else {
        scale = width / originalWidth;
        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(bitmap, transformation, paint);
    return background;
}
Community
  • 1
  • 1
Pablo Quemé
  • 1,414
  • 4
  • 16
  • 29
  • 1
    Image this getting cut from left and right side, by this code. – Lovekush Vishwakarma Mar 08 '17 at 11:53
  • @LovekushVishwakarma the point of this code is to fit any bitmap to any dimensions without getting disproportioned, that means that sometimes it will cut horizontally or vertically to maintain the aspect radio – Pablo Quemé Mar 13 '17 at 18:21
  • no but I want to show actual image, and by your code its getting too much cut from left and right side, my requirement is only resizing not cut the left and right side, I want actual image with the resized height and width. – Lovekush Vishwakarma Mar 14 '17 at 10:37
  • 1
    I guess this code isn't right for you then Lovekush – Pablo Quemé Mar 15 '17 at 21:35
  • this answer has code to fit the image to given scale respecting the ratio and no croppping https://stackoverflow.com/a/32810187/9308731 – CrackerKSR Mar 22 '22 at 07:49
  • if you change the conditional to: float widthRatio = width / originalWidth; float heightRatio = heigh / originHeight; if (widthRatio > heightRatio) { it should give the desired results – Lambage Mar 10 '23 at 15:28
0

This will scale the image to fit into sqaure without any solid color padding in the rest of area and no cropping. If Image is not sqaure then there will be transparent area and aspect ratio of image will as original image. I have tested it with potrait and lanscape images

import android.graphics.*;

 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.TRANSPARENT);
            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;
        }
    }

from https://stackoverflow.com/a/32810187/9308731

CrackerKSR
  • 1,380
  • 1
  • 11
  • 29
0

Answer is in Kotlin, based on Pablo's answer and fixed the issue of getting cropped off:

        myBitmap?.let {
        val originalWidth = it.width.toFloat()
        val originalHeight = it.height.toFloat()
        var scale = 0.0f
        var xTranslation = 0.0f
        var yTranslation = 0.0f
        val widthRatio = viewWidth / originalWidth
        val heightRatio = viewHeight / originalHeight

        if (widthRatio > heightRatio) {
            scale = viewHeight / originalHeight
            xTranslation = (viewWidth - originalWidth * scale) / 2.0f
        } else {
            scale = viewWidth / originalWidth
            yTranslation = (viewHeight - originalHeight * scale) / 2.0f
        }

        val matrix = Matrix()
        matrix.postTranslate(xTranslation, yTranslation)
        matrix.preScale(scale, scale)
        canvas.drawBitmap(it, matrix, myBitmapPainter)
    }
Lambage
  • 367
  • 3
  • 8