Как увеличить / увеличить часть изображения

Я делаю приложение, в котором пользователь сможет нажать на часть изображения и получить увеличенную версию в углу 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);

        }

    }

Технически он должен нарисовать круг в верхнем левом углу и показать увеличенное изображение области, где находится мой палец, он рисует круг, но опять же, масштабирование смещено.

Конечный результат должен выглядеть примерно так:

MainActivity.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);  
    }
}

ZoomView.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);
        }
    }
}

РЕДАКТИРОВАТЬ:

Как вы можете видеть, новый код намного лучше, но все же есть некоторое смещение - черная точка - положение пальца.

1 ответ

Кажется, проблема в том, как вы используете matrix,

Теперь вы используете исходное изображение (1) в качестве шейдера, который затем масштабируется вокруг точки поворота (2), что похоже на масштабирование вокруг точки (3), но не центрирование точки (4)! (Например, откройте карты Google и увеличьте масштаб карты с помощью мыши - точка увеличивается вокруг оси, но точка не центрирована)

То, что будет проще для достижения того, что вы хотите, это с помощью метода Rect to Rect. То есть вы хотите взять небольшую область из исходного изображения (5) и нарисовать ее в большую область (6).

А вот пример кода:

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

Еще несколько моментов:

  • Попробуй не создавать new объект в onTouch - он вызывается много раз, и это плохо сказывается на производительности. Вместо этого создайте один раз и используйте повторно.
  • getAction() будут проблемы, когда на экране более одного пальца, так как это идентификатор действия и идентификатор указателя. Вместо этого используйте getActionMasked() и getActionIndex ().
  • Не используйте жестко закодированные значения (50/100 в примере кода) - это пиксели и они не знают о плотности экрана. Используйте масштабированный размер как dp,
Другие вопросы по тегам