拍照、相册及裁剪的终极实现(二)——相册选择及裁剪功能实现
来源:互联网 发布:linux 关闭mysql服务 编辑:程序博客网 时间:2024/06/06 01:04
在上篇中,我们看到有关拍照和裁剪的方案,这里带大家看看如何从相册中选择文件并裁剪。
一、从相册选择图像并显示
先看看效果图:
如图一,有四个按钮,这里用第一个按钮:(相册选择——返回值),它的意思是通过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, <span style="font-family: Arial, Helvetica, sans-serif;">RESULT_ALBUM_ONLY_THROUGH_DATA</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span>
在开启相册之后,选择对应的图片,然后接收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 {
-
- 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:
附加选项数据类型描述cropString发送裁剪信号aspectXintX方向上的比例aspectYintY方向上的比例outputXint裁剪区的宽outputYint裁剪区的高scaleboolean是否保留比例return-databoolean是否将数据保留在Bitmap中返回dataParcelable相应的Bitmap数据circleCropString圆形裁剪区域?MediaStore.EXTRA_OUTPUT ("output")URI将URI指向相应的file:///...,详见代码示例outputFormatString输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString()noFaceDetectionboolean是否取消人脸识别功能上篇我们说过这些参数可以随意匹配,那这里我们就用来裁剪从相册转过来的图片;首先,启动选择相册Intent,然后配置各个参数:
- 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数据,找到图片地址,代码如下:
我没看懂,只能给大家贴代码了,非常抱歉。
-
- 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;
-
- if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
-
- 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];
- }
- }
-
- 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);
- }
-
- 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);
- }
- }
-
- else if ("content".equalsIgnoreCase(uri.getScheme())) {
- if (isGooglePhotosContentUri(uri))
- return uri.getLastPathSegment();
- return getDataColumn(context, uri, null, null);
- }
-
- 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;
- }
- }
注意,上面的更正在下面的源码中没有改过来,大家还需要在理解上基础上,自行更正。
另一篇很棒的文章:
《你需要知道的 Android 拍照适配方案》:http://diycode.cc/topics/101
源码有四个按钮:
1、相册选取——返回值:对应第一部分
2、相册选择——PATH(终极):对应第四部分
3、相册并截取——URI:对应第二部分
4、相册并截取——PATH(终极):对应第三部分
如果本文有帮到你,记得加关注哦。
源码下载地址:http://download.csdn.net/detail/harvic880925/8445281
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/43314451,谢谢
0 0