android - 如何放大/缩放图像的一部分

标签 android android-canvas

我正在制作一个应用程序,用户可以在其中单击图像的一部分并在 WebView 的一角获得放大版本。我设法制作了一个可以制作缩放版本的 Paint,但它显示了错误的位置,就像有一些偏移一样。

我知道这个问题已被问过很多次并且已经得到回答,但似乎这些解决方案都没有帮助。

这是我使用的代码:

  @Override
        public boolean onTouchEvent(@NonNull MotionEvent event) {
            zoomPos = new PointF();
            zoomPos.x = event.getX();
            zoomPos.y = event.getY();


        matrix = new Matrix();
        mShader = new BitmapShader(MainActivity.mutableBitmap, TileMode.CLAMP, TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setShader(mShader);
        outlinePaint = new Paint(Color.BLACK);
        outlinePaint.setStyle(Paint.Style.STROKE);

        int action = event.getAction(); 

        switch (action) { 
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            zooming = true;
            this.invalidate();
            break; 
        case MotionEvent.ACTION_UP: 
            Point1 = true;
            zooming = false;
            this.invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            zooming = false;
            this.invalidate();
            break; 

        default: 
            break; 
        }



     return true;
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);
        if (zooming) {
            matrix.reset();
            matrix.postScale(2f, 2f, zoomPos.x, zoomPos.y);
            mPaint.getShader().setLocalMatrix(matrix);


            canvas.drawCircle(100, 100, 100, mPaint);

        }

    }

从技术上讲,它应该在左上角画一个圆圈并显示我手指所在区域的缩放图像,它画了一个圆圈,但同样,缩放比例发生了偏移。

最终结果应该是这样的:

enter image description here

主 Activity .java

public class MainActivity extends Activity {
static ImageView takenPhoto;
static PointF zoomPos;
Paint shaderPaint;
static BitmapShader mShader;
BitmapShader shader;
Bitmap bmp;
static Bitmap mutableBitmap;
static Matrix matrix;
Canvas canvas;
static Paint mPaint;
static Paint Paint;
static boolean zooming;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File file = new File(Environment.getExternalStorageDirectory() + "/Pictures/boxes.jpg");

        String fileString = file.getPath();
        takenPhoto = (ZoomView) findViewById(R.id.imageView1);
        bmp = BitmapFactory.decodeFile(fileString);
        mutableBitmap = bmp.copy(Bitmap.Config.ARGB_8888, true);
        takenPhoto.setImageBitmap(mutableBitmap);    
        matrix = new Matrix();
        mShader = new BitmapShader(mutableBitmap, TileMode.CLAMP, TileMode.CLAMP); 
        mPaint = new Paint();
        mPaint.setShader(mShader);
        zoomPos = new PointF();
        Paint = new Paint(Color.RED);  
    }
}

缩放 View .java

public class ZoomView extends ImageView {

    private PointF zoomPos;
    PointF fingerPos;
    private Paint paint = new Paint(Color.BLACK);
    boolean zooming;
    Matrix matrix;
    BitmapShader mShader;
    Paint mPaint;
    Paint outlinePaint;
    boolean Point1;

    public ZoomView(Context context) {
        super(context);
    }

    public ZoomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ZoomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        zoomPos = new PointF();
        zoomPos.x = event.getX();
        zoomPos.y = event.getY();


        matrix = new Matrix();
        mShader = new BitmapShader(MainActivity.mutableBitmap, TileMode.CLAMP, TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setShader(mShader);
        outlinePaint = new Paint(Color.BLACK);
        outlinePaint.setStyle(Paint.Style.STROKE);

        int action = event.getAction(); 

        switch (action) { 
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            zooming = true;
            this.invalidate();
            break; 
        case MotionEvent.ACTION_UP: 
            Point1 = true;
            zooming = false;
            this.invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            zooming = false;
            this.invalidate();
            break; 

        default: 
            break; 
        }



     return true;
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);
        if (zooming) {
            matrix.reset();
        matrix.postScale(2f, 2f, zoomPos.x, zoomPos.y);
        mPaint.getShader().setLocalMatrix(matrix);
        RectF src = new RectF(zoomPos.x-50, zoomPos.y-50, zoomPos.x+50, zoomPos.y+50);
        RectF dst = new RectF(0, 0, 100, 100);
        matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
        matrix.postScale(2f, 2f);
        mPaint.getShader().setLocalMatrix(matrix);


        canvas.drawCircle(100, 100, 100, mPaint);
        canvas.drawCircle(zoomPos.x, zoomPos.y, 100, mPaint);
        canvas.drawCircle(zoomPos.x-110, zoomPos.y-110, 10, outlinePaint);

        }
        if(Point1){
            canvas.drawCircle(zoomPos.x, zoomPos.y, 10, paint);
        }
    }
}

编辑:

如您所见,新代码要好得多,但仍然存在一些偏移量 - 黑点 - 手指的位置。

enter image description here

最佳答案

问题似乎出在您如何使用矩阵

现在您正在使用原始图像 (1) 作为着色器,然后围绕轴心点 (2) post 放大>,这就像围绕点 (3) 进行缩放 - 但不是以点 (4) 为中心! (例如,打开谷歌地图并用鼠标放大 map - 点围绕枢轴缩放但枢轴未居中)

enter image description here

通过使用 RectRect method 可以更轻松地实现您想要的效果. IE。您想要从原始图像(5) 中取出一小块区域并将其绘制到更大的区域(6)

enter image description here

这是一个代码示例:

RectF src = new RectF(zoomPos.x-50, zoomPos.y-50, zoomPos.x+50, zoomPos.y+50);
RectF dst = new RectF(0, 0, 200, 200);
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);

补充几点:

  • 尽量不要在 onTouch 中创建 new 对象 - 它被调用了很多次并且对性能 不利。相反,创建一次并重复使用。
  • getAction() 当屏幕上有多个手指时会出现问题,因为它是操作 ID 和指针 ID。而是使用 getActionMasked()getActionIndex() .
  • 不要使用硬编码值(示例代码中的 50/100)- 这些是像素,不知道屏幕密度。使用像 dp 这样的缩放尺寸。

关于android - 如何放大/缩放图像的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32055525/

相关文章:

android - 更改包名称后出现错误

android - 发布时,显示支持 70 多种语言,但我的应用只有两种

android - 如何在 Canvas 上的两点之间绘制弧线?

c# - 在 C# 中将文件写入 Android

android - opengl android中的纹理坐标显示图像反转

android - 将两条弧闭合在一起

android - SurfaceView 如何处理屏幕外元素?

java - Android - 在 ImageView 上绘制图片

java - React native - 如何修复 Java.lang Double 无法转换为 java.lang.Boolean

安卓编程 : How to draw multiline text in a rectangle?