Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 88783|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-4-9 15:45:57 | 显示全部楼层 |阅读模式

    我们很多时候需要进行图片的裁剪,其实这个功能在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,但之后就出问题了。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-14 23:24 , Processed in 0.063257 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表