android如何实现手绘裁剪?

How to implement freehand image cropping in android?

如何在 Imageview 上实现徒手裁剪。

使用下面的代码,我可以徒手绘制路径并可以裁剪图像,但我遇到了一些其他问题

现在我已经试过了

这是我的代码

code for cropping image using canvas

public class SomeView extends View implements View.OnTouchListener {
    private Paint paint;

    int DIST = 2;
    boolean flgPathDraw = true;

    Point mfirstpoint = null;
    boolean bfirstpoint = false;

    Point mlastpoint = null;

    Bitmap bitmap;

    Context mContext;

    public SomeView(Context c, Bitmap bitmap) {
        super(c);

        mContext = c;
        this.bitmap = bitmap;

        setFocusable(true);
        setFocusableInTouchMode(true);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
        paint.setStrokeWidth(5);
        paint.setColor(Color.RED);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);

        this.setOnTouchListener(this);
        points = new ArrayList<Point>();

        bfirstpoint = false;
    }

    public SomeView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mContext = context;
        setFocusable(true);
        setFocusableInTouchMode(true);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setColor(Color.RED);

        points = new ArrayList<Point>();
        bfirstpoint = false;

        this.setOnTouchListener(this);
    }

    public void onDraw(Canvas canvas) {

        /*Rect dest = new Rect(0, 0, getWidth(), getHeight());

        paint.setFilterBitmap(true);
        canvas.drawBitmap(bitmap, null, dest, paint);*/

        canvas.drawBitmap(bitmap, 0, 0, null);

        Path path = new Path();
        boolean first = true;

        for (int i = 0; i < points.size(); i += 2) {
            Point point = points.get(i);
            if (first) {
                first = false;
                path.moveTo(point.x, point.y);
            } else if (i < points.size() - 1) {
                Point next = points.get(i + 1);
                path.quadTo(point.x, point.y, next.x, next.y);
            } else {
                mlastpoint = points.get(i);
                path.lineTo(point.x, point.y);
            }
        }
        canvas.drawPath(path, paint);
    }

    public boolean onTouch(View view, MotionEvent event) {
        // if(event.getAction() != MotionEvent.ACTION_DOWN)
        // return super.onTouchEvent(event);

        Point point = new Point();
        point.x = (int) event.getX();
        point.y = (int) event.getY();

        if (flgPathDraw) {

            if (bfirstpoint) {

                if (comparepoint(mfirstpoint, point)) {
                    // points.add(point);
                    points.add(mfirstpoint);
                    flgPathDraw = false;
                    showcropdialog();
                } else {
                    points.add(point);
                }
            } else {
                points.add(point);
            }

            if (!(bfirstpoint)) {

                mfirstpoint = point;
                bfirstpoint = true;
            }
        }

        invalidate();
        Log.e("Hi  ==>", "Size: " + point.x + " " + point.y);

        if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.d("Action up*****~~>>>>", "called");
            mlastpoint = point;
            if (flgPathDraw) {
                if (points.size() > 12) {
                    if (!comparepoint(mfirstpoint, mlastpoint)) {
                        flgPathDraw = false;
                        points.add(mfirstpoint);
                        showcropdialog();
                    }
                }
            }
        }

        return true;
    }

    private boolean comparepoint(Point first, Point current) {
        int left_range_x = (int) (current.x - 3);
        int left_range_y = (int) (current.y - 3);

        int right_range_x = (int) (current.x + 3);
        int right_range_y = (int) (current.y + 3);

        if ((left_range_x < first.x && first.x < right_range_x)
                && (left_range_y < first.y && first.y < right_range_y)) {
            if (points.size() < 10) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }

    }

    public void fillinPartofPath() {
        Point point = new Point();
        point.x = points.get(0).x;
        point.y = points.get(0).y;

        points.add(point);
        invalidate();
    }

    public void resetView() {
        points.clear();
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setColor(Color.RED);

        points = new ArrayList<Point>();
        bfirstpoint = false;

        flgPathDraw = true;
        invalidate();
    }

    private void showcropdialog() {
        DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Intent intent;
                switch (which) {
                    case DialogInterface.BUTTON_POSITIVE:
                        cropImage();
                        break;

                    case DialogInterface.BUTTON_NEGATIVE:
                        /*// No button clicked

                        intent = new Intent(mContext, DisplayCropActivity.class);
                        intent.putExtra("crop", false);
                        mContext.startActivity(intent);

                        bfirstpoint = false;*/
                        resetView();

                        break;
                }
            }
        };

        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setMessage("Do you Want to save Crop or Non-crop image?")
                .setPositiveButton("Crop", dialogClickListener)
                .setNegativeButton("Non-crop", dialogClickListener).show()
                .setCancelable(false);
    }
}

Code for cropping bitmap

public void cropImage() {

    setContentView(R.layout.activity_picture_preview);

    imageView = findViewById(R.id.image);

    int widthOfscreen = 0;
    int heightOfScreen = 0;

    DisplayMetrics dm = new DisplayMetrics();
    try {
        getWindowManager().getDefaultDisplay().getMetrics(dm);
    } catch (Exception ex) {
    }
    widthOfscreen = dm.widthPixels;
    heightOfScreen = dm.heightPixels;

    Bitmap bitmap2 = mBitmap;

    Bitmap resultingImage = Bitmap.createBitmap(widthOfscreen,
            heightOfScreen, bitmap2.getConfig());

    Canvas canvas = new Canvas(resultingImage);

    Paint paint = new Paint();

    Path path = new Path();

    for (int i = 0; i < points.size(); i++) {

        path.lineTo(points.get(i).x, points.get(i).y);

    }

    canvas.drawPath(path, paint);

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

    canvas.drawBitmap(bitmap2, 0, 0, paint);

    imageView.setImageBitmap(resultingImage);

}

Here what i get result using above code

Cropping image using Finger touch

This image showing result after cropping image

This is my expected output

请检查下面的屏幕截图是否相同

This Image showing cropping image using Finger touch

This image showing result after cropping image

我在上面的代码中遇到的以下问题

这是我迄今为止尝试过的其他一些 post

none 以上 post 有助于实现我的异常输出

如果需要更多信息,请告诉我。提前致谢。您的努力将不胜感激。

我在我的项目中针对这个问题尝试了很多解决方案,但这段代码有效。 在这里,我把我自己项目的代码放在这里。如果您在其中找到了解决方案,就可以使用它。

public class CropView extends View implements View.OnTouchListener {
public static final String INTENT_KEY_CROP = "crop";
public static final String CACHE_KEY = "bitmap";

public static List<Point> points;
boolean flgPathDraw = true;
boolean bFirstPoint = false;
private Point firstPoint = null;
private Point lastPoint = null;

private final Bitmap originalImageBitmap;
private int canvasWidth;
private int canvasHeight;
private Paint paint;
private Context context;
private static LruCache<String, Bitmap> mMemoryCache;
private final ImageCropListener imageCropListener;

public interface ImageCropListener {
    void onClickDialogPositiveButton();
    void onClickDialogNegativeButton();
}

public static Bitmap getBitmapFromMemCache() {
    return mMemoryCache.get(CACHE_KEY);
}


public CropView(Context c, Bitmap bm, ImageCropListener listener) {
    super(c);

    context = c;
    setFocusable(true);
    setFocusableInTouchMode(true);
    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setStyle(Paint.Style.STROKE);
    paint.setPathEffect(new DashPathEffect(new float[] { 10, 20 }, 0));
    paint.setStrokeWidth(5);
    paint.setColor(Color.WHITE);

    this.setOnTouchListener(this);
    points = new ArrayList<>();

    bFirstPoint = false;
    this.originalImageBitmap = bm;
    this.imageCropListener = listener;

    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };

 }

 public CropView(Context context, AttributeSet attrs, Bitmap bm, 
 ImageCropListener listener) {
    super(context, attrs);
    this.context = context;
    setFocusable(true);
    setFocusableInTouchMode(true);

    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(2);
    paint.setColor(Color.WHITE);

    this.setOnTouchListener(this);
    points = new ArrayList<>();
    bFirstPoint = false;
    this.originalImageBitmap = bm;
    this.imageCropListener = listener;
}

public void addBitmapToMemoryCache(Bitmap bitmap) {
    if (getBitmapFromMemCache() == null) {
        mMemoryCache.put(CACHE_KEY, bitmap);
    }
}

private float calcBitmapScale(int canvasWidth, int canvasHeight, int bmpWidth, int bmpHeight) {

    float scale = (float)canvasWidth / (float)bmpWidth;
    float tmp = bmpHeight * scale;

    if (tmp < canvasHeight) {
        scale = (float)canvasHeight / (float)bmpHeight;
        return scale;
    }

    return scale;
}

public void onDraw(Canvas canvas) {
    canvasWidth = canvas.getWidth();
    canvasHeight = canvas.getHeight();

   /* int bmpWidth = this.originalImageBitmap.getWidth();
    int bmpHeight = this.originalImageBitmap.getHeight();


    float toCanvasScale = this.calcBitmapScale(canvasWidth, canvasHeight, bmpWidth, bmpHeight);


    float diffX = (bmpWidth * toCanvasScale - canvasWidth);
    float diffY = (bmpHeight * toCanvasScale - canvasHeight);


    float addX = (diffX / toCanvasScale) / 2;
    float addY = (diffY / toCanvasScale) / 2;


    Rect rSrc = new Rect((int)addX, (int)addY,
            (int)((canvasWidth / toCanvasScale) + addX), (int)((canvasHeight / 
    toCanvasScale) + addY));
    RectF rDest = new RectF(0, 0, canvasWidth, canvasHeight);
    */
    canvas.drawBitmap(originalImageBitmap, 0, 0, null);

    Path cropAreaPath = new Path();
    boolean isFirstPoint = true;

    for (int i = 0; i < points.size(); i += 2) {
        Point point = points.get(i);
        if (isFirstPoint) {
            isFirstPoint = false;
            // 最初の処理でPathのx,y座標をpointの座標に移動する
            cropAreaPath.moveTo(point.x, point.y);
        } else if (i < points.size() - 1) {
            Point next = points.get(i + 1);
            cropAreaPath.quadTo(point.x, point.y, next.x, next.y);
        } else {
            lastPoint = points.get(i);
            cropAreaPath.lineTo(point.x, point.y);
        }
    }
    canvas.drawPath(cropAreaPath, paint);
}

public boolean onTouch(View view, MotionEvent event) {
    Point point = new Point();
    point.x = (int) event.getX();
    point.y = (int) event.getY();

    if (flgPathDraw) {
        if (bFirstPoint) {
            if (comparePoint(firstPoint, point)) {
                // points.add(point);
                points.add(firstPoint);
                flgPathDraw = false;
                showCropDialog();
            } else {
                points.add(point);
            }
        } else {
            points.add(point);
        }

        if (!(bFirstPoint)) {

            firstPoint = point;
            bFirstPoint = true;
        }
    }

    invalidate();
    //Log.e("Hi  ==>", "Size: " + point.x + " " + point.y);

    if (event.getAction() == MotionEvent.ACTION_UP) {
        Log.d("Action up***>", "called");
        lastPoint = point;
        if (flgPathDraw) {
            if (points.size() > 12) {
                if (!comparePoint(firstPoint, lastPoint)) {
                    flgPathDraw = false;
                    points.add(firstPoint);
                    showCropDialog();
                }
            }
        }
    }

    return true;
}

private boolean comparePoint(Point first, Point current) {
    int left_range_x = (int) (current.x - 3);
    int left_range_y = (int) (current.y - 3);

    int right_range_x = (int) (current.x + 3);
    int right_range_y = (int) (current.y + 3);

    if ((left_range_x < first.x && first.x < right_range_x)
            && (left_range_y < first.y && first.y < right_range_y)) {
        if (points.size() < 10) {
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }

}

public void fillinPartofPath() {
    Point point = new Point();
    point.x = points.get(0).x;
    point.y = points.get(0).y;

    points.add(point);
    invalidate();
}

public void resetView() {
    points.clear();
    paint.setColor(Color.WHITE);
    paint.setStyle(Paint.Style.STROKE);
    flgPathDraw = true;
    invalidate();
}

private void showCropDialog() {
    final Bitmap croppedImage = cropImage(this.originalImageBitmap);
    DialogInterface.OnClickListener dialogClickListener = new 
    DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            switch (which) {
                case DialogInterface.BUTTON_POSITIVE:
                    addBitmapToMemoryCache(croppedImage);
                    imageCropListener.onClickDialogPositiveButton();
                    break;

                case DialogInterface.BUTTON_NEGATIVE:
                    bFirstPoint = false;
                    resetView();
                    imageCropListener.onClickDialogNegativeButton();
                    break;
            }
        }
    };

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setMessage("Do you Want to save Crop or Non-crop image?")
            .setPositiveButton("Crop", dialogClickListener)
            .setNegativeButton("Cancel", dialogClickListener).show()
            .setCancelable(false);
}

private Bitmap cropImage(Bitmap image) {
    Bitmap cropImage = Bitmap.createBitmap(canvasWidth, canvasHeight, 
    image.getConfig());
    Canvas canvas = new Canvas(cropImage);
    Paint paint = new Paint();
    paint.setAntiAlias(true);

    Path path = new Path();
    for (int i = 0; i < CropView.points.size(); i++) {
        path.lineTo(CropView.points.get(i).x, CropView.points.get(i).y);
    }
    canvas.drawPath(path, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(originalImageBitmap, 0, 0, paint);

    return cropImage;
}

class Point {
    public float dy;
    public float dx;
    float x, y;

    @Override
    public String toString(){
        return x + ", " + y;
    }
}
}

然后你可以得到裁剪结果..就像,

Bitmap cropBitmap = CropView.getBitmapFromMemCache();
                cropBitmap = getBitmapWithTransparentBG(cropBitmap,Color.WHITE);
                Drawable d = new BitmapDrawable(getResources(),cropBitmap);

public Bitmap getBitmapWithTransparentBG(Bitmap srcBitmap, int bgColor) {
    Bitmap result = srcBitmap.copy(Bitmap.Config.ARGB_8888, true);
    int nWidth = result.getWidth();
    int nHeight = result.getHeight();
    for (int y = 0; y < nHeight; ++y)
        for (int x = 0; x < nWidth; ++x) {
            int nPixelColor = result.getPixel(x, y);
            if (nPixelColor == bgColor)
                result.setPixel(x, y, Color.TRANSPARENT);
        }
    return result;
}

我认为,此代码将非常适合您的问题解决方案。谢谢

总的来说,您的代码看起来不错,但我有几点意见:

  • 无法使用canvas
  • 设置全屏位图
  • 如果我在 canvas 中将位图设置为全屏,那么图像会被拉伸
    您选择的图像部分需要放置在较小的位图中,以便布局 XML 可以根据需要放置它。您正在创建全屏位图。详情请看下面的demo

  • 如何为裁剪位图设置透明背景
    我不清楚问题是什么。

  • 无法为裁剪后的图像添加边框

  • 图片裁剪结果不符合预期
    见下文。

这是一个使用您的代码的小型演示应用程序。您没有提供 MCVE,所以为了演示目的,我将以下内容放在一起。除了让应用程序运行之外,我认为唯一的变化是在 MainActivity.java 中绘制边框。边框宽度从用户绘制的裁切路径开始,向内延伸至裁切部分。如果你想在不丢失任何像素的情况下实际构图切口,那么你需要扩展路径以适应我任意设置为 20 像素的框架。

我还必须创建所用的布局,所以您可能想看看那些。它们发布在下面。

下面是演示视频,代码如下:

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private Bitmap mBitmap;
    private SomeView mSomeView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);
        mSomeView = new SomeView(this, mBitmap);
        LinearLayout layout = findViewById(R.id.layout);
        LinearLayout.LayoutParams lp =
            new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                                          LinearLayout.LayoutParams.WRAP_CONTENT);
        layout.addView(mSomeView, lp);
    }

    public void cropImage() {
        setContentView(R.layout.activity_picture_preview);
        ImageView imageView = findViewById(R.id.image);

        Bitmap fullScreenBitmap =
            Bitmap.createBitmap(mSomeView.getWidth(), mSomeView.getHeight(), mBitmap.getConfig());

        Canvas canvas = new Canvas(fullScreenBitmap);

        Path path = new Path();
        List<Point> points = mSomeView.getPoints();
        for (int i = 0; i < points.size(); i++) {
            path.lineTo(points.get(i).x, points.get(i).y);
        }

        // Cut out the selected portion of the image...
        Paint paint = new Paint();
        canvas.drawPath(path, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(mBitmap, 0, 0, paint);

        // Frame the cut out portion...
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10f);
        canvas.drawPath(path, paint);

        // Create a bitmap with just the cropped area.
        Region region = new Region();
        Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
        region.setPath(path, clip);
        Rect bounds = region.getBounds();
        Bitmap croppedBitmap =
            Bitmap.createBitmap(fullScreenBitmap, bounds.left, bounds.top,
                                bounds.width(), bounds.height());

        imageView.setImageBitmap(croppedBitmap);
    }
}

SomeView.java
我不认为这个 class.

有任何实质性的变化
public class SomeView extends View implements View.OnTouchListener {  
    private Paint paint;  
    private List<Point> points;  

    int DIST = 2;  
    boolean flgPathDraw = true;  

    Point mfirstpoint = null;  
    boolean bfirstpoint = false;  

    Point mlastpoint = null;  

    Bitmap bitmap;  

    Context mContext;  


        public SomeView(Context c, Bitmap bitmap) {  
            super(c);  

            mContext = c;  
            this.bitmap = bitmap;  

            setFocusable(true);  
            setFocusableInTouchMode(true);  

            paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
            paint.setStyle(Paint.Style.STROKE);  
            paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));  
            paint.setStrokeWidth(5);  
            paint.setColor(Color.RED);  
            paint.setStrokeJoin(Paint.Join.ROUND);  
            paint.setStrokeCap(Paint.Cap.ROUND);  

            this.setOnTouchListener(this);  
            points = new ArrayList<Point>();  

            bfirstpoint = false;  
        }  

        public SomeView(Context context, AttributeSet attrs) {  
            super(context, attrs);  

            mContext = context;  
            setFocusable(true);  
            setFocusableInTouchMode(true);  

            paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
            paint.setStyle(Paint.Style.STROKE);  
            paint.setStrokeWidth(5);  
            paint.setColor(Color.RED);  

            points = new ArrayList<Point>();  
            bfirstpoint = false;  

            this.setOnTouchListener(this);  
        }  

        public void onDraw(Canvas canvas) {  

            /*Rect dest = new Rect(0, 0, getWidth(), getHeight());  

     paint.setFilterBitmap(true); canvas.drawBitmap(bitmap, null, dest, paint);*/  
      canvas.drawBitmap(bitmap, 0, 0, null);  

            Path path = new Path();  
            boolean first = true;  

            for (int i = 0; i < points.size(); i += 2) {  
                Point point = points.get(i);  
                if (first) {  
                    first = false;  
                    path.moveTo(point.x, point.y);  
                } else if (i < points.size() - 1) {  
                    Point next = points.get(i + 1);  
                    path.quadTo(point.x, point.y, next.x, next.y);  
                } else {  
                    mlastpoint = points.get(i);  
                    path.lineTo(point.x, point.y);  
                }  
            }  
            canvas.drawPath(path, paint);  
        }  

        public boolean onTouch(View view, MotionEvent event) {  
            // if(event.getAction() != MotionEvent.ACTION_DOWN)  
     // return super.onTouchEvent(event);  
      Point point = new Point();  
            point.x = (int) event.getX();  
            point.y = (int) event.getY();  

            if (flgPathDraw) {  

                if (bfirstpoint) {  

                    if (comparepoint(mfirstpoint, point)) {  
                        // points.add(point);  
      points.add(mfirstpoint);  
                        flgPathDraw = false;  
                        showcropdialog();  
                    } else {  
                        points.add(point);  
                    }  
                } else {  
                    points.add(point);  
                }  

                if (!(bfirstpoint)) {  

                    mfirstpoint = point;  
                    bfirstpoint = true;  
                }  
            }  

            invalidate();  
            Log.e("Hi  ==>", "Size: " + point.x + " " + point.y);  

            if (event.getAction() == MotionEvent.ACTION_UP) {  
                Log.d("Action up*****~~>>>>", "called");  
                mlastpoint = point;  
                if (flgPathDraw) {  
                    if (points.size() > 12) {  
                        if (!comparepoint(mfirstpoint, mlastpoint)) {  
                            flgPathDraw = false;  
                            points.add(mfirstpoint);  
                            showcropdialog();  
                        }  
                    }  
                }  
            }  

            return true;  
        }  

        private boolean comparepoint(Point first, Point current) {  
            int left_range_x = (int) (current.x - 3);  
            int left_range_y = (int) (current.y - 3);  

            int right_range_x = (int) (current.x + 3);  
            int right_range_y = (int) (current.y + 3);  

            if ((left_range_x < first.x && first.x < right_range_x)  
                && (left_range_y < first.y && first.y < right_range_y)) {  
                if (points.size() < 10) {  
                    return false;  
                } else {  
                    return true;  
                }  
            } else {  
                return false;  
            }  

        }  

        public void fillinPartofPath() {  
            Point point = new Point();  
            point.x = points.get(0).x;  
            point.y = points.get(0).y;  

            points.add(point);  
            invalidate();  
        }  

        public void resetView() {  
            points.clear();  
            paint.setColor(Color.WHITE);  
            paint.setStyle(Paint.Style.STROKE);  

            paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
            paint.setStyle(Paint.Style.STROKE);  
            paint.setStrokeWidth(5);  
            paint.setColor(Color.RED);  

            points = new ArrayList<Point>();  
            bfirstpoint = false;  

            flgPathDraw = true;  
            invalidate();  
        }  

        private void showcropdialog() {  
            DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {  
                @Override  
      public void onClick(DialogInterface dialog, int which) {  
                    Intent intent;  
                    switch (which) {  
                        case DialogInterface.BUTTON_POSITIVE:  
                            ((MainActivity) mContext).cropImage();  
                            break;  

                        case DialogInterface.BUTTON_NEGATIVE:  
                            /*// No button clicked  

     intent = new Intent(mContext, DisplayCropActivity.class); intent.putExtra("crop", false); mContext.startActivity(intent);  
     bfirstpoint = false;*/  resetView();  

                            break;  
                    }  
                }  
            };  

            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);  
            builder.setMessage("Do you Want to save Crop or Non-crop image?")  
                .setPositiveButton("Crop", dialogClickListener)  
                .setNegativeButton("Non-crop", dialogClickListener).show()  
                .setCancelable(false);  
        }  

        public List<Point> getPoints() {  
            return points;  
        }  
    }

activity_main.xml

<LinearLayout 
  android:id="@+id/layout"  
  xmlns:tools="http://schemas.android.com/tools"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent"  
  android:orientation="vertical"  
  tools:context=".MainActivity"/>

activity_picture_preview.xml

<android.support.constraint.ConstraintLayout x
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@drawable/dog" />
</android.support.constraint.ConstraintLayout> 

如果您想创建一个带有 100px 边框的裁剪位图,请在 cropImage() 中使用以下代码:

    // Create a bitmap with just the cropped area.
    Region region = new Region();
    Region clip = new Region(0, 0, fullScreenBitmap.getWidth(), fullScreenBitmap.getHeight());
    region.setPath(path, clip);
    Rect sourceBounds = region.getBounds();
    Rect destBounds =
        new Rect(CROPPED_MARGIN, CROPPED_MARGIN, sourceBounds.width() + CROPPED_MARGIN,
                 sourceBounds.height() + CROPPED_MARGIN);
    Bitmap croppedBitmap =
        Bitmap.createBitmap(sourceBounds.width() + CROPPED_MARGIN * 2,
                            sourceBounds.height() + CROPPED_MARGIN * 2, mBitmap.getConfig());
    canvas.setBitmap(croppedBitmap);
    canvas.drawBitmap(fullScreenBitmap, sourceBounds, destBounds, null);

    imageView.setImageBitmap(croppedBitmap);

    // Add as member variable.
    private static final int CROPPED_MARGIN = 100;