浅谈Android中拍照、从相册选择图片并截图相关知识点
前言
我们在Android开发中经常会需要使用相机或者从相册中选取图片的情况,今天就把这里面相关的知识点总结下,方便以后开发的时候使用。
1、相机拍照并可自定义截图功能
我们先来看如何使用Intent来打开照相机,相信这段代码大伙应该很熟悉了。代码如下:
//打开照相机,进行拍照
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//设置照片的临时保存路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, mTempImageUri);
startActivityForResult(intent, TAKE_PHOTO_BY_CAMERA);
这段代码中我们看到,对于第四行设置了拍照后图片的保存路径。这个我们可以自定义的。然后我们通过startActivityForResult来打开相机,并接受相关的数据。
下面我们来看下相机拍摄后的处理逻辑。代码如下:
/**
* 处理照相或者相册返回的图片数据
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode==Activity.RESULT_OK){
switch (requestCode){
//处理相机
case TAKE_PHOTO_BY_CAMERA:
if(mCrop) {
//对指定路径下的图片进行裁剪
cropCameraImage(mTempImageUri, DEFAULT_CROP_X, DEFAULT_CROP_Y, CROP_PHOTO);
}else {
mBitmap = getThumbnail(mTempImageUri, mImageWidth, mImageHeight);
setResult(true);
}
break;
//处理相册
case SELECT_PHOTO_BY_ALBUM:
Uri selectedPhotoUri=data.getData();
//对图片进行裁剪
if(mCrop) {
cropAlbumImage(selectedPhotoUri, mTempImageUri, DEFAULT_CROP_X, DEFAULT_CROP_Y, CROP_PHOTO);
}else {
//否则就将图片压缩成指定大小返回
mBitmap = getThumbnail(selectedPhotoUri, mImageWidth, mImageHeight);
setResult(true);
}
break;
//裁剪图片
case CROP_PHOTO:
if(data!=null) {
/**
* 如果想使用data.getParcelableExtra("data")获取bitmap
* 只需要在裁剪时设置return-data为true即可
*/
if(mReturnData){
mBitmap = data.getParcelableExtra("data");
if (mBitmap == null) {
setResult(false);
}
}else {
Uri originalUri = data.getData();
if (originalUri == null) {
originalUri = mTempImageUri;
}
//获取缩略图
mBitmap = getThumbnail(originalUri, mImageWidth, mImageHeight);
}
}
setResult(true);
break;
default:
break;
}
}else {
setResult(false);
}
super.onActivityResult(requestCode, resultCode, data);
}
我们来看代码的12-20行,我们看到这段代码会产生一个分支,如果crop为true,那么会调用cropCameraImage方法对拍摄的图片进行截图。否则的话就返回指定大小的图片(bitmap)给调用者。我们分开来看。
1、拍照并截图。相关代码如下:
/**
* 对照相机拍摄的图片进行裁剪
* @param uri
* @param outputX
* @param outputY
* @param requestCode
*/
private void cropCameraImage(Uri uri, int outputX, int outputY, int requestCode){
//相机拍摄的图片像素较高,不使用return-data属性使用Uri返回
mReturnData=false;
cropImage(uri,uri,outputX,outputY,mReturnData,requestCode);
}
我们看到里面调用了cropImage方法(从相册取图也使用了这个方法)。由于现在相机像素都很高,生成的图片很大,往往有5M+的大小。不建议使用return-data属性,这样会占用很大的内存。我们这边使用Uri。下面会详细介绍。
cropImage方法的介绍。
/**
*
* @param sourceUri
* @param outputUri
* @param outputX
* @param outputY
* @param returnData
* @param requestCode
*/
private void cropImage(Uri sourceUri,Uri outputUri,int outputX,int outputY,boolean returnData,int requestCode) {
try {
/**
* 下面解释各个参数的详细信息
*/
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(sourceUri, "image/*");
//发送裁剪信号
intent.putExtra("crop", "true");
//X,Y方向上的比例(1:1就是正方形,2:1就是长方形)
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
//裁剪区的宽,高
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
//是否保留比例
intent.putExtra("scale", true);
if(returnData) {
//是否将数据保留在Bitmap中返回(注意:小图片可以使用return-data:true的设置,大图片的话建议使用extra_output)
intent.putExtra("return-data", returnData);
}else {
//设置裁剪后的图片路径覆盖相机拍摄图片路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
}
//裁剪后图片的后缀名
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
//没有人脸检测
intent.putExtra("noFaceDetection", true);
startActivityForResult(intent, requestCode);
} catch (Exception ex) {
setResult(false);
}
}
在代码的27-32行我们看到通过returnData我们设置是否使用return-data属性。设置了return-data属性,Android系统会自动返回bitmap对象给我们,如:onActivityResult中的data.getParcelableExtra这种方法。这样对于小图片当然非常方便。但是对于大图片会造成内存消耗过高,应用程序产生异常。在最后我们看cropImage方法也是调用了startActivityForResult方法,只不过它的参数是CROP_PHOTO。
2、直接生成指定大小的图片
下面我们来介绍不使用截图,直接将生成指定大小图片并返回的方法,即代码中的getThumbnail方法。这一段代码是可以实现将图片缩小成指定长宽的尺寸。代码如下:
/**
* @param uri
* @param width
* @param height
* @return
* @throws IOException
*/
public Bitmap getThumbnail(Uri uri,int width,int height){
Bitmap bitmap=null;
InputStream input=null;
try {
ContentResolver resolver = getContentResolver();
input = resolver.openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
/**
* 如果设置inJustDecodeBounds为true,仍可以获取到bitmap信息,但完全不用分配内存,因为没有获取像素,所以我们可以利用得到的Bitmap的大小,
* 重新压缩图片,然后在内存中生成一个更小的Bitmap,这样即便是一个4MB的JPG,我们也可以随心所欲地把他压缩到任意大小,从而节省了内存
*/
onlyBoundsOptions.inJustDecodeBounds = true;
onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
if(input!=null) {
input.close();
}
if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
return bitmap;
}
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
/**
* 计算Bitmap的缩放比例
*/
bitmapOptions.inSampleSize = calculateInSampleSize(onlyBoundsOptions, width, height);
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
input = resolver.openInputStream(uri);
bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
}catch (Exception ex){
return bitmap;
}finally {
if(input!=null){
try {
input.close();
}catch (IOException ioEx){}
}
}
return bitmap;
}
这种方法的原理可以参考我的另一篇文章:http://www.cnblogs.com/dreamGong/p/5255528.html。通过介绍我们知道了相机拍摄图片并且进行截图和指定大小图片获取的相关方法。相信聪明的你也一定知道从相册取图肯定也是类似的。的确,从上面onActivityResult方法中我们看到从相册取图也是大同小异的。最后我再来介绍下onActivityResult方法中的CROP_PHOTO的相关逻辑。代码如下:
/**
* 如果想使用data.getParcelableExtra("data")获取bitmap
* 只需要在裁剪时设置return-data为true即可
*/
if(mReturnData){
mBitmap = data.getParcelableExtra("data");
if (mBitmap == null) {
setResult(false);
}
}else {
Uri originalUri = data.getData();
if (originalUri == null) {
originalUri = mTempImageUri;
}
//获取缩略图
mBitmap = getThumbnail(originalUri, mImageWidth, mImageHeight);
}
我们看到如果我们设置了retuan-data属性,是可以使用getParcelabelExtra方法来直接获取bitmap的。如果我们设置return-data为false。设置intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);cropImage方法的29行。我们可以通过获取Uri,然后重新生成一张bitmap返回给调用者。
参考文档
https://my.oschina.net/ryanhoo/blog/86842
附整个代码的逻辑
http://files.cnblogs.com/files/dreamGong/PhotoHelper.rar
浅谈Android中拍照、从相册选择图片并截图相关知识点的更多相关文章
- HTML5 Plus 拍照或者相册选择图片上传
HBuilder+HTML5 Plus+MUI实现拍照或者相册选择图片上传,利用HTML5 Plus的Camera.Gallery.IO.Storage和Uploader来实现手机APP拍照或者从相册 ...
- 浅谈Android中Serializable和Parcelable使用区别
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 Android开发的时候,我们时长遇到传递对象的需求,但是我们无法将对象的引用传给Activity或者Fragment,我们需要将这些对象 ...
- 浅谈android中只使用一个TextView实现高仿京东,淘宝各种倒计时
今天给大家带来的是只使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.近期公司一直加班也没来得及时间去整理,今天难得歇息想把这个分享给大家.只求共同学习,以及自己兴许 ...
- 浅谈Android中Activity的生命周期
引言 我想对于Android开发人员来说,Activity是再熟悉不过了,今天我们就来探讨下Activity的生命周期.熟悉的掌握Activity对于开发健壮的Android应用程序来说至关重要.下面 ...
- 浅谈android中的目录结构
之前在android游戏开发中就遇到本地数据存储的问题:一般情形之下就将动态数据写入SD中存储,在没有SD卡的手机上就需另作处理了;再有在开发android应用的过程中,总要去调试APP,安装时又想去 ...
- 浅谈Android中的startActivityForResult和setResult方法
引言 我们知道,如果想打开一个新的Activity我们可以使用startActivity方法.今天我们介绍的startActivityForResult不仅可以打开全新的Activity,而且当新的A ...
- 浅谈Android中layout_weight
引言 在开发android过程中,我们经常需要对界面进行按比例进行布局,我们一般都会使用layout_属性来进行设置.今天这篇文章我们就来简单介绍下layout_weight的使用和布局原理.随着做项 ...
- 浅谈Android中的事件分发机制
View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...
- 浅谈Android中的组播(多播)
组播使用UDP对一定范围内的地址发送相同的一组Packet,即一次可以向多个接受者发出信息,其与单播的主要区别是地址的形式.IP协议分配了一定范围的地址空间给多播(多播只能使用这个范围内的IP),IP ...
随机推荐
- java操作hdfs实例
环境:window7+eclipse+vmware虚拟机+搭建好的hadoop环境(master.slave01.slave02) 内容:主要是在windows环境下,利用eclipse如何来操作hd ...
- Chrome
一.简介 二.安装 1)离线版 http://www.google.cn/chrome/browser/thankyou.html?statcb=1&platform=win64&st ...
- 你们信不信一句Console.WriteLine就能让你的控制台程序失去响应
好久没更新博客了,今天是扒衣见君节,难得闲下来就来说说一个最近有趣的发现吧. 首先废话不多说,直接上代码吧 class Program { static void Main(string[] args ...
- spring类型自动转换——@InitBinder和Converter
spring有2种类型转换器,一种是propertyEditor,一种是Converter.虽然都是类型转换,但是还是有细微差别. 所以这里以一个例子的形式来分析一下这2种类型转换的使用场景和差别. ...
- 面试中关于Java你所需知道的的一切
本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺. 1. Java中的原始数据类型都有哪些, ...
- ThinkPHP常用查询
1.常规 $map2['state'] = 1; $User->where ( $map2 )->find(); 2. OR 查询 $where['name'] = array('neq' ...
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 增加安全性增加内网的电脑才可以调用的限制
大型业务应用系统很容易受到各种攻击,每加上一道防护就可以减少80%-90%的攻击.我们的核心接口组件里也做了一些限制,有些接口方法只有内网的用户才可以调用,防止外网的用户调用,这样安全性会有很大的提升 ...
- 代码覆盖工具(gcov、lcov)的使用
一.安装 gcov:是随gcc一起发布的,并不需要独立安装:lcov:其他博客说是随ltp发布的,结果下载下ltp之后编译了10多分钟,最后也没见lcov,最后到sourceforge下载了lcov单 ...
- CentOS 6.5 PPTPD VPN服务器安装,解决807等问题。
需要两个组件: ppp pptpd 需要配置的地方有三处: /etc/pptpd.conf /etc/ppp/options.pptpd /etc/ppp/chap-secrets 需要开启IP转发: ...
- 软件工程(FZU2015)赛季得分榜,第一回合
目录 第一回合 第二回合 第三回合 第四回合 第五回合 第6回合 第7回合 第8回合 第9回合 第10回合 第11回合 积分规则 积分制: 作业为10分制,练习为3分制:alpha30分: 团队项目分 ...