天天看點

Android實作bitmap指定區域滑動截取

突然不知道什麼心态,說要做這個,網上找了半天沒找到合适的,就自己做了一個。

先上效果圖:

Android實作bitmap指定區域滑動截取

圖檔資源我寫死儲存在了raw中,有需要可以自己寫擷取bitmap。

界面layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.admin.myapplication.MainActivity">
    <com.admin.myapplication.ScreenShotView
        android:id="@+id/screenShotView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <LinearLayout
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="#000000">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="選擇要截取區域"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_alignParentBottom="true"
        android:background="#000000"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/cancel_btn"
            android:text="取消"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:gravity="center"/>
        <TextView
            android:id="@+id/certain_btn"
            android:text="确定"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:gravity="center"/>
        <TextView
            android:id="@+id/restart_btn"
            android:text="重試"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:gravity="center"/>
    </LinearLayout>

</RelativeLayout>
           

ScreenShotView為自定義View用來顯示bitmap,以及滑動截圖,其中Dot類用來儲存坐标點的x,y值。

public class ScreenShotView extends View {
    private Dot startDot;
    private Dot endDot;
    private Bitmap mBitmap;
    private Bitmap ocrBitmap;
    private int screenHeight;
    private int screenWidth;
    private Dot leftTopDot;
    private Dot rightBottomDot;
    private Paint paintShadow;
    int shadow = ;
    int clear = ;


    public ScreenShotView(Context context) {
        super(context);
        startDot = new Dot();
        endDot = new Dot();
        leftTopDot = new Dot();
        rightBottomDot = new Dot();
    }

    public ScreenShotView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        startDot = new Dot();
        endDot = new Dot();
        leftTopDot = new Dot();
        rightBottomDot = new Dot();
    }

    public ScreenShotView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        startDot = new Dot();
        endDot = new Dot();
        leftTopDot = new Dot();
        rightBottomDot = new Dot();
    }

    public void setBitmap(Bitmap bitmap, int screenHeight, int screenWidth) {
        mBitmap = bitmap;
        this.screenHeight = screenHeight;
        this.screenWidth = screenWidth;
        changeBitmapSize();
        invalidate();
    }

    public void restart(){
        startDot = new Dot();
        endDot = new Dot();
        leftTopDot = new Dot();
        rightBottomDot = new Dot();
        invalidate();
    }
   /**
   *将将要顯示的bitmap進行變形,使其鋪滿螢幕
   *
   */
    private void changeBitmapSize() {
        int width = mBitmap.getWidth();
        int height = mBitmap.getHeight();
        float scaleWidth = ((float) screenWidth) / width;
        float scaleHeight = ((float) screenHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        mBitmap = Bitmap.createBitmap(mBitmap, , , width, height, matrix, true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        getLeftTopDot();
        getRightBottomDot();
        drawBitmap(canvas);
        drawArea(canvas);
        drawShadowTop(canvas);
        drawShadowLeft(canvas);
        drawShadowRight(canvas);
        drawShadowBottom(canvas);
    }

    /**
    *繪制陰影
    *
    */
    private void drawShadowBottom(Canvas canvas) {
        paintShadow = new Paint();
        paintShadow.setColor(shadow);
        canvas.drawRect(, rightBottomDot.getY(), screenWidth, screenHeight, paintShadow);
    }

    private void drawShadowRight(Canvas canvas) {
        paintShadow = new Paint();
        paintShadow.setColor(shadow);
        canvas.drawRect(rightBottomDot.getX(), leftTopDot.getY(), screenWidth, rightBottomDot.getY(), paintShadow);
    }

    private void drawShadowLeft(Canvas canvas) {
        paintShadow = new Paint();
        paintShadow.setColor(shadow);
        canvas.drawRect(, leftTopDot.getY(), leftTopDot.getX(), rightBottomDot.getY(), paintShadow);
    }

    private void drawShadowTop(Canvas canvas) {
        paintShadow = new Paint();
        paintShadow.setColor(shadow);
        canvas.drawRect(, , screenWidth, leftTopDot.getY(), paintShadow);
    }

    private void drawBitmap(Canvas canvas) {
        Paint paint = new Paint();
        canvas.drawBitmap(mBitmap, , , paint);
    }

    /**
     * 畫出截圖區域
     *
     * @param canvas
     */
    private void drawArea(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(clear);
        canvas.drawRect(leftTopDot.getX(), leftTopDot.getY(), rightBottomDot.getX(), rightBottomDot.getY(), paint);
    }


    /**
     * 擷取截圖區域bitmap
     *
     * @return 截圖
     */
    public Bitmap getBitmap() {
        if (mBitmap != null) {
            getLeftTopDot();
            getRightBottomDot();
            if (getBitmapOutWidth() >  && getBitmapOutHeight() > ) {
                if(leftTopDot.getY()<){
                    leftTopDot.setY();
                }
                ocrBitmap = Bitmap.createBitmap(mBitmap, (int) leftTopDot.getX(), (int) leftTopDot.getY(), getBitmapOutWidth(), getBitmapOutHeight());
            }
        }
        return ocrBitmap;
    }

    /**
     * 擷取截圖區域寬度
     *
     * @return
     */
    private int getOutWidth() {
        return (int) (rightBottomDot.getX() - leftTopDot.getX());
    }

    /**
     * 擷取截圖區域高度
     *
     * @return
     */
    private int getOutHeight() {
        return (int) (rightBottomDot.getY() - leftTopDot.getY());
    }

    private int getBitmapOutWidth() {
        int bitmapOutWidth;
        int scale = getOutWidth() * mBitmap.getWidth();
        bitmapOutWidth = scale / screenWidth;
        return bitmapOutWidth;
    }

    private int getBitmapOutHeight() {
        int bitmapOutHeight;
        int scale = getOutHeight() * mBitmap.getHeight();
        bitmapOutHeight = scale / screenHeight;
        return bitmapOutHeight;
    }

    private void getLeftTopDot() {
        if (endDot.getX() > startDot.getX()) {
            leftTopDot.setX(startDot.getX());
        } else {
            leftTopDot.setX(endDot.getX());
        }
        if (endDot.getY() > startDot.getY()) {
            leftTopDot.setY(startDot.getY());
        } else {
            leftTopDot.setY(endDot.getY());
        }
    }

    private void getRightBottomDot() {
        if (startDot.getX() > endDot.getX()) {
            rightBottomDot.setX(startDot.getX());
        } else {
            rightBottomDot.setX(endDot.getX());
        }
        if (startDot.getY() > endDot.getY()) {
            rightBottomDot.setY(startDot.getY());
        } else {
            rightBottomDot.setY(endDot.getY());
        }

    }

    public Dot getStartDot() {
        return startDot;
    }

    public void setStartDot(Dot startDot) {
        this.startDot = startDot;
    }

    public Dot getEndDot() {
        return endDot;
    }

    public void setEndDot(Dot endDot) {
        this.endDot = endDot;
    }

}
           

MainActivity中完成對點選滑動的監控,通過坐标點的方式獲得需要繪制的矩形位置和形狀。

public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnClickListener {
    private ScreenShotView screenShotView;
    private Bitmap bmp;
    private Bitmap ocrBitmap;
    private TextView certainBtn;
    private TextView cancelBtn;
    private TextView restartBtn;
    private int screenWidth;
    private int screenHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        screenShotView = (ScreenShotView) findViewById(R.id.screenShotView);
        cancelBtn = (TextView) findViewById(R.id.cancel_btn);
        cancelBtn.setOnClickListener(this);
        certainBtn = (TextView) findViewById(R.id.certain_btn);
        certainBtn.setOnClickListener(this);
        restartBtn = (TextView)findViewById(R.id.restart_btn);
        restartBtn.setOnClickListener(this);
        DisplayMetrics dm = new DisplayMetrics();
        //擷取螢幕資訊
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        screenWidth = dm.widthPixels;
        screenHeight = dm.heightPixels;
        Resources r = this.getResources();
        InputStream is = r.openRawResource(R.raw.bg);
        BitmapDrawable bmpDraw = new BitmapDrawable(is);
        bmp = bmpDraw.getBitmap();
        screenShotView.setBitmap(bmp, screenHeight, screenWidth);
        screenShotView.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                screenShotView.setStartDot(new Dot(motionEvent.getX(), motionEvent.getY()));
                break;
            case MotionEvent.ACTION_MOVE:
                screenShotView.setEndDot(new Dot(motionEvent.getX(), motionEvent.getY()));
                screenShotView.setBitmap(bmp, screenHeight, screenWidth);
                break;
            case MotionEvent.ACTION_UP:
                ocrBitmap = screenShotView.getBitmap();
                break;
        }
        return true;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.cancel_btn:
                finish();
                break;
            case R.id.certain_btn:
                if (ocrBitmap != null) {
                    BitmapUtil.getInstance().setImageBitmap(ocrBitmap);
                    Intent intent = new Intent(MainActivity.this, Main2Activity.class);
                    startActivity(intent);
                }else{
                    Toast.makeText(MainActivity.this,"請選擇截取區域",Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.restart_btn:
                screenShotView.restart();
                break;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        screenShotView.restart();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        screenShotView.restart();
    }
}
           

運用了單例模式用來存儲截取出來的bitmap,友善跳轉時調用,不需要自己再寫類,點選确定後,會将區域中的bitmap提取并存儲在單例中,在下一個頁面再調用。