I'm developing an Android project using canvas and I have a scaling problem. to make it more simple I'm going to use an example.
Let's supposed my view is : width 1300px and height 800px , I'm putting a canvas inside that goes a static width 1300px but the height is a variable. If my canvas is > 800px so the canvas will goes out of the view so I was trying to use canvas.scale() but I don't know how to calculate the exact value to put inside the scale !
Any ideas ?
My personally, I think you should create a new Canvas. To do that you should resize your bitmap first. Using the below method to compute the scale between size of view and size of bitmap.
public static float computeScale(float w1, float h1, float w2, float h2) {
if (w1 > 0 && h1 > 0 && w2 > 0 && h2 > 0) {
return Math.max(w1 / w2, h1 / h2);
}
return 1;
}
So the scale and the new bitmap width, height will be calculated by the below code:
float scale = computeScale(viewWidth, viewHeight, bitmapWith, bitmapHeight);
if(scale > 1){
int newWidth = Math.round(bitmapWidth / scale);
int newHeight = Math.round(bitmapHeight / scale);
}
// The code for resizing the source bitmap with the newWidth and newHeight.
// Bitmap newBitmap = ...;
Finally, you use the new bitmap to create a new Canvas.
Canvas canvas = new Canvas(newBitmap);
Related
I've been searching for a solution to this problem for quite some time and haven't found anything to match my needs yet.
I want to scale a bitmap to a specific size while maintaining aspect ratio.
Think of it as scaling a bitmap using fitCenter in an ImageView, only in a new bitmap.
The source bitmap has to fit inside the destination bitmap which has a specific size, and the rest of the pixels have to be transparent.
I have tried using Glide like so:
Glide.with(context).load(url)
.asBitmap()
.override(1280, 720)
.fitCenter()
.into(1280, 720)
.get();
But this method returns a bitmap that fits only width (or hight) and wraps the size.
I've heard that using Canvas is a possible solution but haven't found any way of achieving my goal using it.
Any help or insight would be greatly appreciated. I will post any needed clarifications if requested.
I managed to solve it using this function:
Bitmap resizeBitmap(Bitmap image, int destWidth, int destHeight) {
Bitmap background = Bitmap.createBitmap(destWidth, destHeight, Bitmap.Config.ARGB_8888);
float originalWidth = image.getWidth();
float originalHeight = image.getHeight();
Canvas canvas = new Canvas(background);
float scaleX = (float) 1280 / originalWidth;
float scaleY = (float) 720 / originalHeight;
float xTranslation = 0.0f;
float yTranslation = 0.0f;
float scale = 1;
if (scaleX < scaleY) { // Scale on X, translate on Y
scale = scaleX;
yTranslation = (destHeight - originalHeight * scale) / 2.0f;
} else { // Scale on Y, translate on X
scale = scaleY;
xTranslation = (destWidth - originalWidth * scale) / 2.0f;
}
Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(image, transformation, paint);
return background;
}
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.
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;
}
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
I have searched alot for this but got no proper solution!
i have a drawing area in my android app and i want to take image from camera/gallery and set it as a background of canvas.
I get Bitmap after taking photo from camera/gallery and i pass my bitmap to this method to make it aspect fit to my drawView keeping its aspect ratio.
Here newHeight/newWidth are my drawView's height and width.
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.min(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
It works good on mt Htc m7 but on my galaxy tab4 it makes image strech so sleek as you can see in image below:
do anyone know any method through which i can set bitmap to my drawView like this
Bitmap backgroundBitMap= c.scaleCenterCrop(bmp, drawView.getHeight(), drawView.getWidth());
String tempPath = getPath(selectedImageUri, MainActivity.this);
backgroundBitMap= c.rotateImage(backgroundBitMap,tempPath);
drawView.setBackgroundDrawable(new BitmapDrawable(backgroundBitMap));
but keeping its aspect ration same. Actually i want CenterFit functionality for a bitmap.
Any help would be appreciated! Thanks
I have a bitmap image that is larger than then screen size. I want to scale the image in pixels down to the screen size ? How can i do this ? I want to scale it maintaining aspect ratio not just resize it ?
Kind Regards
Get the screen size and pass those parameters into the following function :
Bitmap.createScaledBitmap(originalimage, width, height, true);
use this function with argument as screenWidth and screenHeight
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
for how to get screen width and height see this
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to crop the parsed image in android?
How does one crop the same way as Androids ImageView is doing
android:scaleType="centerCrop"
Your question is a bit short of information on what you want to accomplish, but I guess you have a Bitmap and want to scale that to a new size and that the scaling should be done as "centerCrop" works for ImageViews.
From Docs
Scale the image uniformly (maintain the image's aspect ratio) so that
both dimensions (width and height) of the image will be equal to or
larger than the corresponding dimension of the view (minus padding).
As far as I know, there is no one-liner to do this (please correct me, if I'm wrong), but you could write your own method to do it. The following method calculates how to scale the original bitmap to the new size and draw it centered in the resulting Bitmap.
Hope it helps!
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}