I'm trying to use Canvas.drawBitmap(...) to draw Bitmaps onto a Canvas but it's not appearing in the correct position or size.
Below is an example on how I'm attempting to achieve this:
Canvas canvas = new Canvas();
Matrix matrix = new Matrix();
/// scale = 0.5
/// image.getX() = 250
/// image.getY() = 250
matrix.setTranslate(
imageView.getX() * scale,
imageView.getY() * scale
);
matrix.setScale(
scale,
scale
);
matrix.postRotate(imageView.getRotation(), imageView.getX() * scale, imageView.getY() * scale);
canvas.drawBitmap(bitmap, matrix, null);
The result that I'm getting is that the image is at the original size at 0x0 position.
The expected result is for the image to be half-size and in the center of the canvas.
NOTE: I'm using matrix.postRotate(...) to draw the bitmap rotated to the same angle as the ImageView.
Can you give this a shot, I have tried to explain the logic in the comments:
// as you wanted Half size so reduced width and height to half
Bitmap dstBitmap = Bitmap.createScaledBitmap(srcbitmap,(srcbitmap.getWidth()/2 ),(srcbitmap.getHeight()/2),true);
// Here I calculate screen size
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
//Create screen size bitmap to position image at center easily
Bitmap bitmap = Bitmap.createBitmap(
width,
height,
Bitmap.Config.ARGB_8888
);
// Initialize a new Canvas with above bitmap
Canvas canvas = new Canvas(bitmap);
Matrix matrix = new Matrix();
// Rotating about center of image
matrix.setRotate(
45, // your angle
dstBitmap.getWidth() / 2,
dstBitmap.getHeight() / 2
);
matrix.postTranslate(
(width - dstBitmap.getWidth()) / 2,
(height - dstBitmap.getHeight() )/ 2
);
canvas.drawBitmap(dstBitmap, matrix, null);
Now you should be good to proceed , this should give you correct output
Related
I want to place the watermark on the bottom right of the picture. But, in some mobiles it is coming perfectly and in some mobile phones, the watermark is coming on the whole image.
Here is my code:
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,
loadedImage.getWidth(), loadedImage.getHeight(),
rotateMatrix, false);
int w = rotatedBitmap.getWidth();
int h = rotatedBitmap.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, rotatedBitmap.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(rotatedBitmap, 0, 0, null);
Bitmap waterMark = BitmapFactory.decodeResource(getResources(), R.drawable.watermark2);
int ww = waterMark.getWidth();
int hh = waterMark.getHeight();
canvas.drawBitmap(waterMark,(w-ww),(h-hh), null);
EDIT: Here are the screenshots of the result. In second picture, the watermark is coming perfectly and in first picture, it is coming on the whole picture.
Make use of aspect ratio. Calculate aspect ratio of device and accordingly calculate appropriate size for your water mark.
How to calculate aspect ratio?
Check for width and height of screen whichever is bigger divide it by smaller one
example:
if(screen_width > screen_height){
aspectRatio = screen_width/screen_height
}else{
aspectRatio = screen_height/screen_width
}
now that you have calculated aspect ratio multiply it with size of you water mark and scale it accordingly.
like:
float ww = watermark.getWidth()*aspectRatio;
float wh = watermark.getHeight()*aspectRatio;
and use these values.
Hope this helps...
Just Give ratio and you go to go,try changing ratio values that best fit for your src bitmap .
Embeds an image watermark over a source image to produce a
watermarked one.
#param source The source image where watermark should be placed
#param ratio A float value < 1 to give the ratio of watermark's
height to image's height,
try changing this from 0.20 to 0.60 to obtain right results
public static Bitmap addWatermark(Context context, Bitmap source, float ratio)
{
Canvas canvas;
Paint paint;
Bitmap bmp;
Matrix matrix;
RectF r;
int width, height;
float scale;
Bitmap waterMark = BitmapFactory.decodeResource(context.getResources(), R.drawable.watermark3x);
width = source.getWidth();
height = source.getHeight();
// Create the new bitmap
bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
// Copy the original bitmap into the new one
canvas = new Canvas(bmp);
canvas.drawBitmap(source, 0, 0, paint);
// Scale the watermark to be approximately to the ratio given of the source image height
scale = (float) (((float) height * ratio) / (float) waterMark.getHeight());
// Create the matrix
matrix = new Matrix();
matrix.postScale(scale, scale);
// Determine the post-scaled size of the watermark
r = new RectF(0, 0, waterMark.getWidth(), waterMark.getHeight());
matrix.mapRect(r);
// Move the watermark to the bottom right corner
matrix.postTranslate(width - r.width(), height - r.height());
// Move the watermark to the bottom left corner
// matrix.postTranslate(0 , height - r.height());
// Move the watermark to the top-left corner
// matrix.postTranslate(0 ,0);
// Move the watermark to the top right corner
// matrix.postTranslate(width - r.width(), 0l̥);
// Draw the watermark
canvas.drawBitmap(waterMark, matrix, paint);
return bmp;
}
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.
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 two ImageView/Bitmap, one for visible background and it not movable one, Another one is movable bitmap on the background view. The movable bitmap have pinch zoom and rotate with matrix. Finally find movable co-ordinates/rect position and crop background bitmap using those rect position. My question is how to calculate/get rect position?.
For my sample, what i need for your view. Pleas post your idea here, it help to every one.
I spend more time to search and after few weeks for get this result.
private Bitmap getCroppedBmp(Bitmap childBmp, Bitmap ParentBmp) {
// viewBmp is movable bitmap, orgBitmap is Parent Bitmap
Bitmap viewBmp = childBmp;
Bitmap orgBitmap = ParentBmp;
float[] v = new float[9];
// get Matrix from View
cropImage.savedMatrix.getValues(v);
float left = v[Matrix.MTRANS_X];
float top = v[Matrix.MTRANS_Y];
// calculate the degree of rotation
float rAngle = Math.round(Math.atan2(v[Matrix.MSKEW_X],
v[Matrix.MSCALE_X]) * (180 / Math.PI));
// Rotate viewBmp
Matrix m = new Matrix();
m.postRotate(rAngle, viewBmp.getWidth() / 2, viewBmp.getHeight() / 2);
Bitmap bmap = Bitmap.createBitmap(viewBmp, 0, 0, viewBmp.getWidth(),
viewBmp.getHeight(), m, true);
// calculate real scale
float rScale = (float) Math
.sqrt((v[Matrix.MSCALE_X] * v[Matrix.MSCALE_X])
+ (v[Matrix.MSKEW_Y] * v[Matrix.MSKEW_Y]));
// Scale viewBmp
Matrix m1 = new Matrix();
m1.postScale(rScale, rScale, width / 2, height / 2);
Bitmap scaledBitmap = Bitmap.createBitmap(bmap, 0, 0, width, height,
m1, true);
// Finally Get cropped Bitmap
Bitmap resultingImage = Bitmap.createBitmap(orgBitmap, (int) left,
(int) top, scaledBitmap.getWidth(), scaledBitmap.getHeight());
return resultingImage;
}
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.