开篇
基于我们开App发过程中经常要选择图片(或拍照)并裁剪做为头像上传到服务器,我把选取图片、拍照、裁剪图片功能整理优化了,有了它你再也不用为这些芝麻小事所烦恼啦!这一篇就够了!
立即体验
扫描以下二维码下载体验App(从0.2.3
版本开始,体验App内嵌版本更新检测功能):
JSCKit库传送门:https://github.com/JustinRoom/JSCKit
源码简析
- 在
void onActivityResult(int requestCode, int resultCode, Intent data)
中处理选择、拍照、裁剪结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK)
return;
switch (requestCode) {
case REQUEST_CODE_PIC_PHOTO://手机相册
onPickPhotoResult(data.getData());
break;
case REQUEST_CODE_TAKE_PHOTO://拍照
onTakePhotoResult(FileProviderCompat.getUriForFile(this, takePhotoTempFile), takePhotoTempFile);
break;
case REQUEST_CODE_PHOTO_CROP://裁剪
onCropPhotoResult(data.getData(), cropPhotoTempFile);
break;
}
}
在使用到Uri
,请注意兼容Android7.0。FileProviderCompat.java
- 1、从相册选取图片
特别提示:
1、需要权限android.permission.READ_EXTERNAL_STORAGE
。
public void openAlbum() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setDataAndType(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, REQUEST_CODE_PIC_PHOTO);
}
- 2、调用系统相机拍照
特别提示:
1、需要权限android.permission.WRITE_EXTERNAL_STORAGE
、android.permission.CAMERA
。
public void openCamera(File directory, String photoPathName) {
//如果没有设置文件夹,拍照后则保存在sdk根目录的Pictures文件夹下面
if (directory == null)
directory = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
//如果没有设置图片名称,则根据当前系统时间设置默认的图片名称
if (photoPathName == null || photoPathName.trim().length() == 0)
photoPathName = getDefaultTakePhotoFileName(Bitmap.CompressFormat.JPEG);
takePhotoTempFile = new File(directory, photoPathName);
String takePhotoTempFilePath = takePhotoTempFile.getPath();
//如果保存图片的文件夹还没有创建,则创建文件夹
File dir = new File(takePhotoTempFilePath.substring(0, takePhotoTempFilePath.lastIndexOf(File.separator)));
if (!dir.exists())
dir.mkdirs();
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderCompat.getUriForFile(this, takePhotoTempFile));
startActivityForResult(cameraIntent, REQUEST_CODE_TAKE_PHOTO);
}
- 3、裁剪
特别提示:
1、需要权限android.permission.WRITE_EXTERNAL_STORAGE
。
2、如果有设置aspectX、aspectY或者outputX、outputY,那么它就是按比例裁剪;否则是自由裁剪
3、比例优先。举个栗子:如果有设置aspectX=4、aspectY=3、outputX=480、outputY=560,那么它裁剪时真正的outputX=480、outputY=360。
/**
* open system crop photo feature.
* <br/>1、如果有设置aspectX、aspectY或者outputX、outputY,那么它就是按比例裁剪;否则是自由裁剪
* <br/>2、比例优先。举个栗子:如果有设置aspectX=4、aspectY=3、outputX=480、outputY=560,那么它裁剪时真正的outputX=480、outputY=360。
* <br/>Caller must ensure {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.
*
* @param uri
* @param config
*/
public void cropPhoto(Uri uri,CropConfig config) {
if (config == null)
config = new CropConfig();
Intent intent = new Intent("com.android.camera.action.CROP");
FileProviderCompat.setDataAndType(intent, uri, "image/*", true);
intent.putExtra(CropConfig.EXTRA_CROP, String.valueOf(config.isCrop()));
int outputX = config.getOutputX();
int outputY = config.getOutputY();
int aspectX = config.getAspectX();
int aspectY = config.getAspectY();
boolean isOutputSet = outputX > 0 && outputY > 0;
boolean isAspectSet = aspectX > 0 && aspectY > 0;
if (isAspectSet) {
intent.putExtra(CropConfig.EXTRA_ASPECT_X, aspectX);
intent.putExtra(CropConfig.EXTRA_ASPECT_Y, aspectY);
//如果有设置outputX、outputY,则根据aspectX、aspectY计算出合适的outputX、outputY
if (isOutputSet) {
if (aspectX == aspectY) {
outputX = outputY = Math.min(outputX, outputY);
} else {
double ratioX = outputX * 1.0 / aspectX;
double ratioY = outputY * 1.0 / aspectY;
if (ratioX > ratioY) {//以outputY为标准
int avg = outputY / aspectY;
outputX = avg * aspectX;
outputY = avg * aspectY;
} else if (ratioX < ratioY) {//以outputX为标准
int avg = outputX / aspectX;
outputX = avg * aspectX;
outputY = avg * aspectY;
}
}
config.setOutputX(outputX);
config.setOutputY(outputY);
}
}
if (isOutputSet) {
intent.putExtra(CropConfig.EXTRA_OUTPUT_X, outputX);
intent.putExtra(CropConfig.EXTRA_OUTPUT_Y, outputY);
}
intent.putExtra(CropConfig.EXTRA_SCALE, config.isScale());
intent.putExtra(CropConfig.EXTRA_CIRCLE_CROP, String.valueOf(config.isCircleCrop()));
//如果没有设置文件夹,裁剪后则保存在sdk根目录的Pictures文件夹下面
File directory = config.getDirectory();
if (directory == null){
directory = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
config.setDirectory(directory);
}
//如果没有设置图片名称,则根据当前系统时间设置默认的图片名称
String photoPathName = config.getPhotoPathName();
if (photoPathName == null || photoPathName.trim().length() == 0){
photoPathName = getDefaultCropPhotoFileName(config.getOutputFormat());
config.setPhotoPathName(photoPathName);
}
cropPhotoTempFile = new File(directory, photoPathName);
String cropPhotoTempFilePath = cropPhotoTempFile.getPath();
//如果保存图片的文件夹还没有创建,则创建文件夹
File dir = new File(cropPhotoTempFilePath.substring(0, cropPhotoTempFilePath.lastIndexOf(File.separator)));
if (!dir.exists())
dir.mkdirs();
intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderCompat.getUriForFile(this, cropPhotoTempFile));
intent.putExtra(CropConfig.EXTRA_RETURN_DATA, config.isReturnData());
intent.putExtra(CropConfig.EXTRA_NO_FACE_DETECTION, config.isNoFaceDetection());
intent.putExtra(CropConfig.EXTRA_OUTPUT_FORMAT, config.getOutputFormat().name());
startActivityForResult(intent, REQUEST_CODE_PHOTO_CROP);
}
看看CropConfig.java
请参照注释:
public static final String EXTRA_CROP = "crop";
public static final String EXTRA_ASPECT_X = "aspectX";
public static final String EXTRA_ASPECT_Y = "aspectY";
public static final String EXTRA_OUTPUT_X = "outputX";
public static final String EXTRA_OUTPUT_Y = "outputY";
public static final String EXTRA_SCALE = "scale";
public static final String EXTRA_CIRCLE_CROP = "circleCrop";
public static final String EXTRA_RETURN_DATA = "return-data";
public static final String EXTRA_NO_FACE_DETECTION = "noFaceDetection";
public static final String EXTRA_OUTPUT_FORMAT = "outputFormat";
private boolean crop;//发送裁剪信号(不一定有效)
private int aspectX;//X方向上的比例
private int aspectY;//Y方向上的比例
private int outputX;//裁剪后的图片的宽。与裁剪框的宽没有半毛钱关系,不要搞混了!
private int outputY;//裁剪后的图片的高。与裁剪框的高没有半毛钱关系,不要搞混了!
private boolean scale;//是否保留比例(不一定有效)
private boolean circleCrop;//是否是圆形裁剪区域(不一定有效)
private boolean returnData;//是否将数据保留在Bitmap中返回
private boolean noFaceDetection;//是否取消人脸识别
private File directory;//裁剪后的图片的保存目录
private String photoPathName;//裁剪后的图片名称,可以包含目录路径
private Bitmap.CompressFormat outputFormat;//裁剪后的图片格式,系统默认为jpeg格式(不一定有效)。如果文件格是png,但图片格式可能是jpeg。
如何使用
篇尾
如果在使用过程中有问题请给我留言,一起学习,一起进步!我是JustinEoy,QQ:1006368252。
人类的全部历史都告诫有智慧的人,不要笃信时运,而应坚信思想。 —— 爱献生
网友评论