How to distort an image to any quadrangle?

前端 未结 5 1276
执念已碎
执念已碎 2020-12-16 05:19

Do any of you have an idea, how to distort an image in any quadrangle? I want to implement an image, which you can pull any corner in any direction, distorting the image. A

5条回答
  •  情深已故
    2020-12-16 06:12

    I hope this helps. The corner top-left, top-right is working except for bottom-left and bottom-right. Can somebody add it. I can't figure out how to do the bottom parts. :)

    public class PerspectiveDistortView extends View  implements OnTouchListener {
    
    private Paint paintRect, paintCircle;
    public int LEFT;
    public int TOP;
    public int RIGHT;
    public int BOTTOM;
    Point CIRCLE_TOP_LEFT;
    Point CIRCLE_TOP_RIGHT;
    Point CIRCLE_BOTTOM_LEFT;
    Point CIRCLE_BOTTOM_RIGHT;
    private int lastX, lastY;
    Bitmap image;
    Rect src, dst;
    Matrix matrix2;
    boolean isTouchCirclePoints = true;
    float deform2 = 5f;
    
    public PerspectiveDistortView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        init();
    }
    
    public PerspectiveDistortView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        init();
    }
    
    public PerspectiveDistortView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        init();
    }
    
    private void init(){
        this.setOnTouchListener(this);
        paintRect = new Paint();
        paintRect.setColor(0xffff0000);
        paintRect.setAntiAlias(true);
        paintRect.setDither(true);
        paintRect.setStyle(Paint.Style.STROKE);
        paintRect.setStrokeJoin(Paint.Join.BEVEL);
        paintRect.setStrokeCap(Paint.Cap.BUTT);
        paintRect.setStrokeWidth(3);
        paintCircle = new Paint();
        paintCircle.setColor(0xff000000);
        paintCircle.setAntiAlias(true);
        paintCircle.setDither(true);
        paintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
        paintCircle.setStrokeJoin(Paint.Join.BEVEL);
        paintCircle.setStrokeCap(Paint.Cap.BUTT);
    
        LEFT = 90;
        TOP = 40;
        RIGHT = 500;
        BOTTOM = 700;
        CIRCLE_TOP_LEFT = new Point(LEFT, TOP);
        CIRCLE_TOP_RIGHT = new Point(RIGHT, TOP);
        CIRCLE_BOTTOM_LEFT = new Point(LEFT, BOTTOM);
        CIRCLE_BOTTOM_RIGHT = new Point(RIGHT, BOTTOM);
    
        image = BitmapFactory.decodeResource(getResources(), R.drawable.ai);
    
        src = new Rect();
        dst = new Rect();
    
        matrix2 = new Matrix();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        // draw image
        src.left = LEFT;
        src.top = TOP;
        src.right = RIGHT;
        src.bottom = BOTTOM + image.getHeight();
    
        dst.left = CIRCLE_TOP_LEFT.x;
        dst.top = CIRCLE_TOP_LEFT.y;
        dst.right = CIRCLE_TOP_RIGHT.x;
        dst.bottom = CIRCLE_BOTTOM_RIGHT.y;
    
        // Free Transform bitmap
            int bw = image.getWidth();
            int bh = image.getHeight();
            RectF src = new RectF(LEFT, TOP, bw, bh);
            RectF dst = new RectF(CIRCLE_TOP_LEFT.x + 35, CIRCLE_TOP_LEFT.y + 30, CIRCLE_TOP_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y);
            matrix2.setRectToRect(src, dst, ScaleToFit.FILL);
    
            float[] pts = {
                           // source
                           0, 0, 
                           0, bh, 
                           bw, bh, 
                           bw, 0,
                           // destination
                           0, 0,
                           0, 0, 
                           0, 0, 
                           0, 0};
            matrix2.mapPoints(pts, 8, pts, 0, 4);
            int DX = 100;
            pts[10] -= CIRCLE_TOP_LEFT.x - LEFT; 
            pts[12] -= CIRCLE_TOP_RIGHT.x - RIGHT;
            pts[13] += 0;
            pts[14] += 0;
            pts[15] += CIRCLE_TOP_RIGHT.y - CIRCLE_TOP_LEFT.y;
    
            matrix2.setPolyToPoly(pts, 0, pts, 8, 4);
            canvas.drawBitmap(image, matrix2, null);
            isTouchCirclePoints = false;
    
        // line left
        canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, paintRect);
        // line top
        canvas.drawLine(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, paintRect);
        // line right
        canvas.drawLine(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect);
        // line bottom
        canvas.drawLine(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, paintRect);
        // circle top left
        canvas.drawCircle(CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 10, paintCircle);
        // circle top right
        canvas.drawCircle(CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 10, paintCircle);
        // circle bottom left
        canvas.drawCircle(CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 10, paintCircle);
        // circle bottom right
        canvas.drawCircle(CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 10, paintCircle);
    }
    
    @Override
    public boolean onTouch(View view, MotionEvent event) {
        lastX = (int) event.getX();
        lastY = (int)event.getY();
        if (inCircle(lastX, lastY, CIRCLE_TOP_LEFT.x, CIRCLE_TOP_LEFT.y, 40))
        {
            isTouchCirclePoints = true;
            CIRCLE_TOP_LEFT.set(lastX, lastY);
        } else if (inCircle(lastX, lastY, CIRCLE_TOP_RIGHT.x, CIRCLE_TOP_RIGHT.y, 40))
        {
            isTouchCirclePoints = true;
            CIRCLE_TOP_RIGHT.set(lastX, lastY);
        } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_LEFT.x, CIRCLE_BOTTOM_LEFT.y, 40))
        {
            isTouchCirclePoints = true;
            CIRCLE_BOTTOM_LEFT.set(lastX, lastY);
        } else if (inCircle(lastX, lastY, CIRCLE_BOTTOM_RIGHT.x, CIRCLE_BOTTOM_RIGHT.y, 40))
        {
            isTouchCirclePoints = true;
            CIRCLE_BOTTOM_RIGHT.set(lastX, lastY);
        }
        invalidate();
        return true;
    }
    
    private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) {
        double dx = Math.pow(x - circleCenterX, 2);
        double dy = Math.pow(y - circleCenterY, 2);
    
        if ((dx + dy) < Math.pow(circleRadius, 2)) {
            return true;
        } else {
            return false;
        }
    }
    

    }

提交回复
热议问题