開發中我們常須要通過相機獲取照片(拍照上傳等)。一般通過調用系統提供的相機應用就可以滿足需求;有一些復雜需求還須要我們自己定義相機相關屬性,下篇我們會涉及到。
首先我們來研究怎樣簡單調用系統相機應用來獲取照片
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地址:
參考資料:
Android Camera 官方資料