android : drawing to canvas without stretching - android

I an trying to draw a bitmap to canvas. it results in stretching the bitmap. What i want is not to stretch if image small and crop the image if it is bigger than the display. How this can be achieved.
I have a custom drawable that extends DrawableWrapper
public class MyDrawable extends DrawableWrapper {
public MyDrawable(Drawable drawable) {
super(drawable);
}
public MyDrawable(final Context context, Bitmap bitmap) {
this(new BitmapDrawable(context.getResources(),bitmap));
}
I am having this code in boundsChnage()
protected void onBoundsChange(Rect bounds) {
mBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mBitmap);
super.draw(canvas);
}
This results in drawing a cropped part of the stretched drawable.

i think it will help you.
Bitmap scaleBitmap = scaleBitmap(bitmap);
RectF rectF = new RectF(0, (mHeight scaleBitmap.getHeight()),
scaleBitmap.getWidth(), scaleBitmap.getHeight());
canvas.drawBitmap(scaleBitmap, null, rectF, null);
private Bitmap scaleBitmap(Bitmap bm) {
int width = bm.getWidth();
int height = bm.getHeight();
Log.v("Pictures", "Width and height are " + width + "--" + height);
int mWidth = this.getResources().getDisplayMetrics().widthPixels;
int mHeight = this.getResources().getDisplayMetrics().heightPixels;
if (width > height) {
// landscape
int ratio = width / mWidth;
width = mWidth;
height = height / ratio;
} else if (height > width) {
// portrait
int ratio = height / mHeight;
height = mHeight;
width = width / ratio;
} else {
// square
height = mWidth;
width = mWidth;
}
Log.v("Pictures", "after scaling Width and height are " + width + "--" + height);
bm = Bitmap.createScaledBitmap(bm, width, height, true);
return bm;
}

Related

Android scaling down a Bitmap based on SurfaceView

So I am trying to scale down a bitmap based on the size of a surface view I have written the following code
public Bitmap scaleBitMap(int width, int height, Bitmap b){
// scale down based on the size of the Surface view.
// width and height = canvas.getHeight(), canvas.getWidth();
// this should set the height and width of the bitmap based on a percentage
// the bit map is returned and then displayed by canvas.drawBitmap(scaleBitMap(canvas.getHeight(),canvas.getWidth(),bitmapHere)....
Bitmap bitmap = null;
try{
bitmap = Bitmap.createScaledBitmap(b, (height/100 * 10), (width/100 * 10), true);
}catch(Exception e){
}
return bitmap;
}
Ok so this code works! returns a scaled bitmap.
I am not sure what are you trying to do, but i have done similar thing before. This code scales bitmap to match screensize. Maybe it will help you.
public Bitmap scaleBitMap(int width, int height, Bitmap b){
// scale down based on the size of the Surface view.
// width and height = canvas.getHeight(), canvas.getWidth();
// this should set the height and width of the bitmap based on a percentage
// the bit map is returned and then displayed by canvas.drawBitmap(scaleBitMap(canvas.getHeight(),canvas.getWidth(),bitmapHere)....
Bitmap bitmap = null;
try{
float scaledvalues[] = scale(b.getWidth(), b.getHeight(), width, height);
bitmap = Bitmap.createScaledBitmap(b, scaledvalues[1], scaledvalues[0], true);
}catch(Exception e){
}
return bitmap;
}
public float[] scale(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight){
float scaledheight = -1f;
float scaledwidth = -1f;
float scaledheightpros = -1f;
float scaledwidthpros = -1f;
float finalheight = -1f;
float finalwidth = -1f;
if(bitmapHeight > viewHeight){
scaledheight = bitmapHeight - viewHeight;
float s = scaledheight*100f;
scaledheightpros = s / 100f;
}
if(bitmapWidth > viewWidth){
scaledwidth = bitmapWidth - viewWidth;
float z = scaledwidth * 100f;
scaledwidthpros = z / bitmapWidth;
}
if(scaledheightpros > scaledwidthpros){
float a = bitmapHeight/100f;
float b = bitmapWidth/100f;
finalheight = bitmapHeight - (a * scaledheightpros);
finalwidth = bitmapWidth - (b * scaledheightpros);
}
else{
float a = bitmapHeight/100f;
float b = bitmapWidth/100f;
finalheight = bitmapHeight - (a * scaledwidthpros);
finalwidth = bitmapWidth - (b * scaledwidthpros);
}
float array[] = {finalwidth, finalheight};
return array;
}
It works.. but perhaps i should check my math!
here is the working code....
public Bitmap scaleBitMap(int width, int height, Bitmap b){
// scale down based on the size of the Surface view.
// width and height = canvas.getHeight(), canvas.getWidth();
// this should set the height and width of the bitmap based on a percentage
// the bit map is returned and then displayed by canvas.drawBitmap(scaleBitMap(canvas.getHeight(),canvas.getWidth(),bitmapHere)....
Bitmap bitmap = null;
try{
bitmap = (Bitmap) createScaledBitmap(b, (height/100 * 22), (width/100 * 22), false);
}catch(Exception e){
Log.d("Bitmap","Issue: "+e);
}
return bitmap;
}

Scaled Bitmap maintaining aspect ratio

I would like to scale a Bitmap to a runtime dependant width and height, where the aspect ratio is maintained and the Bitmap fills the entire width and centers the image vertically, either cropping the excess or filling in the gap with 0 alpha pixels.
I'm currently redrawing the bitmap myself by creating a Bitmap of all 0 alpha pixels and drawing the image Bitmap on top of it, scaling to the exact specified width and maintaining the aspect ratio, however, it ends up losing/screwing up the pixel data.
Here is how I'm doing it:
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;
Is there a library out there or some better code that can do this better? I would like the image to look as crisp as possible, but I knew that my function wouldn't provide a great result.
I know I could have the image stay fine by using integer scaling, instead of float scaling, but I need the width to be 100% filled.
Also, I know about an ImageView's Gravity.CENTER_CROP capability, however, that also uses integer scaling, so it cuts off the width of the image when it shouldn't.
This will respect maxWidth and maxHeight, which means the resulting bitmap will never have dimensions larger then those:
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;
}
}
What about this:
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;
I added a paint to filter the scaled bitmap.
here is a method from my Utils class, that does the job:
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;
}
Here I have a tested solution where I create a scaled Bitmap out of a bitmap file:
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;
}
Notice that I need scaled Bitmaps which have a maximum size of 4096x4096 Pixels but the aspect ratio needs to be kept while resizing. If you need other values for width or height just replace the values "4096".
This is just an addition to the answer of Coen but the problem in his code is the line where he calculates the ratio. Dividing two Integers gives an Integer and if the result is < 1 it will be rounded to 0. So this throws the "divide by zero" exception.
None of the above answers worked for me and I just created a method that sets all of the dimensions into the desired ones by painting the empty area black. Here is my method:
/**
* 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;
}
}
For example;
Let's say you have an image as 100 x 100 but the desired size is 300x50, then this method will convert your image to 50 x 50 and paint it into a new image that has dimensions of 300 x 50 (and empty fields will be black).
Another example: let's say you have an image as 600 x 1000 and the desired sizes are 300 x 50 again, then your image will be converted into 30 x 50 and painted into a newly created image which has sizes of 300 x 50.
I think this is what it must be, Rs.
simpler solution : note we set the width to 500 pixels
public void scaleImageKeepAspectRatio()
{
int imageWidth = scaledGalleryBitmap.getWidth();
int imageHeight = scaledGalleryBitmap.getHeight();
int newHeight = (imageHeight * 500)/imageWidth;
scaledGalleryBitmap = Bitmap.createScaledBitmap(scaledGalleryBitmap, 500, newHeight, false);
}
It can also be done by calculating the ratio yourself, like this.
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;
}
Added RESIZE_CROP to Gowrav's answer.
enum RequestSizeOptions {
RESIZE_FIT,
RESIZE_INSIDE,
RESIZE_EXACT,
RESIZE_CENTRE_CROP
}
static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, RequestSizeOptions options) {
try {
if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT ||
options == RequestSizeOptions.RESIZE_INSIDE ||
options == RequestSizeOptions.RESIZE_EXACT || options == RequestSizeOptions.RESIZE_CENTRE_CROP)) {
Bitmap resized = null;
if (options == RequestSizeOptions.RESIZE_EXACT) {
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
} else {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight);
if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) {
resized = Bitmap.createScaledBitmap(bitmap, (int) (width / scale), (int) (height / scale), false);
}
if (scale > 1 || options == RequestSizeOptions.RESIZE_CENTRE_CROP) {
int smaller_side = (height-width)>0?width:height;
int half_smaller_side = smaller_side/2;
Rect initialRect = new Rect(0,0,width,height);
Rect finalRect = new Rect(initialRect.centerX()-half_smaller_side,initialRect.centerY()-half_smaller_side,
initialRect.centerX()+half_smaller_side,initialRect.centerY()+half_smaller_side);
bitmap = Bitmap.createBitmap(bitmap, finalRect.left, finalRect.top, finalRect.width(), finalRect.height(), null, true);
//keep in mind we have square as request for cropping, otherwise - it is useless
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
}
}
if (resized != null) {
if (resized != bitmap) {
bitmap.recycle();
}
return resized;
}
}
} catch (Exception e) {
Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e);
}
return bitmap;
}
Kotlin extension function version based on joaomgcd's answer
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
}
This is an awesome library from ArthurHub to handle the image crops both programmatically and interactively if you don't want to reinvent the wheel.
But if you prefer a non bloated version like me.., the internal function shown here is a rather sophisticated to perform Image Scaling with few standard options
/**
* Resize the given bitmap to the given width/height by the given option.<br>
*/
enum RequestSizeOptions {
RESIZE_FIT,
RESIZE_INSIDE,
RESIZE_EXACT
}
static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, RequestSizeOptions options) {
try {
if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT ||
options == RequestSizeOptions.RESIZE_INSIDE ||
options == RequestSizeOptions.RESIZE_EXACT)) {
Bitmap resized = null;
if (options == RequestSizeOptions.RESIZE_EXACT) {
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
} else {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight);
if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) {
resized = Bitmap.createScaledBitmap(bitmap, (int) (width / scale), (int) (height / scale), false);
}
}
if (resized != null) {
if (resized != bitmap) {
bitmap.recycle();
}
return resized;
}
}
} catch (Exception e) {
Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e);
}
return bitmap;
}
public static Bitmap scaleBitmap(Bitmap bitmap, int wantedWidth, int wantedHeight) {
float originalWidth = bitmap.getWidth();
float originalHeight = bitmap.getHeight();
Bitmap output = Bitmap.createBitmap(wantedWidth, wantedHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
Matrix m = new Matrix();
float scalex = wantedWidth/originalWidth;
float scaley = wantedHeight/originalHeight;
float xTranslation = 0.0f, yTranslation = (wantedHeight - originalHeight * scaley)/2.0f;
m.postTranslate(xTranslation, yTranslation);
m.preScale(scalex, scaley);
// m.setScale((float) wantedWidth / bitmap.getWidth(), (float) wantedHeight / bitmap.getHeight());
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(bitmap, m, paint);
return output;
}
My solution was this, which maintains aspect ratio, and requires only one size, for example if you have a 1920*1080 and an 1080*1920 image and you want to resize it to 1280, the first will be 1280*720 and the second will be 720*1280
public static Bitmap resizeBitmap(final Bitmap temp, final int size) {
if (size > 0) {
int width = temp.getWidth();
int height = temp.getHeight();
float ratioBitmap = (float) width / (float) height;
int finalWidth = size;
int finalHeight = size;
if (ratioBitmap < 1) {
finalWidth = (int) ((float) size * ratioBitmap);
} else {
finalHeight = (int) ((float) size / ratioBitmap);
}
return Bitmap.createScaledBitmap(temp, finalWidth, finalHeight, true);
} else {
return temp;
}
}
There is simple math involved in rescaling the image, consider the following snippet and follow along,
1. Suppose, you have Imaan image with 720x1280 and you want to to be fit in 420 width, get the percentage of reduction required by given math,
originalWidth = 720;
wP = 720/100;
/* wP = 7.20 is a percentage value */
Now subtract the required width from original width and then multiply the outcome by wP. You will get the percentage of width being reduced.
difference = originalWidth - 420;
dP = difference/wP;
Here dP will be 41.66, means you are reducing the size 41.66%. So you have to reduce the height by 41.66(dP) to maintain the ration or scale of that image.
Calculate the height as given below,
hP = originalHeight / 100;
//here height percentage will be 1280/100 = 12.80
height = originalHeight - ( hp * dP);
// here 1280 - (12.80 * 41.66) = 746.75
Here is your fitting scale, you can resize image/Bitmap in 420x747. It will return the resized image without losing the ratio/scale.
Example
public static Bitmap scaleToFit(Bitmap image, int width, int height, bool isWidthReference) {
if (isWidthReference) {
int originalWidth = image.getWidth();
float wP = width / 100;
float dP = ( originalWidth - width) / wP;
int originalHeight = image.getHeight();
float hP = originalHeight / 100;
int height = originalHeight - (hP * dP);
image = Bitmap.createScaledBitmap(image, width, height, true);
} else {
int originalHeight = image.getHeight();
float hP = height / 100;
float dP = ( originalHeight - height) / hP;
int originalWidth = image.getWidth();
float wP = originalWidth / 100;
int width = originalWidth - (wP * dP);
image = Bitmap.createScaledBitmap(image, width, height, true);
}
return image;
}
here you are simply scaling the image with reference of height or width parameter to fit into required criteria.

Resizeing bitmap

Hie. I am working on the live wallpaper and I have got a problem. I am done with the parallax effect in my wallpaper. Now, the problem is the bitmap (i.e., the static background) of my live wallpaper, is not getting scaled properly. In some screens the width is proper but in some the bitmap (i.e., the background) appears only half way.
I have tried the density, windowmanager and the px to dp conversion.
None of them seem to work for me. Or may be my approach towards it is not in a proper manner.
I need help for the same.
Code Snippet
this._backgroundImage = BitmapFactory.decodeResource(context.getResources(),R.drawable.scene, options);
Bitmap background_image = Bitmap.createScaledBitmap(_backgroundImage, width, height, false);
canvas.drawBitmap(this.background_image, 0, 0, null);
I was using following methods sometimes back.. I dont know if these will be helpful for you or not .. please check if this works for you
float scale = getResources().getDisplayMetrics().density;
Display display = ((WindowManager) main.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
int WIDTH = display.getWidth();
int HEIGHT = display.getHeight();
public static Drawable resizeDrawable(Drawable d, float scale) {
Drawable drawable = null;
if (d != null) {
try {
Bitmap bitmap1 = ((BitmapDrawable) d).getBitmap();
int width = 0;
int height = 0;
if (Math.min(WIDTH, HEIGHT) > 600) {
width = (int) (100 * scale + 0.5f);
height = (int) (100 * scale + 0.5f);
} else if (Math.min(WIDTH, HEIGHT) > 240) {
width = (int) (70 * scale + 0.5f);
height = (int) (70 * scale + 0.5f);
} else {
width = (int) (44 * scale + 0.5f);
height = (int) (44 * scale + 0.5f);
}
drawable = new BitmapDrawable(resizeBitmap(bitmap1,
width, height));
} catch (Exception e) {
e.printStackTrace();
}
}
return drawable;
}
please note that value used in if-else conditions in resizeDrawable method are just arbitrary values taken by trial n error (which suits my app).. you can try other values according to screens you are targeting
public static Bitmap resizeBitmap(final Bitmap bitmap, final int width,
final int height) {
final int oldWidth = bitmap.getWidth();
final int oldHeight = bitmap.getHeight();
final int newWidth = width;
final int newHeight = height;
// calculate the scale
final float scaleWidth = ((float) newWidth) / oldWidth;
final float scaleHeight = ((float) newHeight) / oldHeight;
// create a matrix for the manipulation
final Matrix matrix = new Matrix();
// resize the Bitmap
matrix.postScale(scaleWidth, scaleHeight);
// if you want to rotate the Bitmap
// recreate the new Bitmap
final Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
oldWidth, oldHeight, matrix, true);
return resizedBitmap;
}
Try this:
Bitmap resizedBitmap=Bitmap.createScaledBitmap(bb, newWidth, newHeight, false);
Tell me if it works.
You can use this to get the screen size and scale it accordingly.
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth(); // deprecated
int height = display.getHeight();

resize image in android drawable

I have full resolution images in drawable folder need to resize according to phone screen size how to do that ?
Do it like this
/************************ Calculations for Image Sizing *********************************/
public Drawable ResizeImage (int imageID) {
//Get device dimensions
Display display = getWindowManager().getDefaultDisplay();
double deviceWidth = display.getWidth();
BitmapDrawable bd=(BitmapDrawable) this.getResources().getDrawable(imageID);
double imageHeight = bd.getBitmap().getHeight();
double imageWidth = bd.getBitmap().getWidth();
double ratio = deviceWidth / imageWidth;
int newImageHeight = (int) (imageHeight * ratio);
Bitmap bMap = BitmapFactory.decodeResource(getResources(), imageID);
Drawable drawable = new BitmapDrawable(this.getResources(),getResizedBitmap(bMap,newImageHeight,(int) deviceWidth));
return drawable;
}
/************************ Resize Bitmap *********************************/
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);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
to get the width you should do this :
Display display = getWindowManager().getDefaultDisplay();
double deviceWidth;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB_MR1)
deviceWidth= display.getWidth();
else {
display.getSize(size);
deviceWidth=size.x;
}

How to Resize a Bitmap in Android?

I have a bitmap taken of a Base64 String from my remote database, (encodedImage is the string representing the image with Base64):
profileImage = (ImageView)findViewById(R.id.profileImage);
byte[] imageAsBytes=null;
try {
imageAsBytes = Base64.decode(encodedImage.getBytes());
} catch (IOException e) {e.printStackTrace();}
profileImage.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
);
profileImage is my ImageView
Ok, but I have to resize this image before showing it on my ImageView of my layout. I have to resize it to 120x120.
Can someone tell me the code to resize it?
The examples I found could not be applied to a base64 string obtained bitmap.
Change:
profileImage.setImageBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
To:
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
profileImage.setImageBitmap(Bitmap.createScaledBitmap(b, 120, 120, false));
import android.graphics.Matrix
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
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);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(
bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
}
EDIT: as suggested by by #aveschini, I have added bm.recycle(); in order to avoid the memory leaks. Please note that in case if you are using the previous object for some other purposes, then handle accordingly.
If you already have a bitmap, you could use the following code to resize:
Bitmap originalBitmap = <original initialization>;
Bitmap resizedBitmap = Bitmap.createScaledBitmap(
originalBitmap, newWidth, newHeight, false);
Scale based on aspect ratio:
float aspectRatio = yourSelectedImage.getWidth() /
(float) yourSelectedImage.getHeight();
int width = 480;
int height = Math.round(width / aspectRatio);
yourSelectedImage = Bitmap.createScaledBitmap(
yourSelectedImage, width, height, false);
To use height as base intead of width change to:
int height = 480;
int width = Math.round(height * aspectRatio);
Scale a bitmap with a target maximum size and width, while maintaining aspect ratio:
int maxHeight = 2000;
int maxWidth = 2000;
float scale = Math.min(((float)maxHeight / bitmap.getWidth()), ((float)maxWidth / bitmap.getHeight()));
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
try this this code :
BitmapDrawable drawable = (BitmapDrawable) imgview.getDrawable();
Bitmap bmp = drawable.getBitmap();
Bitmap b = Bitmap.createScaledBitmap(bmp, 120, 120, false);
I hope it's useful.
Someone asked how to keep aspect ratio in this situation:
Calculate the factor you are using for scaling and use it for both dimensions.
Let´s say you want an image to be 20% of the screen in height
int scaleToUse = 20; // this will be our percentage
Bitmap bmp = BitmapFactory.decodeResource(
context.getResources(), R.drawable.mypng);
int sizeY = screenResolution.y * scaleToUse / 100;
int sizeX = bmp.getWidth() * sizeY / bmp.getHeight();
Bitmap scaled = Bitmap.createScaledBitmap(bmp, sizeX, sizeY, false);
for getting the screen resolution you have this solution:
Get screen dimensions in pixels
Although the accepted answer is correct, it doesn't resize Bitmap by keeping the same Aspect Ratio. If you are looking for a method to resize Bitmap by keeping the same aspect ratio you can use the following utility function. The usage details and explanation of the function are present at this link.
public static Bitmap resizeBitmap(Bitmap source, int maxLength) {
try {
if (source.getHeight() >= source.getWidth()) {
int targetHeight = maxLength;
if (source.getHeight() <= targetHeight) { // if image already smaller than the required height
return source;
}
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (targetHeight * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
} else {
int targetWidth = maxLength;
if (source.getWidth() <= targetWidth) { // if image already smaller than the required height
return source;
}
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (targetWidth * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
}
return result;
}
}
catch (Exception e)
{
return source;
}
}
public Bitmap scaleBitmap(Bitmap mBitmap) {
int ScaleSize = 250;//max Height or width to Scale
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
float excessSizeRatio = width > height ? width / ScaleSize : height / ScaleSize;
Bitmap bitmap = Bitmap.createBitmap(
mBitmap, 0, 0,(int) (width/excessSizeRatio),(int) (height/excessSizeRatio));
//mBitmap.recycle(); if you are not using mBitmap Obj
return bitmap;
}
public static Bitmap resizeBitmapByScale(
Bitmap bitmap, float scale, boolean recycle) {
int width = Math.round(bitmap.getWidth() * scale);
int height = Math.round(bitmap.getHeight() * scale);
if (width == bitmap.getWidth()
&& height == bitmap.getHeight()) return bitmap;
Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
Canvas canvas = new Canvas(target);
canvas.scale(scale, scale);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (recycle) bitmap.recycle();
return target;
}
private static Bitmap.Config getConfig(Bitmap bitmap) {
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
return config;
}
Try this:
This function resizes a bitmap proportionally. When the last parameter is set to "X" the newDimensionXorY is treated as s new width and when set to "Y" a new height.
public Bitmap getProportionalBitmap(Bitmap bitmap,
int newDimensionXorY,
String XorY) {
if (bitmap == null) {
return null;
}
float xyRatio = 0;
int newWidth = 0;
int newHeight = 0;
if (XorY.toLowerCase().equals("x")) {
xyRatio = (float) newDimensionXorY / bitmap.getWidth();
newHeight = (int) (bitmap.getHeight() * xyRatio);
bitmap = Bitmap.createScaledBitmap(
bitmap, newDimensionXorY, newHeight, true);
} else if (XorY.toLowerCase().equals("y")) {
xyRatio = (float) newDimensionXorY / bitmap.getHeight();
newWidth = (int) (bitmap.getWidth() * xyRatio);
bitmap = Bitmap.createScaledBitmap(
bitmap, newWidth, newDimensionXorY, true);
}
return bitmap;
}
profileImage.setImageBitmap(
Bitmap.createScaledBitmap(
BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length),
80, 80, false
)
);
Bitmap Resize based on Any Display size
public Bitmap bitmapResize(Bitmap imageBitmap) {
Bitmap bitmap = imageBitmap;
float heightbmp = bitmap.getHeight();
float widthbmp = bitmap.getWidth();
// Get Screen width
DisplayMetrics displaymetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
float height = displaymetrics.heightPixels / 3;
float width = displaymetrics.widthPixels / 3;
int convertHeight = (int) hight, convertWidth = (int) width;
// higher
if (heightbmp > height) {
convertHeight = (int) height - 20;
bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
convertHighet, true);
}
// wider
if (widthbmp > width) {
convertWidth = (int) width - 20;
bitmap = Bitmap.createScaledBitmap(bitmap, convertWidth,
convertHeight, true);
}
return bitmap;
}
Try this kotlin code for resize....Where Max size any size you
want
fun getResizedBitmap(image: Bitmap?, maxSize: Int): Bitmap {
var width = image!!.width
var height = image.height
val bitmapRatio = width.toFloat() / height.toFloat()
if (bitmapRatio > 0) {
width = maxSize
height = (width / bitmapRatio).toInt()
} else {
height = maxSize
width = (height * bitmapRatio).toInt()
}
return Bitmap.createScaledBitmap(image, width, height, true)
}
As of API 19, Bitmap setWidth(int width) and setHeight(int height) exist.
http://developer.android.com/reference/android/graphics/Bitmap.html
/**
* Kotlin method for Bitmap scaling
* #param bitmap the bitmap to be scaled
* #param pixel the target pixel size
* #param width the width
* #param height the height
* #param max the max(height, width)
* #return the scaled bitmap
*/
fun scaleBitmap(bitmap:Bitmap, pixel:Float, width:Int, height:Int, max:Int):Bitmap {
val scale = px / max
val h = Math.round(scale * height)
val w = Math.round(scale * width)
return Bitmap.createScaledBitmap(bitmap, w, h, true)
}
Keeping the aspect ratio,
public Bitmap resizeBitmap(Bitmap source, int width,int height) {
if(source.getHeight() == height && source.getWidth() == width) return source;
int maxLength=Math.min(width,height);
try {
source=source.copy(source.getConfig(),true);
if (source.getHeight() <= source.getWidth()) {
if (source.getHeight() <= maxLength) { // if image already smaller than the required height
return source;
}
double aspectRatio = (double) source.getWidth() / (double) source.getHeight();
int targetWidth = (int) (maxLength * aspectRatio);
return Bitmap.createScaledBitmap(source, targetWidth, maxLength, false);
} else {
if (source.getWidth() <= maxLength) { // if image already smaller than the required height
return source;
}
double aspectRatio = ((double) source.getHeight()) / ((double) source.getWidth());
int targetHeight = (int) (maxLength * aspectRatio);
return Bitmap.createScaledBitmap(source, maxLength, targetHeight, false);
}
}
catch (Exception e)
{
return source;
}
}
While the previous answers do scale the image and take care of the aspect ratio, the resampling itself should be done so that there is no aliasing. Taking care of scale is a matter of fixing arguments correctly. There are many comments about the quality of the output images from standard scaling call. to maintain quality of the image one should use the standard call:
Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);
with the last argument set to true because it will do the bilinear filtering for resampling to prevent aliasing. Read more about aliasing here: https://en.wikipedia.org/wiki/Aliasing
From android documentation:
https://developer.android.com/reference/android/graphics/Bitmap#createScaledBitmap(android.graphics.Bitmap,%20int,%20int,%20boolean)
public static Bitmap createScaledBitmap (Bitmap src,
int dstWidth,
int dstHeight,
boolean filter)
filter : boolean, Whether or not bilinear filtering should be used when scaling the bitmap. If this is true then bilinear filtering will be used when scaling which has better image quality at the cost of worse performance. If this is false then nearest-neighbor scaling is used instead which will have worse image quality but is faster. Recommended default is to set filter to 'true' as the cost of bilinear filtering is typically minimal and the improved image quality is significant.
* For resize bitmap with width and height ratio.
public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
int width = image.getWidth();
int height = image.getHeight();
float bitmapRatio = (float) width / (float) height;
if (bitmapRatio > 1) {
width = maxSize;
height = (int) (width / bitmapRatio);
} else {
height = maxSize;
width = (int) (height * bitmapRatio);
}
return Bitmap.createScaledBitmap(image, width, height, true);
}
apply Matrix.ScaleToFit.CENTER) for getting a new bitmap keeps aspect ratio.
public static Bitmap getScaledwonBitmap(Bitmap srcBmp, int deisredWidth, int desiredHeight) {
Matrix matrix = new Matrix();
matrix.setRectToRect(new RectF(0, 0, srcBmp.getWidth(), srcBmp.getHeight()),
new RectF(0, 0, deisredWidth, desiredHeight),
Matrix.ScaleToFit.CENTER);
return Bitmap.createBitmap(srcBmp, 0, 0, srcBmp.getWidth(), srcBmp.getHeight(), matrix, true);
}

Categories

Resources