问题
I'm looking for a solution for the following problem: how to change the size of a Bitmap
to 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