1. 程式人生 > >Android圖片編輯,畫箭頭,畫圓,畫矩形(等)

Android圖片編輯,畫箭頭,畫圓,畫矩形(等)

最近再做聊天功能,遇到需求傳送圖片前編輯,查了好多沒見一個合適的,就自己寫了一個,希望對看到的人有所幫助(拋磚引玉),因為時間倉促請忽視編碼風格

-箭頭原理圖

這裡寫圖片描述

-效果圖

這裡寫圖片描述

-佈局程式碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:id="@+id/ll"
        android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv" android:scaleType="fitCenter"
android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1"
android:onClick="pics" android:text="相簿" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="photo" android:text="拍照" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_red_dark" android:onClick="red" android:text="紅" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_green_dark" android:onClick="green" android:text="綠" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:background="@android:color/holo_blue_dark" android:onClick="blue" android:text="藍" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1" android:onClick="small" android:text="細" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="zhong" android:text="中" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="big" android:text="粗" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="arrow" android:text="箭頭" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="fang" android:text="方" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="circle" android:text="圓" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="40dp"> <Button android:layout_weight="1" android:onClick="one" android:text="單步撤銷" android:layout_width="wrap_content" android:layout_height="match_parent"/> <Button android:layout_weight="1" android:onClick="all" android:text="全部撤銷" android:layout_width="wrap_content" android:layout_height="match_parent"/> </LinearLayout> </LinearLayout>

-Activity程式碼

public class MainActivity extends Activity {
    private static final int MY_REQUEST_CODE = 3022;
    private ArrayList<Shapes> shapes = new ArrayList<Shapes>();
    private ImageView iv;//展示圖片
    private Bitmap copyPic;//編輯圖片
    private Canvas canvas;//畫板
    private Paint paint;//畫筆
    private Matrix matrix;//矩陣
    private Bitmap srcPic;//原圖
    private int color = Color.BLACK;//畫筆顏色
    private int width = 0;//畫筆大小
    private int circle;//形狀
    /* 用來標識請求照相功能的activity */
    private static final int CAMERA_WITH_DATA = 3023;

    /* 用來標識請求galleryactivity */
    private static final int PHOTO_PICKED_WITH_DATA = 3021;

    private String photoPath, camera_path, tempPhotoPath;
    //圖片儲存路徑
    public static final String filePath = Environment.getExternalStorageDirectory() + "/PictureTest/";
    private int screenWidth;
    private File mCurrentPhotoFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv = (ImageView) findViewById(R.id.iv);
        DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        // 螢幕寬度(畫素)
        screenWidth = metric.widthPixels;
    }

    /**
     * 畫畫
     */
    private void drawPic() {
        srcPic = BitmapFactory.decodeFile(camera_path);
        copyPic = Bitmap.createBitmap(srcPic.getWidth(), srcPic.getHeight(),
                srcPic.getConfig());
        canvas = new Canvas(copyPic);
        paint = new Paint();
        paint.setAntiAlias(true);
        //繪製原圖
        drawOld();
        iv.setImageBitmap(copyPic);
        //觸控事件
        iv.setOnTouchListener(new View.OnTouchListener() {

            private float endY;
            private float endX;
            private float startX;
            private float startY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN:// 按下的事件型別
                        startX = event.getX();
                        startY = event.getY();
                        drawGuiji();
                        break;

                    case MotionEvent.ACTION_MOVE:// 移動的事件型別
                        // 得到結束位置的座標點
                        endX = event.getX();
                        endY = event.getY();
                        // 清除之前軌跡
                        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                        canvas.drawPaint(paint);
                        drawGuiji();
                        paint.setStrokeWidth(width);
                        paint.setColor(color);
                        if (circle == 1) {
                            paint.setStyle(Paint.Style.STROKE);//設定邊框
                            canvas.drawRect(startX, startY, endX, endY, paint);// 正方形
                        } else if (circle == 0) {
                            paint.setStyle(Paint.Style.STROKE);//設定邊框
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                canvas.drawOval(startX, startY, endX, endY, paint);
                            }
                        } else if (circle == 2) {
                            paint.setStyle(Paint.Style.FILL);//設定邊框
                            drawArrow(startX, startY, endX, endY, width, paint);
                        }
                        iv.setImageBitmap(copyPic);
                        break;

                    case MotionEvent.ACTION_UP:// 移動的事件型別
                        shapes.add(new Shapes(startX, startY, endX, endY, width, paint.getColor(), circle));//儲存歷史軌跡
                        break;
                }
                return true;
            }
        });
    }

    private void drawGuiji() {
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        drawOld();
        for (Shapes sp : shapes) {//畫歷史軌跡
            paint.setColor(sp.color);
            paint.setStrokeWidth(sp.width);
            if (sp.circle == 1) {
                paint.setStyle(Paint.Style.STROKE);//設定邊框
                canvas.drawRect(sp.startX, sp.startY, sp.endX, sp.endY, paint);// 正方形
            } else if (sp.circle == 0) {
                paint.setStyle(Paint.Style.STROKE);//設定邊框
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//api21之後的方法
                    canvas.drawOval(sp.startX, sp.startY, sp.endX, sp.endY, paint);//橢圓
                }
            } else if (sp.circle == 2) {
                paint.setStyle(Paint.Style.FILL);//設定邊框
                drawArrow(sp.startX, sp.startY, sp.endX, sp.endY, sp.width, paint);//箭頭
            }
        }
        iv.setImageBitmap(copyPic);
    }

    /**
     * 繪製底圖
     */
    private void drawOld() {
        // 給畫筆設定預設的顏色,在畫畫的過程中會使用原圖的顏色來畫畫
        paint.setColor(Color.BLACK);

        // 處理圖形
        matrix = new Matrix();
        // 5、使用畫筆在畫板上畫畫
        // 參看原圖畫畫
        // srcPic 原圖
        // matrix 表示圖形的矩陣物件,封裝了處理圖形的api
        // paint 畫畫時使用的畫筆
        canvas.drawBitmap(srcPic, matrix, paint);
    }

    /**
     * 紅色按鈕
     *
     * @param view
     */
    public void red(View view) {

        color = Color.RED;
    }

    /**
     * 綠色按鈕
     *
     * @param view
     */
    public void green(View view) {
        color = Color.GREEN;

    }

    /**
     * 藍色按鈕
     *
     * @param view
     */
    public void blue(View view) {
        color = Color.BLUE;
    }

    public void small(View view) {
        //改變刷子的寬度
        width = 1;
    }

    public void zhong(View view) {
        //改變刷子的寬度
        width = 5;
    }

    public void big(View view) {
        //改變刷子的寬度
        width = 10;
    }

    /**
     * 圓形
     *
     * @param view
     */
    public void circle(View view) {
        circle = 0;
    }

    /**
     * 矩形
     *
     * @param view
     */
    public void fang(View view) {
        circle = 1;
    }

    /**
     * 矩形
     *
     * @param view
     */
    public void arrow(View view) {
        circle = 2;
    }

    /**
     * 相簿
     *
     * @param view
     */
    public void pics(View view) {
        getPictureFromPhoto();
    }

    /**
     * 拍照
     *
     * @param view
     */
    public void photo(View view) {
        //申請照相機許可權
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.CAMERA},
                        MY_REQUEST_CODE);
            } else {
                getPictureFromCamera();
            }
        }
    }

    /**
     * 單步撤銷
     *
     * @param view
     */
    public void one(View view) {
        int size = shapes.size();
        if (size > 0) {
            shapes.remove(size - 1);
            drawGuiji();
        }
    }

    /**
     * 全部撤銷
     *
     * @param view
     */
    public void all(View view) {
        shapes.clear();
        drawGuiji();
    }

    /**
     * 畫箭頭
     *
     * @param sx
     * @param sy
     * @param ex
     * @param ey
     * @param paint
     */
    private void drawArrow(float sx, float sy, float ex, float ey, int width, Paint paint) {
        int size = 5;
        int count = 20;
        switch (width) {
            case 0:
                size = 5;
                count = 20;
                break;
            case 5:
                size = 8;
                count = 30;
                break;
            case 10:
                size = 11;
                count = 40;
                break;
        }
        float x = ex - sx;
        float y = ey - sy;
        double d = x * x + y * y;
        double r = Math.sqrt(d);
        float zx = (float) (ex - (count * x / r));
        float zy = (float) (ey - (count * y / r));
        float xz = zx - sx;
        float yz = zy - sy;
        double zd = xz * xz + yz * yz;
        double zr = Math.sqrt(zd);
        Path triangle = new Path();
        triangle.moveTo(sx, sy);
        triangle.lineTo((float) (zx + size * yz / zr), (float) (zy - size * xz / zr));
        triangle.lineTo((float) (zx + size * 2 * yz / zr), (float) (zy - size * 2 * xz / zr));
        triangle.lineTo(ex, ey);
        triangle.lineTo((float) (zx - size * 2 * yz / zr), (float) (zy + size * 2 * xz / zr));
        triangle.lineTo((float) (zx - size * yz / zr), (float) (zy + size * xz / zr));
        triangle.close();
        canvas.drawPath(triangle, paint);
    }

    /* 從相簿中獲取照片 */
    private void getPictureFromPhoto() {
        Intent openphotoIntent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(openphotoIntent, PHOTO_PICKED_WITH_DATA);
    }

    /* 從相機中獲取照片 */
    private void getPictureFromCamera() {
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");

        tempPhotoPath = filePath + getNewFileName()
                + ".png";

        mCurrentPhotoFile = new File(tempPhotoPath);

        if (!mCurrentPhotoFile.exists()) {
            try {
                mCurrentPhotoFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT,
                Uri.fromFile(mCurrentPhotoFile));
        startActivityForResult(intent, CAMERA_WITH_DATA);
    }

    /**
     * 根據時間戳生成檔名
     *
     * @return
     */
    public static String getNewFileName() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        Date curDate = new Date(System.currentTimeMillis());

        return formatter.format(curDate);
    }

    /**
     * 將生成的圖片儲存到記憶體中
     *
     * @param bitmap
     * @param name
     * @return
     */
    public String saveBitmap(Bitmap bitmap, String name) {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            File dir = new File(filePath);
            if (!dir.exists())
                dir.mkdir();
            File file = new File(filePath + name + ".jpg");
            FileOutputStream out;
            try {
                out = new FileOutputStream(file);
                if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
                    out.flush();
                    out.close();
                }
                return file.getAbsolutePath();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根據路徑獲取圖片並且壓縮,適應view
     *
     * @param filePath    圖片路徑
     * @param contentView 適應的view
     * @return Bitmap 壓縮後的圖片
     */
    public Bitmap compressionFiller(String filePath, View contentView) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, opt);
        int layoutHeight = contentView.getHeight();
        float scale = 0f;
        int bitmapHeight = bitmap.getHeight();
        int bitmapWidth = bitmap.getWidth();
        scale = bitmapHeight > bitmapWidth
                ? layoutHeight / (bitmapHeight * 1f)
                : screenWidth / (bitmapWidth * 1f);
        Bitmap resizeBmp;
        if (scale != 0) {
            int bitmapheight = bitmap.getHeight();
            int bitmapwidth = bitmap.getWidth();
            Matrix matrix = new Matrix();
            matrix.postScale(scale, scale); // 長和寬放大縮小的比例
            resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmapwidth,
                    bitmapheight, matrix, true);
        } else {
            resizeBmp = bitmap;
        }
        return resizeBmp;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode != RESULT_OK) {
            return;
        }
        switch (requestCode) {
            case CAMERA_WITH_DATA:
                photoPath = tempPhotoPath;
                break;
            case PHOTO_PICKED_WITH_DATA:
                Uri selectedImage = data.getData();
                String[] filePathColumns = {MediaStore.Images.Media.DATA};
                Cursor c = getContentResolver().query(selectedImage, filePathColumns, null, null, null);
                int columnIndex = c.getColumnIndex(filePathColumns[0]);
                c.moveToFirst();
                photoPath = c.getString(columnIndex);
                c.close();
                break;
        }
        shapes.clear();
        Bitmap bitmap = compressionFiller(photoPath, iv);
        camera_path = saveBitmap(bitmap, "saveTemp");
        drawPic();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MY_REQUEST_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 呼叫相機
                getPictureFromCamera();
            } else {
                //沒有許可權
                Toast.makeText(MainActivity.this, "沒有許可權", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

-儲存軌跡的實體類Shapes

class Shapes {
    public float startX, startY, endX, endY ;
    public int width,color,circle;

    public Shapes(float startX, float startY, float endX, float endY, int width, int color , int circle) {
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        this.width = width;
        this.color = color;
        this.circle = circle;
    }
}