Android 图片裁剪及保存

来源:互联网 发布:php unpack函数 编辑:程序博客网 时间:2024/04/28 16:39

最近项目中有个需求,就是进行图片的裁剪。
裁剪分为两种方式:1.矩形框裁剪 2.手势裁剪
在手势裁剪的过程中遇到一个问题,就是图片裁剪之后,背景不是透明的,下面给出我的解决方案。

@SuppressLint("DrawAllocation")public class CropPictureView extends ImageView {    private float density;    private Paint mPaint;    private Path mCirclePath;    private Paint mImagePaint;    private Path mFreehandPath;    private Paint mPaintBitmap;    private final Matrix mCircleatrix = new Matrix();    // 放大镜的半径    private static int RADIUS = 160;    // 放大倍数    private static final int FACTOR = 1;    // 裁剪保留的bitmap    private List<Bitmap> bitmaps = new ArrayList<Bitmap>();    /**     * 一次剪切手势动作     */    private boolean isTouchArea = false;    private int mViewWidth = 0;    private int mViewHeight = 0;    private float scale = 1.0f;    private float diff = 0.0f;    private Bitmap sourceBitmap = null;    public enum ViewType {        RECTTYPE, PATHTYPE    }    private ViewType mViewType = ViewType.RECTTYPE;    public void setmViewType(ViewType mViewType) {        this.mViewType = mViewType;    }    public CropPictureView(Context context) {        super(context);        init();    }    public CropPictureView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public CropPictureView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init() {        setLayerType(View.LAYER_TYPE_SOFTWARE, null);        density = getContext().getResources().getDisplayMetrics().density;        RADIUS = dipToPx(160);        diff = diff;        setFocusable(true);        DRAW_STATUS = 0;        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setStrokeWidth(diff);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setColor(Color.RED);        mImagePaint = new Paint();        mImagePaint.setAntiAlias(true);        mImagePaint.setStrokeWidth(diff);        mImagePaint.setStyle(Paint.Style.STROKE);        mImagePaint.setColor(Color.BLACK);        mCirclePath = new Path();        mCirclePath.addRect(diff, diff, RADIUS + diff, RADIUS + diff, Direction.CW);        // mCirclePath.addCircle(RADIUS, RADIUS, RADIUS, Direction.CW);        mCircleatrix.setScale(FACTOR, FACTOR);        mFrameRect = new RectF();        mFreehandPath = new Path();        mPaintBitmap = new Paint();        mPaintBitmap.setFilterBitmap(true);    }    private Bitmap bm;    // 重写该方法,在这里绘图    @SuppressLint({ "DrawAllocation", "NewApi" })    @Override    protected void onDraw(Canvas mcanvas) {        // super.onDraw(canvas);        if (getDrawable() == null) {            return;        }        // 生成画布图像        bm = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bm);// 使用空白图片生成canvas        canvas.save();        canvas.translate(mImageRect.left, mImageRect.top);        canvas.drawBitmap(getBitmap(), mCircleatrix, mPaintBitmap);        canvas.restore();        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG));        canvas.drawRect(mImageRect, mImagePaint);        if (DRAW_STATUS == 2) {            if (!isTouchArea) {                return;            }            if (mViewType == ViewType.RECTTYPE) {                drawRect(canvas);                move(canvas);                drawRect(canvas);            } else {                canvas.drawPath(mFreehandPath, mPaint);                move(canvas);                canvas.drawPath(mFreehandPath, mPaint);            }        } else if (DRAW_STATUS == 3) {            if (mViewType == ViewType.PATHTYPE) {                mFreehandPath.close();                mFrameRect = new RectF();                mFreehandPath.computeBounds(mFrameRect, true);            }            // 如果画的矩形太小就不进行剪切            if (Math.hypot(mFrameRect.width(), mFrameRect.height()) < 50) {                isTouchArea = false;            } else {                if (mViewType == ViewType.PATHTYPE) {                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.DST_IN);                    canvas.clipPath(mFreehandPath);                    canvas.translate(mImageRect.left, mImageRect.top);                    PaintFlagsDrawFilter dfd = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG, Paint.FILTER_BITMAP_FLAG);                    canvas.setDrawFilter(dfd);                    canvas.drawBitmap(getBitmap(), mCircleatrix, null);                }                up();                return;            }        } else if (DRAW_STATUS == 0) {        } else if (DRAW_STATUS == 1) {        }        mcanvas.drawBitmap(bm, 0, 0, mPaintBitmap);    }    private void move(Canvas canvas) {        // 剪切        canvas.clipPath(mCirclePath);        // 画放大后的图        canvas.translate(RADIUS / 2 - endX * FACTOR + mImageRect.left, RADIUS / 2 - endY * FACTOR + mImageRect.top);        canvas.drawBitmap(getBitmap(), mCircleatrix, null);        canvas.translate(-mImageRect.left, -mImageRect.top);        canvas.drawRect(mImageRect, mImagePaint);    }    /**     * dip 转换成px     *      * @param dip     * @return     */    private int dipToPx(float dip) {        return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));    }    /**     * 一次裁剪动作完成     */    public void up() {        DRAW_STATUS = 0;        Bitmap tempBitmap = getCropImage();        bitmaps.add(tempBitmap);        setImageBitmap(tempBitmap);    }    float startX = 0;    float startY = 0;    float endX = 0;    float endY = 0;    public static int DRAW_STATUS = 0;// 0,初始状态、1点击状态、2移动状态、3抬起状态    private RectF mFrameRect = new RectF();    private RectF mImageRect = new RectF();    /**     * 初始化边框     */    public void initRect() {        startX = 0;        startY = 0;        endX = 0;        endY = 0;        mFrameRect = new RectF();        if (mFreehandPath != null) {            mFreehandPath.reset();        } else {            mFreehandPath = new Path();        }    }    /**     * 画矩形边框     *      * @param canvas     */    public void drawRect(Canvas canvas) {        if (endX > startX) {            mFrameRect.left = (int) startX;            mFrameRect.right = (int) endX;        } else {            mFrameRect.left = (int) endX;            mFrameRect.right = (int) startX;        }        if (endY > startY) {            mFrameRect.top = (int) startY;            mFrameRect.bottom = (int) endY;        } else {            mFrameRect.top = (int) endY;            mFrameRect.bottom = (int) startY;        }        mFrameRect.setIntersect(mFrameRect, mImageRect);        canvas.drawRect(mFrameRect, mPaint);    }    private Bitmap getCovertBitmap() {        Bitmap tmpBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.RGB_565);        Canvas canvas = new Canvas(tmpBitmap);        Drawable tempDrawable = getDrawable();        tempDrawable.setBounds(new Rect(Math.round(mImageRect.left), Math.round(mImageRect.top), Math.round(mImageRect.right), Math.round(mImageRect.bottom)));        tempDrawable.draw(canvas);        return tmpBitmap;    }    /**     *      * @param bitmap     * @param w     * @param h     * @return     */    public Bitmap resizeBitmap(Bitmap bitmap, int w, int h) {        if (bitmap != null) {            int width = bitmap.getWidth();            int height = bitmap.getHeight();            int newWidth = w;            int newHeight = h;            float scaleWight = ((float) newWidth) / width;            float scaleHeight = ((float) newHeight) / height;            Matrix matrix = new Matrix();            matrix.postScale(scaleWight, scaleHeight);            return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);        } else {            return null;        }    }    private Bitmap getBitmap() {        Bitmap bm = null;        Drawable d = getDrawable();        if (d != null && d instanceof BitmapDrawable)            bm = ((BitmapDrawable) d).getBitmap();        return bm;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // TODO Auto-generated method stub        int antion = event.getAction();        if (antion == MotionEvent.ACTION_CANCEL) {            return true;        }        float touchX = event.getX();        float touchY = event.getY();        // 点击时        if (antion == MotionEvent.ACTION_DOWN) {            initRect();            startX = touchX;            startY = touchY;            endX = touchX;            endY = touchY;            mFreehandPath.moveTo(touchX, touchY);            DRAW_STATUS = 1;            if (mImageRect.contains(startX, startY)) {                isTouchArea = true;            } else {                isTouchArea = false;            }            invalidate();            return true;        }        // 拖动时        if (antion == MotionEvent.ACTION_MOVE) {            if (mViewType == ViewType.PATHTYPE) {                if (mImageRect.contains(touchX, touchY)) {                    touchMove(event);                    // mFreehandPath.lineTo(touchX, touchY);                }            }            endX = touchX;            endY = touchY;            DRAW_STATUS = 2;            invalidate();            return true;        }        // 抬起时        if (antion == MotionEvent.ACTION_UP) {            endX = touchX;            endY = touchY;            DRAW_STATUS = 3;            invalidate();            return true;        }        return super.onTouchEvent(event);    }    // 手指在屏幕上滑动时调用    private void touchMove(MotionEvent event) {        final float x = event.getX();        final float y = event.getY();        final float previousX = endX;        final float previousY = endY;        final float dx = Math.abs(x - previousX);        final float dy = Math.abs(y - previousY);        // 两点之间的距离大于等于3时,生成贝塞尔绘制曲线        if (dx >= 3 || dy >= 3) {            // 设置贝塞尔曲线的操作点为起点和终点的一半            float cX = (x + previousX) / 2;            float cY = (y + previousY) / 2;            // 二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点            mFreehandPath.quadTo(previousX, previousY, cX, cY);            // 第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值        }    }    // 进行图片的裁剪,所谓的裁剪就是根据Drawable的新的坐标在画布上创建一张新的图片    private Bitmap getCropImage() {        if (mFrameRect.width() <= 0 || mFrameRect.height() <= 0) {            isTouchArea = false;            return null;        }        // this has a error: java.lang.IllegalArgumentException: x + width must        // be <=bitmap.width()        int x = Math.round(mFrameRect.left);        int y = Math.round(mFrameRect.top);        int w = Math.round(mFrameRect.width());        int h = Math.round(mFrameRect.height());        if (x + w > bm.getWidth()) {            w = bm.getWidth() - x;        }        if (y + h > bm.getHeight()) {            h = bm.getHeight() - y;        }        return Bitmap.createBitmap(bm, x, y, w, h, null, true);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        final int viewWidth = MeasureSpec.getSize(widthMeasureSpec);        final int viewHeight = MeasureSpec.getSize(heightMeasureSpec);        setMeasuredDimension(viewWidth, viewHeight);        mViewWidth = viewWidth - getPaddingLeft() - getPaddingRight();        mViewHeight = viewHeight - getPaddingTop() - getPaddingBottom();    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        if (getDrawable() != null)            setupLayout(mViewWidth, mViewHeight);    }    /**     * 重新设置view的图片     */    public void setupLayout(int viewW, int viewH) {        if (viewW == 0 || viewH == 0)            return;        float imgWidth = getDrawable().getIntrinsicWidth();        float imgHight = getDrawable().getIntrinsicHeight();        float viewRatio = (float) viewW / (float) viewH;        float imgRatio = imgWidth / imgHight;        if (imgRatio >= viewRatio) {            scale = (float) viewW / imgWidth;        } else if (imgRatio < viewRatio) {            scale = (float) viewH / imgHight;        }        float w = imgWidth * scale;        float h = imgHight * scale;        float left = (viewW - w) / 2;        float top = (viewH - h) / 2;        float right = left + w;        float bottom = top + h;        mImageRect = new RectF(left, top, right, bottom);        mCircleatrix.setScale(FACTOR * scale, FACTOR * scale);    }    public Bitmap getCropBitmap() {        if (bitmaps != null && bitmaps.size() > 0) {            return bitmaps.get(bitmaps.size() - 1);        } else {            return getBitmap();        }    }    public void retroversion() {        LogUtil.e("撤销tupain   = " + bitmaps.size());        if (bitmaps != null && bitmaps.size() > 1) {            setImageBitmap(bitmaps.get(bitmaps.size() - 2));            invalidate();            bitmaps.remove(bitmaps.size() - 1);        }        if (bitmaps.size() == 0) {            bitmaps.add(sourceBitmap);        }    }    /**     * Set source image bitmap     *     * @param bitmap     *            src image bitmap     */    @Override    public void setImageBitmap(Bitmap bitmap) {        super.setImageBitmap(bitmap); // calles setImageDrawable internally        if (sourceBitmap == null) {            sourceBitmap = bitmap;        }        if (sourceBitmap != null && bitmaps.size() == 0) {            bitmaps.add(sourceBitmap);        }    }    /**     * Set source image resource id     *     * @param resId     *            source image resource id     */    @Override    public void setImageResource(int resId) {        super.setImageResource(resId);        updateLayout();    }    /**     * Set image drawable.     *     * @param drawable     *            source image drawable     */    @Override    public void setImageDrawable(Drawable drawable) {        super.setImageDrawable(drawable);        updateLayout();    }    /**     * Set image uri     *     * @param uri     *            source image local uri     */    @Override    public void setImageURI(Uri uri) {        super.setImageURI(uri);        updateLayout();    }    private void updateLayout() {        Drawable d = getDrawable();        if (d != null) {            setupLayout(mViewWidth, mViewHeight);        }    }    private Bitmap getTransBitmap(Bitmap bm) {        int[] pix = new int[bm.getWidth() * bm.getHeight()];        for (int y = 0; y < bm.getHeight(); y++)            for (int x = 0; x < bm.getWidth(); x++) {                int index = y * bm.getWidth() + x;                int r = ((pix[index] >> 16) & 0xff) | 0xff;                int g = ((pix[index] >> 8) & 0xff) | 0xff;                int b = (pix[index] & 0xff) | 0xff;                pix[index] = 0xff000000 | (r << 16) | (g << 8) | b;            }        bm.setPixels(pix, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());        return Bitmap.createBitmap(bm);    }}

(代码比较乱)
上面分为两种裁剪方式:RECTTYPE–矩形, PATHTYPE–手势路径。
解决背景不是透明的方式:

if (mViewType == ViewType.PATHTYPE) {                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.DST_IN);                    canvas.clipPath(mFreehandPath);                    canvas.translate(mImageRect.left, mImageRect.top);                    PaintFlagsDrawFilter dfd = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG, Paint.FILTER_BITMAP_FLAG);                    canvas.setDrawFilter(dfd);                    canvas.drawBitmap(getBitmap(), mCircleatrix, null);                }

canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.DST_IN);
黑色粗体位置就是设置裁剪的背景颜色和层叠方式的,PorterDuff.Mode的具体方式如下:
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色

可以转到链接查看:http://blog.csdn.net/t12x3456/article/details/10432935

另外还有一个就是:图片保存到本地背景是黑色的,这里要将保存格式改为png:
* bm.compress(Bitmap.CompressFormat.PNG, 90, baos);*

public static InputStream bitmapToStream(Bitmap bm) {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        bm.compress(Bitmap.CompressFormat.PNG, 90, baos);        InputStream is = new ByteArrayInputStream(baos.toByteArray());        return is;    }
1 0
原创粉丝点击