Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 圖片裁剪及保存

Android 圖片裁剪及保存

編輯:關於Android編程

最近項目中有個需求,就是進行圖片的裁剪。
裁剪分為兩種方式: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 bitmaps = new ArrayList();
    /**
     * 一次剪切手勢動作
     */
    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
取兩圖層全部區域,交集部分變為透明色

另外還有一個就是:圖片保存到本地背景是黑色的,這裡要將保存格式改為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. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved