今天总结一下,在我们APP中拍照和选择图片的相关处理。
拍照ACTION:
MediaStore.ACTION_IMAGE_CAPTURE
启用相册ACTION:
Intent.ACTION_GET_CONTENT
裁剪ACTION:
com.android.camera.action.CROP
我们使用系统自带的Activity就行拍照、裁剪的话,肯定是使用隐式的Intent。可配置的参数如下:
附加选项 数据类型 描述
crop String 发送裁剪信号
aspectX int X方向上的比例
aspectY int Y方向上的比例
outputX int 裁剪区的宽
outputY int 裁剪区的高
scale boolean 是否保留比例
return-data boolean 是否将数据保留在Bitmap中返回
data Parcelable 相应的Bitmap数据
circleCrop String 圆形裁剪区域?
MediaStore.EXTRA_OUTPUT ("output") URI 将URI指向相应的file:///...,详见代码示例
outputFormat String 输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString()
noFaceDetection boolean 是否取消人脸识别功能
这里要分以下几种情况:
1. 直接启动系统拍照的activity,在onActivityResult中获取到data数据,这个数据其实就是bitmap,当然启动的intent中,return-data设置为true,但是这样也是有问题的,如果data数据太多,bitmap只能是一个缩略图。
2. 启动拍照的activity的intent,设置return-data为false,并且指定MediaStore.EXTRA_OUTPUT,即图片的存放路径,这样在onActivityResult中,根据指定的位置拿到图片。
3. 启动拍照的act时,同时让其进行裁剪,这样的话,很容易出问题,当图片比较大时,拍照界面将数据传递给裁剪界面时,就会出现崩溃。
4. 拍照和裁剪分成两个步骤进行,在onActivityResult处理返回结果.
这里要特别注意第四种情况,在指定拍照的图片的存放路径时,会出现图片旋转90度的情况,最后发现是我在指定拍照返回的路径Uri时图片的后缀是png,我改成jpg以后,就没有出现旋转90度的情况,我的手机是node3,
其他的机型还没有验证。针对这个问题我做了延伸,如果确实是图片旋转了90度,我的处理思路是可以先将拍照的图片,先旋转90度,然后存放在sd路径中,裁剪时是依据新保存的这个图片,但是这样以来,很容易导致图片OOM。
以上是针对拍照。
下面我们说说选择系统相册中的图片的几种情况:
1. 从相册中直接选取,在onActivityResult中intent的getData获取路径信息
2. 从相册中直接选择,在onactivityresult中intent的data获取到图片的路径信息,通过路径信息获取到Uri,转成bitmap(这种方式很多的开源项目都在用)。
3. 从相册中选择的同时并裁剪,图片比较大时,就会出现奔溃,还是两个界面传递数据的问题。
4. 先从相册中选取图片,然后再进行裁剪,是比较理想的情况。
从相册中选择图片时,在onActivityResult中如何从data中图片对应路径信息呢?
if (data != null) {
Uri selectedImg = data.getData();
if (selectedImg != null) {
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = this.getContentResolver().query(selectedImg, filePathColumn, null, null, null);
if (null == cursor) {
String path = selectedImg.getPath();
File file = new File(path);
if (file.isFile()) {
copyAndCrop(file);
return;
} else {
Toast.makeText(this, this.getString(R.string.picture_not_found),Toast.LENGTH_SHORT).show();
return;
}
} else if (!cursor.moveToFirst()) {
Toast.makeText(this, this.getString(R.string.picture_not_found),Toast.LENGTH_SHORT).show();
return;
}
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String path = cursor.getString(columnIndex);
if (path != null) {
File file = new File(path);
if (!file.isFile()) {
Toast.makeText(this, this.getString(R.string.picture_not_found),
Toast.LENGTH_SHORT).show();
cursor.close();
} else {
//如果是选择本地图片进行头像设置,复制到临时文件,并进行裁剪
copyAndCrop(file);
cursor.close();
}
}
}
}
终极解决方案为第四种
接下来会考虑拍摄图片太大时,如何防止图片OOM的情况.
图片的压缩和旋转处理:
public static Bitmap revitionImage(String path) throws IOException {
if (null == path || TextUtils.isEmpty(path) || !new File(path).exists())
return null;
BufferedInputStream in = null;
try {
// 获取到图片的旋转属性
int degree = readPictureDegree(path);
in = new BufferedInputStream(new FileInputStream(new File(path)));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
// 计算出图片的缩放比例
options.inSampleSize = calculateInSampleSize(options, 400, 600);
in.close();
in = new BufferedInputStream(new FileInputStream(new File(path)));
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeStream(in, null, options);
Bitmap newbitmap = rotaingImageView(degree, bitmap);
return newbitmap;
} catch (Exception e) {
Logger.getLogger(PhotoHelper.class).e(e.getMessage());
return null;
} finally {
if (null != in) {
in.close();
in = null;
}
}
}
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
Logger.getLogger(PhotoHelper.class).e(e.getMessage());
}
return degree;
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// 源图片的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// 计算出实际宽高和目标宽高的比率
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
// 一定都会大于等于目标的宽和高。
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
if (null == bitmap) {
return null;
}
// 旋转图片 动作
Matrix matrix = new Matrix();
matrix.postRotate(angle);
// 创建新的图片
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizedBitmap;
}