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

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

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

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

Введите описание изображения здесь

Solutions Collecting From Web of "Как увеличить / увеличить часть изображения"

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

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

Введите описание изображения здесь

Каким будет более простой способ добиться того, чего вы хотите, с помощью метода Rect to Rect . IE вы хотите взять небольшую область из исходного изображения (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 .