Resizing a bitmap to a fixed value but without changing the aspect ratio

本秂侑毒 提交于 2020-11-30 05:10:41

问题


I'm looking for a solution for the following problem: how to change the size of a Bitmapto a fixed size (for example 512x128). The aspect ratio of the bitmap content must be preserved.

I think it should be something like this:

  • create an empty 512x128 bitmap

  • scale the original bitmap down to fit the 512x128 pixels with keeping the aspect ratio

  • copy the scaled into the empty bitmap (centered)

What is the simplest way to achieve this?

The reason for all this is, that the GridView messes the layout up when the aspect ratio of an image differs from the other. Here is a screenshot (all images except the last one have the aspect ratio of 4:1):

screenshot


回答1:


Try this, calculate the ratio and then rescale.

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
        float ratio = (float) width / maxWidth;
        width = maxWidth;
        height = (int)(height / ratio);
    } else if (height > width) {
        // portrait
        float ratio = (float) height / maxHeight;
        height = maxHeight;
        width = (int)(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;
}



回答2:


The answer by Coen Damen doesn't always respect Max Height and Max Width. Here's an answer that does:

 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 > 1) {
            finalWidth = (int) ((float)maxHeight * ratioBitmap);
        } else {
            finalHeight = (int) ((float)maxWidth / ratioBitmap);
        }
        image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
        return image;
    } else {
        return image;
    }
}



回答3:


I have stumbled upon the same problem a number of times in my projects and each time due to lack of time (and laziness) I would be satisfied with a less than optimum solution. But recently I found some time to crack down this particular issue. Here is my solution and I hope it helps someone down the line...

Bitmap scaleDownLargeImageWithAspectRatio(Bitmap image)
            {
                int imaheVerticalAspectRatio,imageHorizontalAspectRatio;
                float bestFitScalingFactor=0;
                float percesionValue=(float) 0.2;

                //getAspect Ratio of Image
                int imageHeight=(int) (Math.ceil((double) image.getHeight()/100)*100);
                int imageWidth=(int) (Math.ceil((double) image.getWidth()/100)*100);
                int GCD=BigInteger.valueOf(imageHeight).gcd(BigInteger.valueOf(imageWidth)).intValue();
                imaheVerticalAspectRatio=imageHeight/GCD;
                imageHorizontalAspectRatio=imageWidth/GCD;
                Log.i("scaleDownLargeImageWIthAspectRatio","Image Dimensions(W:H): "+imageWidth+":"+imageHeight);
                Log.i("scaleDownLargeImageWIthAspectRatio","Image AspectRatio(W:H): "+imageHorizontalAspectRatio+":"+imaheVerticalAspectRatio);

                //getContainer Dimensions
                int displayWidth = getWindowManager().getDefaultDisplay().getWidth();
                int displayHeight = getWindowManager().getDefaultDisplay().getHeight();
               //I wanted to show the image to fit the entire device, as a best case. So my ccontainer dimensions were displayWidth & displayHeight. For your case, you will need to fetch container dimensions at run time or you can pass static values to these two parameters 

                int leftMargin = 0;
                int rightMargin = 0;
                int topMargin = 0;
                int bottomMargin = 0;
                int containerWidth = displayWidth - (leftMargin + rightMargin);
                int containerHeight = displayHeight - (topMargin + bottomMargin);
                Log.i("scaleDownLargeImageWIthAspectRatio","Container dimensions(W:H): "+containerWidth+":"+containerHeight);

                //iterate to get bestFitScaleFactor per constraints
                while((imageHorizontalAspectRatio*bestFitScalingFactor <= containerWidth) && 
                        (imaheVerticalAspectRatio*bestFitScalingFactor<= containerHeight))
                {
                    bestFitScalingFactor+=percesionValue;
                }

                //return bestFit bitmap
                int bestFitHeight=(int) (imaheVerticalAspectRatio*bestFitScalingFactor);
                int bestFitWidth=(int) (imageHorizontalAspectRatio*bestFitScalingFactor);
                Log.i("scaleDownLargeImageWIthAspectRatio","bestFitScalingFactor: "+bestFitScalingFactor);
                Log.i("scaleDownLargeImageWIthAspectRatio","bestFitOutPutDimesions(W:H): "+bestFitWidth+":"+bestFitHeight);
                image=Bitmap.createScaledBitmap(image, bestFitWidth,bestFitHeight, true);

                //Position the bitmap centre of the container
                int leftPadding=(containerWidth-image.getWidth())/2;
                int topPadding=(containerHeight-image.getHeight())/2;
                Bitmap backDrop=Bitmap.createBitmap(containerWidth, containerHeight, Bitmap.Config.RGB_565);
                Canvas can = new Canvas(backDrop);
                can.drawBitmap(image, leftPadding, topPadding, null);

                return backDrop;
            }



回答4:


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

and make sure that both the dstWidth and dstHeight are obtained from src.getWidth()*scale and src.getHeight()*scale, where scale is a value that you need to determine to make sure the scaled bitmap fits inside 512x128.




回答5:


I think @Coen's answer is not right solution for this question. I also needed a method like this but I wanted to square image.

Here is my solution for square image;

public static Bitmap resizeBitmapImageForFitSquare(Bitmap image, int maxResolution) {

    if (maxResolution <= 0)
        return image;

    int width = image.getWidth();
    int height = image.getHeight();
    float ratio = (width >= height) ? (float)maxResolution/width :(float)maxResolution/height;

    int finalWidth = (int) ((float)width * ratio);
    int finalHeight = (int) ((float)height * ratio);

    image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);

    if (image.getWidth() == image.getHeight())
        return image;
    else {
        //fit height and width
        int left = 0;
        int top = 0;

        if(image.getWidth() != maxResolution)
            left = (maxResolution - image.getWidth()) / 2;

        if(image.getHeight() != maxResolution)
            top = (maxResolution - image.getHeight()) / 2;

        Bitmap bitmap = Bitmap.createBitmap(maxResolution, maxResolution, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawBitmap(image, left, top, null);
        canvas.save();
        canvas.restore();

        return  bitmap;
    }
}


来源:https://stackoverflow.com/questions/15124179/resizing-a-bitmap-to-a-fixed-value-but-without-changing-the-aspect-ratio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!