Android: How to get bitmap's scaled width in onDraw() - android

Simple question where the simple answer isn't working. I have a bitmap and I want to get its dimensions as scaled to the display by the system for different DPI screens within the onDraw() method. bitmap.width() returns its unscaled width successfully. However, bitmap.getScaledWidth() returns zero. I have tried getScaledWidth(canvas) and getScaledWidth(canvas.getDensity()), but both return 0. Indeed, canvas.getDensity() returns zero so I can't even calculate it manually.
What am I doing wrong?
Bit more detail. I'm using a custom view. The bitmap is declared in the class and loaded in the constructor.
Edit:
I've found that using:
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
bitmap.getScaledHeight(metrics) returns the same value as bitmap.getHeight().
It would appear that bitmap.getWidth() returns the dimension of the resident bitmap after it has been scaled, meaning there's no apparent way to get the bitmap's original width.

The Canvas class has a lots of overloads for the drawBitmap() function. One of them allows you to scale/cut a Bitmap through a pretty comfortable interface.
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
Where
Bitmap bitmap - is your bitmap you want to draw
Rect src - the source rect from your bitmap. If its not null, it will
cut out a piece from your bitmap (in the size and position of src)
RectF dst - This Rect will represent the Rectangle, your Bitmap will
fit in.
Paint paint - optional paint
And now an example! Lets say, you want to shrink your Bitmaps width to 1/2 and increase its height to 2 times of the original:
float startX = 0; //the left
float startY = 0; //and top corner (place it wherever you want)
float endX = startX + bitmap.getWidth() * 0.5f; //right
float endY = startY + bitmap.getHeight() * 2.0f; //and bottom corner
canvas.drawBitmap(bitmap, null, new RectF(startX, startY, endX, endY), null);
UPDATE
I don't really understand, what you are trying to acomplish, after reading your comment, but here is some extra info to get started:
Get the original size of a Bitmap without loading it into the memory:
BitmapFactory.Options options = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true; // bitmap wont be loaded into the memory
//won't load the Bitmap, but the options will contain the required information.
BitmapFactory.decodeStream(inputStream, null, options);
/*or*/ BitmapFactory.decodeFile(pathName, options);
int originalWidth = bitmapOptions.outWidth;
int originalHeight = bitmapOptions.outHeight;
Now if you have another your actual (scaled) Bitmap, or an ImageView, what you want to compare to the original, then you can use this (to get the width and height use getWidth() and getHeight()):
/*Get these values*/
int originalWidth, originalHeight, scaledWidth, scaledHeight;
float scaleWidthRatio = (float)scaledWidth / originalWidth;
float scaleHeightRatio = (float)scaledHeight / originalHeight;

How about this? You scale the bitmap yourself. :-)
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Drawable drawable = getDrawable();
if(drawable==null)
Log.d("onDraw()","getDrawable returns null");
Bitmap fullSizeBitmap,scaledBitmap = null,roundBitmap = null;
fullSizeBitmap = ((BitmapDrawable)drawable).getBitmap() ;
//get width & height of ImageView
int scaledWidth = getMeasuredWidth();
int scaledHeight = getMeasuredHeight();
//bitmap, which will receive the reference to a bitmap scaled to the bounds of the ImageView.
if(fullSizeBitmap!=null)
scaledBitmap= getScaledBitmap(fullSizeBitmap,scaledWidth,scaledHeight);
//Now, draw the bitmap on the canvas
if(roundBitmap!=null)
canvas.drawBitmap(roundBitmap, 0,0 , null);
}

Related

Transform original bitmap on android

So, I'm using this library https://github.com/thuytrinh/android-collage-views to add "MultiTouchListener" feature to my ImageView. Basically I let user to modify a photo to his needs using rotation, scale and translation. Now the only problem is how to save it. I did it like this:
Bitmap bitmap = Bitmap.createBitmap(imageContainer.getWidth(), imageContainer.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
imageContainer.draw(canvas);
It works, but image is not big enough - it's as big as view on phone so it depends on screen resolution. And I want to "apply" these transformations on given bitmap with full size. And I want transformed image to look like on screen (so it'll need to crop everything out of screen)
I tried the following:
Bitmap newBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(image, imageView.getMatrix(), paint);
But it doesn't look as expected.
User screen:
And output image (without cropping, because I don't want which side I should crop):
How can I fix this? Is there any solution?
Here is one way to do it, definitely not perfect but should give you a good start :
In this, container refers to the view that contains the transformed ImageView, the phone case on your screenshot and src the raw source bitmap.
First, you need to compute the desired width and height of the output bitmap, i.e the size it would be to make the image fit in it while keeping the ratio of the container :
float containerWidth = containerView.getWidth();
float containerHeight = containerView.getHeight();
float srcWidth = src.getWidth();
float srcHeight = src.getHeight();
float containerRatio = containerWidth / containerHeight;
float srcRatio = srcWidth / srcHeight;
float outputWidth, outputHeight;
if(srcRatio > containerRatio) { //fits in width
outputWidth = srcWidth;
outputHeight = srcWidth / containerRatio;
}
else if(srcRatio < containerRatio) { //fits in height
outputHeight = srcHeight;
outputWidth = srcHeight * containerRatio;
}
else {
outputWidth = srcWidth;
outputHeight = srcHeight;
}
Apply the ratio between container width/height and output width/height to the translation part of the matrix that hold the transformation that the user did
float containerToOutputRatioWidth = outputWidth / containerWidth;
float containerToOutputRatioHeight = outputHeight / containerHeight;
float[] values = new float[9];
transformedImageView.getMatrix().getValues(values);
values[2] = values[2] * containerToOutputRatioWidth;
values[5] = values[5] * containerToOutputRatioHeight;
Matrix outputMatrix = new Matrix();
outputMatrix.setValues(values);
Draw the output bitmap as you were doing with the correct size (outputWidth, outputHeight) and matrix (outputMatrix).
Bitmap newBitmap = Bitmap.createBitmap(Math.round(outputWidth), Math.round(outputHeight), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(src, outputMatrix, paint);
.
Warnings
You should be careful about memory allocation, this code will lead to allocate some massive bitmaps, you should implement some kind of limit that get along with your needs. (Also do allocation and drawing in background)
You might need to do some adjustment depending on where you place the image in the first place.

Making Bitmap aspect ratio to centerFit Android

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

Android - Cut bitmap starting from some point

I've been searching here about cut bitmaps in android, however I could not make it work for me.
I would like to cut off some part of one specific bitmap, but I want to do that starting from center to the bottom of my image.
I already tried to use:
createBitmap(android.graphics.Bitmap source, int x, int y, int width, int height)
However, it always start to cut my image from the TOP, even changing x and y values.
I want to cut my bitmap as below blue square.
Someone have any idea about how to cut my bitmap?
You should take a look at this:
private Bitmap cropBitmap1()
{
Bitmap bmp2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.image1);
Bitmap bmOverlay = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
Paint p = new Paint();
p.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
Canvas c = new Canvas(bmOverlay);
c.drawBitmap(bmp2, 0, 0, null);
c.drawRect(30, 30, 100, 100, p);
return bmOverlay;
}
Link: Source
Try this:
Bitmap source = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
int width = source.getWidth();
int height = source.getHeight();
int required = 25;// 25 pixels width and height
int startX = (width - required) / 2;
int startY = (height - required) / 2;
Bitmap resized = Bitmap.createBitmap(source, startX, startY, required,
required);
The only relevant part is the startX and startY calculations. The code asumes that you need a 25*25 pixels image.

How to crop Bitmap Center like imageview? [duplicate]

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;
}

Resizing bitmaps

I'm writing a Music application and I have already gotten the album arts. However, they came up in various sizes. So, how do I standardized the size of the returned bitmap ?
You'd do something like this:
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.android);
int width = bitmapOrg.width();
int height = bitmapOrg.height();
int newWidth = 200;
int newHeight = 200;
// 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);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true);
Or you could scale the bitmap to the required size when you draw it on the canvas:
From the android documentation:
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle.
Make src null and dst is a Rect the size/position you want it on the canvas, set up like
Rect rect = new Rect(0, 0, width, height)
canvas.drawBitmap(bitmap, null, rect)
In my experience the code in the accepted answer does not work, at least on some platforms.
Bitmap.createBitmap(bitmapOrg, 0, 0, width, height, matrix, true);
will give you a downsampled image at the full size of the original - so just a blurry image.
Interestingly enough, the code
Bitmap resizedBitmap = Bitmap.createScaledBitmap(square, (int) targetWidth, (int) targetHeight, false);
also gives the blurry image. In my case it was necessary to do this:
// RESIZE THE BIT MAP
// According to a variety of resources, this function should give us pixels from the dp of the screen
// From http://stackoverflow.com/questions/4605527/converting-pixels-to-dp-in-android
float targetHeight = DWUtilities.convertDpToPixel(80, getActivity());
float targetWidth = DWUtilities.convertDpToPixel(80, getActivity());
// However, the above pixel dimension are still too small to show in my 80dp image view
// On the Nexus 4, a factor of 4 seems to get us up to the right size
// No idea why.
targetHeight *= 4;
targetWidth *= 4;
matrix.postScale( (float) targetHeight / square.getWidth(), (float) targetWidth / square.getHeight());
Bitmap resizedBitmap = Bitmap.createBitmap(square, 0, 0, square.getWidth(), square.getHeight(), matrix, false);
// By the way, the below code also gives a full size, but blurry image
// Bitmap resizedBitmap = Bitmap.createScaledBitmap(square, (int) targetWidth, (int) targetHeight, false
I don't have a further solution on this yet, but hopefully this is helpful to someone.

Categories

Resources