Android 图片裁剪踩坑
今天做图库图片的裁剪遇到了不少坑,今天记录一下,以下坑位供各位看官参考;
如果有不对之处,欢迎各位看官留言评论!
图片裁剪踩坑锦囊:
问题一:相册裁剪权限问题
解:这个简单,对于Android6.0以上的手机需要进行动态权限的申请:
1>AndroidManifest.xml文件中添加
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2>调用之前动态申请
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"}; /**
* 打开相册
*/
private void openPhotoAlbum(int requestCode) { if (hasPermission()) {
ChoosePicUtil.getInstance().choosePic(getContext(), requestCode);
}
} private boolean hasPermission() { try {
//检测是否有写的权限
int permission = ActivityCompat.checkSelfPermission(getActivity(),
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
ActivityCompat.requestPermissions(getActivity(), PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
} else {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} return false;
}
问题2:android android.system.ErrnoException: open failed: ENOENT (No such file or directory)
对于Android 7 以上的设备加强了文件权限的管理,需要使用FileProvider获取文件(此处是原图片)的uri,值得一提的是如果不使用FileProvider,debug包虽然没有不会crash,但是release包必crash,所以各位看官记得测一测release包。
解决:使用FileProvider:
1>AndroidManifest.xml中配置
<provider
android:authorities="包名.fileProvider"
android:name="android.support.v4.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
/>
</provider>
2>在res文件夹中创建xml文件夹,创建file_paths.xml
可以根据自己的图片存储选择对应的path标签,当然,如过不确定,也可以全部选择。
<paths>
<!-- 物理路径为Context.getFilesDir() + /files/* -->
<files-path path="files" name="files" />
<!-- 物理路径为Context.getCacheDir() + /files/* -->
<cache-path path="files" name="cache" />
<!-- 物理路径为Environment.getExternalStorageDirectory() + /files/* -->
<external-path path="files" name="external" />
<!-- 物理路径为Context.getExternalFilesDir(String) + /files/* -->
<external-files-path path="files" name="externalfiles"/>
<!-- 物理路径为Context.getExternalCacheDir() + /files/* -->
<external-cache-path path="files" name="externalcache"/>
<!-- 物理路径为`Context.getExternalMediaDirs() + /files/*, 要求API21+ -->
<external-media-path name="externalmedia" path="files" />
</paths>
注意:如果图片存储路径与我们选择的path标签不一致就会报错,可以根据报错日志找到对应图片存储路径,选择正确的标签。
3>使用FileProvider
FileProvider.getUriForFile(context, "包名.fileProvider", file) //file: 我们创建的原图片文件
//注意intent跳转时版本大于N时添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
注意:
这里的包名一定要和AndroidManifest中的包名一致且,如果是组件式开发,建议放在主app module的包中,避免包名不一致问题。
问题3:裁剪后提示“无法保存裁剪后的图片”
存在以下几种可能
1:图片存储路径问题
2.对于部分机型图片太大会产生该问题,通过设置setOutputX/Y()小一点
3.裁剪后的图片file的uri不能是使用FileProvider生成的uri,即检查一下 imageCropUri
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageCropUri);
源代码如下:
//图片选取工具类
public class ChoosePicUtil {
public static final int CHOOSE_BG_PICTURE_CODE = 1;
public static final int CHOOSE_COVER_PICTURE_CODE = 2;
public static final int CODE_CAMERA_CROP_1_1_REQUEST = 3;
public static final int CODE_CAMERA_CROP_9_16_REQUEST = 4; private PickParams mPickParams; private static ChoosePicUtil mInstance; public static ChoosePicUtil getInstance() {
if (mInstance == null) {
mInstance = new ChoosePicUtil();
}
return mInstance;
} public ChoosePicUtil buildPickParams(PickParams params) {
mPickParams = params;
return this;
} /**
* 裁剪图片
*
* @param uri
*/
public void cropImg(Context context, Uri uri, Uri imageCropUri, int requestCode) {
Intent intent = new Intent("com.android.camera.action.CROP"); //调用裁剪
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
if (mPickParams == null) {
mPickParams = new PickParams();
}
intent.putExtra("aspectX", mPickParams.aspectX); //设置宽高比例
intent.putExtra("aspectY", mPickParams.aspectY);
intent.putExtra("outputX", mPickParams.outputX); //设置裁剪图片宽高
intent.putExtra("outputY", mPickParams.outputY);
intent.putExtra("return-data", false);
intent.putExtra("scale", true);
intent.putExtra("scaleUpIfNeeded", true); //防止出现黑边框
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageCropUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); //设置输出格式
intent.putExtra("noFaceDetection", true); if (context instanceof Activity) {
((Activity) context).startActivityForResult(intent, requestCode);
}
} /**
* 选取图片
* @param context
*/
public void choosePic(Context context, int requestCode) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
if (context instanceof Activity) {
((Activity) context).startActivityForResult(intent, requestCode);
}
} /**
* 该方法为了适配小米手机裁剪
* 将file://的uri转换为content的content:// 的uri;
* @param context
* @return
*/
public static Uri getImageUri(Context context,Intent data){
String imagePath = null;
Uri uri = data.getData();
if(Build.VERSION.SDK_INT >= 19){
if(DocumentsContract.isDocumentUri(context,uri)){
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())){
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID+"="+id;
imagePath = getImagePath(context,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(context,contentUri,null);
}
}else if("content".equalsIgnoreCase(uri.getScheme())){
imagePath = getImagePath(context,uri,null);
}else if("file".equalsIgnoreCase(uri.getScheme())){
imagePath = uri.getPath();
}
}else{
uri= data.getData();
imagePath = getImagePath(context,uri,null);
}
File file = new File(imagePath);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(context, "io.liuliu.music.fileProvider", file);
} else {
return Uri.fromFile(file);
}
} private static String getImagePath(Context context,Uri uri, String selection) {
String path = null;
Cursor cursor = context.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;
} public static class PickParams {
private int outputX = 300;
private int outputY = 300;
private int aspectX = 1;
private int aspectY = 1; public PickParams() { } public int getOutputX() {
return outputX;
} public PickParams setOutputX(int outputX) {
this.outputX = outputX;
return this;
} public int getOutputY() {
return outputY;
} public PickParams setOutputY(int outputY) {
this.outputY = outputY;
return this; } public int getAspectX() {
return aspectX;
} public PickParams setAspectX(int aspectX) {
this.aspectX = aspectX;
return this; } public int getAspectY() {
return aspectY;
} public PickParams setAspectY(int aspectY) {
this.aspectY = aspectY;
return this; } }
}
//接收图片返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) {
return;
}
if (requestCode == CHOOSE_BG_PICTURE_CODE) { Uri uri = ChoosePicUtil.getImageUri(this, data);
//375 * 900 太大了,部分手机不支持 ChoosePicUtil.PickParams params =
new ChoosePicUtil.PickParams()
.setAspectX(9)
.setAspectY(16)
.setOutputX(270)
.setOutputY(480); imageCropUri = getImageCropUri(CHOOSE_BG_PICTURE_CODE); ChoosePicUtil.getInstance()
.buildPickParams(params)
.cropImg(this, uri, imageCropUri, ChoosePicUtil.CODE_CAMERA_CROP_9_16_REQUEST);
} else if (requestCode == CHOOSE_COVER_PICTURE_CODE) { Uri uri = ChoosePicUtil.getImageUri(this, data); imageCropUri = getImageCropUri(CHOOSE_COVER_PICTURE_CODE); ChoosePicUtil.PickParams params =
new ChoosePicUtil.PickParams()
.setAspectX(1)
.setAspectY(1)
.setOutputX(300)
.setOutputY(300); ChoosePicUtil.getInstance()
.buildPickParams(params)
.cropImg(this, uri, imageCropUri, ChoosePicUtil.CODE_CAMERA_CROP_1_1_REQUEST);
} else if (requestCode == ChoosePicUtil.CODE_CAMERA_CROP_9_16_REQUEST) {
if (imageCropUri != null) {
//do what you want
}
} else if (requestCode == ChoosePicUtil.CODE_CAMERA_CROP_1_1_REQUEST) {
if (imageCropUri != null) {
//do what you want
}
} }
Android 图片裁剪踩坑的更多相关文章
- [Android] 图片裁剪总结——调用系统裁剪
花了两天时间看了下android的图片裁剪功能的实现.其实刚开始做这个我挺虚的,以为整个功能都需要自己写出来,但查了些资料,发现android已经提供了裁剪功能,需要的话自己调用就成了.soga,这下 ...
- Android Studio安装踩坑
title: Android Studio安装踩坑 date: 2018-09-07 19:31:32 updated: tags: [Android,Android Studio,坑] descri ...
- Android 图片裁剪库 uCrop
引语 晚上好,我是猫咪,我的公众号「程序媛猫咪」会推荐 GitHub 上好玩的项目,挖掘开源的价值,欢迎关注我. 现在 Android 开发,离不开图片,必然也需要图片裁剪功能,这个实现可以调用系统的 ...
- React Native Android配置部署踩坑日记
万事开头难 作为一只进入ECMAScript世界不久的菜鸟,已经被React Native的名气惊到了,开源一周数万星勾起了我浓烈的兴趣.新年新气象,来个HellWorld压压惊吧^_^(故意少打个' ...
- Android图片裁剪之自由裁剪
我的博客http://blog.csdn.net/dawn_moon 客户的需求都是非常怪的.我有时候在给客户做项目的时候就想骂客户是sb.可是请你相信我,等你有需求,自己变成客户的时候,给你做项目的 ...
- Android图片裁剪解决方案 -- 从相册截图
在看Storage Access Framework,里面有一个加载相册图片的程序片断,可能是系统版本的问题,无法返回结果,这里找到一个适用于旧版本的方法. 在Android开发中,可以轻松调用一个I ...
- [Android] 图片裁剪总结——自定义裁剪工具
上次弄完调用系统裁剪之后,我又试着做一个自定义的裁剪工具. 原文地址请保留http://www.cnblogs.com/rossoneri/p/3988405.html 老习惯,文章开始前还是先把我参 ...
- Android WebView 文明踩坑之路
情景一 webview 以头布局的形式添加到 RecyclerView 中,第一次进入页面,当页面中有 EditText 并且点击时,甚至是类似点赞更换图片.点击 WebView 任意区域,都会造成 ...
- Android 之 ToolBar 踩坑笔记
写在前面 •前言 这两天,学完了 Fragment 的基础知识,正准备跟着<第一行代码>学习制作一个简易版的新闻应用: 嘀嘀嘀~~~ 一声消息传来,像往常一样,打开 QQ,当我看到 QQ ...
随机推荐
- 【python(deap库)实现】GEAP 遗传算法/遗传编程 genetic programming +
目录 前言 1.优化问题的定义 单目标优化 多目标优化 2.个体编码 实数编码 二进制编码 序列编码(Permutation encoding) 粒子(Particles) 3 初始种群建立 一般族群 ...
- Python列表,元组,字典,字符串方法笔记
01. 列表 1.1 列表的定义 List(列表) 是 Python 中使用 最频繁 的数据类型,在其他语言中通常叫做 数组 专门用于存储 一串 信息 列表用 [] 定义,数据 之间使用 , 分隔 列 ...
- scrapy框架简介与安装启动
Scrapy 是一个专业的.高效的爬虫框架,它使用专业的 Twisted 包(基于事件驱动的网络引擎包)高效地处理网络通信,使用 lxml(专业的 XML 处理包).cssselect 高效地提取 H ...
- 2.3 Go内置函数
内置函数 Go 语言拥有一些不需要进行导入操作就可以使用的内置函数.它们有时可以针对不同的类型进行操作,例如:len.cap 和 append,或必须用于系统级的操作,例如:panic.因此,它们需要 ...
- docker基本维护命令
docker search centos ##查服务器上面的镜像:docker images ##查本地的镜像.docker pull centos ##拉镜像. docker run centos ...
- 王艳 201771010127《面向对象程序设计(java)》第七周学习总结
1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: (2)掌握Object类的常用API用法: (3)掌握ArrayList类用法与常用API: (4)掌握枚举类使用方法: (5)结合 ...
- [!] Unable to find a pod with name, author, summary, or description matching `AFNetworking`
大量的答案是删除~/Library/Caches/CocoaPods/search_index.json 没有起作用 有用答案: https://blog.csdn.net/qq_35827461/ ...
- hdu6005找带权最小环
题意:给你点和边,让你找最小环的权值,其权值是所有边权的和,没环输出-1. 解法:枚举每一条边,找到其端点,做最短路.. #include<cstdio> #include<cstr ...
- python+selenium实现百度关键词搜索自动化操作
缘起 之前公司找外面网络公司做某些业务相关关键词排名,了解了一下相关的情况,网络公司只需要我们提供网站地址和需要做的关键词即可,故猜想他们采取的方式应该是通过模拟用户搜索提升网站权重进而提升排名. 不 ...
- Java学习大纲-0412更新
非科班报培训班学习Java,从博客园,知乎,CNDS上搜了一圈,暂时按以下计划执行,有问题随时更新--0412 1.培训班的课程按时按点学习完成(毕竟掏钱在学的是不,不好好听亏不亏...) keys: ...