1. 程式人生 > >Android拍照+擷取+相簿獲取擷取圖片+水印功能【完整】

Android拍照+擷取+相簿獲取擷取圖片+水印功能【完整】

1  拍照擷取

原理就是通過intent呼叫系統的相機,拍完照後再回調進行操作,成功獲取到拍完照的圖片根據uri呼叫系統的裁剪頁面,裁剪完也是在回撥中進行處理,顯示在頁面的imageview中。

2  相簿選取圖片擷取

原理也是通過intent開啟系統的圖片,使用者選擇完成以後在回撥中根據圖片的uri呼叫系統的裁剪頁面,裁剪後在回撥中進行處理並顯示在本頁面的控制元件中。

3 下面進行程式碼展示

佳姝1:在Xml佈局檔案中

<LinearLayout
    android:id="@+id/main_ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <!--這個是自定義類CircleImageView它繼承於ImageView-->
    <com.example.dashixu_day2_a.CircleImageView
        android:id="@+id/main_icon"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_marginTop="20dp"
        android:src="@mipmap/ic_launcher"/>

    <Button
        android:id="@+id/main_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:text="更換頭像"/>
</LinearLayout>

佳姝2:在MainActivity中

public class MainActivity extends AppCompatActivity {

    //定義變數值
    private CircleImageView main_icon;
    private Button main_btn;
    private PopWindow mpopWindow;
    private static final int REQUEST_IMAGE_GET = 0;
    private static final int REQUEST_IMAGE_CAPTURE = 1;
    private static final int REQUEST_SMALL_IMAGE_CUTTING = 2;
    private static final int REQUEST_BIG_IMAGE_CUTTING = 3;
    private static final String IMAGE_FILE_NAME = "icon.jpg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控制元件及在拍照和相簿選擇的按鈕中處理點選事件
        initView();
    }
    
    //繪製水印監聽關鍵程式碼(在Fragment使用同理)
    private Bitmap createWatermark(Bitmap bitmap, String mark) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bmp);
        Paint p = new Paint();
        // 水印顏色
        p.setColor(Color.parseColor("#c5576370"));
        // 水印字型大小
        p.setTextSize(40);
        //抗鋸齒
        p.setAntiAlias(true);
        //繪製圖像
        canvas.drawBitmap(bitmap, 0, 0, p);
        //繪製文字
        canvas.drawText(mark, 0, h / 2, p);
        canvas.save(Canvas.ALL_SAVE_FLAG);
        canvas.restore();
        return bmp;
    }

    private void initView() {
        main_icon = (CircleImageView) findViewById(R.id.main_icon);
        main_btn = (Button) findViewById(R.id.main_btn);

        main_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mpopWindow = new PopWindow(MainActivity.this, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //相簿處理
                        mpopWindow.dismiss();
                        Intent intent = new Intent(Intent.ACTION_PICK);
                        intent.setType("image/*");
                       // 判斷系統中是否有處理該 Intent 的 Activity
                        if (intent.resolveActivity(getPackageManager()) != null) {
                            startActivityForResult(intent, REQUEST_IMAGE_GET);
                        } else {
                            Toast.makeText(MainActivity.this, "未找到圖片檢視器", Toast.LENGTH_SHORT).show();
                        }
                    }

                }, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //拍照處理
                        mpopWindow.dismiss();
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT,
                           Uri.fromFile(new File(Environment.getExternalStorageDirectory(), IMAGE_FILE_NAME)));                         
                        startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
                    }

                });
                View rootView = LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_main, null);
                mpopWindow.showAtLocation(rootView,
                        Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
            }
        });
    }

    //處理點選回撥的監聽事件
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 回撥成功
        if (resultCode == RESULT_OK) {
            switch (requestCode) {

                // 小圖切割
                case REQUEST_SMALL_IMAGE_CUTTING:
                    if (data != null) {
                        setPicToView(data);
                    }
                    break;

                // 相簿選取
                case REQUEST_IMAGE_GET:
                    try {
                        startSmallPhotoZoom(data.getData());
                    } catch (NullPointerException e) {
                        e.printStackTrace();
                    }
                    break;
                // 拍照
                case REQUEST_IMAGE_CAPTURE:
                    File temp = new File(Environment.getExternalStorageDirectory() + "/" + IMAGE_FILE_NAME);
                    startSmallPhotoZoom(Uri.fromFile(temp));
                    break;
            }
        }
    }
    
    //裁剪圖片的方法
    private void startSmallPhotoZoom(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1); // 裁剪框比例
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300); // 輸出圖片大小
        intent.putExtra("outputY", 300);
        intent.putExtra("scale", true);
        intent.putExtra("return-data", true);
        startActivityForResult(intent, REQUEST_SMALL_IMAGE_CUTTING);
    }
    
   //顯示裁剪後的圖片
    private void setPicToView(Intent data) {
        Bundle extras = data.getExtras();
        if (extras != null) {
            Bitmap photo = extras.getParcelable("data"); // 直接獲得記憶體中儲存的 bitmap
            // 建立 smallIcon 資料夾
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                String storage = Environment.getExternalStorageDirectory().getPath();
                File dirFile = new File(storage + "/smallIcon");
                if (!dirFile.exists()) {
                    if (!dirFile.mkdirs()) {
                        Log.e("TAG", "資料夾建立失敗");
                    } else {
                        Log.e("TAG", "資料夾建立成功");
                    }
                }
                File file = new File(dirFile, System.currentTimeMillis() + ".jpg");
                // 儲存圖片
                FileOutputStream outputStream = null;
                try {
                    outputStream = new FileOutputStream(file);
                    photo.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                    outputStream.flush();
                    outputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // 在檢視中顯示圖片(原圖顯示)
            // main_icon.setImageBitmap(photo);

            // 在檢視中顯示圖片(水印顯示)
            Bitmap bitmap = createWatermark(photo, "來自四川的小仙女");
            main_icon.setImageBitmap(bitmap);
        }
    }

 佳姝3:自定義類PopoWindow繼承PopupWindow

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.PopupWindow;

public class PopWindow extends PopupWindow {
    private View mView; // PopupWindow 選單佈局
    private Context mContext;
    private View.OnClickListener mSelectListener; // 相簿選取的點選監聽器
    private View.OnClickListener mCaptureListener; // 拍照的點選監聽器
    private Button icon_btn_camera;
    private Button icon_btn_select;
    private Button icon_btn_cancel;


    public PopWindow(Activity context, View.OnClickListener selectListener, View.OnClickListener captureListener) {
        super(context);
        this.mContext = context;
        this.mSelectListener = selectListener;
        this.mCaptureListener = captureListener;
        initView();
    }

    private void initView() {
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
        mView = inflater.inflate(R.layout.layout_pop_xml, null);
        icon_btn_camera = (Button) mView.findViewById(R.id.icon_btn_camera);
        icon_btn_select = (Button) mView.findViewById(R.id.icon_btn_select);
        icon_btn_cancel = (Button) mView.findViewById(R.id.icon_btn_cancel);
        icon_btn_camera.setOnClickListener(mCaptureListener);
        icon_btn_select.setOnClickListener(mSelectListener);
        icon_btn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        this.setContentView(mView);

        // 設定動畫
        this.setAnimationStyle(R.style.popwindow_anim_style);
        this.setWidth(WindowManager.LayoutParams.MATCH_PARENT);
        this.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
        // 設定可觸
        this.setFocusable(true);
        ColorDrawable dw = new ColorDrawable(0x0000000);
        this.setBackgroundDrawable(dw);
        // 單擊彈出窗以外處 關閉彈出窗
        mView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int height = mView.findViewById(R.id.ll_pop).getTop();
                int y = (int) event.getY();
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    if (y < height) {
                        dismiss();
                    }
                }
                return true;
            }
        });
    }
} 

 佳姝4:在PupupWindow佈局中layout_pop_xml.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="#66000000">
    <LinearLayout
        android:id="@+id/ll_pop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:orientation="vertical"
        android:layout_alignParentBottom="true">
        <Button
            android:id="@+id/icon_btn_camera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_item2"
            android:textColor="@color/colorMainGreen"
            android:text="拍照"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#fff"/>
        <Button
            android:id="@+id/icon_btn_select"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_item3"
            android:textColor="@color/colorMainGreen"
            android:text="從相簿選擇"/>
        <Button
            android:id="@+id/icon_btn_cancel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="15dp"
            android:background="@drawable/shape_item1"
            android:textColor="@color/colorMainGreen"
            android:text="取消"/>
    </LinearLayout>
</RelativeLayout>

 @drawable/shape_item1:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@android:color/white"/>
    <corners android:radius="10dp"/>
    <stroke android:width="0dp" android:color="@android:color/white"></stroke>

</shape>

 @drawable/shape_item2:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@android:color/white" />
    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp" />/>
    <stroke
        android:width="0dp"
        android:color="@android:color/white"></stroke>

</shape>

 @drawable/shape_item3:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@android:color/white" />
    <corners
        android:bottomLeftRadius="10dp"
        android:bottomRightRadius="10dp"
        android:topLeftRadius="0dp"
        android:topRightRadius="0dp" />/>
    <stroke
        android:width="0dp"
        android:color="@android:color/white"></stroke>

</shape>

佳姝5:自定義類CircleImageView繼承ImageView

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;

@SuppressLint("AppCompatCustomView")
public class CircleImageView extends ImageView {

    private Paint mpaint; //畫筆
    private int mreadius; //圓形圖片的半徑
    private float mscale; //圖片的縮放比例

    public CircleImageView(Context context) {
        super(context);
    }

    public CircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CircleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //圓形圖片的半徑,寬高保持一致
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        int size=Math.min(getMeasuredWidth(),getMeasuredHeight());
        mreadius=size/2;
        setMeasuredDimension(size,size);
    }
    //畫筆
    @Override
    protected void onDraw(Canvas canvas) {
        mpaint=new Paint();
        Bitmap bitmap=drawableToBitmap(getDrawable());
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mscale=(mreadius * 2.0f)/Math.min(bitmap.getHeight(),bitmap.getWidth());

        Matrix matrix = new Matrix();
        matrix.setScale(mscale,mscale);
        bitmapShader.setLocalMatrix(matrix);

        mpaint.setShader(bitmapShader);

        canvas.drawCircle(mreadius,mreadius,mreadius,mpaint);

    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }
}

 佳姝6:res/anim/popup_gone.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="200"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

 res/anim/popup_show.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>

 佳姝7:values/colors中

<color name="colorMainGreen">#40cab3</color>

 values/styles中

<style name="popwindow_anim_style">
    <item name="android:windowEnterAnimation">@anim/popup_show</item>
    <item name="android:windowExitAnimation">@anim/popup_gone</item>
</style>

 程式碼挺全的,這也方便我做筆記嘿嘿,雖然過程比較簡單,但可能會有一些判斷的地方沒有處理,如果有不對的地方希望有高手可以幫忙改進,謝謝~~