前言

  我们在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中拍照、从相册选择图片并截图相关知识点的更多相关文章

  1. HTML5 Plus 拍照或者相册选择图片上传

    HBuilder+HTML5 Plus+MUI实现拍照或者相册选择图片上传,利用HTML5 Plus的Camera.Gallery.IO.Storage和Uploader来实现手机APP拍照或者从相册 ...

  2. 浅谈Android中Serializable和Parcelable使用区别

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.概述 Android开发的时候,我们时长遇到传递对象的需求,但是我们无法将对象的引用传给Activity或者Fragment,我们需要将这些对象 ...

  3. 浅谈android中只使用一个TextView实现高仿京东,淘宝各种倒计时

    今天给大家带来的是只使用一个TextView实现一个高仿京东.淘宝.唯品会等各种电商APP的活动倒计时.近期公司一直加班也没来得及时间去整理,今天难得歇息想把这个分享给大家.只求共同学习,以及自己兴许 ...

  4. 浅谈Android中Activity的生命周期

    引言 我想对于Android开发人员来说,Activity是再熟悉不过了,今天我们就来探讨下Activity的生命周期.熟悉的掌握Activity对于开发健壮的Android应用程序来说至关重要.下面 ...

  5. 浅谈android中的目录结构

    之前在android游戏开发中就遇到本地数据存储的问题:一般情形之下就将动态数据写入SD中存储,在没有SD卡的手机上就需另作处理了;再有在开发android应用的过程中,总要去调试APP,安装时又想去 ...

  6. 浅谈Android中的startActivityForResult和setResult方法

    引言 我们知道,如果想打开一个新的Activity我们可以使用startActivity方法.今天我们介绍的startActivityForResult不仅可以打开全新的Activity,而且当新的A ...

  7. 浅谈Android中layout_weight

    引言 在开发android过程中,我们经常需要对界面进行按比例进行布局,我们一般都会使用layout_属性来进行设置.今天这篇文章我们就来简单介绍下layout_weight的使用和布局原理.随着做项 ...

  8. 浅谈Android中的事件分发机制

    View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...

  9. 浅谈Android中的组播(多播)

    组播使用UDP对一定范围内的地址发送相同的一组Packet,即一次可以向多个接受者发出信息,其与单播的主要区别是地址的形式.IP协议分配了一定范围的地址空间给多播(多播只能使用这个范围内的IP),IP ...

随机推荐

  1. 自己开发一个 vsts agent 的 task

    vsts 中支持自定义Build/Release的过程Task 目标:做一个可以读取 Xamarin.Android 所生成的 APK 的 基本信息的 task ,包括 package(包名) / a ...

  2. 迅为最新推出iTOP-6818开发平台无缝支持4418开发板

    iTOP-6818开发板是一款四核ARM 八核开发板与iTOP-4418开发板完全兼容,CPU主频1.4GHz,内存1GB DDR3(2GB可选),存储16GB EMMC,板载千兆以太网,GPS,WI ...

  3. 直播时代--IOS直播客户端SDK,美颜直播【开源】

    当前视频直播非常火爆,手机端的视频直播也非常火爆,PGC.UGC的视频直播门槛都降低了很多. 本文介绍一个:IOS 客户端直播的SDK,代码完全开源. 直播时代:让IOS普通开发者一天内做出一个RTM ...

  4. linux 文件系统结构及命令

    1.linux 文件系统结构 / 根目录 root |--mnt/ | |--sdcard/  挂载点 | |--usb0 | |--cdrom |--home | |--soft01 <- 用 ...

  5. ASP.NET Core--根据方案来限制身份

    翻译如下: 在某些情况下,比如单页的应用程序,可以与多种认证来方式结合.例如,您的应用程序可能使用基于Cookie的身份验证来登录和JavaScript的请求承载认证.在某些情况下,可能一个授权验证的 ...

  6. MMORPG大型游戏设计与开发(服务器 游戏场景 事件)

    今天第星期天,知识是永远是学习不完的,所以今天这部分算比较轻松,同时也希望大家会有一个好的周末.场景事件即场景的回调,和别的事件一样是在特定的条件下产生的,前面也介绍过场景的各种事件,今天详细的说一说 ...

  7. 【Python数据分析】Python3操作Excel-以豆瓣图书Top250为例

    本文利用Python3爬虫抓取豆瓣图书Top250,并利用xlwt模块将其存储至excel文件,图片下载到相应目录.旨在进行更多的爬虫实践练习以及模块学习. 工具 1.Python 3.5 2.Bea ...

  8. 洛谷P2055 [ZJOI2009]假期的宿舍 [二分图最大匹配]

    题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识. ...

  9. BZOJ 3505 【Cqoi2014】 数三角形

    Description 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个. 下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. Input 输入一行,包含两个空格分隔的正整数m ...

  10. C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 角色权限的配置页面改进优化

    往往开发的人不是维护的人,开发的单位不是维护的单位.信息的畅通沟通交流很多时候会有打折.扭曲.甚至是容易得到歪解.配置错业务操作权限.为了防止发生没必要的麻烦,甚至是发生重大错误,我们的软件需要不断换 ...