• 详细解释如何通过Android自带的方式来实现图片的裁剪——原理分析+解决方案


    我们很多时候需要进行图片的裁剪,其实这个功能在android系统中已经有一套解决方案了,虽然界面和效果并不是很优秀但功能毫无疑问是完美实现了。至于,不用自带的方案怎么做自定义,这个就是后话了。本篇主要讲解的是裁剪的原理和流程,外带分析了大图裁剪和小图裁剪的不同之处,同时给出具体的实现方案。

    一、原理+流程

    andorid提供了一个action,com.android.camera.action.CROP

    Intent intent = new Intent("com.android.camera.action.CROP");

    通过这个action就可以实现图片的裁剪,具体就是实现这个intent,然后在这个intent中putExtra()中put各种参数,最后通过来启动一个startActivityForResult(intent, requestCode);,这是裁剪图片的activity,进行裁剪。

    裁剪完后返回一个bitmap,交给开发者进行处理。

    也就是说,我们是通过系统写好的Activity进行了主要的操作,自己只需要在activity类中的onActivityResult中根据requestCode来进行判断和处理即可。

    启动系统相册的Activity:

        /**
         * 从相册获取图片 
         */
        private void choicePicFromAlbum() {
            // 来自相册
            Intent albumIntent = new Intent(Intent.ACTION_PICK, null);
            /**
             * 下面这句话,与其它方式写是一样的效果,如果:
             * intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
             * intent.setType(""image/*");设置数据类型
             * 要限制上传到服务器的图片类型时可以直接写如:"image/jpeg 、 image/png等的类型"
             */
            albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
            startActivityForResult(albumIntent, ALBUM_OK);
        }

    启动系统照相的Activity:

        /**
         * 拍照后获取图片
         */
        private void choicePicFromCamera() {
            // 来自相机
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            // 下面这句指定调用相机拍照后的照片存储的路径,这样通过这个uri就可以得到这个照片了
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
            startActivityForResult(cameraIntent, CAMERA_OK);// CAMERA_OK是用作判断返回结果的标识
        }

    启动裁剪图片的Activity:

        /**
         * 裁剪图片方法实现
         * @param uri
         */
        public void clipPhoto(Uri uri) {
    
            Intent intent = new Intent("com.android.camera.action.CROP");
            //可以选择图片类型,如果是*表明所有类型的图片
            intent.setDataAndType(uri, "image/*");
            // 下面这个crop = true是设置在开启的Intent中设置显示的VIEW可裁剪
            intent.putExtra("crop", "true");
            // aspectX aspectY 是宽高的比例,这里设置的是正方形(长宽比为1:1)
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
            // outputX outputY 是裁剪图片宽高
            intent.putExtra("outputX", 1000);
            intent.putExtra("outputY", 1000);
            //裁剪时是否保留图片的比例,这里的比例是1:1
            intent.putExtra("scale", true);
            //是否是圆形裁剪区域,设置了也不一定有效
            //intent.putExtra("circleCrop", true);
            //设置输出的格式
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            //是否将数据保留在Bitmap中返回
            intent.putExtra("return-data", true);
    
            startActivityForResult(intent, CUT_OK);
        }

    二、主要问题

    如果我们截取的图片是大图,那么我们首先会想着提高输出图片的大小

    // outputX outputY 是裁剪图片宽高
    intent.putExtra("outputX", 800);
    intent.putExtra("outputY", 800);

    但这样就会出现问题,由于图片过大,占用内存过多所以系统会自行将图片进行压缩,以避免出现OOM的问题。下面摘录一篇博文的部分内容来解释这个问题:

    原文:http://blog.csdn.net/floodingfire/article/details/8144604

      在Android中,Intent触发Camera程序,拍好照片后,将会返回数据,但是考虑到内存问题,Camera不会将全尺寸的图像返回给调用的Activity,一般情况下,有可能返回的是缩略图,比如120*160px。

      这是为什么呢?这不是一个Bug,而是经过精心设计的,却对开发者不透明。以我的小米手机为例,摄像头800W像素,根据我目前设置拍出来的图片尺寸为3200*2400px。有人说,那就返回呗,大不了耗1-2M的内存,不错,这个尺寸的图片确实只有1.8M左右的大小。但是你想不到的是,这个尺寸对应的Bitmap会耗光你应用程序的所有内存。Android出于安全性考虑,只会给你一个寒碜的缩略图。

        在Android2.3中,默认的Bitmap为32位,类型是ARGB_8888,也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题:3200*2400*4 bytes =   30M。

        如此惊人的数字!哪怕你愿意为一张生命周期超不过10s的位图愿意耗费这么巨大的内存,Android也不会答应的。

    1 Mobile devices typically have constrained system resources.
    2 Android devices can have as little as 16MB of memory available to a single application.

        这是Android Doc的原文,虽然不同手机系统的厂商可能围绕16M这个数字有微微的上调,但是这30M,一般的手机还真挥霍不起。也只有小米这种牛机,内存堪比个人PC,本着土财主般挥金如土的霸气才能做到。

     

    得出的结论是,如果你截取的是小图那么就返回一个bitmap,但如果是大图那么就返回一个uri。这样就不会出现问题啦。

    三、从相册中截图

    参考自:http://blog.csdn.net/floodingfire/article/details/8144615

    现在原作者托管的代码已经用了lib包作为例子了,和博客中略有差异。

    原作者博文中写了两种方式,我个人用的不是很习惯。通过自己的测试发现博主提供的方法在手机上也没法适用,于是贴出自己的解决方案。目前在小米2-原生4.4系统上测试通过

     具体写法参照:

    http://www.cnblogs.com/tianzhijiexian/p/3989296.html

    这个文章是参照博主的写的,在miui上测试通过:http://www.cnblogs.com/tianzhijiexian/p/3859480.html,但之后就出问题了。

  • 相关阅读:
    [CF920E] Connected Components?
    [CF981E] Addition on Segments
    [BZOJ2152] 聪聪可可
    [CF1355E] Restorer Distance
    [CF1101D] GCD Counting
    [CF827C] DNA Evolution
    [HNOI2008] 明明的烦恼
    [CF712D] Memory and Scores
    [CF609E] Minimum spanning tree for each edge
    后缀自动机应用小结 I
  • 原文地址:https://www.cnblogs.com/tianzhijiexian/p/4059006.html
Copyright © 2020-2023  润新知