0

我正在尝试编写一个 android 应用程序,它可以让我在图像上绘制图形,然后缩放和缩放图像,图形停留在图像上已绘制在其上的同一位置,同时实时更改图形.

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

//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    
    }
}
4

1 回答 1

1

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

但是,查看您的代码,我认为您可能一次搞砸了太多转换,这很难调试。

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

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

遵循这两个建议,看看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();
    }
}
于 2013-02-03T23:45:31.030 回答