1. 程式人生 > >Android呼叫系統圖庫和相機獲取圖片並裁剪

Android呼叫系統圖庫和相機獲取圖片並裁剪

最近用到從系統圖庫和相機獲取圖片並裁剪當頭像,根據郭霖大神的第一行程式碼呼叫相機和圖冊,來進行擴充套件和總結。

1、獲取許可權

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

2、點選按鈕來提示選擇相簿還是相機

private String[]mCustomItems=new String[]{"本地相簿","相機拍照"};

//顯示選擇相機,相簿對話方塊

    private void showDialogCustom(){
        //建立對話方塊
        AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("請選擇:");
        builder.setItems(mCustomItems, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if(which==0) {
                    //相簿

                }else if(which==1){
                    //照相機
                    
                }
            }
        });
        builder.create().show();
    }

3、相機拍照

//拍照後照片的Uri

private Uri imageUri;

//返回碼,相機
private static final int RESULT_CAMERA=200;

                    //先驗證手機是否有sdcard 
                    String status=Environment.getExternalStorageState();
                    if(status.equals(Environment.MEDIA_MOUNTED))
                    {
                        //建立File物件,用於儲存拍照後的照片
                        File outputImage=new File(getExternalCacheDir(),"out_image.jpg");//SD卡的應用關聯快取目錄
                        try {
                            if(outputImage.exists()){
                                outputImage.delete();
                            }
                            outputImage.createNewFile();
                            Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                imageUri=FileProvider.getUriForFile(MainActivity.this,
                                        "com.hanrui.android.fileprovider",outputImage);//新增這一句表示對目標應用臨時授權該Uri所代表的檔案
                            }else{
                                imageUri=Uri.fromFile(outputImage);
                            }
                            //啟動相機程式
                            intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
                            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                            startActivityForResult(intent,RESULT_CAMERA);
                        } catch (Exception e) {
                            // TODO Auto-generated catch block 
                            Toast.makeText(MainActivity.this, "沒有找到儲存目錄",Toast.LENGTH_LONG).show();
                        }
                    }else{
                        Toast.makeText(MainActivity.this, "沒有儲存卡",Toast.LENGTH_LONG).show();
                    }
                    dialog.dismiss();

應用關聯快取目錄指SD卡中專門用於存放當前應用快取資料的位置,呼叫getExternalCacheDir()方法可以得到這個目錄,具體路徑是/sdcard/Android/data/<package name>/cache。為什麼要存放這個目錄呢?因為從Android6.0系統開始,讀寫SD卡被列為危險許可權,若將圖片存放在SD卡的任何其他目錄,都要進行許可權處理才行,使用應用關聯目錄可以跳過這一步。

接著進行一個判斷,若裝置版本低於Android7.0,就呼叫Uri的fromFile()方法將File物件轉換成Uri物件,這個Uri物件標識圖片的本地真實路徑。否則,就呼叫FileProvider的getUriForFile()方法將File物件轉換成一個封裝過的Uri物件。getUriForFile()方法接收3個引數,第一個要求傳入Context物件,第二個可以是任意字串,第三個是我們剛剛建立的File物件。進行這樣一層轉換,因為從Android7.0開始,直接使用本地真實路徑的Uri被認為是不安全的,會丟擲一個FileUriExposedException異常。而FileProvider則是一種特殊的內容提供器,它使用了和內容提供器類似的機制來對資料進行保護,可以選擇性的將封裝過的Uri共享給外部,從而提高了應用的安全性。

在AndroidManifest.xml中對內容提供器進行註冊

<manifest

...>

<application

.....>

....

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
    <meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
    </meta-data>
</provider>

</application>

</manifest>

android:name屬性值是固定的,android:authorities屬性的值必須要和剛才FileProvider.getUriForFile()方法中的第二個引數一致。另外,在<provider>標籤的內部使用<mata-data>來指定Uri的共享路徑,並引用了一個@xml/file_paths資源,下面建立這個資源:

在res目錄下建立一個xml目錄,在xml目錄下建立一個file_paths.xml檔案,內容如下:

<?xml version="1.0" encoding="utf-8"?>
<path xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path=""/>
</path>

external-path就是用來指定Uri共享的,name屬性的值可以隨便填,path屬性的值表示共享的具體路徑,設定空值表示將整個SD卡進行共享。當然也可以僅共享我們存放照片的路徑。

回撥方法對圖片進行裁剪

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
 case RESULT_CAMERA:
                if(resultCode==RESULT_OK){
                    //進行裁剪
                    startPhotoZoom(imageUri);
                }    
}
}


4、呼叫相簿

//返回碼,本地相簿
private static final int RESULT_IMAGE=100;

//相簿
                    if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!=
                            PackageManager.PERMISSION_GRANTED){
                        ActivityCompat.requestPermissions(MainActivity.this,new String[]{
                                Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
                    }else{
                        openAlbum();
                    }
開啟相簿
private void openAlbum(){
        Intent intent=new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,RESULT_IMAGE);//開啟相簿
    }

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    openAlbum();
                }else{
                    Toast.makeText(this,"你沒有開啟許可權",Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

呼叫相簿時先進行一個執行時許可權處理,動態申請WRITE_EXTERNAL_STORAGE這個危險許可權。因為相簿照片存放在SD卡中,從SD卡讀取照片需要申請這個許可權。WRITE_EXTERNAL_STORAGE表示同時授予程式對SD卡讀和寫的能力。

回撥方法

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
case RESULT_IMAGE:
                if(resultCode==RESULT_OK&&data!=null){
                    //判斷手機系統版本號
                    if(Build.VERSION.SDK_INT>=19){
                        //4.4及以上系統使用這個方法處理圖片
                        handlerImageOnKitKat(data);
                    }else{
                        //4.4以下系統使用這個方法處理圖片
                        handlerImageBeforeKitKat(data);
                    }
                }
                break;
}

Android系統從4.4版本開始,選取相簿中圖片不再返回圖片真實的Uri了,而是一個封裝過的Uri,隱因此4.4版本以上要對這個Uri進行解析。
private void handlerImageOnKitKat(Intent data){
        String imagePath=null;
        Uri uri=data.getData();
        if(DocumentsContract.isDocumentUri(this,uri)){
            //如果是document型別的Uri,則通過document id處理
            String docId=DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id=docId.split(":")[1];//解析出數字格式的id
                String selection=MediaStore.Images.Media._ID+"="+id;
                imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection);
            }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
                Uri contentUri= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
                imagePath=getImagePath(contentUri,null);
            }
        }else if("content".equalsIgnoreCase(uri.getScheme())){
            //如果是content型別的URI,則使用普通方式處理
            imagePath=getImagePath(uri,null);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
            //如果是file型別的Uri,直接獲取圖片路徑即可
            imagePath=uri.getPath();
        }
        startPhotoZoom(uri);
    }
private String getImagePath(Uri uri, String selection) {
        String path = null;
        //通過Uri和selection來獲取真實的圖片路徑
        Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        return path;
    }


如果返回的Uri是document型別的話,就取出doculent_id進行處理,若不是,就是用普通方法處理。另外,若Uri的authority是media格式的話,documentid還需要進行一次解析,要通過字串分割的方式取出後半部分才能得到真正的數字id。取出的id用於構建新的Uri和條件語句,然後把這些值作為引數傳入到getImagePath()方法中,就可以獲取圖片的真實路徑了。
private void handlerImageBeforeKitKat(Intent data){
        Uri cropUri=data.getData();
        startPhotoZoom(cropUri);
    }
直接取出Uri進行裁剪。

5、圖片裁剪的方法

private static final int CROP_PICTURE = 2;//裁剪後圖片返回碼
//裁剪圖片存放地址的Uri
private Uri cropImageUri;

public void startPhotoZoom(Uri uri) {
        File CropPhoto=new File(getExternalCacheDir(),"crop_image.jpg");
        try{
            if(CropPhoto.exists()){
                CropPhoto.delete();
            }
            CropPhoto.createNewFile();
        }catch(IOException e){
            e.printStackTrace();
        }
        cropImageUri=Uri.fromFile(CropPhoto);
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //新增這一句表示對目標應用臨時授權該Uri所代表的檔案
        }
        // 下面這個crop=true是設定在開啟的Intent中設定顯示的VIEW可裁剪
        intent.putExtra("crop", "true");
        intent.putExtra("scale", true);

        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);

        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);

        intent.putExtra("return-data", false);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri); 
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true); // no face detection
        startActivityForResult(intent, CROP_PICTURE);
    }

附加選項 資料型別 描述
crop String 傳送裁剪訊號
aspectX int X方向上的比例
aspectY int Y方向上的比例
outputX int 裁剪區的寬
outputY int 裁剪區的高
scale boolean 是否保留比例
return-data boolean 是否將資料保留在Bitmap中返回
data Parcelable 相應的Bitmap資料
circleCrop String 圓形裁剪區域?
MediaStore.EXTRA_OUTPUT ("output") URI 將URI指向相應的file:///...

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
case CROP_PICTURE: // 取得裁剪後的圖片
                if(resultCode==RESULT_OK) {
                    try {
                        Bitmap headShot = BitmapFactory.decodeStream(getContentResolver().openInputStream(cropImageUri));
                       .....
} catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }

                break;
            default:
                break;
        }
    }


到此,獲得裁剪圖片結束。

還有一個問題:三星手機自帶的相機會轉屏而引起當前activity銷燬,重建。

我們可以在當前Activity的manifest檔案裡新增這一行程式碼:

android:configChanges="orientation|keyboardHidden| screenSize"

關鍵就是新增screenSize

然後在Activityl裡新增以下程式碼:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }
好了,到此結束。

相關推薦

Android呼叫系統相機獲取圖片裁剪

最近用到從系統圖庫和相機獲取圖片並裁剪當頭像,根據郭霖大神的第一行程式碼呼叫相機和圖冊,來進行擴充套件和總結。 1、獲取許可權 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORA

Android呼叫系統

//呼叫系統圖庫 Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startAc

android 呼叫系統檢視指定路徑的圖片

//使用Intent Intent intent = new Intent(Intent.ACTION_VIEW); //Uri mUri = Uri.parse("file://" + picFi

安卓呼叫手機的相簿與相機獲取圖片適配到控制元件

在之前做專案的時候用到了調取系統相機的工能所以在這裡做了一下總結,這是本人第一次寫東西有很多不懂得地方或者有解釋不明白的地方 希望大家前來指正不多說直接上程式碼: 首先是佈局頁面 <LinearLayout xmlns:android="http://schemas

Android呼叫系統獲取影象裁剪,安卓 4.4可用

3.區分Android系統版本,解析uri 若系統版本低於4.4,uri=data.getData()直接可用,4.4及以上要根據uri中的id來查詢檔案路徑,然後自己構造新的uri 下圖為安卓4.4呼叫相簿訪問圖片的路徑,預設返回的字首為content:// ,最後的3A741是圖片id 根據id我們轉

Android呼叫系統的打電話發簡訊功能

一、打電話      1、新增打電話的許可權在manifast檔案中。            <uses-permission android:name="android.permission.CALL_PHONE"/>      2、使用Uri.parse(S

android開啟系統終極適配

android中呼叫系統圖庫本來是一個很基本的東西,幾乎每個app都用的到(最基本的更換使用者頭像),網上的相關 容很多,本來找了幾篇看了一下,拿幾臺測試機試了一下感覺就沒什麼問題了,但是適配問題慢慢就來了。 一.開啟相簿的基本方法。 通過查詢資料,呼叫系統圖庫基本有3

Android 呼叫系統照相機拍照錄影

專案的佈局相當簡單,只有一個Button: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

Android獲取圖片裁剪

手機獲取圖片兩種方式 通過相機拍照 從系統圖庫中選取 基本流程 無論是選擇拍照還是選擇現成的圖片進行裁剪,都要分為以下三個步驟: S1. 呼叫系統的拍照介面或者相簿的管理介面,由於我們要對該介面的操作結果進行監聽,因此我們在啟動Activity的

Android之拍照相簿選取圖片裁剪得到路徑

-----------------轉載請註明出處:http://blog.csdn.net/android_cll 一:先來兩張效果圖: 1.這是我們專案用到這個功能的截圖、 2.demo的截圖,功能和上面截圖功能一樣,懶得截圖、 二:實現步驟: 1.xml的實現

Android呼叫系統相機拍照 獲取

拍照時候在onActivityResult中獲得相機拍照後點擊確定後的照片。 Android中用Intent提取縮圖和原始影象 可以接受照片的縮圖 Bundle bundle =data.ge

android 呼叫系統照相機拍照後儲存到系統相簿,在系統中能看到

需求:  呼叫系統照相機進行拍照,並且儲存到系統相簿,呼叫系統相簿的時候能看到 系統相簿的路徑:String cameraPath= Environment.getExternalStorageDi

Android呼叫系統相機相簿

拍照和相簿的功能在實際開發中是最常見的功能,這裡記錄下。 準備工作 許可權 1234 <!-- 往SDCard寫入資料許可權 --> <uses-permission android:name="android.permission.WRIT

android 呼叫系統相機獲取圖片路徑

思路: 呼叫系統的相機之前,設法指定圖片的路徑, 然後從指定的路徑中獲取圖片.不要從返回的意圖Intent中獲取圖片的路徑, 因為,不同的手機廠商對此的處理不同.有些可能會獲取到圖片的路徑,有些卻返回null. /** *

android呼叫系統相機相簿上傳頭像

話說昨天的冰碴下得真心大,騎車回來的路上臉被打的生疼啊!清明小長假第一天,借這個時間把前兩天想記錄的一點內容補充上吧。這篇文章主要記錄呼叫系統相機或者從系統相簿中選取照片然後上傳頭像,這是一個很平常的需求,網上的例子也很多,但是,(注意:前方高能預警!!!)我遇到了一個坑,選

Android呼叫系統相機、相簿功能,適配6.0許可權獲取以及7.0以後獲取URI(相容多版本)

  Android中呼叫系統相機來拍攝照片的程式碼,如下:1、首先設定Uri獲取判斷以及相機請求Codepublicfinalint TYPE_TAKE_PHOTO = 1;//Uri獲取型別判斷publicfinalint CODE_TAKE_PHOTO = 1;//相機R

Android呼叫系統相簿系統相機拍照

呼叫系統相機拍照: intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, RESULT_CAMARA_IMAGE); // RESULT_CAMARA_IMA

iOS圖片處理(一)呼叫系統相機相簿獲取圖片,給相機新增自定義覆蓋物

[摘要:起首,拍照或從相簿挑選照片須要應用 UIImagePickerController,應用時須要增加兩個協定 #import UIKit/UIKit.h @interface ViewContr

Android 呼叫系統相機相簿獲取路徑進行圖片壓縮

我直接從專案copy過來了專案程式碼段落,有些可以直接不要,我會加註釋的 1.先定義一個相機或者相簿的標識碼 private int REQUEST_CODE_PICK = 101; private int REQUEST_CODE_CAMERA = 10

Android nomedia 避免圖片等資源泄露在系統其中

cep wid 收錄 rac csdn eat 文件夾 nts 應用開發 總結 Android nomedia 避免文件泄露在系統圖庫和系統鈴聲中 在應用開發中 項目的圖片總是被系統的圖庫收錄了 避免圖片被系統圖庫收錄的發現有2個方法 第一種針對圖