zoukankan      html  css  js  c++  java
  • [Android] 图片裁剪总结——调用系统裁剪

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

    原文地址请保留http://www.cnblogs.com/rossoneri/p/3976530.html 

    首先推荐几篇博客

    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     }

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

    下面就是不调用系统,自己写一个裁剪图片的工具了

  • 相关阅读:
    数字签名与HTTPS详解
    利用策略模式优化过多 if else 代码
    Redis 的事务到底是不是原子性的
    Spring Boot项目的接口防刷
    深入分析 ThreadLocal
    什么是四层和七层负载均衡?他们之间的区别是什么?
    MyEclipse或Eclipse中project的导入和导出
    org.hibernate.exception.ConstraintViolationException: could not insert:
    C++ STL vector(向量容器)的使用(附完整程序代码)
    Swift2.0语言教程之函数嵌套调用形式
  • 原文地址:https://www.cnblogs.com/rossoneri/p/3976530.html
Copyright © 2011-2022 走看看