1

假设我有 2 个位图。一个是smallBitmap,一个是largeBitmap。

我想将整个 smallBitmap 绘制到 largeBitmap 中,但只绘制到 largeBitmap 的一部分,而不是直接矩形,而是变成四边形

我认为草图最能描述我的意思:

在此处输入图像描述

这种情况的一个示例是倾斜的智能手机图像(如thisthis),您需要将屏幕截图放入其屏幕中。

输入是:smallBitmap、largeBitmap、largeBitmap 的“四边形”坐标(放置 smallBitmap 的位置)。

largeBitmap 的“四边形”只有 4 个坐标,不一定是矩形。例如,它可以是平行四边形或梯形。

我需要将 smallBitmap 缩放成 largeBitmap 内的四边形,并且还支持 center-crop 缩放,这样它就不会变形

我还需要知道如何以相同的方式处理文本,但我想这是相同的解决方案。


这是我尝试过的东西,但它甚至无法扩展:

    //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());
4

3 回答 3

1

根据这篇文章找到了答案。

似乎不能使用 Matrix,因为它不能创建可能出现在 3d 世界中的梯形形状。

所以建议使用“ Camera ”类,如下所示:

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

遗憾的是,正如您所看到的,坐标没有被使用,因此您需要使用数字直到正确为止,或者找到一个公式在坐标和所需值之间进行转换。

我不会将此答案标记为正确答案,因为它不完全符合原始问题的要求(没有使用坐标)。

另外,在使用此解决方案时,我找不到如何处理文本。

但是,它确实有效,因此可能对其他人有用。


编辑:似乎 setPolyToPoly 根本不缩放图像的原因是第一个输入数组不正确:它被设置为大位图的大小,而不是小位图的大小。

所以,这是正确的代码:

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

但是,对于中心裁剪,它仍然存在这个问题,但是如果您在矩形倾斜之前知道矩形的正确大小,您可以在之前进行裁剪,并将其设置为输入。

至于文本,这与往常一样是可能的,因为画布与创建的矩阵保持一致。

于 2015-08-25T09:24:55.133 回答
0

要倾斜位图,矩阵可能会很方便。

   /*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);
于 2015-08-24T11:04:05.220 回答
0

对于我的回答,我将较小的画Bitmap到较大的Bitmap画上,然后将其画到SurfaceView.

  1. 使用边界四边形创建边界矩形。
  2. 使用边界矩形创建变换Matrix
  3. 用于Matrix.ScaleToFit.CENTER将边界矩形填充到较小的Bitmap.

采取这些步骤后,只需将较大的画布绘制到Bitmap正在使用的画布上。边界四边形绘制为红色,边界矩形绘制为蓝色,大Bitmap的绘制为绿色。Bitmap用蓝色Bitmap(边界矩形)替换较小的。

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());
    }
}
于 2015-08-25T21:53:03.600 回答