1 写在前面

前两天看了下别人保存图片的方式,又看了郭神的第一行代码的拍照和打开相册,又研究了下对图片的裁剪,然后合在一起做了个demo,以后要用直接用就可以了。先说说这个代码比网上其他的代码好的地方。
* 在打开摄像头拍照时兼容了7.0获取uri的方式;
* 打开相册通过uri获取bitmap时使用郭神的方法和框架提供的方法,查了下资料没发现这两种方法的区别以及对比,后面会说;
* 裁剪框架裁剪图片框架中减轻了很多项目中用不到的东西,等下看效果;
* 保存图片把前两天博客中的方法保存图片至相册提炼出来,提供了两种方法选择,只保存图片至系统图库和保存图片至自己连理的文件和系统图片都保存;

2 效果



3 实现

a. 拍照并获取bitmap,主要注意刚才我拍完照片后照片在图库并没有看到,因为我这里拍照完成后图片的的地址使用的是

File photoFile = new File(getExternalCacheDir(),"hehe.jpg");

其中这个getExternalCacheDir()并没有牵涉到sd卡,因为6.0之后读取sd卡是危险权限,要申请权限,这里避免麻烦,就直接使用这个缓存的地址sdcard/android/包名/cache。还有一点就是7.0以后,获取uri对象不能使用以前的getUriForFile(),因为会报FileUriExposedException,这个我没验证过,但是郭神的书里是这样说的。这里我直接上代码,代码里注释写的很清楚。

 /*** 打开相机*/public void takePhoto(){//将照片文件保存在缓存文件夹中,注意这里使用的是缓存文件夹,地址应该是sdcard/android/包名/cache,这样子拍照完后在图库是看不到拍照照片的//如果想在图库看到照片 则这里应该用 Environment.getExternalStorageDirectory()File photoFile = new File(getExternalCacheDir(),"hehe.jpg");if(photoFile.exists()){photoFile.delete();}else{try {photoFile.createNewFile();} catch (IOException e) {e.printStackTrace();}}/*** 运行到这,photoFile已经存在,这里需要获得这个文件的uri* 分两种情况,android7.0以上和以下*/if(Build.VERSION.SDK_INT>=24){/*** FileProvider.getUriForFile(),这个方法中需要填写三个参数,* 第一个Context,* 第二个S* tring 任意* 第三个File*/photoUri = FileProvider.getUriForFile(this, "guozhaohui.com.picturecropeasy", photoFile);}else{photoUri = Uri.fromFile(photoFile);}Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");intent.putExtra(MediaStore.EXTRA_OUTPUT,photoUri);startActivityForResult(intent,100);}

点击拍照完成返回结果的处理

//            case 100:  //拍照返回结果
//
//                if(resultCode==RESULT_OK){//
//                    try {//                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(photoUri));
//                        iv.setImageBitmap(bitmap);
//                    } catch (FileNotFoundException e) {//                        e.printStackTrace();
//                    }
//
//                }

b. 打开相册,裁剪图片并获取bitmap。先把这个裁剪框架效果贴出来吧,因为如果单纯的打开相册获取bitmap不是很难。
框架地址地址


这里面东西很多,但是我们项目中能用到的不是很多,所以如果可以删减那就好了,我这里在点击 他的基础上又去掉一些东西,所以最好自己跑起来体验体验,顺便提一句那位大神的github地址好像不能在as中直接clone,我搞了很久,gradle一直卡住估计是qiang的原因,我是下载源码导入的。
打开相册

    /*** 打开相册*/public void takeAlbum(){Intent intent = new Intent("android.intent.action.GET_CONTENT");intent.setType("image/*");
//        startActivityForResult(Intent.createChooser(intent,"选择图片aaaa"),200);startActivityForResult(intent,200);}

这里的代码主要注意一点

//        startActivityForResult(Intent.createChooser(intent,"选择图片aaaa"),200);

那位大佬用的是这种,其实没有什么区别,就是我们在打开相册时那个提示语可以我们设定。对返回结果的处理,我们一般都是用switch,但是我发现要和大佬的框架结合,不能这样写,所以前面我的代码是注释调的。先上简单的吧,郭神书中的写法很直观。

//
//            case 200:   //相册返回结果
//
//                if(resultCode==RESULT_OK){//
////                    if(Build.VERSION.SDK_INT>=19){  //版本4.4以上选取图片返回的uri处理方式
////
////                        handleImgOver(data);
////
////                    }else{  //版本4.4以下选取图片返回的uri处理方式
////                        handleImgBefore(data);
////                    }
//
//                }
//                break;

因为从4.4开始,选取相册返回的图片不再返回真事的Uri了,而是一个封装过的uri,因为4.4以上的手机需要对这个uri解析。

 /*** 4.4以上对返回的Intent处理,获取图片的path* @param data*/@TargetApi(19)public void handleImgOver(Uri data){String imagePath = null;Uri uri = data;if(DocumentsContract.isDocumentUri(this,uri)){//如果是document类型的uri,则通过documentid处理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(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(contentUri,null);}}else if("content".equalsIgnoreCase(uri.getScheme())){//如果是content类型的uri,则使用普通方式处理imagePath = getImagePath(uri, null);}else if("file".equalsIgnoreCase(uri.getScheme())){//如果是file类型的uri,直接获取图片的路径imagePath = uri.getPath();}showImg(imagePath);}
  /*** 4.4以下对Intent的处理,获取img的path* @param data*/public void handleImgBefore(Uri data){Uri uri = data;String imgPath = getImagePath(uri, null);showImg(imgPath);}
  /*** 此方法用于uri是content类型,通过这个方法可以获取路径path* @param uri* @param selection* @return*/public String getImagePath(Uri uri, String selection){String path = null;Cursor cursor = 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;}

前面我说了,那位大佬获取bitmap的方法并不是郭神的这种,就一行就解决了

//            Bitmap bmp;
//            try {//                bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), resultUri);
//                iv.setImageBitmap(bmp);

然后我查看了下源码

           public static final Bitmap getBitmap(ContentResolver cr, Uri url)throws FileNotFoundException, IOException {InputStream input = cr.openInputStream(url);Bitmap bitmap = BitmapFactory.decodeStream(input);input.close();return bitmap;}

其实很明显可以看到,这个方法的核心就是前面拍照代码一样,知道文件的地址

      InputStream input = cr.openInputStream(url);Bitmap bitmap = BitmapFactory.decodeStream(input);

所以总结来说,如果我们如果只是打开相册并且获取bitmap,这个文件uri的地址并不是我们定义的,刚好我们需要结果uri来获取path,但是这个框架中,我们实现写好了裁剪完成后图片的保存地址,所以可以这样直接写。

  // 剪切后图像文件private Uri mDestinationUri;mDestinationUri = Uri.fromFile(new File(getCacheDir(), "cropImage.jpeg"));

注意刚才这个getCacheDir(),和上面那个getExternalCacheDir(),都是样的,随便不需要申请读写sd权限,但是在manifest中还是要配置的。
还有一点重要的要注意,我们要改裁剪activity的一些东西,就在这个类
UCropActivity,所以我们如果要改变裁剪框的样式改变,比如正方形的,有无边框的,都是在这里设置

 private void initView() {mUCropView = (UCropView) this.findViewById(R.id.weixin_act_ucrop);saveTv = (TextView) this.findViewById(R.id.weixin_act_crop_tv_save);mGestureCropImageView = mUCropView.getCropImageView();mOverlayView = mUCropView.getOverlayView();// 设置允许缩放mGestureCropImageView.setScaleEnabled(true);// 设置禁止旋转mGestureCropImageView.setRotateEnabled(false);// 设置剪切后的最大宽度
//        mGestureCropImageView.setMaxResultImageSizeX(300);// 设置剪切后的最大高度
//        mGestureCropImageView.setMaxResultImageSizeY(300);// 设置外部阴影颜色mOverlayView.setDimmedColor(Color.parseColor("#AA000000"));// 设置周围阴影是否为椭圆(如果false则为矩形)mOverlayView.setOvalDimmedLayer(true);// 设置显示裁剪边框mOverlayView.setShowCropFrame(false);// 设置不显示裁剪网格mOverlayView.setShowCropGrid(false);}

c. 保存图片比较简单,这篇博文点击合理中说的比较乱,所以我根据说明,提出了两个方法

 /*** 仅把图片保存在系统图库中* @param context* @param bmp*/public void saveImgToSystem(Context context, Bitmap bmp){// 直接把图片插入到系统图库,不保存在本地自己建立的文件夹中,避免产生两张一样的图片MediaStore.Images.Media.insertImage(context.getContentResolver(), bmp, "title", "description");//发送广播,提醒刷新context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File("/"+ Environment.getExternalStorageDirectory()+"/image.jpg"))));}
/*** 既保存在系统图库中也保存在自己建立的图库文件夹中* @param context* @param bmp*/public void saveImgToDouble(Context context, Bitmap bmp){// 首先保存图片File appDir = new File(Environment.getExternalStorageDirectory(), "hehe");if (!appDir.exists()) {appDir.mkdir();}String fileName = System.currentTimeMillis() + ".jpg";File file = new File(appDir, fileName);try {FileOutputStream fos = new FileOutputStream(file);bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);fos.flush();fos.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}// 其次把文件插入到系统图库try {MediaStore.Images.Media.insertImage(context.getContentResolver(),file.getAbsolutePath(), fileName, null);} catch (FileNotFoundException e) {e.printStackTrace();}// 最后通知图库更新context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.getPath())));}

3 源码

源码地址

拍照相册和裁剪保存图片集合相关推荐

  1. android编程 自动裁剪图片,Android编程实现调用相册、相机及拍照后直接裁剪的方法...

    本文实例讲述了Android编程实现调用相册.相机及拍照后直接裁剪的方法.分享给大家供大家参考,具体如下: package com.cvte.health.phone; import java.io. ...

  2. Android拍照和相册+系统裁剪功能返回图片

    最近在使用一加3手机,Android系统6.0,进行测试的时候,发现调用手机的拍照和相册选择图片的功能返回的时候都无法调用系统的裁剪功能,Log日志也没有输出有用的信息.经过在网上大量的查找资料,拍照 ...

  3. Android拍照相册裁剪封装

    Android拍照相册裁剪封装 先列出来需要解决问题 展示效果 注意事项 代码 参考资料 最近用到从相机/相册选择图片的功能,这个功能虽然不复杂,网上的代码也一大堆,但是考虑到可能以后别的地方也会用到 ...

  4. 【iOS】拍照/相册单选、相册多选、图片浏览、图片裁剪

    有一段时间没有写iOS系列的博客了.最近由于项目的需要,就有封装了一个拍照/相册单选.相册多选.图片浏览.图片裁剪的工具类.在封装这这类是站在巨人的肩膀上做的. 1.ZLPhotoBrowser:ht ...

  5. 拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现

    前言:这段时间也真是忙到死,本来一个月四篇的承诺,眼看就要打破了,咬着牙再出两篇,最近写工程时,遇到拍照和裁剪功能,也真是服了,各种问题有木有,最后终于找着了一个解决方案,就目前来讲,应用在工程中,还 ...

  6. android --拍照相册选取图片[兼容小米等其他手机]

    前几天做项目中选择图片的过程中遇到小米手机出现不能够选取把图片放入到view中,这里是因为小米采用的是树形结构,而其他手机普遍是图形结构,本质就是url结构有些不同,小米的是绝对路径 1.定义常量: ...

  7. Android 7.0拍照/相册/截取图片FileProvider使用

    Android 7.0拍照/相册/截取图片FileProvider使用 Android 70拍照相册截取图片FileProvider使用 GitHub地址 HIT THE PIT 需求 实现解析 一 ...

  8. Android自定义相机拍照、图片裁剪的实现

    原文:Android自定义相机拍照.图片裁剪的实现 最近项目里面又要加一个拍照搜题的功能,也就是用户对着不会做的题目拍一张照片,将照片的文字使用ocr识别出来,再调用题库搜索接口搜索出来展示给用户,类 ...

  9. android 7.0 裁剪,Android 7.0中拍照和图片裁剪适配的问题详解

    前言 Android 7.0系统发布后,拿到能升级的nexus 6P,就开始了7.0的适配.发现在Android 7.0以上,在相机拍照和图片裁剪上,可能会碰到以下一些错误: Process: com ...

最新文章

  1. Microbiome:所谓的“富集培养”获得的微生物真的都是被“富集”出来的吗?(一作解读)...
  2. PHP框架CodeIgniter之连接MS Sqlserver2014及URL Rewrite问题解决
  3. 错误:android.util.SuperNotCalledException
  4. 机器学习(六)——优化器
  5. IOS网络框架的Alamofire5.4高版本网络工具封装
  6. P4245 【模板】任意模数多项式乘法
  7. 分享一款自用网站导航分类目录程序源码
  8. [转载] Python输入,输出,Python导入
  9. 蓝桥杯2016年第七届C/C++省赛B组第九题-交换瓶子
  10. Oracle设置主键自增
  11. matlab伴随矩阵怎么表示,怎样用Matlab求矩阵的伴随矩阵
  12. tplink703无线打印服务器,tplink703路由器怎么配置client模式
  13. 怎么做移动APP测试,移动应用测试有哪些?
  14. access中本年度的四月一日_吉林十二中古时孔夫子栽银杏设坛讲学 今日十二中植银杏校园生辉...
  15. Avatarify 爆火不到 7 天下架,抖音、快手接棒 “蚂蚁牙黑”刷屏特效制作
  16. 【微信红包封面】哆啦A梦 x GUCCI古驰限定版!!
  17. 十八、阿里云api调用
  18. OpenHarmony如何控制屏幕亮度
  19. ue4怎么用虚幻商城场景_如何利用虚幻商城创造被动收入【经验分享】
  20. 壹角硬币是错版币,也是残币,有收藏价值吗?

热门文章

  1. Mongo数据库简介
  2. 搜狗搜索图片查看器调用帮助
  3. 为季前卡牌游戏 MotoGP™ Ignition Champions 做好准备!
  4. 中华黄金·金生态合伙人颁奖典礼在珠海站开幕完美收官!!
  5. VSCode的一些小操作
  6. 清北学堂2019.8.7
  7. Scrapy爬取贝壳网并存入csv
  8. 使用H5中的表单标签制作一个简单的网页登陆页面
  9. EMD基础学习---emd例子
  10. 木棍游戏(深搜 模板