设置Android画布中显示图像的缩放比例

时间:2013-02-03 22:45:19

标签: android graphics transformation

我正在尝试编写一个Android应用程序,让我在图像上绘制图形,然后缩放和缩放图像,图形保留在图像上的同一位置,同时更改图形实时。

然而,我一直有很多问题让它在保持图像中心的同时放大。我编写了代码,我有一个更新图像的线程。使用我通过ArrayBlockingQueue创建的名为“PendingUpdate”的类传递更新。此更新包含所需的缩放级别,该缩放级别应该是图像像素与画布像素和图像中心的比率。但是,下面的代码使我在缩放时平移,这让我很困惑。

//Scale the image
canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom());

//Translate the image
double updateCx = pendingUpdate.getCenter().getX();
double updateCy = pendingUpdate.getCenter().getY();
double halfCanvasWidthInImagePixels = pendingUpdate.getZoom()*(canvas.getWidth()/2);
double halfCanvasHeightInImagePixels = pendingUpdate.getZoom()*(canvas.getHeight()/2);
double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
canvas.translate(-(float)imageTranslateX, -(float)imageTranslateY);
canvas.drawBitmap(pendingUpdate.getImage(), matrix, new Paint());

感谢您的帮助!

编辑:这是完整的功能,如果这有帮助,我也可以发布PendingUpdate,但它只是一个数据类。

    private void doDraw(Canvas canvas, PendingUpdate pendingUpdate) {
        int iWidth = pendingUpdate.getImage().getWidth();
        int iHeight = pendingUpdate.getImage().getHeight();
        Matrix matrix = new Matrix();

        canvas.drawColor(Color.BLACK);
        //TODO: add scrolling functionality to this
        if(pendingUpdate.getZoom()>0) {

            //Scale the image
            canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom());

            //Translate the image
            double updateCx = pendingUpdate.getCenter().getX();
            double updateCy = pendingUpdate.getCenter().getY();
            double halfCanvasWidthInImagePixels = pendingUpdate.getZoom()*(canvas.getWidth()/2);
            double halfCanvasHeightInImagePixels = pendingUpdate.getZoom()*(canvas.getHeight()/2);
            double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
            double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
            canvas.translate(-(float)imageTranslateX, -(float)imageTranslateY);
            canvas.drawBitmap(pendingUpdate.getImage(), matrix, new Paint());

        }else {
            //matrix.postTranslate(canvas.getWidth()-iWidth/2, canvas.getWidth()-iHeight/2);
            canvas.drawBitmap(pendingUpdate.getImage(),
                    (canvas.getWidth()-iWidth)/2,
                    (canvas.getHeight()-iHeight)/2, null);
        }
        //TODO: draw other stuff on canvas here such as current location

    }

编辑2:这就是我最终让它发挥作用的方式,只是在翻译之前对其进行缩放。

    private void doDraw(Canvas canvas, PendingUpdate pendingUpdate) {
        int iWidth = pendingUpdate.getImage().getWidth();
        int iHeight = pendingUpdate.getImage().getHeight();

        canvas.drawColor(Color.BLACK);
        //TODO: add scrolling functionality to this
        if(pendingUpdate.getZoom()>0) {

            //Scale the image
            canvas.save();
            double updateCx = pendingUpdate.getCenter().getX();
            double updateCy = pendingUpdate.getCenter().getY();
            double halfCanvasWidthInImagePixels = (canvas.getWidth()/2);
            double halfCanvasHeightInImagePixels = (canvas.getHeight()/2);
            double imageTranslateX = updateCx - halfCanvasWidthInImagePixels;
            double imageTranslateY = updateCy - halfCanvasHeightInImagePixels;
            //canvas.scale(pendingUpdate.getZoom(), pendingUpdate.getZoom(), (float)pendingUpdate.getCenter().getX(), (float)pendingUpdate.getCenter().getY());

            canvas.scale(pendingUpdate.getZoom(),
                    pendingUpdate.getZoom(),
                    canvas.getWidth()/2,
                    canvas.getHeight()/2);

            canvas.translate(-(float)imageTranslateX,
                    -(float)imageTranslateY);
            canvas.drawBitmap(pendingUpdate.getImage(), 0, 0, null);

            canvas.restore();
        }else {
            //TODO: update this so it displays image scaled to screen and updates current zoom somehow
            canvas.drawBitmap(pendingUpdate.getImage(),
                    (canvas.getWidth()-iWidth)/2,
                    (canvas.getHeight()-iHeight)/2, null);
        }
        //TODO: draw other stuff on canvas here such as current location    
    }
}

1 个答案:

答案 0 :(得分:1)

如果我是你,我会使用Canvas.scale(float sx, float sy, float px, float py)方法,它完全符合您的要求。

但是看看你的代码我认为你可能会一次搞乱太多的转换,这很难调试。

  1. 总是(我的意思是总是)如果你打算在Canvas.save()获得的初始矩阵上调用Canvas.restore()Canvas改变它。这是因为您可以使用的Canvas可能是画布,例如:整个窗口只剪切设置为当前绘制自身的控件的边界。

  2. 使用Canvas方法提供的矩阵变换方法,并使用最简单的调用绘制位图。

  3. 根据这两个建议,查看我刚刚编写的整个View,将bitmap缩放3,将点(16,16)设置为枢轴(未更改的点 - 缩放中心)。经过测试 - 工作。

    public class DrawingView extends View {
        Bitmap bitmap;
    
        public DrawingView(Context context) {
            super(context);
            bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            float sx = 3;
            float sy = 3;
            float px = 16;
            float py = 16;
            canvas.save();
            canvas.scale(sx, sy, px, py);
            canvas.drawBitmap(bitmap, 0, 0, null);
            canvas.restore();
        }
    }