调用系统相机/相册获取图片的完美解决方案

时间:2021-12-09 13:30:16
 


调用系统相机/相册获取图片,并裁剪图片,在百度上找一下能搜到一大堆文章,然而拿过来在真机上跑一下大部分都有问题,根本达不到想要的效果。
为什么会拿不到想要的图片呢,最主要的原因是因为图片太大,而获取的图片数据是放在Intent中的。而现在手机的像素普遍都是800W+,一张普通的尺寸为3200*2400px的照片要消耗30MB的内存空间,而一个Intent能传递的数据怎么可能支持这么大的空间,我测试过一些手机能有1MB已经很开心了。


那么图片不放在Intent中,放在哪里呢。好吧,重要的事情我要说三遍:

“截大图用Uri,截小图用Bitmap”
“截大图用Uri,截小图用Bitmap”

“截大图用Uri,截小图用Bitmap”


对待大图片时应该用Uri返回数据,小图片才用Bitmap返回数据,不过现在基本都是大图片,还是放弃Bitmap的方式吧。

裁剪图片的关键代码:

intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);


实现代码如下:


	private static final String IMAGE_FILE_LOCATION = "file://" + new File(Environment.getExternalStorageDirectory(), "temp.jpg").getAbsolutePath();//temp file
	private Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		//Log.i(TAG, "onActivityResult() requestCode = " + requestCode + "   resultCode = " + resultCode);
		if (resultCode == RESULT_OK) {
			switch (requestCode) {
			case Constant.UPLOAD_LOCAL_IMAGE: // 获取本地相片
				// 获取本地相片的地址
				getImagpath(data);
				startPhotoZoom(data.getData());
				break;
			case Constant.UPLOAD_CAMERA_IMAGE: // 拍摄照片
				//Log.i(TAG, "onActivityResult() case Constant.UPLOAD_CAMERA_IMAGE ");
				// 获取原图
				getYuanTu();
				break;
			case Constant.CAI_JIAN_IMAGE:
				Log.i(TAG, "onActivityResult() requestCode = case Constant.CAI_JIAN_IMAGE (imageUri != null) = " + (imageUri != null));
				if(imageUri != null){
			        Bitmap bitmap = decodeUriAsBitmap(imageUri);//decode bitmap
			        Log.i(TAG, "onActivityResult() CAI_JIAN_IMAGE = bitmap " + bitmap);
			        if (bitmap != null) {
			        	mImageColorTip.setImageBitmap(bitmap);
					}
			    }
				break;
			}
		}
		if (resultCode == Constant.ACTIVIT_FINISH) {
			//Log.i(TAG, "onActivityResult() (resultCode == Constant.ACTIVIT_FINISH)");
			finish();
		}
		//super.onActivityResult(requestCode, resultCode, data);
	}
	
	private Bitmap decodeUriAsBitmap(Uri uri){
	    Bitmap bitmap = null;
	    try {
	        bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
	    } catch (FileNotFoundException e) {
	        Log.w(TAG, "decodeUriAsBitmap()", e);
	        return null;
	    }
	    return bitmap;
	}

	private void takePicture() {
		String sDCard = SDCardPath.checkSDCard();
		//Log.i(TAG, "takePicture() (sDCard == null) = " + (sDCard == null));
		if (sDCard == null) {
			showToast(R.string.text_sd_card_invailable);
		} else {
			try {
				String filePath = SDCardPath.getFilePath(sDCard);
				String imagePath = SDCardPath.getImagePath(filePath);
				// 下面这句指定调用相机拍照后的照片存储的路径
				File dir = new File(filePath + "/");
				if (!dir.exists()) {
					dir.mkdirs();
				}
				File tmpFile = new File(dir, imagePath);
				if (!tmpFile.exists()) {
						tmpFile.createNewFile();
				}
				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tmpFile));
				TakePhotoColorActivity.sImagePath = tmpFile.getAbsolutePath();
				startActivityForResult(intent,Constant.UPLOAD_CAMERA_IMAGE);
			} catch (IOException e) {
				Log.e(TAG, "openAlbum() IOException", e);
			}
		}
	}

	private void openAlbum() {
		//Log.i(TAG, "openAlbum()");
		Intent intent = new Intent(Intent.ACTION_PICK, null);
		intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
		startActivityForResult(intent,Constant.UPLOAD_LOCAL_IMAGE);
	}
	
	/**
	 * 获取原图的方法
	 */
	private void getYuanTu() {
		//Log.i(TAG, "getYuanTu() PictureColorActivity.sImagePath = " + PictureColorActivity.sImagePath);
		File f = new File(TakePhotoColorActivity.sImagePath);
//		Log.i(TAG, "getYuanTu() filePath = " + (f == null ? "iOnesNull" : f.getAbsolutePath()));
		try {
			String imgURL = null;
			try {
				imgURL = android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), f.getAbsolutePath(), null, null);
			} catch (Exception e) {
				Log.e(TAG, "getYuanTu() imgURL", e);
			}
//			Log.i(TAG, "getYuanTu() imgURL = " + imgURL);
			Uri u = null;
			if (imgURL != null) {
				u = Uri.parse(imgURL);
			} else {
				u = Uri.fromFile(f);
			}
//			Log.i(TAG, "getYuanTu() uri = " + (u == null ? "iOnesNull" : u.toString()));
			startPhotoZoom(u);
		} catch (Exception e) {
			Log.e(TAG, "getYuanTu()", e);
		}
	}
	
	/**
	 * 获取本地图片的路径
	 * 
	 * @param data
	 */
	private void getImagpath(Intent data) {
		//Log.i(TAG, "getImagpath() PictureColorActivity.sImagePath = " + PictureColorActivity.sImagePath);
		Uri originalUri = data.getData(); // 获得图片的uri
		String[] proj = { MediaStore.Images.Media.DATA };
		// 好像是android多媒体数据库的封装接口,具体的看Android文档
//		Cursor cursor = managedQuery(originalUri, proj, null, null, null);
		Cursor cursor = getContentResolver().query(originalUri, proj, null, null, null);
		// 按我个人理解 这个是获得用户选择的图片的索引值
		int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
		// 将光标移至开头 ,这个很重要,不小心很容易引起越界
		cursor.moveToFirst();
		// 最后根据索引值获取图片路径
		String path = cursor.getString(column_index);
		TakePhotoColorActivity.sImagePath = path;
	}
	
	/**
	 * 裁剪图片方法实现
	 * 
	 * @param uri
	 */
	public void startPhotoZoom(Uri uri) {
		//Log.i(TAG, "startPhotoZoom() PictureColorActivity.sImagePath = " + PictureColorActivity.sImagePath);
		Intent intent = new Intent("com.android.camera.action.CROP");
		intent.setDataAndType(uri, "image/*");
		// 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
		intent.putExtra("crop", "true");
		// aspectX aspectY 是宽高的比例
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		intent.putExtra("scale", true);
		// outputX outputY 是裁剪图片宽高
		// TODO 详情参考:http://my.oschina.net/ryanhoo/blog/86842
		intent.putExtra("outputX", 500);
		intent.putExtra("outputY", 500);
		intent.putExtra("noFaceDetection", true);
		intent.putExtra("return-data", false);
		Log.i(TAG, "startPhotoZoom() (imageUri != null) = " + (imageUri != null));
		intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
		intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
		startActivityForResult(intent, Constant.CAI_JIAN_IMAGE);
	}

	/** 大图图片的路径 */
	private static String sImagePath = "";
	
	public interface Constant {
		/**
		 * 获取本地图片
		 */
		public static  final int UPLOAD_LOCAL_IMAGE  = 0x0001; 
	  /**
	   * 获取相机图片
	   */
		public  static final int UPLOAD_CAMERA_IMAGE = 0x0002;  
		public  static final String SD_CARD_ROOT = "sdcard";
		/**
		 * 裁剪图片
		 */
		public  static final  int CAI_JIAN_IMAGE=0x0003;
		/**
		 * 回调结束当前界面
		 */
		public static final int ACTIVIT_FINISH = 0x0004; 
		/**相机裁剪后的照片*/
		public static final int IMAGE_CODE_PATH = 0x0005;

	}


如果对你有帮助,不要谢我。大神在这里:http://my.oschina.net/ryanhoo/blog/86842