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

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

  1. android开发——从相冊中选择图片不裁剪

    转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46864777 问题: 在郭神的第一行代码中,第8章的从相冊中选择图片这块,从相冊选 ...

  2. Activity详细解释(生命周期、以各种方式启动Activity、状态保存,等完全退出)

    一.什么是Activity? 简单的说:Activity或者悬浮于其它窗体上的交互界面. 在一个应用程序中通常由多个Activity构成.都会在Manifest.xml中指定一个主的Activity, ...

  3. POI操作Excel详细解释,HSSF和XSSF两种方式

    HSSF道路: package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  4. Android slidingmenu详细解释 滑动的优化

    Android slidingmenu 详细解释 性能优化 转载请注明:   http://blog.csdn.net/aaawqqq 简单介绍 SlidingMenu 是github 上Androi ...

  5. Android中时间戳的详细解释

    Android中时间戳的详细解释: (1).定义: 时间戳就是根据当前系统时间生成的一组随机数字. (2).作用: 作为对数据唯一性的一种判断依据.避免了重复修改数据所带来的错误! (3).应用: ( ...

  6. 记一次使用 android 自带 WebView 做富文本编辑器之API、机型的兼容及各种奇葩bug的解决

    转载请声明出处(http://www.cnblogs.com/linguanh/) 目录 1,测试设备介绍 2,开源项目richeditor及CrossWalk的选择 3,遇到的bug及其解决方法 4 ...

  7. Linux学习笔记15——GDB 命令详细解释【转】

    GDB 命令详细解释 Linux中包含有一个很有用的调试工具--gdb(GNU Debuger),它可以用来调试C和C++程序,功能不亚于Windows下的许多图形界面的调试工具. 和所有常用的调试工 ...

  8. Android 4.4 KitKat NotificationManagerService使用具体解释与原理分析(一)__使用具体解释

    概况 Android在4.3的版本号中(即API 18)增加了NotificationListenerService,依据SDK的描写叙述(AndroidDeveloper)能够知道,当系统收到新的通 ...

  9. Nginx location配置详细解释

    nginx location配置详细解释 语法规则: location [=|~|~*|^~] /uri/ { - } = 开头表示精确匹配 ^~ 开头表示uri以某个常规字符串开头,理解为匹配 ur ...

随机推荐

  1. IE下css bug集合-翻译自haslayout.net

    概述IE浏览器以不支持大量的css 属性出名,同时也因其支持的css属性中存在大量bug. 本页列举了IE下的一些问题,实例样本和一些我们已知的解决方法. 尽管我已经尽力按照它们本来的性质对它们进行分 ...

  2. mysql5.6.34在默认配置文件修改字符集为utf8后重启mysql服务没效果

    1:事情是这样的,我下载了一个mysql5.6.34版本(windows版本的),下载下来后里面只有个my-default.ini,然后我就直接在my-default.ini 里面配置basedir, ...

  3. linux通过wget直接下载jdk

    下载语句: tar包下载 wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-se ...

  4. linux 安装redis4.0

    1.安装redis 第一步:下载redis安装包 wget http://download.redis.io/releases/redis-4.0.6.tar.gz 1 2 3 4 5 6 7 8 9 ...

  5. MySQL的lock tables和unlock tables的用法(转载)

    早就听说lock tables和unlock tables这两个命令,从字面也大体知道,前者的作用是锁定表,后者的作用是解除锁定.但是具体如何用,怎么用,不太清楚.今天详细研究了下,总算搞明白了2者的 ...

  6. PHP中使用OpenSSL生成RSA公钥私钥及进行加密解密示例(非对称加密)

    php服务端与客户端交互.提供开放api时,通常需要对敏感的部分api数据传输进行数据加密,这时候rsa非对称加密就能派上用处了,下面通过一个例子来说明如何用php来实现数据的加密解密 先了解一下关于 ...

  7. Windows下CRF++进行中文人名识别的初次尝试

    语料来自1998年1月份人民日报语料 1 语料处理 1.1 原始语料数据格式 语料中,句子已经被分词好,并且在人名后以“/”标注了“nr”表示是人名,其他非人名的分词没有进行标注 1.2 CRF++要 ...

  8. FreeMarker快速入门

    虽然当前比较推荐使用thymeleaf替代jsp作为java网页开发的模板语言,不过公司推荐使用freemarker,那就顺势而为,速度学一发,然后迅速开始新项目了. 简介 FreeMarker第一个 ...

  9. phpexcel导出excel等比例缩放图片

    list($width, $height, $type, $attr) = getimagesize($img_path); if( $width>100 || $height >100 ...

  10. JDK 动态代理的简单理解

    动态代理 代理模式是 Java 中的常用设计模式,代理类通过调用被代理类的相关方法,提供预处理.过滤.事后处理等服务,动态代理及通过反射机制动态实现代理机制.JDK 中的 java.lang.refl ...