1. 程式人生 > >Android拍照和從相簿獲取圖片(解決android7.0開啟相機崩潰的問題),同時也解決了拍完照後圖片方向不正的問題

Android拍照和從相簿獲取圖片(解決android7.0開啟相機崩潰的問題),同時也解決了拍完照後圖片方向不正的問題

再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; } } }