How to draw a bitmap different, but in a given quad (do not need a rectangle)?

Suppose I have 2 bitmaps. One of them is smallBitmap and the other is a big bit.

I want to draw the entire smallBitmap in a largeBitmap, but only for part of a large bit, but not in a straight regtangle, but in a quad .

I think the sketch best describes what I mean:

enter image description here

An example of this scenario is a tilted image of a smartphone (for example, this or this ), that you need to place a screenshot on the screen.

Input: smallBitmap, largeBitmap, the "quadrangular" coordinates of the large bitmap (where to place the smallBitmap).

The "quadrangle" of a large bitmap has only 4 coordinates and does not need a rectangle. For example, it can be a parallelogram or a trapezoid.

I need to scale the smallBitmap into a quadrangle inside the largeBitmap, and also support the scaling of the center so that it doesn't distort

I also need to know how to process texts the same way, but I am thinking about this solution.


Here's something I tried, but it doesn't even scale:

//mBigBitmap: size is 720x1280 //mSmallBitmap: size is 720x720 mLeftTop = new Point(370, 358); mRightTop = new Point(650, 384); mLeftBot = new Point(375, 972); mRightBot = new Point(660, 942); Canvas canvas = new Canvas(mBigBitmap); final Matrix matrix = new Matrix(); matrix.setPolyToPoly(new float[]{0, 0, mBigBitmap.getWidth() - 1, 0, 0, mBigBitmap.getHeight() - 1, mBigBitmap.getWidth() - 1, mBigBitmap.getHeight() - 1}, 0, new float[]{mLeftTop.x, mLeftTop.y, mRightTop.x, mRightTop.y, mLeftBot.x, mLeftBot.y, mRightBot.x, mRightBot.y } , 0, 4); canvas.drawBitmap(mSmallBitmap, matrix, new Paint()); 
+1
android bitmap android-canvas tilt
source share
3 answers

An answer was found based on this post .

It seems that the Matrix cannot be used because it cannot create Trapezoid shapes that can occur in the 3D world.

So, it is suggested to use the Camera class:

  Canvas canvas = new Canvas(bigBitmap); Matrix matrix = new Matrix(); Camera camera = new Camera(); camera.save(); camera.translate(...,...,0); camera.rotateX(...); camera.rotateY(...); camera.rotateZ(...); camera.getMatrix(matrix); int centerX = bigBitmap.getWidth() / 2; int centerY = bigBitmap.getHeight() / 2; matrix.preTranslate(-centerX, -centerY); //This is the key to getting the correct viewing perspective matrix.postTranslate(centerX, centerY); canvas.concat(matrix); camera.restore(); canvas.drawBitmap(mSmallBitmap, matrix, new Paint()); 

Unfortunately, as you can see, the coordinates are not used, so you need to either play with the numbers until it works out, or find a formula for converting between the coordinates and the necessary values.

I will not mark this answer as correct, because it does not fully meet the requirements of the original question (no coordinates are used).

Plus, I can’t find how to work with text when using this solution.

However, it works, so it can be useful to others.


EDIT: It seems that the reason setPolyToPoly doesn't scale the image at all is because the first input array was wrong: it was set as the size of a large bitmap, not a small one.

So this is the correct code:

 mLeftTop = new Point(370, 358); mRightTop = new Point(650, 384); mLeftBot = new Point(375, 972); mRightBot = new Point(660, 942); Canvas canvas = new Canvas(mBigBitmap); final Matrix matrix = new Matrix(); matrix.setPolyToPoly(new float[]{0, 0, mSmallBitmap.getWidth() - 1, 0, 0, mSmallBitmap.getHeight() - 1, mSmallBitmap.getWidth() - 1, mSmallBitmap.getHeight() - 1}, 0, new float[]{mLeftTop.x, mLeftTop.y, mRightTop.x, mRightTop.y, mLeftBot.x, mLeftBot.y, mRightBot.x, mRightBot.y } , 0, 4); canvas.concat(matrix); final Paint paint = new Paint(); paint.setAntiAlias(true); canvas.drawBitmap(mSmallBitmap, 0, 0, paint); 

However, there is still this problem for center cropping, but if you know the correct size of the rectangle before it is tilted, you can crop it earlier and set it as input.

As for the text, this is possible, as usual, since the canvas remains with the created matrix.

+1
source share

to skew the bitmap, perhaps the Matrix may be convenient.

  /*use values accordingly*/ Matrix matrix = new Matrix(); matrix.postScale(curScale, curScale); matrix.postRotate(curRotate); matrix.postSkew(curSkewX, curSkewY); Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bmpWidth, bmpHeight, matrix, true); myImageView.setImageBitmap(resizedBitmap); 
0
source share

For my answer, I draw a smaller Bitmap on a larger Bitmap , and then draw it on a SurfaceView .

  • Use the bounding box to create a bounding box.
  • Use the bounding box to create a Matrix transform
  • Use Matrix.ScaleToFit.CENTER to fill the bounding box to the maximum size possible for a smaller Bitmap .

After completing these steps, simply draw on the canvas the larger Bitmap . The bounding box is drawn in red, the bounding box is blue, and the large Bitmap drawn in green. Replace the smaller Bitmap blue Bitmap (bounding box).

 public class MainActivity extends Activity { final String TAG = this.getClass().getName(); SurfaceView surfaceView; Bitmap bitmap; Bitmap bigBitmap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(R.id.surfaceView); surfaceView.getHolder().addCallback(new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { } @Override public void surfaceCreated(SurfaceHolder holder) { Canvas surfaceCanvas = holder.lockCanvas(); surfaceCanvas.drawBitmap(bigBitmap, 0, 0, new Paint()); holder.unlockCanvasAndPost(surfaceCanvas); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }); bitmap = Bitmap.createBitmap(64, 192, Bitmap.Config.ARGB_8888); { Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setColor(Color.RED); canvas.drawRect(0, 0, 64, 192, paint); } bigBitmap = Bitmap.createBitmap(768,768, Bitmap.Config.ARGB_8888); { Canvas canvas = new Canvas(bigBitmap); // Fill background - For visual reference Paint paint = new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(0, 0, bigBitmap.getWidth(), bigBitmap.getHeight(), paint); // Setup transformation Matrix matrixPoly = new Matrix(); Log.i(TAG, "matrixPoly: " + matrixPoly); // Draw Quadrilateral - For visual reference boolean canScale; canScale = matrixPoly.setPolyToPoly(new float[]{0,0, 64,0, 0,192, 64,192}, 0, new float[]{32,32, 96,16, 16,300, 128,256}, 0, 4); Log.i(TAG, "matrixPoly: " + matrixPoly); Log.i(TAG, "matrixPoly canScale: " + canScale); canvas.drawBitmap(bitmap, matrixPoly, new Paint()); // Points of Quadrilateral // {32,32, 96,16, 16,300, 128,256} float rectInQLeft = Math.max(32, 16); float rectInQTop = Math.min(32, 16); float rectInQRight = Math.min(96, 128); float rectInQBottom = Math.max(300, 256); ; Matrix matrixRect = new Matrix(); Log.i(TAG, "matrixRect: " + matrixRect); canScale = matrixRect.setRectToRect(new RectF(0, 0, 64, 192), new RectF(rectInQLeft, rectInQTop, rectInQRight, rectInQBottom), Matrix.ScaleToFit.CENTER); Log.i(TAG, "matrixRect: " + matrixRect); Log.i(TAG, "matrixRect canScale: " + canScale); // Draw scaled bitmap Canvas smallBitmapCanvas = new Canvas(bitmap); Paint smallBitmapPaint = new Paint(); smallBitmapPaint.setColor(Color.BLUE); smallBitmapCanvas.drawRect(0, 0, 64, 192, smallBitmapPaint); canvas.drawBitmap(bitmap, matrixRect, new Paint()); } } 
0
source share

All Articles