Android图片裁剪功能——调用系统裁剪

花了两天时间看了下android的图片裁剪功能的实现。其实刚开始做这个我挺虚的,以为整个功能都需要自己写出来,但查了些资料,发现android已经提供了裁剪功能,需要的话自己调用就成了。soga,这下轻松多了。

首先推荐几篇博客

Android大图片裁剪终极解决方案

要想弄明白裁剪功能,这系列博客非常重要,你可以不看我下面总结的,但你一定要看他这系列的几篇文章。

Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)

这篇也不错,比较喜欢他的注释。虽然也有些误导,比如说他有一段对setData,setType和setDataAndType方法的区别疑问,他说两种写法一样效果,我就信了,害得我找bug找了两个小时,一直怀疑别的参数出问题,实际上是这两个方法的差别。这一点后面会说。

其他的相关博客有很多,但基本上大同小异,包括我这篇。有了上面的两个博客,就可以大概搞懂这方面的原理了。

我要写的,就是多写一些注释,改变一些写法,增加点说明,积累点经验,为了自己以后方便重温自己做过的东西,而已。

不再浪费你我的时间,开始了。



丑得不能忍的分割区



RyanHoo的Demo写的很详细。但要学习,我习惯先把代码简化,看的逻辑清楚些。我选择了最适应自己需求的选择大图片裁剪的部分代码

我测试的简化代码

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context=".MainActivity" >
 6
 7     <Button
 8         android:id="@+id/button"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="click me!" />
12
13     <ImageView
14         android:id="@+id/imageview"
15         android:layout_width="match_parent"
16         android:layout_height="match_parent"
17         android:scaleType="centerInside" />
18
19 </LinearLayout>
  1 public class MainActivity extends Activity implements OnClickListener {
  2
  3     private Uri imageUri;
  4     private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";
  5     private Button btn;
  6     private ImageView iv;
  7
  8     @Override
  9     protected void onCreate(Bundle savedInstanceState) {
 10         super.onCreate(savedInstanceState);
 11         setContentView(R.layout.activity_main);
 12         btn = (Button) findViewById(R.id.button);
 13         btn.setOnClickListener(this);
 14         imageUri = Uri.parse(IMAGE_FILE_LOCATION);
 15         iv = (ImageView) findViewById(R.id.imageview);
 16     }
 17
 18     @Override
 19     public boolean onCreateOptionsMenu(Menu menu) {
 20         // Inflate the menu; this adds items to the action bar if it is present.
 21         getMenuInflater().inflate(R.menu.activity_main, menu);
 22         return true;
 23     }
 24
 25     @Override
 26     public void onClick(View v) {
 27         // TODO Auto-generated method stub
 28
 29         // 试着改成打开自己写的图片浏览器
 30         switch (v.getId()) {
 31         case R.id.button:
 32             //这段代码使用ACTION_GET_CONTENT和ACTION_PICK效果相同
 33             Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
 34             // Intent intent = new Intent(Intent.ACTION_PICK, null);
 35
 36             // 如果使用com.android.camera.action.CROP 则直接打开裁剪照片的activity 那么可以用自己的图片浏览器选择图片 传入参数并使用之
 37             // Intent intent = new Intent("com.android.camera.action.CROP");
 38
 39             // 如果不设置type,则 ACTION_GET_CONTENT 会弹出异常FATAL EXCEPTION:main android.content.ActivityNotFoundException
 40             // 而 ACTION_PICK 会弹出可用程序列表 但没有打开图片相关的程序(在我的两个设备上是这样)
 41             intent.setType("image/*");
 42
 43             // 设置在开启的Intent中设置显示的view可裁剪
 44             // 这段代码里设置成false也能裁剪啊。。。这是为什么?懂的给我讲讲了
 45             // 这段注释掉就不会跳转到裁剪的activity
 46             intent.putExtra("crop", "true");
 47
 48             // 设置x,y的比例,截图方框就按照这个比例来截 若设置为0,0,或者不设置 则自由比例截图
 49             intent.putExtra("aspectX", 2);
 50             intent.putExtra("aspectY", 1);
 51
 52             // 裁剪区的宽和高 其实就是裁剪后的显示区域 若裁剪的比例不是显示的比例,则自动压缩图片填满显示区域。若设置为0,0 就不显示。若不设置,则按原始大小显示
 53             intent.putExtra("outputX", 200);
 54             intent.putExtra("outputY", 100);
 55
 56             // 不知道有啥用。。可能会保存一个比例值 需要相关文档啊
 57             intent.putExtra("scale", true);
 58
 59             // true的话直接返回bitmap,可能会很占内存 不建议
 60             intent.putExtra("return-data", false);
 61             // 上面设为false的时候将MediaStore.EXTRA_OUTPUT即"output"关联一个Uri
 62             intent.putExtra("output", imageUri);
 63             // 看参数即可知道是输出格式
 64             intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
 65             // 面部识别 这里用不上
 66             intent.putExtra("noFaceDetection", false);
 67
 68             // 想从Activity中获得返回数据,在启动Activity时候使用startActivityForResult方法
 69             // 1为请求代码,可以是任意值,个人感觉用资源id会比较清楚,而且不会重复 比如当前控件的R.id.button
 70             startActivityForResult(intent, 1);
 71             break;
 72         default:
 73             break;
 74         }
 75     }
 76
 77     @Override
 78     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 79         // TODO Auto-generated method stub
 80         super.onActivityResult(requestCode, resultCode, data);
 81         if (resultCode != Activity.RESULT_OK) {// result is not correct
 82             return;
 83         } else {
 84             switch (requestCode) {
 85             case 1:
 86                 if (imageUri != null) {
 87                     Bitmap bitmap = decodeUriAsBitmap(imageUri);
 88                     // 把解析到的位图显示出来
 89                     iv.setImageBitmap(bitmap);
 90                 }
 91                 break;
 92             default:
 93                 break;
 94             }
 95
 96         }
 97     }
 98
 99     private Bitmap decodeUriAsBitmap(Uri uri) {
100         Bitmap bitmap = null;
101         try {
102             // 先通过getContentResolver方法获得一个ContentResolver实例,
103             // 调用openInputStream(Uri)方法获得uri关联的数据流stream
104             // 把上一步获得的数据流解析成为bitmap
105             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
106         } catch (FileNotFoundException e) {
107             e.printStackTrace();
108             return null;
109         }
110         return bitmap;
111     }
112 }

其实用法看前面的博客就已经很清楚了,这里主要部分就是Intent附加数据的具体含义解释与使用方法,我都尽量写在代码的注释当中了。



再丑也得忍的分割线



我后来想只调用裁剪窗口,而选图片的时候使用自己写的图片选择器,那么这个参数怎么传,怎么调用裁剪activity呢?

使用裁剪功能用"com.android.camera.action.CROP"就可以。

传图片的话有两个方法,一个是intent直接传bitmap数据,另一个是传uri。

 1     private void startCropIntent(String path) throws FileNotFoundException {
 2         Bitmap bmp = BitmapFactory.decodeFile(path);
 5         Intent intent = new Intent("com.android.camera.action.CROP"); 9         // Intent传输的bytes不能超过40k。不建议这样 无法处理大图
10         intent.putExtra("data", bmp);
11         // intent.setData(uri);
12         // intent.setType("image/*");
13         intent.setDataAndType(imageUri, "image/*");
14         intent.putExtra("crop", "true");
15         intent.putExtra("aspectX", 2);
16         intent.putExtra("aspectY", 1);
17         intent.putExtra("outputX", 300);
18         intent.putExtra("outputY", 150);
19         // 设置为true直接返回bitmap
20         intent.putExtra("return-data", true);
24         startActivityForResult(intent, 1);
25     }
26
27     @Override
28     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
29         super.onActivityResult(requestCode, resultCode, data);
30         if (resultCode != Activity.RESULT_OK) {// result is not correct
31             return;
32         } else {
33             switch (requestCode) {
34             case 1:
40                 Bundle bundle = data.getExtras();
41                 Bitmap bitmap = bundle.getParcelable("data");
42                 iv.setImageBitmap(bitmap);
43
44                 break;
45
46             default:
47                 break;
48             }
49         }
51     }

这里参数path是选择的图片的绝对路径。

这种方法有局限性,因为intent传递的数据不超过40k,只能选择40k以下的图片裁剪

还是使用uri比较好

 1 private void startCropIntent(String path) throws FileNotFoundException {
 2         Bitmap bmp = BitmapFactory.decodeFile(path);
 3
 4         File file = new File(path);
 5         Intent intent = new Intent("com.android.camera.action.CROP");
 7         Uri uri = Uri.fromFile(file);// parse(pathUri);13         intent.setDataAndType(uri, "image/*");
14         intent.putExtra("crop", "true");
15         intent.putExtra("aspectX", 2);
16         intent.putExtra("aspectY", 1);
17         intent.putExtra("outputX", 300);
18         intent.putExtra("outputY", 150);
19         // 设置为true直接返回bitmap
20         intent.putExtra("return-data", false);
21         // 上面设为false的时候将MediaStore.EXTRA_OUTPUT关联一个Uri
22         intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
23         intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
24         startActivityForResult(intent, 1);
25     }
26
27     @Override
28     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
29         super.onActivityResult(requestCode, resultCode, data);
30         if (resultCode != Activity.RESULT_OK) {// result is not correct
31             return;
32         } else {
33             switch (requestCode) {
34             case 1:
35                 if (imageUri != null) {
36                     Bitmap bitmap = decodeUriAsBitmap(imageUri);
37                     // 把解析到的位图显示出来
38                     iv.setImageBitmap(bitmap);
39                 }
44                 break;
45
46             default:
47                 break;
48             }
49         }
50
51     }
52
53     private Bitmap decodeUriAsBitmap(Uri uri) {
54         Bitmap bitmap = null;
55         try {
59             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
60         } catch (FileNotFoundException e) {
61             e.printStackTrace();
62             return null;
63         }
64         return bitmap;
65     }

这里需要注意

intent.setData(uri);intent.setType("image/*");和
intent.setDataAndType(uri, "image/*");是有区别的。

我开始以为两个方法一样的,但看了源码就清楚了。

1  public Intent setDataAndType(Uri data, String type) {
2         mData = data;
3         mType = type;
4         return this;
5     }
1     public Intent setData(Uri data) {
2         mData = data;
3         mType = null;
4         return this;
5     }
1     public Intent setType(String type) {
2         mData = null;
3         mType = type;
4         return this;
5     }

好了,调用系统裁剪就这么些内容,这方面除了文档太难找,也没什么难的。

下面就是不调用系统,自己写一个裁剪图片的方法了。知道下面要干什么了,就抽时间搞吧。

时间: 2024-08-09 23:48:25

Android图片裁剪功能——调用系统裁剪的相关文章

Android 相册图片选取+自定义裁剪方式(非系统裁剪)

不多说,直接上代码(裁剪的代码摘自网络.)(项目可运行) 主要是系统自身的剪切方式在有些机型上会程序崩溃的问题. 1 package com.jichun.activity; 2 3 import java.io.FileNotFoundException; 4 5 import com.jichun.view.CropCanvas; 6 7 import android.app.Activity; 8 import android.content.ContentResolver; 9 impo

【Android】使用Intent调用系统其它程序,使用onKeyDown对音量键的监听,长按事件

Intent在安卓编程中非常常见,在<[Android]多个Activity之间利用bundle传递数值>(点击打开链接)中已经展示了它可以唤醒其它Activity并在Activity之间传递数据.其实Intent的作用远非于此,它还可以调用系统中其它固有程序,比如拨打电话.发送短信等.onKeyDown也是如此,不仅仅可以对设备的菜单键进行监听,这在<[Android]各式各样的弹出框与对菜单键.返回键的监听>(点击打开链接)中已经展示过的,对设备的音量调节键也是可以监听的, 下

hbuilder mui调用系统裁剪图片、头像裁剪-Android

head.addEventListener('tap', function() { var IMAGE_UNSPECIFIED = "image/*"; //相册显示的文件类型 var PHOTOZOOM = 2; // 获取完图片返回key var PHOTOLAT = 1; // 剪裁完毕后返回key var main = plus.android.runtimeMainActivity(); //h5+获取应用主Activity实例对象 var Intent = plus.and

android调用系统裁剪图片的设置

// 裁剪图片 public void cropPhoto(Uri uri) { if (uri == null) { return; } Intent intent = new Intent("com.android.camera.action.CROP");//动作-裁剪 intent.setDataAndType(uri, "image/*");//类型 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile

调用系统相机拍照,保存照片,调用系统裁剪API对照片处理,显示裁剪之后的照片

package com.pingyijinren.test; import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Intent; impo

高版本Android如何利用反射调用系统隐藏的远程服务拦截来电

要说拦截Android系统来电,就不得不说起在低版本的时候Android提供给开发者使用的一个方法:endCall(),但由于谷歌后来考虑到对于一部手机来说,最重要的功能就是打电话了,如果这个功能随随便便就被人屏蔽了,安全性太差,所以在高版本的Android将这个方法屏蔽了,不再在TelephoneManager中暴露这个方法. 那么我们下面的目标就是要想办法调用到这个方法,当然首先我们还是需要实现一个广播接收者,来接收电话状态改变的广播,这里使用在服务中动态注册广播接收者的方法来实现,主要好处

Android连接wifi,调用系统API【转】

本文转载自:http://blog.csdn.net/aaa1050070637/article/details/54136472 直接上代码,简单粗暴,一看就懂 [java] view plain copy import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; impor

[Android Pro] 调用系统相机和图库,裁剪图片

private static final int PHOTO_REQUEST_TAKEPHOTO = 1;// 拍照 private static final int PHOTO_REQUEST_GALLERY = 2;// 从相册中选择 private static final int PHOTO_REQUEST_CUT = 3;// 结果 private File tempFile = new File(Environment.getExternalStorageDirectory(), g

调用系统相机和图库,裁剪图片

private static final int PHOTO_REQUEST_TAKEPHOTO = 1;// 拍照 private static final int PHOTO_REQUEST_GALLERY = 2;// 从相册中选择 private static final int PHOTO_REQUEST_CUT = 3;// 结果 private File tempFile = new File(Environment.getExternalStorageDirectory(), g