拍照、相册及裁剪的终极实现(二)——相册选择及裁剪功能实现
2015-01-30 21:04
489 查看
前言,a马上要回家过年了,回家前争取把这篇文章写出来给大家,这三个月真是跟打仗似的,天天累的跟狗一样,不过看着自己做的东西被别人用,那真是爽,虽然俺还比较菜,也不是什么核心功能,能一毕业就能加入到这么大的项目中来也是很荣幸的,插一句,这几天阿里有七个工作日极速面试哦,有能力的同学拿简历来,嘿嘿
在上篇中,我们看到有关拍照和裁剪的方案,这里带大家看看如何从相册中选择文件并裁剪。
如图一,有四个按钮,这里用第一个按钮:(相册选择——返回值),它的意思是通过intent.的data域来获取返回的图像数据;点击后转到图片选择页面,选择后,在底部将显示的图片显示出来。
(一) (二) (三)
在上篇中我们提到过启动相册的ACTION为:
这里要注意一下,这里没有将return-data设为false,也就是使用了默认值,即直接使用Intent中的data域来传递结果值,但问题在于Data域最大传递的值的大小为1M,所以图片的BITMAP当超过1M时就会失败。从而显示缩略图。
这里先演示这种方法的效果,至于从相册选择的终极方案,同样,我们会在讲过裁剪后给出。
点击“相册并截取——URI”(图一),转入相册页面(图二),选中一张图片,转到裁剪页面(图三),将裁剪后的图片显示在imageView中(图四)
(一) (二)
(三) (四)
还记得上篇中的裁剪用的N多参数么,这里再给大家贴一下
Exta Options Table for image/* crop:
上篇我们说过这些参数可以随意匹配,那这里我们就用来裁剪从相册转过来的图片;首先,启动选择相册Intent,然后配置各个参数:
然后在接收时:
直接从URI中获取图片,然后显示在imageView中;
还记得在上篇中拍照时也出现过出不来裁剪页面的情况,当时是由于Intent之间传递数据最大只能传1M左右,当超过这个数据时就会传递不成功,所以在上篇中我们为了传递拍照的结果,把它暂存到本地图片中,然后在重新调用裁剪Intent,把数据传进去,让它裁剪。通过绕过Intent之间直接数据传递,而使用间接传递数据的方法来完成较大数据的传递。那这里要怎么办呢?有没有一种方法能找到用户点击的图片的地址呢?如果能找到地址,那在用户点击一个图片后,再调用裁剪的Intent,从本地读取图片数据传进去裁剪Intent让它来裁剪,这样就绕过了直接通过Intent数据传递的大小限制。
我没看懂,只能给大家贴代码了,非常抱歉。
先调用相册Intent:
将保存的本地的图片取出,设置到ImageView中,为了停止显示不出来所以将其缩小到1/2
首先启动相册Intent:
好了,这篇文章到这里就结束了,工作太忙,一直没时间写,今天总算赶完给大家了。
上面我是这样写的:
即直接从TempFile中获取当前保存的图片:
注意,上面的更正在下面的源码中没有改过来,大家还需要在理解上基础上,自行更正。
源码有四个按钮:
1、相册选取——返回值:对应第一部分
2、相册选择——PATH(终极):对应第四部分
3、相册并截取——URI:对应第二部分
4、相册并截取——PATH(终极):对应第三部分
如果本文有帮到你,记得加关注哦。
源码下载地址:http://download.csdn.net/detail/harvic880925/8445281
请大家尊重原创者版权,转载请标明出处:/article/2594058.html,谢谢
在上篇中,我们看到有关拍照和裁剪的方案,这里带大家看看如何从相册中选择文件并裁剪。
一、从相册选择图像并显示
先看看效果图:如图一,有四个按钮,这里用第一个按钮:(相册选择——返回值),它的意思是通过intent.的data域来获取返回的图像数据;点击后转到图片选择页面,选择后,在底部将显示的图片显示出来。
(一) (二) (三)
在上篇中我们提到过启动相册的ACTION为:
public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";所以隐匿启动相册Intent的代码为:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); startActivityForResult(intent, RESULT_ALBUM_ONLY_THROUGH_DATA);在开启相册之后,选择对应的图片,然后接收Result:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_ALBUM_ONLY_THROUGH_DATA: { //照片的原始资源地址 try { //使用ContentProvider通过URI获取原始图片 Bitmap photo = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData()); if (photo != null) { Bitmap smallBmp = setScaleBitmap(photo, 2); mImageView.setImageBitmap(smallBmp); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } break; } }
这里要注意一下,这里没有将return-data设为false,也就是使用了默认值,即直接使用Intent中的data域来传递结果值,但问题在于Data域最大传递的值的大小为1M,所以图片的BITMAP当超过1M时就会失败。从而显示缩略图。
这里先演示这种方法的效果,至于从相册选择的终极方案,同样,我们会在讲过裁剪后给出。
二、从相册选取并裁剪(通过URI返回)
先看下效果:点击“相册并截取——URI”(图一),转入相册页面(图二),选中一张图片,转到裁剪页面(图三),将裁剪后的图片显示在imageView中(图四)
(一) (二)
(三) (四)
还记得上篇中的裁剪用的N多参数么,这里再给大家贴一下
Exta Options Table for image/* crop:
附加选项 | 数据类型 | 描述 |
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 | 是否取消人脸识别功能 |
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 1000); intent.putExtra("outputY", 1000); intent.putExtra("scale", true); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); startActivityForResult(intent, RESULT_ALBUM_CROP_URI);上面这段代码首先将action设为启动相册Intent的action:
public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";然后不让数据从Intent的data域返回,而是保存在我们指定的URI中;
然后在接收时:
直接从URI中获取图片,然后显示在imageView中;
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_ALBUM_CROP_URI: { try { Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); if (bitmap != null) { Bitmap smallBmp = setScaleBitmap(bitmap, 2); mImageView.setImageBitmap(smallBmp); } } catch (Exception e) { e.printStackTrace(); } } break; } }看着好像没什么事情,但问题来了:在有些手机上根本出不来裁剪页面,这是为什么呢?
还记得在上篇中拍照时也出现过出不来裁剪页面的情况,当时是由于Intent之间传递数据最大只能传1M左右,当超过这个数据时就会传递不成功,所以在上篇中我们为了传递拍照的结果,把它暂存到本地图片中,然后在重新调用裁剪Intent,把数据传进去,让它裁剪。通过绕过Intent之间直接数据传递,而使用间接传递数据的方法来完成较大数据的传递。那这里要怎么办呢?有没有一种方法能找到用户点击的图片的地址呢?如果能找到地址,那在用户点击一个图片后,再调用裁剪的Intent,从本地读取图片数据传进去裁剪Intent让它来裁剪,这样就绕过了直接通过Intent数据传递的大小限制。
三、从相册选取并裁剪(通过Path:终极方案)
找来找去,终于在开源项目中找到了一个方法,通过传进去Intent的data域返回的URI数据,找到图片地址,代码如下:我没看懂,只能给大家贴代码了,非常抱歉。
// 解析获取图片库图片Uri物理路径 public static String parsePicturePath(Context context, Uri uri) { if (null == context || uri == null) return null; boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentUri if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageDocumentsUri if (isExternalStorageDocumentsUri(uri)) { String docId = DocumentsContract.getDocumentId(uri); String[] splits = docId.split(":"); String type = splits[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + File.separator + splits[1]; } } // DownloadsDocumentsUri else if (isDownloadsDocumentsUri(uri)) { String docId = DocumentsContract.getDocumentId(uri); Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); return getDataColumn(context, contentUri, null, null); } // MediaDocumentsUri else if (isMediaDocumentsUri(uri)) { String docId = DocumentsContract.getDocumentId(uri); String[] split = docId.split(":"); String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } String selection = "_id=?"; String[] selectionArgs = new String[] {split[1]}; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (general) else if ("content".equalsIgnoreCase(uri.getScheme())) { if (isGooglePhotosContentUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; }整体过程是这样的:
先调用相册Intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); startActivityForResult(intent, RESULT_ALBUM_CROP_PATH);然后在接收时,找到图片路径,生成对应的URI,转给裁剪页面:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_ALBUM_CROP_PATH:{ String picPath = parsePicturePath(MyActivity.this,data.getData()); File file = new File(picPath); Uri uri = Uri.fromFile(file); cropImg(uri); } break; } }然后是裁剪图片的代码:cropImg(Uri uri)
public void cropImg(Uri uri) { File tempFile = getTempFile(); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 700); intent.putExtra("outputY", 700); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); startActivityForResult(intent, RESULT_CAMERA_CROP_PATH_RESULT); }在裁剪图片后,将结果保存到暂存的本地图片URI中,然后在接收Result时:
将保存的本地的图片取出,设置到ImageView中,为了停止显示不出来所以将其缩小到1/2
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_CAMERA_CROP_PATH_RESULT: { Bundle extras = data.getExtras(); if (extras != null) { Bitmap bitmap = BitmapFactory.decodeFile(getTempFile().getAbsolutePath(), null); if (bitmap != null) { Bitmap smallBmp = setScaleBitmap(bitmap, 2); mImageView.setImageBitmap(smallBmp); } } } break; } }
四、从相册选择图像并显示的终极方案
在第一部分,我们讲过,当图片过大时,会出现数据传递失败的情况,因为Intent的data域最大只能传1M的数据,当数据超过1M时就会出现传递失败,上面我们有了一个方法根本返回的data找到对应的路径。这里大家是不是有什么想法了,这里知道了路径,直接从路径取图片不就好了,所以通过路径的显示选择图片的终极方案就出来了。首先启动相册Intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); startActivityForResult(intent, RESULT_ALBUM_ONLY_THROUGH_URI);然后在接收时:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_ALBUM_ONLY_THROUGH_URI: { try { String picPath = parsePicturePath(MyActivity.this, data.getData()); File file = new File(picPath); Uri uri = Uri.fromFile(file); Bitmap photo = MediaStore.Images.Media.getBitmap(getContentResolver(), uri); if (photo != null) { Bitmap smallBmp = setScaleBitmap(photo, 2); mImageView.setImageBitmap(smallBmp); } } catch (Exception e) { e.printStackTrace(); } } break; } }直接从data域获取图片路径,然后从路径加载出Bitmap,这就不会因为图片太大显示不出来了。
好了,这篇文章到这里就结束了,工作太忙,一直没时间写,今天总算赶完给大家了。
更正:
在《三、从相册选取并裁剪(通过Path:终极方案)》中,在接收时:上面我是这样写的:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_CAMERA_CROP_PATH_RESULT: { Bundle extras = data.getExtras(); if (extras != null) { Bitmap bitmap = BitmapFactory.decodeFile(getTempFile().getAbsolutePath(), null); if (bitmap != null) { Bitmap smallBmp = setScaleBitmap(bitmap, 2); mImageView.setImageBitmap(smallBmp); } } } break; } }由于在cropImg(Uri uri)中,我们设置了MediaStore.EXTRA_OUTPUT参数,即我们已经将结果转成URI,输出到tempFile中去了,所以在Intent的Data域可能就没有值了;(极少个别机型会出现),所以正确的接收方式应该为:
即直接从TempFile中获取当前保存的图片:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK) { return; } switch (requestCode) { case RESULT_CAMERA_CROP_PATH_RESULT: { if (getTempFile() != null) { Bitmap bitmap = BitmapFactory.decodeFile(getTempFile().getAbsolutePath(), null); if (bitmap != null) { Bitmap smallBmp = setScaleBitmap(bitmap, 2); mImageView.setImageBitmap(smallBmp); } } } break; } }
注意,上面的更正在下面的源码中没有改过来,大家还需要在理解上基础上,自行更正。
源码有四个按钮:
1、相册选取——返回值:对应第一部分
2、相册选择——PATH(终极):对应第四部分
3、相册并截取——URI:对应第二部分
4、相册并截取——PATH(终极):对应第三部分
如果本文有帮到你,记得加关注哦。
源码下载地址:http://download.csdn.net/detail/harvic880925/8445281
请大家尊重原创者版权,转载请标明出处:/article/2594058.html,谢谢
相关文章推荐
- 拍照、相册及裁剪的终极实现(二)——相册选择及裁剪功能实现
- 拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现
- 拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现
- Android实现拍照、选择相册图片并裁剪功能
- 拍照、相册及裁剪的终极实现(一)——拍照及裁剪功能实现
- Android实现拍照,以及从相册选择图片裁剪功能同时保存在本地
- 图片拍照或相册选择的实现以及裁剪功能
- Android 设置用户头像 -》拍照/相册选择+裁剪 实现
- 前端实现调用移动端拍照以及打开相册裁剪功能
- 7.0相机的路径问题,附带裁剪功能,相册或拍照选择图片均可
- Android 头像(拍照,相册)选择后裁剪功能
- 即时聊天的拍照做图像和相册选择做图像的功能的实现
- Android开发:仿微信和QQ空间发说说相册读取、拍照、图片裁剪和图片上传服务器等功能的实现
- 带你实现拍照||从相册选择->裁剪->上传服务器
- Cocos2d-x 3.x 头像选择器,本地相册与拍照+头像编辑功能(Android、IOS双平台实现)
- Android开发:相册读取、拍照、图片裁剪和图片上传服务器等功能的实现
- Android之圆形头像(实现相机拍摄+相册选择+图片裁剪功能)
- Android实现拍照、选择图片并裁剪图片功能
- Android实现拍照、选择图片并裁剪图片功能
- Android之圆形头像(实现相机拍摄+相册选择+图片裁剪功能)