Android拍照和從相簿獲取圖片(解決android7.0開啟相機崩潰的問題),同時也解決了拍完照後圖片方向不正的問題
阿新 • • 發佈:2019-01-09
再android7.0中相機操作需要動態申請許可權,在點選開啟相機按鈕時要先判斷許可權,沒有許可權要申請,有許可權再操作,同時在申請許可權的回撥方法中也要判斷是否有許可權,有許可權的話再呼叫開啟相機的方法
package test.img.com.myimgtest.activity;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import test.img.com.myimgtest.R;
import test.img.com.myimgtest.util.ImgPretreatment;
public class ORCActivity888 extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;//啟動相機標識
public static final int SELECT_PHOTO = 2;//啟動相簿標識
private ImageView imageView;
private TextView textView;
private File outputImagepath;//儲存拍完照後的圖片
private Bitmap orc_bitmap;//拍照和相簿獲取圖片的Bitmap
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_orc);
imageView = (ImageView) findViewById(R.id.shangchuan_img);
textView = (TextView) findViewById(R.id.chazhi_tv);
}
/**
* 開啟相機
*
* @param view
*/
public void xiangjiClick(View view) {
//checkSelfPermission 檢測有沒有 許可權
// PackageManager.PERMISSION_GRANTED 有許可權
// PackageManager.PERMISSION_DENIED 拒絕許可權
//一定要先判斷許可權,再開啟相機,否則會報錯
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
//許可權發生了改變 true // false,沒有許可權時
if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)){
new AlertDialog.Builder(this).setTitle("title")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 請求授權
ActivityCompat.requestPermissions(ORCActivity888.this,new String[]{Manifest.permission.CAMERA},1);
}
}).setNegativeButton("cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//不請求許可權的操作
}
}).create().show();
}else {
ActivityCompat.requestPermissions(ORCActivity888.this,new String[]{Manifest.permission.CAMERA},1);
}
}else{
take_photo();//已經授權了就呼叫開啟相機的方法
}
}
/**
* 開啟相簿
*/
public void xiangceClick(View view) {
select_photo();
}
/**
* 拍照獲取圖片
**/
public void take_photo() {
//獲取系統版本
int currentapiVersion = Build.VERSION.SDK_INT;
// 啟用相機
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判斷儲存卡是否可以用,可用進行儲存
if (hasSdcard()) {
SimpleDateFormat timeStampFormat = new SimpleDateFormat(
"yyyy_MM_dd_HH_mm_ss");
String filename = timeStampFormat.format(new Date());
outputImagepath = new File(Environment.getExternalStorageDirectory(),
filename + ".jpg");
if (currentapiVersion < 24) {
// 從檔案中建立uri
Uri uri = Uri.fromFile(outputImagepath);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
} else {
//相容android7.0 使用共享檔案的形式
ContentValues contentValues = new ContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, outputImagepath.getAbsolutePath());
Uri uri = getApplication().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
}
}
// 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CAREMA
startActivityForResult(intent, TAKE_PHOTO);
}
/*
* 判斷sdcard是否被掛載
*/
public static boolean hasSdcard() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
/**
* 從相簿中獲取圖片
*/
public void select_photo() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(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, SELECT_PHOTO);
}
/**
* 4.4以下系統處理圖片的方法
*/
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
/**
* 4.4及以上系統處理圖片的方法
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private void handleImgeOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
Log.d("uri=intent.getData :", "" + uri);
if (DocumentsContract.isDocumentUri(this, uri)) {
String docId = DocumentsContract.getDocumentId(uri); //資料表裡指定的行
Log.d("getDocumentId(uri) :", "" + docId);
Log.d("uri.getAuthority() :", "" + uri.getAuthority());
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1];
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())) {
imagePath = getImagePath(uri, null);
}
displayImage(imagePath);
}
/**
* 通過uri和selection來獲取真實的圖片路徑,從相簿獲取圖片時要用
*/
private String getImagePath(Uri uri, String selection) {
String path = null;
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;
}
/**
* 拍完照和從相簿獲取玩圖片都要執行的方法(根據圖片路徑顯示圖片)
*/
private void displayImage(String imagePath) {
if (!TextUtils.isEmpty(imagePath)) {
//orc_bitmap = BitmapFactory.decodeFile(imagePath);//獲取圖片
orc_bitmap = comp(BitmapFactory.decodeFile(imagePath)); //壓縮圖片
ImgUpdateDirection(imagePath);//顯示圖片,並且判斷圖片顯示的方向,如果不正就放正
} else {
Toast.makeText(this, "圖片獲取失敗", Toast.LENGTH_LONG).show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
//開啟相機後返回
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
/**
* 這種方法是通過記憶體卡的路徑進行讀取圖片,所以的到的圖片是拍攝的原圖
*/
displayImage(outputImagepath.getAbsolutePath());
Log.i("tag", "拍照圖片路徑>>>>" + outputImagepath);
}
break;
//開啟相簿後返回
case SELECT_PHOTO:
if (resultCode == RESULT_OK) {
//判斷手機系統版本號
if (Build.VERSION.SDK_INT > 19) {
//4.4及以上系統使用這個方法處理圖片
handleImgeOnKitKat(data);
} else {
handleImageBeforeKitKat(data);
}
}
break;
default:
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
//判斷是否有許可權
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAlbum();//開啟相簿
take_photo();//開啟相機
} else {
Toast.makeText(this, "你需要許可", Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (orc_bitmap != null) {
orc_bitmap.recycle();
} else {
orc_bitmap = null;
}
}
/**
* 質量壓縮方法
*
* @param image
* @return
*/
public static Bitmap compressImage(Bitmap image) {
if (image != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { //迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
baos.reset();//重置baos即清空baos
options -= 10;//每次都減少10
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裡壓縮options%,把壓縮後的資料存放到baos中
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮後的資料baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream資料生成圖片
return bitmap;
} else {
return null;
}
}
//比例壓縮
private Bitmap comp(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
if (baos.toByteArray().length / 1024 > 1024) {//判斷如果圖片大於1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢位
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//這裡壓縮50%,把壓縮後的資料存放到baos中
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//開始讀入圖片,此時把options.inJustDecodeBounds 設回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//現在主流手機比較多是800*480解析度,所以高和寬我們設定為
float hh = 800f;//這裡設定高度為800f
float ww = 480f;//這裡設定寬度為480f
//縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
int be = 1;//be=1表示不縮放
if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//設定縮放比例
newOpts.inPreferredConfig = Bitmap.Config.RGB_565;//降低圖片從ARGB888到RGB565
//重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了
isBm = new ByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
return bitmap;//壓縮好比例大小後再進行質量壓縮
}
//改變拍完照後圖片方向不正的問題
private void ImgUpdateDirection(String filepath) {
int digree = 0;//圖片旋轉的角度
//根據圖片的URI獲取圖片的絕對路徑
Log.i("tag", ">>>>>>>>>>>>>開始");
//String filepath = ImgUriDoString.getRealFilePath(getApplicationContext(), uri);
Log.i("tag", "》》》》》》》》》》》》》》》" + filepath);
//根據圖片的filepath獲取到一個ExifInterface的物件
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
Log.i("tag", "exif》》》》》》》》》》》》》》》" + exif);
if (exif != null) {
// 讀取圖片中相機方向資訊
int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
// 計算旋轉角度
switch (ori) {
case ExifInterface.ORIENTATION_ROTATE_90:
digree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
digree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
digree = 270;
break;
default:
digree = 0;
break;
}
}
//如果圖片不為0
if (digree != 0) {
// 旋轉圖片
Matrix m = new Matrix();
m.postRotate(digree);
orc_bitmap = Bitmap.createBitmap(orc_bitmap, 0, 0, orc_bitmap.getWidth(),
orc_bitmap.getHeight(), m, true);
}
if (orc_bitmap != null) {
imageView.setImageBitmap(orc_bitmap);
}
} catch (IOException e) {
e.printStackTrace();
exif = null;
}
}
}