Android應用內啟動相機拍照并獲取照片的兩種方式
首先加入需要的權限,如果是6.0系統需要加權限申請
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
方式一:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
//用于展示選擇的圖片
private ImageView mImageView;
private static final int CAMERA_CODE = 1;
private static final int GALLERY_CODE = 2;
private static final int CROP_CODE = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mImageView = (ImageView) findViewById(R.id.show_image);
Button chooseCamera = (Button) findViewById(R.id.choose_camera);
chooseCamera.setOnClickListener(this);
Button chooseGallery = (Button) findViewById(R.id.choose_gallery);
chooseGallery.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.choose_camera:
//拍照選擇
chooseFromCamera();
break;
case R.id.choose_gallery:
//從相冊選取
chooseFromGallery();
break;
default:
break;
}
}
/**
* 拍照選擇圖片
*/
private void chooseFromCamera() {
//構建隱式Intent
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//調用系統相機
startActivityForResult(intent, CAMERA_CODE);
}
/**
* 從相冊選擇圖片
*/
private void chooseFromGallery() {
//構建一個內容選擇的Intent
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
//設置選擇類型為圖片類型
intent.setType("image/*");
//打開圖片選擇
startActivityForResult(intent, GALLERY_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case CAMERA_CODE:
if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "取消了拍照", Toast.LENGTH_LONG).show();
return;
}
if(data != null){
Bitmap photo = data.getParcelableExtra("data");
//將Bitmap轉化為uri
Uri uri = saveBitmap(photo, "temp");
//啟動圖像裁剪
startImageZoom(uri);
}
break;
case GALLERY_CODE:
if (data == null){
return;
}else{
//用戶從圖庫選擇圖片后會返回所選圖片的Uri
Uri uri;
//獲取到用戶所選圖片的Uri
uri = data.getData();
//返回的Uri為content類型的Uri,不能進行復制等操作,需要轉換為文件Uri
uri = convertUri(uri);
startImageZoom(uri);
}
break;
case CROP_CODE:
if (data == null){
return;
}else{
Bundle extras = data.getExtras();
if (extras != null){
//獲取到裁剪后的圖像
Bitmap bm = extras.getParcelable("data");
mImageView.setImageBitmap(bm);
}
}
break;
default:
break;
}
}
/**
* 將content類型的Uri轉化為文件類型的Uri
* @param uri
* @return
*/
private Uri convertUri(Uri uri){
InputStream is;
try {
//Uri ----> InputStream
is = getContentResolver().openInputStream(uri);
//InputStream ----> Bitmap
Bitmap bm = BitmapFactory.decodeStream(is);
//關閉流
is.close();
return saveBitmap(bm, "temp");
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 將Bitmap寫入SD卡中的一個文件中,并返回寫入文件的Uri
* @param bm
* @param dirPath
* @return
*/
private Uri saveBitmap(Bitmap bm, String dirPath) {
//新建文件夾用于存放裁剪后的圖片
File tmpDir = new File(Environment.getExternalStorageDirectory() + "/" + dirPath);
if (!tmpDir.exists()){
tmpDir.mkdir();
}
//新建文件存儲裁剪后的圖片
File img = new File(tmpDir.getAbsolutePath() + "/avator.png");
try {
//打開文件輸出流
FileOutputStream fos = new FileOutputStream(img);
//將bitmap壓縮后寫入輸出流(參數依次為圖片格式、圖片質量和輸出流)
bm.compress(Bitmap.CompressFormat.PNG, 85, fos);
//刷新輸出流
fos.flush();
//關閉輸出流
fos.close();
//返回File類型的Uri
return Uri.fromFile(img);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 通過Uri傳遞圖像信息以供裁剪
* @param uri
*/
private void startImageZoom(Uri uri){
//構建隱式Intent來啟動裁剪程序
Intent intent = new Intent("com.android.camera.action.CROP");
//設置數據uri和類型為圖片類型
intent.setDataAndType(uri, "image/*");
//顯示View為可裁剪的
intent.putExtra("crop", true);
//裁剪的寬高的比例為1:1
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
//輸出圖片的寬高均為150
intent.putExtra("outputX", 150);
intent.putExtra("outputY", 150);
//裁剪之后的數據是通過Intent返回
intent.putExtra("return-data", true);
startActivityForResult(intent, CROP_CODE);
}
}
注:第一種方式參考自冰鑒IT包括了拍照,裁剪和從相冊選擇圖片,注釋很詳細.簡單說明一下,通過startActivityForResult啟動系統相機,然后在onActivityResult通過data.getParcelableExtra("data");方法獲取到Bitmap對像,再通過IO保存到本地.
需要注意的是,這種方式獲取到的圖片是被系統壓縮過的,優點是不容易OOM,適用于小圖展示,如頭像等.
下面介紹第二種,獲取拍照的高清無碼大圖
hhhhh
方式二:
先指定拍照文件的保存路徑Environment.ExternalStorageDirectory/eos/time.jpg,再通過 MediaStore.ACTION_IMAGE_CAPTURE 獲取系統相機,并指定 MediaStore.EXTRA_OUTPUT ,的存儲位置為我們剛剛指定路徑的uri,intent.putExtra(MediaStore.EXTRA_OUTPUT,currentUri); 這樣,最終返回的信息會存儲在我們的file中。
private Uri currentUri;
private final int TakePhoto = 123;
private void openTakePhoto() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File appDir = new File(Environment.getExternalStorageDirectory(), "eos");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
file.createNewFile();
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
currentUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, currentUri);
startActivityForResult(intent, TakePhoto);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "文件存儲路徑異常", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "請插入sd卡", Toast.LENGTH_SHORT).show();
}
}
在onActivityResult進行相應的處理這里使用Glide通過之前的uri顯示圖片,如果是需要獲取圖片的file或bitmap則需要進行相應的壓縮,防止發生OOM
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_CANCELED) {
// Toast.makeText(this, "取消了拍照", Toast.LENGTH_LONG).show();
return;
}
if (requestCode == TakePhoto && currentUri != null) {
photos.add(0, new PhotoBean(currentUri, 1));
adapter.notifyDataSetChanged();
}
}
dzj