Android image view matrix scale + translate
There's a convenient method called Matrix.setRectToRect(RectF, RectF, ScaleToFit) to help you here.
Matrix m = imageView.getImageMatrix();
RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
RectF viewRect = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);
imageView.setImageMatrix(m);
That should set the matrix m
to have combo of scaling and translate values that is needed to show the drawable centered and fit within the ImageView widget.
Android ImageView scale image and center
All you have to do is to find new x and y coordinates where to place the image and then translate the matrix, so the image moves to the center of the ImageView. Your entire scaleImage method can look something like this:
private void scaleImage(float scaleFactor, float focusX, float focusY) {
Matrix displayMatrix = new Matrix();
Matrix matrix = imageView.getImageMatrix();
float x = (imageView.getWidth() - imageView.getDrawable().getIntrinsicWidth() * scaleFactor) / 2;
float y = (imageView.getHeight() - imageView.getDrawable().getIntrinsicHeight() * scaleFactor) / 2;
matrix.postScale(scaleFactor, scaleFactor);
matrix.postTranslate(x, y);
displayMatrix.set(matrix);
imageView.setImageMatrix(displayMatrix);
}
How to center imageView with matrix scaletype?
Picasso.with(this).load(url).into(imageView, new Callback.EmptyCallback() {
@Override
public void onSuccess() {
Drawable d = imageView.getDrawable();
// TODO: check that d isn't null
RectF imageRectF = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
RectF viewRectF = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
matrix.setRectToRect(imageRectF, viewRectF, ScaleToFit.CENTER);
imageView.setImageMatrix(matrix);
}
});
Edit 2:
How to center the image like CENTER_INSIDE
but using matrix:
First we need a rectangle with the image dimensions:
Drawable d = imageView.getDrawable();
// TODO: check that d isn't null
RectF imageRectF = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
Next you need a rectangle with the view dimensions:
RectF viewRectF = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
Now we run a method on matrix that will center the image in the view:
matrix.setRectToRect(imageRectF, viewRectF, ScaleToFit.CENTER);
What this does is set up the matrix so that the first rectangle will transform to the second rectangle. ScaleToFit.CENTER
will preserve the aspect ratio and have the same effect as scale type CENTER_INSIDE
.
So if you call
imageView.setImageMatrix(matrix);
at this point, you will have a centered image.
Edit: I think you are almost there.
Your matrix will undo the image centering that Picasso did, so you need to put in a translation to center the image before you scale it.
@Override
public boolean onScale(ScaleGestureDetector detector) {
Drawable d = imageView.getDrawable();
// if d is null, then Picasso hasn't loaded the image yet
float offsetX = (imageView.getWidth() - d.getIntrinsicWidth()) / 2F;
float offsetY = (imageView.getHeight() - d.getIntrinsicHeight()) / 2F;
float centerX = imageView.getWidth() / 2F;
float centerY = imageView.getHeight() / 2F;
// note that these offset and center values don't change with the scaling,
// so you can calculate them somewhere else and then use them here.
scale *= detector.getScaleFactor();
scale = Math.max(0.1f, Math.min(scale, 5f));
matrix.setScale(scale, scale, centerX, centerY);
matrix.preTranslate(offsetX, offsetY);
imageView.setImageMatrix(matrix);
}
You are using setScale(float sx, float sy)
. There is another version, setScale(float sx, float sy, float px, float py)
where px,py is a pivot point.
So if you want to center your image, determine the center of your view and use the x,y value as the pivot point.
You will also want to center the image inside the view, so you will need to move the image first before you scale.
float offsetX = (imageView.getWidth() - bitmap.getIntrinsicWidth()) / 2F;
float offsetY = (imageView.getHeight() - bitmap.getIntrinsicHeight()) / 2F;
float centerX = imageView.getWidth() / 2F;
float centerY = imageView.getHeight() / 2F;
matrix.setScale(scale, scale, centerX, centerY);
matrix.preTranslate(offsetX, offsetY);
Android image transformation with matrix, translate touch coordinates back
Ok, I get it.
First I separated the rotation from the translation and zooming of image.
Because I created a custom ImageView, this was simple. I apply the rotation to the canvas of the ImageView, and the other transformations to the matrix of the image.
I get trace of the canva's matrix throught a global matrix variable.
Some code:
To set the correct movement for the corresponding onTouch event, first I "rotate back" the points passed from onTouch (start and stop points) using the inverse of the matrix of the canvas
Then I calculate the difference between x and y, and apply that to the image matrix.
float[] movement = {start.x, start.y, stop.x, stop.y};
Matrix c_t = new Matrix();
canvas.invert(c_t);
c_t.mapPoints(movement);
float dx = movement[2] - movement[0];
float dy = movement[3] - movement[1];
image.postTranslate(dx, dy);
If instead you want to check that the image movement don't exceed its size, before the image.postTranslate(dx, dy); you put this code:
float[] new_center = {screen_center.x, screen_center.y};
Matrix copy = new Matrix();
copy.set(image);
copy.postTranslate(dx, dy);
Matrix translated = new Matrix();
copy.invert(translated);
translated.mapPoints(new_center);
if ((new_center[0] > 0) && (new_center[0] < bmp.getWidth()) &&
(new_center[1] > 0) && (new_center[1] < bmp.getHeight())) {
// you can remove the image.postTranslate and copy the "copy" matrix instead
image.set(copy);
...
It's important to note that:
A) The center rotation of the image is the center of the screen, so it will not change coordinates during the canvas' rotation
B) You can use the coordinates of the center of the screen to get the rotation center of the image.
With this method you can also convert every touch event to image coordinates.
Related Topics
Android Beginner Difference Between Padding and Margin
Android Exporting to CSV and Sending as Email Attachment
Android Listview Setselection() Does Not Seem to Work
Need to Disable Expand on Collapsingtoolbarlayout for Certain Fragments
Get Temperature of Battery on Android
Android Viewpager Setcurrentitem Not Working After Onresume
Android Drawerlayout - No Drawer View Found with Gravity
How to Get Documents in an Android Directory That Phonegap Will See
How to Show Dialog in Oncreate Method
How to Modify Ripple Color When Using Attr/Selectableitembackground as Background
Start Activity Using Custom Action
Video Streaming Using Rtsp: Android
Incorrect Coordinates from Getlocationonscreen/Getlocationinwindow
What Are the Differences Among Internal Storage, External Storage, Sd Card and Removable Storage
Volley Out of Memory Error, Weird Allocation Attempt
How to Get Screen Size of Device
What Is the "Ignoring Innerclasses Attribute" Warning Output During Compilation