2013-02-03 90 views
0

我正在尝试编写一个Android应用程序,让我可以在图像上绘制图形,然后缩放图像并使图像保留在图像上的同一位置在实时更改图形的同时已经绘制在其上。在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  
    } 
} 
+0

什么是矩阵?它在哪里定义?请显示更多代码。 – andr

+0

感谢您的回复,我已更新完整的功能定义。矩阵是drawBitmap函数需要的空矩阵。我曾尝试将转换应用于此矩阵而不是画布,并且它似乎也执行相同的操作。 – FearTheCron

+0

我还应该补充说,pendingUpdate.center的值根本没有被修改,pendingUpdate.zoom被调整的范围为1到10. – FearTheCron

回答

1

如果我是你,我会使用Canvas.scale(float sx, float sy, float px, float py)方法,它正是你想要的。

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

  1. 总是(我的意思是总是)调用Canvas.save()Canvas.restore()对你在Canvas得到,如果你打算改变它的初始矩阵。这是因为您可以使用的Canvas可以是例如整个窗口的剪裁设置为当前正在绘制的控件的边界。

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

按照这两个建议看看整个View我刚才提出了,通过的3因子与点(16,16)设定为支点(不变点 - 缩放中心)缩放bitmap。测试 - 工作。

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(); 
    } 
} 
+0

谢谢你提供的信息,我大大减少了我的代码,并相信我拥有它现在工作。我不知道我明白了canvas.save()和restore()在做什么。这是独立的锁定和解锁和张贴? – FearTheCron

+0

''保存'和'恢复'推动和弹出当前矩阵的画布到堆栈上,类似于你在OpenGL中。事情是,除非你确定没有任何东西会画在画布上,否则需要将矩阵恢复到开始绘制时的状态。这是因为您正在绘制的画布很可能由当前窗口中的所有视图共享。你可以通过简单地调用'canvas.setMatrix(null);'来加载一个单位矩阵并且看到(奇怪的)结果来测试它:> – andr

+0

这很有道理。下一个问题,你如何将它设置为以给定点为中心并放大它。如果我将枢轴点设置为图像的中心,那么它将在那里枢轴转动,但画布仍然位于同一个点上,因此如果我尝试翻译它,它就会飞过,然后在放大时似乎会做出奇怪的事情。 – FearTheCron