Android实用工具类-GrallyAndPhotoUtils图片处理工具
目录
目录 概述 前言 拍照 创建存储拍照图片的文件 调用系统拍照程序 读取相册图片 获取返回URI中的图片路径 统一的回调处理 图片缩略图加载 加载流程 计算缩略图比例 缩略图加载 源码 图片加载结果 示例GIF </div>
概述
此类是用于简便调用系统拍照及打开相册选择图片.通用于多种机型.(亲测魅族MX4,三星note 2,三星note 3)
前言
在执行拍照和打开相册之前,我们需要注意一下.
由于Android开放的系统,很多手机厂商是定制自己的系统的,那么就存在一个问题.尽管大部分时候拍照或者打开相册都有一个基本的标准,但可能不同的系统操作方式或者是细节表现是不同的.
可能存在以下的情况:
拍照时相机会自动旋转一定的角度(出现在三星机型上) 相册图片返回路径存在URI中(原生系统)
以上只是遇到过的情况,包括魅族也存在一些问题.不管是拍照还是相册获取图片,我们都希望能正确获取到图片.因此,这里采用的方式是:
拍照时将图片保存到指定位置,加载图片时通过图片路径加载 获取相册图片时通过返回URI图片路径加载图片
拍照
拍照调用的是系统的拍照程序而不是自己实现的拍照程序.通用性更广泛,也不需要自己去处理各种情况从而实现拍照程序,节省了大量的时间.
但是系统拍照程序可能会存在的问题是,系统的拍照程序是我们无法监视和控制的.有可能某些系统的拍照程序会造成一些问题.比如部分机型会自动旋转相片角度.
所以我们在拍照后获取图片时,可以检测图片是否存在旋转角度从而修正图片的方向.
创建存储拍照图片的文件
存储拍照图片的路径从外部提供,原因后面会解释到.
检测路径下的文件是否存在,不存在则创建一个新的空文件.文件不存在的情况下无法将拍照所得的图片写入到文件中.
该路径应该为完整路径,带图片格式后缀.
//尝试创建文件夹及用于存储拍照后的文件
File outputImage = new File(filePath);
if (!outputImage.exists()) {
try {
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
调用系统拍照程序
调用系统拍照程序的Action
是通用的.我们需要注意的是调用时需要设置拍照参数为图片输出到指定路径
//将File对象转换为Uri并启动照相程序
Uri photoUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); //照相
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); //指定图片输出地址
try {
act.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO); //启动照相
} catch (SecurityException se) {
se.printStackTrace();
return null;
}
其中启动拍照程序使用的requestCode
默认使用自定义值REQUEST_CODE_TAKE_PHOTO
.因为后面会提供统一的处理方法.
读取相册图片
读取相册图片使用的也是系统的相册工具.
//设置选择Action
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
//存在多个相册类型的应用时,显示给用户选择的打开相册的应用界面
act.startActivityForResult(Intet.createChooser(intent,"请选择"),REQUEST_CODE_OPEN_GRALLY);
获取返回URI中的图片路径
相册打开图片后返回的往往是一个URI,存放的是图片的路径.但有时又不一定是绝对路径,即我们无法通过这个URI去读取到图片.可能返回的是一个如下的URI:
content://media/external/images/media/45928
这并不是一个文件的绝对路径,我们也无法从该路径直接获取到图片,但是此URI确实指向了某个资源文件.
因此我们需要将该URI转化成我们能获取到的图片的路径.
public static String getBmpPathFromContent(Context context, Intent bmpIntent) {
if (bmpIntent != null && bmpIntent.getData() != null) {
Uri contentUri = bmpIntent.getData();
String uriPath = contentUri.getPath();
//content存在时
if (!TextUtils.isEmpty(uriPath)) {
String[] filePathColumn = {MediaStore.Images.Media.DATA};
//加载系统数据库
Cursor cursor = context.getContentResolver().query(contentUri,
filePathColumn, null, null, null);
//移动到第一行,不移动将越界
cursor.moveToFirst();
//加载查询数据的列号
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
//获取图片路径
String picturePath = cursor.getString(columnIndex);
//游标应该关闭
cursor.close();
return picturePath;
} else {
return null;
}
} else {
return null;
}
}
通过ContentResolver
查询该URI对应的图片的信息,从而我们得到可以直接读取加载的图片路径.
统一的回调处理
以上不管是拍照还是打开相册,都是通过startActivityForResult()
的方式打开并获取数据的.
因此可以使用统一的方式进行处理拍照或者是相册获取图片的回调.
/**
* 处理拍照/打开相册后进入裁剪工作
*
* @param requestCode 连接
* @param resultCode
* @param data Intent数据
* @param act 启动裁剪Activity的act
* @param inputPath 裁剪图片的路径(针对拍照保存的路径,相册获取的路径在data中)
* @param outputPath 图片裁剪后输出的路径(提供给裁剪Activity)
* @return
*/
public static boolean onActivityResult(int requestCode, int resultCode, Intent data, Activity act, String inputPath, String outputPath) {
switch (requestCode) {
case REQUEST_CODE_TAKE_PHOTO:
case REQUEST_CODE_OPEN_GRALLY:
//当启动使用的activity不存在或者是拍照/打开相册失败时(resultCode不为RESULT_OK),不处理
if (act == null || resultCode != Activity.RESULT_OK) {
return false;
}
//若当前为拍照回调,尝试读取图片的旋转角度
int degree = requestCode == REQUEST_CODE_TAKE_PHOTO ? readPictureDegree(inputPath) : 0;
//获取intent中返回的图片路径(如果是打开相册部分机型可能将图片路径存放在intent中返回)
String tempPath = getBmpPathFromContent(act, data);
//若intent路径存在,使用该路径,否则使用inputPath
inputPath = TextUtils.isEmpty(tempPath) ? inputPath : tempPath;
//源图片路径或者输出路径为无效时,不处理
if (TextUtils.isEmpty(inputPath) || TextUtils.isEmpty(outputPath)) {
return false;
} else {
Intent cropIntent = new Intent(act, CropBitmapActivity.class);
cropIntent.putExtra("inputPath", inputPath);
cropIntent.putExtra("outputPath", outputPath);
cropIntent.putExtra("degree", degree);
//启动裁剪工具
act.startActivityForResult(cropIntent, REQUEST_CODE_CROP_PHOTO);
return true;
}
default:
return false;
}
}
以上需要注意的是,同一时间onActivityResult()
仅会回调一次,也就是说任何时候只会处理拍照或者是相册图片中的一种情况.其中
//若当前为拍照回调,尝试读取图片的旋转角度
int degree = requestCode == REQUEST_CODE_TAKE_PHOTO ? readPictureDegree(inputPath) : 0;
为处理拍照后的图片的角度旋转问题.
//获取intent中返回的图片路径(如果是打开相册部分机型可能将图片路径存放在intent中返回)
String tempPath = getBmpPathFromContent(act, data);
处理相册图片路径的问题.
inputPath
仅为拍照图片存储的路径,而与相册图片路径无关.所以最后只会保留一个.
//若intent路径存在,使用该路径,否则使用inputPath
inputPath = TextUtils.isEmpty(tempPath) ? inputPath : tempPath;
<