I am trying to scale down a bitmap while keeping the same aspect ratio.
The following code works just ok, but I know its not the best approach.
I definitely do not like creating a holder bitmap and then another to scale it down as well.
Any suggestions on how to improve this are appreciated.
//width and height are passed in as params
Bitmap viewBM = view.getBitMap();
float aspectRatio = (float) width/height;
int newWidth= viewBM.getWidth();
int newHeight = viewBM.getHeight();
if (newHeight > newWidth) {
newHeight= (int)Math.round(newWidth * aspectRatio);
} else {
newWidth= (int)Math.round(newHeight * aspectRatio);
}
Bitmap holderBitmap = Bitmap.createBitmap(viewBM, 0, 0, newWidth, newHeight);
final Bitmap finalBitmap = Bitmap.createScaledBitmap(holderBitmap, width, height, true);
Related
I need to display images which are stored in database and I'm having issues with image (Bitmap) width/height and ImageView ...
Just for test - when I add same image in project's drawables I can use this:
Works:
Bitmap b = BitmapFactory.decodeResource(context.getResources(), R.drawable.menu_image);
BitmapDrawable bd = new BitmapDrawable(context.getResources(), b);
imageView.setImageDrawable(bd);
same as
imageView.setImageResource(R.drawable.menu_image);
This following isn't working because image isn't resized:
imageView.setImageBitmap(image);
same as
imageView.setImageDrawable(new BitmapDrawable(context.getResources(), image));
Where image is constructed using this:
public static Bitmap base64ToBitmap(String b64) {
byte[] imageAsBytes = Base64.decode(b64.getBytes(), Base64.DEFAULT);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = context.getResources().getDisplayMetrics().densityDpi;
options.inTargetDensity = context.getResources().getDisplayMetrics().densityDpi;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length, options);
return bitmap;
}
Image original size is 338x94.
676x188, this is image size when I'm using image from project's drawables directory. This is size that I'm looking for, in this case. I suppose a quick fix would be to use Bitmap.createScaledBitmap(), but I have couple of different image formats and I would like to use imageView.setImageBitmap or imageView.setImageDrawable to behave like I loaded Bitmap from project's drawables directory.
Use the following helper class from github
public class BitmapScaler
{
// scale and keep aspect ratio
public static Bitmap scaleToFitWidth(Bitmap b, int width)
{
float factor = width / (float) b.getWidth();
return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
}
// scale and keep aspect ratio
public static Bitmap scaleToFitHeight(Bitmap b, int height)
{
float factor = height / (float) b.getHeight();
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
}
// scale and keep aspect ratio
public static Bitmap scaleToFill(Bitmap b, int width, int height)
{
float factorH = height / (float) b.getWidth();
float factorW = width / (float) b.getWidth();
float factorToUse = (factorH > factorW) ? factorW : factorH;
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factorToUse),
(int) (b.getHeight() * factorToUse), true);
}
// scale and don't keep aspect ratio
public static Bitmap strechToFill(Bitmap b, int width, int height)
{
float factorH = height / (float) b.getHeight();
float factorW = width / (float) b.getWidth();
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factorW),
(int) (b.getHeight() * factorH), true);
}
}
I use the following method to resize images on Android.
public Bitmap resize(Bitmap img, int Width, int Height) {
int width = img.getWidth();
int height = img.getHeight();
int newWidth = (int) Width;
int newHeight = (int) Height;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
//matrix.postRotate(45);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
return resizedBitmap;
}
It works fine on most Android devices. But on some devices the resized image is not displaying. How might I resolve this?
You may create a scaled bitmap with
Bitmap bitmap = Bitmap.createScaledBitmap(b, width, height, true);
Here, width and height you can provide according to the device's screen size for different devices, by reading screen sizes programmatically. Here is how you can read the screen size of a device programmatically.
Most likely, on "some devices" and depending on the requested width and height, there's not enough memory to create the resized bitmap. Check (in debugger) if the resizedBitmap is null when the image "is not displaying".
I have an already decoded bitmap that I would like to temporarily scale before drawing it on a canvas. So decoding a file and setting the size before is out of the question. I would like to keep the size of the existing bitmap and just scale it to be smaller before drawing it on the canvas. Is this posible?
using Matrix postScale(sx, sy, px, py) scales it correctly but doesn't position it right. And canvas.drawBitmap doesn't have an option with matrix and x & y position from what I can see.
Any suggestions?
Here is the code:
public static Bitmap scaleBitmap(Bitmap bitmap, int width, int height) {
final int bitmapWidth = bitmap.getWidth();
final int bitmapHeight = bitmap.getHeight();
final float scale = Math.min((float) width / (float) bitmapWidth,
(float) height / (float) bitmapHeight);
final int scaledWidth = (int) (bitmapWidth * scale);
final int scaledHeight = (int) (bitmapHeight * scale);
final Bitmap decoded = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);
final Canvas canvas = new Canvas(decoded);
return decoded;
}
Please note: Pass the bitmap to scale and it's new height and width.
I have one image, image width is 290 and height is 330.when i used bitmap factory for convert into bitmap width and height is increasing.My code is,
mILearnBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.capital_a_1);
mILearnBitmap = mILearnBitmap.copy(Bitmap.Config.ARGB_8888, true);
mILearnPixelsArry = new int[mILearnBitmap.getWidth() * mILearnBitmap.getHeight()];
mILearnBitmap.getPixels(mILearnPixelsArry, 0, mILearnBitmap.getWidth(), 0, 0,mILearnBitmap.getWidth(), mILearnBitmap.getHeight());
Log.d("mILearnPixelsArry", "---" + mILearnPixelsArry.length);
Log.d("Width", "---" + mILearnBitmap.getWidth());
Log.d("Height", "---" + mILearnBitmap.getHeight());
After using this code width increased to 435 and height increased to 495.Please tell i made mistake some there please help me.
please use this function to resize image
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
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);
// matrix.postRotate(90);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
You can use this -
Bitmap.createScaledBitmap(bm, int destinationWidth, int destinationHeight, boolean filter);
I've been trying this for some time, I would like to create a wallpaper from a Bitmap. Let's say the desired wallpaper size is 320x480, and the source image size is 2048x2048.
I'm not sure whether crop-to-fit is the right term, but what I would like to achieve is to get most part of the picture that has the equal ratio as the desired wallpaper size (320x480).
So in this case, I would like to get 2048x1365 or (1365.333... to be exact) from the source Bitmap, and scale it down to 320x480.
The technique that I have tried is:
1) Crop the Bitmap into 2048x1365 first
bm = Bitmap.createBitmap(bm, xOffset, yOffset, 2048, 1365);
2) Scale it down to 320x480
bm = Bitmap.createScaledBitmap(bm, 320, 480, false);
which produced OutOfMemory error.
Is there any way to achieve this?
Regards,
dezull
Thanks to open source, I found the answer from Android Gallery source code here at line 230 :-D
croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(croppedImage);
Rect srcRect = mCrop.getCropRect();
Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);
int dx = (srcRect.width() - dstRect.width()) / 2;
int dy = (srcRect.height() - dstRect.height()) / 2;
// If the srcRect is too big, use the center part of it.
srcRect.inset(Math.max(0, dx), Math.max(0, dy));
// If the dstRect is too big, use the center part of it.
dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));
// Draw the cropped bitmap in the center
canvas.drawBitmap(mBitmap, srcRect, dstRect, null);
I know this is an incredibly late reply, but something like this maybe:
public static Bitmap scaleCropToFit(Bitmap original, int targetWidth, int targetHeight){
//Need to scale the image, keeping the aspect ration first
int width = original.getWidth();
int height = original.getHeight();
float widthScale = (float) targetWidth / (float) width;
float heightScale = (float) targetHeight / (float) height;
float scaledWidth;
float scaledHeight;
int startY = 0;
int startX = 0;
if (widthScale > heightScale) {
scaledWidth = targetWidth;
scaledHeight = height * widthScale;
//crop height by...
startY = (int) ((scaledHeight - targetHeight) / 2);
} else {
scaledHeight = targetHeight;
scaledWidth = width * heightScale;
//crop width by..
startX = (int) ((scaledWidth - targetWidth) / 2);
}
Bitmap scaledBitmap = Bitmap.createScaledBitmap(original, (int) scaledWidth, (int) scaledHeight, true);
Bitmap resizedBitmap = Bitmap.createBitmap(scaledBitmap, startX, startY, targetWidth, targetHeight);
return resizedBitmap;
}
here is an answer that gets you most of the way there:
How to crop an image in android?