Android 图像视图矩阵比例 +翻译

发布于 2024-11-08 21:29:26 字数 1093 浏览 0 评论 0原文

我正在尝试手动获取以图像视图为中心并适合屏幕的图像。我需要用矩阵来完成(稍后我将动态更改矩阵变换)。

问题是我无法使图像在视图中居中(比例合适)。这是代码:

// Compute the scale to choose (this works)
float scaleX = (float) displayWidth / (float) imageWidth;
float scaleY = (float) displayHeight / (float) imageHeight;
float minScale = Math.min(scaleX, scaleY);

// tx, ty should be the translation to take the image back to the screen center
float tx = Math.max(0, 
        0.5f * ((float) displayWidth - (minScale * imageWidth)));
float ty = Math.max(0, 
        0.5f * ((float) displayHeight - (minScale * imageHeight)));

// Compute the matrix
Matrix m = new Matrix();
m.reset();

// Middle of the image should be the scale pivot
m.postScale(minScale, imageWidth/2, imageHeight/2);

// Translate
m.postTranslate(tx, ty);

imageView.setImageMatrix(m);

如果我不将比例尺放在图像中心的中心,上面的代码就可以工作(但我稍后需要这样做,所以我现在需要弄清楚公式)。

我认为执行以下操作可以解决问题,但图像仍然偏移(朝底部和右侧)。

tx += 0.5*imageWidth*minScale;
ty += 0.5*imageHeight*minScale;

我有一些价值观: - 图片:200x133 - 显示:800x480 - 最小规模:2.4 - 图像的最终左上角:100, 67(应为 17, 0)

I am trying to manually get an image inside an imageview centered and fitting the screen. I need to do it with a matrix (I will later dynamically change the matrix transformation).

Problem is I can't get the image centered in the view (scale is appropriate). Here is the code:

// Compute the scale to choose (this works)
float scaleX = (float) displayWidth / (float) imageWidth;
float scaleY = (float) displayHeight / (float) imageHeight;
float minScale = Math.min(scaleX, scaleY);

// tx, ty should be the translation to take the image back to the screen center
float tx = Math.max(0, 
        0.5f * ((float) displayWidth - (minScale * imageWidth)));
float ty = Math.max(0, 
        0.5f * ((float) displayHeight - (minScale * imageHeight)));

// Compute the matrix
Matrix m = new Matrix();
m.reset();

// Middle of the image should be the scale pivot
m.postScale(minScale, imageWidth/2, imageHeight/2);

// Translate
m.postTranslate(tx, ty);

imageView.setImageMatrix(m);

The above code works if I don't center the scale on the image center (but I will need to do it later so I need to figure out the formula now).

I thought doing the following would correct the issue, but the image is still offset (towards bottom and right).

tx += 0.5*imageWidth*minScale;
ty += 0.5*imageHeight*minScale;

Some values I have:
- image: 200x133
- display: 800x480
- minScale: 2.4
- final top-left corner of the image: 100, 67 (should be 17, 0)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

澜川若宁 2024-11-15 21:29:26

有一个名为 Matrix.setRectToRect(RectF, RectF, ScaleToFit) 在这里为您提供帮助。

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

这应该将矩阵 m 设置为具有缩放和平移值的组合,这些值是显示可绘制对象居中并适合 ImageView 小部件所需的。

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.

人疚 2024-11-15 21:29:26

以下是我如何使用矩阵解决我的问题(由 joakime 在另一个答案中请求):

private void setImageTransformation(float tx, float ty, float scale) {
    savedMatrix.reset();
    savedMatrix.postTranslate(-imageWidth / 2f, -imageHeight / 2f);
    savedMatrix.postScale(scale, scale);
    savedMatrix.postTranslate(tx, ty);
    imageView.setImageMatrix(savedMatrix);
}

public void resetImageMatrix() {
    if (!isImageLoaded()) return;

    imageWidth = imageView.getDrawable().getIntrinsicWidth();
    imageHeight = imageView.getDrawable().getIntrinsicHeight();

    float scaleX = (float) displayWidth / (float) imageWidth;
    float scaleY = (float) displayHeight / (float) imageHeight;
    minScale = Math.min(scaleX, scaleY);
    maxScale = 2.5f * minScale;

    initialTranslation.set(
              Math.max(0, 
                minScale * imageWidth / 2f 
                + 0.5f * (displayWidth - (minScale * imageWidth))), 
              Math.max(0, 
                minScale * imageHeight / 2f
                + 0.5f * (displayHeight - (minScale * imageHeight))));

    currentScale = minScale;
    currentTranslation.set(initialTranslation);
    initialImageRect.set(0, 0, imageWidth, imageHeight);

    setImageTransformation(initialTranslation.x, initialTranslation.y, 
                minScale);
}

我在这里有点作弊,因为捏合并不是真正在用户手指之间居中,这在我的情况下是可以接受的。

Here is how I solved my problem using matrices (requested by joakime in the other answer):

private void setImageTransformation(float tx, float ty, float scale) {
    savedMatrix.reset();
    savedMatrix.postTranslate(-imageWidth / 2f, -imageHeight / 2f);
    savedMatrix.postScale(scale, scale);
    savedMatrix.postTranslate(tx, ty);
    imageView.setImageMatrix(savedMatrix);
}

public void resetImageMatrix() {
    if (!isImageLoaded()) return;

    imageWidth = imageView.getDrawable().getIntrinsicWidth();
    imageHeight = imageView.getDrawable().getIntrinsicHeight();

    float scaleX = (float) displayWidth / (float) imageWidth;
    float scaleY = (float) displayHeight / (float) imageHeight;
    minScale = Math.min(scaleX, scaleY);
    maxScale = 2.5f * minScale;

    initialTranslation.set(
              Math.max(0, 
                minScale * imageWidth / 2f 
                + 0.5f * (displayWidth - (minScale * imageWidth))), 
              Math.max(0, 
                minScale * imageHeight / 2f
                + 0.5f * (displayHeight - (minScale * imageHeight))));

    currentScale = minScale;
    currentTranslation.set(initialTranslation);
    initialImageRect.set(0, 0, imageWidth, imageHeight);

    setImageTransformation(initialTranslation.x, initialTranslation.y, 
                minScale);
}

I am cheating here a bit because the pinch is not really centered between the user fingers, which is acceptable in my case.

安人多梦 2024-11-15 21:29:26

或者使用

    m.postScale(minScale, minScale); //keep aspect ratio

    float tx = (getWidth() - bitmap1.getWidth()* scale) * 0.5f ;
    float ty = (getHeight() - bitmap1.getHeight()* scale) * 0.5f ;

    matrix.postTranslate(tx, ty );

getWidth 是 imageView 的宽度。
非常适合我

Or using

    m.postScale(minScale, minScale); //keep aspect ratio

    float tx = (getWidth() - bitmap1.getWidth()* scale) * 0.5f ;
    float ty = (getHeight() - bitmap1.getHeight()* scale) * 0.5f ;

    matrix.postTranslate(tx, ty );

where getWidth is the width of your imageView.
Works perfectly for me

当梦初醒 2024-11-15 21:29:26

嘿,我也遇到了同样的问题,而且你太接近了!这是一个操作顺序问题,至少对我来说是这样。以下对我有用:

tx = (width - imgWidth) * 0.5f * scale;

Hey I was having the same issue, and you were oh so close! It was an order of operations issue, at least for me. The following worked for me:

tx = (width - imgWidth) * 0.5f * scale;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文