1. 程式人生 > >android 呼叫系統相機進行拍照及照片的裁切

android 呼叫系統相機進行拍照及照片的裁切

呼叫系統相機進行拍照是android開發中常用到的功能,例如:拍照了直接發朋友圈等。還有常用的要進行圖片的裁剪,例如:上傳自己的頭像等。你又不能拍完照直接上傳,然後在讀取截止中間的,這樣不一定是使用者想要的部分。所以,我們通常是讓使用者自己按照我們的比例,來進行裁剪。這就要用到裁剪技術了。

今天,就是要說一下呼叫系統的相機的一些常用的技術。

一、呼叫系統的相機

//呼叫系統相機
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent,SMALL_CAMERA)

呼叫這個程式碼之後,系統就會自動呼叫在清單檔案裡配置

(如下面的程式碼)了預設相機的app,一般的手機都會有一個系統帶的預設相機,有的手機也安裝了其他相機,如果多個情況向系統會用選擇一個相機。

清單了的配置如下:

<intent-filter >
    <action android:name="android.media.action.IMAGE_CAPTURE"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

二、獲取拍照的圖片通常有兩種方式:

1.直接獲取,不需要存到本地

 //如果圖太大會造成記憶體溢位(OOM),取出的圖片系統會預設壓縮
Bundle bundle = data.getExtras(); Bitmap bitmap = (Bitmap) bundle.get("data"); iv.setImageBitmap(bitmap);
2.先把圖片存到本地,然後可以獲取到原圖,自己也可以控制壓縮多少,一般的專案都用這種方式
btn_original.setOnClickListener(new View.OnClickListener() {
    @Override
public void onClick(View v) {
        //先驗證手機是否有sdcard
String status= Environment.getExternalStorageState
(); if(!status.equals(Environment.MEDIA_MOUNTED)) { Toast.makeText(getApplicationContext(),"你的sd卡不可用。",Toast.LENGTH_SHORT).show(); return; } filePath=Environment.getExternalStorageDirectory().getPath()+"/temp/"; File fileDir=new File(filePath); if(!fileDir.exists()) { fileDir.mkdirs(); } file=new File(filePath,temp); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } Uri uri = Uri.fromFile(file); //呼叫系統相機 Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT,uri); startActivityForResult(intent,ORIGINAL_CAMERA); } });
onActivityResult裡的程式碼是:
    //這種方法是通過記憶體卡的路徑進行讀取圖片,獲取的是原圖
FileInputStream fis = null;
    try {
        //把圖片轉化為位元組流
fis = new FileInputStream(file);
//把流轉化圖片
Bitmap bitmapOriginal = BitmapFactory.decodeStream(fis);
iv.setImageBitmap(bitmapOriginal);
} catch (FileNotFoundException e) {
        e.printStackTrace();
}finally{
        try {
            if(fis!=null)
            fis.close();//關閉流
} catch (IOException e) {
            e.printStackTrace();
}
    }

三、把拍照的照片根據比例或大小進行裁切
btn_square.setOnClickListener(new View.OnClickListener() {
    @Override
public void onClick(View v) {
        //先驗證手機是否有sdcard
String status= Environment.getExternalStorageState();
        if(!status.equals(Environment.MEDIA_MOUNTED))
        {
            Toast.makeText(getApplicationContext(),"你的sd卡不可用。",Toast.LENGTH_SHORT).show();
            return;
}
        filePath=Environment.getExternalStorageDirectory().getPath()+"/temp/";
File fileDir=new File(filePath);
        if(!fileDir.exists()) {
            fileDir.mkdirs();
}

        file=new File(filePath,temp);
        if (!file.exists()) {
            try {
                file.createNewFile();
} catch (IOException e) {
                e.printStackTrace();
}
        }
        Uri uri = Uri.fromFile(file);
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
startActivityForResult(intent,SQUARE_CAMERA_PRE);
}
});

onActivityResult裡的程式碼是:

    //跳到擷取圖片
case SQUARE_CAMERA_PRE:
    fileTemp=new File(filePath,picTemp);
    if (!fileTemp.exists()) {
        try {
            file.createNewFile();
} catch (IOException e) {
            e.printStackTrace();
}
    }
    Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(Uri.fromFile(file), "image/*");//要裁切的圖片源
intent.putExtra("crop", "true");//是否要裁切
    // aspectX aspectY 是裁剪框寬高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);// 去黑邊
    // outputX outputY 是裁剪後生成圖片的寬高
    // intent.putExtra("outputX", 800);
    // intent.putExtra("outputY", 800);
intent.putExtra("scaleUpIfNeeded", true);// 去黑邊
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//返回圖片的格式
intent.putExtra("noFaceDetection", true);
// return-data為true時,會直接返回bitmap資料,推薦下面為false時的方式,同上面的
    // return-data為false時,不會返回bitmap,但需要指定一個MediaStore.EXTRA_OUTPUT儲存圖片uri
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(fileTemp));
startActivityForResult(intent, SQUARE_CAMERA);
    break;
//獲取擷取的圖片
case SQUARE_CAMERA:
    //這種方法是通過記憶體卡的路徑進行讀取圖片,獲取的是原圖
FileInputStream fisSquare = null;
    try {
        //把圖片轉化為位元組流
fisSquare = new FileInputStream(fileTemp);
//把流轉化圖片
Bitmap bitmapOriginal = BitmapFactory.decodeStream(fisSquare);
iv.setImageBitmap(bitmapOriginal);
} catch (FileNotFoundException e) {
        e.printStackTrace();
}finally{
        try {
            if(fisSquare!=null)
            fisSquare.close();//關閉流
} catch (IOException e) {
            e.printStackTrace();
}
    }
    break;

不要忘了加上一個訪問sd許可權:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

最後放上activity的程式碼:

package com.sunshanglei.camera.system;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
 * use 呼叫系統相機
 * author 孫尚磊
 * create time 2017-4-22
 */
public class MainActivity extends AppCompatActivity {
    private Button btn_original,btn_small,btn_square;
    private static final int SMALL_CAMERA=1;//壓縮圖請求碼
private static final int ORIGINAL_CAMERA=2;//原圖請求碼
private static final int SQUARE_CAMERA_PRE=3;//跳到正方形請求碼
private static final int SQUARE_CAMERA=4;//正方形請求碼
private ImageView iv;
    private String pathTemp,filePath;
    private File file,fileTemp;
    private String temp="temp.png",picTemp="picTemp.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_original= (Button) findViewById(R.id.btn_original);
btn_small= (Button) findViewById(R.id.btn_small);
btn_square= (Button) findViewById(R.id.btn_square);
iv= (ImageView) findViewById(R.id.iv);
btn_original.setOnClickListener(new View.OnClickListener() {
            @Override
public void onClick(View v) {
                //先驗證手機是否有sdcard
String status= Environment.getExternalStorageState();
                if(!status.equals(Environment.MEDIA_MOUNTED))
                {
                    Toast.makeText(getApplicationContext(),"你的sd卡不可用。",Toast.LENGTH_SHORT).show();
                    return;
}
                filePath=Environment.getExternalStorageDirectory().getPath()+"/temp/";
File fileDir=new File(filePath);
                if(!fileDir.exists()) {
                    fileDir.mkdirs();
}

                file=new File(filePath,temp);
                if (!file.exists()) {
                    try {
                        file.createNewFile();
} catch (IOException e) {
                        e.printStackTrace();
}
                }
                Uri uri = Uri.fromFile(file);
//呼叫系統相機
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
startActivityForResult(intent,ORIGINAL_CAMERA);
}
        });
btn_small.setOnClickListener(new View.OnClickListener() {
            @Override
public void onClick(View v) {
                //呼叫系統相機
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent,SMALL_CAMERA);
}
        });
btn_square.setOnClickListener(new View.OnClickListener() {
            @Override
public void onClick(View v) {
                //先驗證手機是否有sdcard
String status= Environment.getExternalStorageState();
                if(!status.equals(Environment.MEDIA_MOUNTED))
                {
                    Toast.makeText(getApplicationContext(),"你的sd卡不可用。",Toast.LENGTH_SHORT).show();
                    return;
}
                filePath=Environment.getExternalStorageDirectory().getPath()+"/temp/";
File fileDir=new File(filePath);
                if(!fileDir.exists()) {
                    fileDir.mkdirs();
}

                file=new File(filePath,temp);
                if (!file.exists()) {
                    try {
                        file.createNewFile();
} catch (IOException e) {
                        e.printStackTrace();
}
                }
                Uri uri = Uri.fromFile(file);
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
startActivityForResult(intent,SQUARE_CAMERA_PRE);
}
        });
}


    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode==RESULT_OK){
            switch (requestCode){
                //返回壓縮的圖片
case SMALL_CAMERA:
                    if(data==null){
                        return;
}
                     //如果圖太大會造成記憶體溢位(OOM),取出的圖片系統會預設壓縮
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
iv.setImageBitmap(bitmap);
                    break;
//返回原圖
case ORIGINAL_CAMERA:
                    //這種方法是通過記憶體卡的路徑進行讀取圖片,獲取的是原圖
FileInputStream fis = null;
                    try {
                        //把圖片轉化為位元組流
fis = new FileInputStream(file);
//把流轉化圖片
Bitmap bitmapOriginal = BitmapFactory.decodeStream(fis);
iv.setImageBitmap(bitmapOriginal);
} catch (FileNotFoundException e) {
                        e.printStackTrace();
}finally{
                        try {
                            if(fis!=null)
                            fis.close();//關閉流
} catch (IOException e) {
                            e.printStackTrace();
}
                    }
                    break;
//跳到擷取圖片
case SQUARE_CAMERA_PRE:
                    fileTemp=new File(filePath,picTemp);
                    if (!fileTemp.exists()) {
                        try {
                            file.createNewFile();
} catch (IOException e) {
                            e.printStackTrace();
}
                    }
                    Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(Uri.fromFile(file), "image/*");//要裁切的圖片源
intent.putExtra("crop", "true");//是否要裁切
                    // aspectX aspectY 是裁剪框寬高的比例
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("scale", true);// 去黑邊
                    // outputX outputY 是裁剪後生成圖片的寬高
                    // intent.putExtra("outputX", 800);
                    // intent.putExtra("outputY", 800);
intent.putExtra("scaleUpIfNeeded", true);// 去黑邊
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//返回圖片的格式
intent.putExtra("noFaceDetection", true);
// return-data為true時,會直接返回bitmap資料,推薦下面為false時的方式,同上面的
                    // return-data為false時,不會返回bitmap,但需要指定一個MediaStore.EXTRA_OUTPUT儲存圖片uri
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(fileTemp));
startActivityForResult(intent, SQUARE_CAMERA);
                    break;
//獲取擷取的圖片
case SQUARE_CAMERA:
                    //這種方法是通過記憶體卡的路徑進行讀取圖片,獲取的是原圖
FileInputStream fisSquare = null;
                    try {
                        //把圖片轉化為位元組流
fisSquare = new FileInputStream(fileTemp);
//把流轉化圖片
Bitmap bitmapOriginal = BitmapFactory.decodeStream(fisSquare);
iv.setImageBitmap(bitmapOriginal);
} catch (FileNotFoundException e) {
                        e.printStackTrace();
}finally{
                        try {
                            if(fisSquare!=null)
                            fisSquare.close();//關閉流
} catch (IOException e) {
                            e.printStackTrace();
}
                    }
                    break;
}
        }

    }


}

佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
    <Button
android:id="@+id/btn_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="呼叫系統相機_獲取壓縮圖"/>
    <Button
android:id="@+id/btn_original"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="呼叫系統相機_獲取原圖"/>
    <Button
android:id="@+id/btn_square"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="呼叫系統相機_裁切寬高1:1"/>
    <ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="wrap_content" />
</LinearLayout>

效果圖: