Android Camera解析(上) 調用系統相機拍攝照片


開發中我們常須要通過相機獲取照片(拍照上傳等)。一般通過調用系統提供的相機應用就可以滿足需求;有一些復雜需求還須要我們自己定義相機相關屬性,下篇我們會涉及到。

首先我們來研究怎樣簡單調用系統相機應用來獲取照片

GitHub地址:CameraDemo

調用系統相機獲取照片基本上涉及下面三個過程:

1.啟動系統相機拍照

2.獲取拍攝到的圖片

3.圖片處理

下面是詳細編碼過程

Camera Permission

我們要使用系統相機,首先須要在Manifest中聲明

    <Manifest>
        <uses-features android:name="android.hardware.camera"
                        android:required="true"/>
        ...
    </Manifest>

附注<uses-features/> 用來請求使用某些硬件或軟件資源

詳細使用詳見

Intent

啟動相機的Intent構造 MediaSotre.ACTION_IMAGE_CAPTURE

 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

我們須要獲得相機拍攝的照片。所以startActivity(intent,requestCode);之后在onActivityResult()中接收返回的數據

    startActivityForResult(takePictureIntent,REQUEST_IMAGE_CAPTURE);

獲得圖片

這里須要注意,直接調用相機返回的照片是縮略圖,並非完整尺寸,要想獲得完整尺寸還須要做進一步處理:

1,獲得縮略圖(Thumbnail)

onActivityResult()方法的返回的intent的extras中存儲在相應data下。一張縮略圖

    public void onActivityResult(int requestCode,int resultCode,Intent data){
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap)extras.get("data") ;
        mImageView.setImageBitmap(imageBitmap);
    }

2。獲得完整尺寸圖片

很多時候,縮略圖並不能滿足我們的需求。我們須要完整尺寸的圖片。為此我們還須要做些工作;

首先我們須要將拍到的照片存儲為文件(提供文件名稱和完整的文件路徑),之后通過該文件Uri便可訪問完整尺寸的圖片;

1).涉及到文件存儲。因此我們須要在Manifest中聲明讀寫Storage的權限

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

2).文件路徑問題,我們須要通過getExternalFileDir()getExternalStoragePublicDirectory()兩個方法得到存儲路徑。二者的差別是:前者獲得路徑是private。僅僅能供本程序讀取,后者是public,全部應用均可訪問該圖片。

...
    private static final String CAMERA_DIR = "/dcim/";
    private static final String albumName ="CameraSample";
    ...
    //獲得文件路徑,這里以public為例
    private File getPhotoDir(){
        File storDirPrivate = null;
        File storDirPublic = null;

        if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){

            //private,僅僅有本應用可訪問
            storDirPrivate = new File (
                    Environment.getExternalStorageDirectory()
                            + CAMERA_DIR
                            + albumName
            );

            //public 全部應用均可訪問
            storDirPublic = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                    albumName);

            if (storDirPublic != null) {
                if (! storDirPublic.mkdirs()) {
                    if (! storDirPublic.exists()){
                        Log.d("CameraSample", "failed to create directory");
                        return null;
                    }
                }
            }
        }else {
            Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE.");
        }

        return storDirPublic;//或者return storDirPrivate;

    }

3).文件名稱問題。假設我們將文件名稱寫死,明顯會出現文件名稱沖突,同一路徑無法存儲多個文件,因此我們一般通過“時間戳”的方式命名圖片;下面是一個簡單的經常使用創建文件名稱演示樣例:

...
    private static final String JPEG_FILE_PREFIX = "IMG_";
    private static final String JPEG_FILE_SUFFIX = ".jpg";
    ...
    private File createFile() throws IOException {
        File photoFile = null;

        String fileName;
        //通過時間戳差別文件名稱
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());


        fileName = JPEG_FILE_PREFIX+timeStamp+"_";

        photoFile = File.createTempFile(fileName,JPEG_FILE_SUFFIX,getPhotoDir());

        return photoFile;
    }

4).我們還須要將文件的Uri傳遞給intent。同前面簡易調用相機不同。這里我們須要將獲得圖片后,圖片存儲的文件Uri傳遞給Intent

    Intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photoFile)); 

5).完整尺寸照片的解碼

我們還須要將保存的圖片解碼一次,代碼演示樣例

private void setPic() {

        //獲得圖像的尺寸
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(photoFile.getAbsolutePath(),bmOptions);

        int photoW = bmOptions.outWidth;
        int photoH =bmOptions.outHeight;

        //計算縮放
        int scaleFactor = 1;
        if((targetW>0)||(targetH>0)){
            scaleFactor = Math.min(photoW/targetW,photoH/targetH);
        }

        //將保存的文件解碼
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;


        Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath(), bmOptions);


        mImageView.setImageBitmap(bitmap);
    }

6).Tips:一般這么獲得的照片一般無法在手機相冊中直接瀏覽,能夠將其加入至相冊以便我們瀏覽。

//將圖片文件加入至相冊(便於瀏覽)
    private void galleryAddPic() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri contentUri = Uri.fromFile(photoFile);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    }

綜合演示樣例:

假設還有疑問,請參考:

完整代碼GitHub地址:

CameraDemo

參考資料:

Taking Photos Simply

Android 4高級編程 P579

Android Camera 官方資料

Controlling the Camera

Camera


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM