Android Image View Matrix Scale + Translate

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



Leave a reply



Submit