[Android] 拍照、截图、保存并显示在ImageView控件中

    最近在做Android的项目,其中部分涉及到图像处理的内容.这里先讲述如何调用Camera应用程序进行拍照,并截图和保存显示在ImageView控件中以及遇到的困难和解决方法.
    PS:作者购买了本《Android第一行代码 著:郭霖》,参照里面的内容完成(推荐该书,前面的布局及应用非常不错).网上这类资料非常多,作者仅仅分享给初学者同时在线记录些内容,希望对大家有所帮助.
   首先,设置activity_main.xml为LinearLayout布局且 android:orientation="vertical"

<Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TakePhoto Button" />

<ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

   然后,在MainActivity.java文件中public class MainActivity extends Activity修改源代码.添加自定义变量:

//自定义变量
public static final int TAKE_PHOTO = 1;
public static final int CROP_PHOTO = 2;
private Button takePhotoBn;
private ImageView showImage;
private Uri imageUri; //图片路径
private String filename; //图片名称

   添加函数实现点击拍照功能:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    takePhotoBn = (Button) findViewById(R.id.button1);
    showImage = (ImageView) findViewById(R.id.imageView1);
    //点击"Photo Button"按钮照相
    takePhotoBn.setOnClickListener(new OnClickListener() {
    	@Override
    	public void onClick(View v) {
    		//图片名称 时间命名
    		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            Date date = new Date(System.currentTimeMillis());
            filename = format.format(date);
    		//创建File对象用于存储拍照的图片 SD卡根目录
    		//File outputImage = new File(Environment.getExternalStorageDirectory(),"test.jpg");
    		//存储至DCIM文件夹
    		File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
    		File outputImage = new File(path,filename+".jpg");
    		try {
    			if(outputImage.exists()) {
     				outputImage.delete();
    			}
    			outputImage.createNewFile();
    		} catch(IOException e) {
    			e.printStackTrace();
    		}
    		//将File对象转换为Uri并启动照相程序
    		imageUri = Uri.fromFile(outputImage);
    		Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); //照相
    		intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); //指定图片输出地址
    		startActivityForResult(intent,TAKE_PHOTO); //启动照相
    		//拍完照startActivityForResult() 结果返回onActivityResult()函数
    	}
    });

    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }
}

   通过startActivityForResult和onActivityResult方法实现拍照截图和保存功能:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	if (resultCode != RESULT_OK) {
		Toast.makeText(MainActivity.this, "ActivityResult resultCode error", Toast.LENGTH_SHORT).show();
		return;
	}
	switch(requestCode) {
	case TAKE_PHOTO:
		Intent intent = new Intent("com.android.camera.action.CROP"); //剪裁
		intent.setDataAndType(imageUri, "image/*");
		intent.putExtra("scale", true);
		//设置宽高比例
		intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        //设置裁剪图片宽高
        intent.putExtra("outputX", 340);
	    intent.putExtra("outputY", 340);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
		Toast.makeText(MainActivity.this, "剪裁图片", Toast.LENGTH_SHORT).show();
		//广播刷新相册
	    Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
		intentBc.setData(imageUri);
		this.sendBroadcast(intentBc);
		startActivityForResult(intent, CROP_PHOTO); //设置裁剪参数显示图片至ImageView
		break;
	case CROP_PHOTO:
		try {
			//图片解析成Bitmap对象
			Bitmap bitmap = BitmapFactory.decodeStream(
					getContentResolver().openInputStream(imageUri));
			Toast.makeText(MainActivity.this, imageUri.toString(), Toast.LENGTH_SHORT).show();
			showImage.setImageBitmap(bitmap); //将剪裁后照片显示出来
		} catch(FileNotFoundException e) {
			e.printStackTrace();
		}
		break;
	default:
		break;
	}
}

   
由于涉及到SD卡中写数据操作和Camera操作,需要在AndroidMainfest.xml文件中声明权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" /> 

    运行结果如下图所示:

       

    需要注意以下几个问题:
    1.拍照和截图都涉及到startActivityForResult和onActivityResult的交互操作.

startActivityForResult(
	Intent intent,   //Intent对象
	int requestCode  //>=0 当Activity结束时requestCode将归还在onActivityResult()中
)
onActivityResult(
	int requestCode,  //提供给onActivityResult,以确认返回的数据是从哪个Activity返回的
	int resultCode,   //由子Activity通过其setResult()方法返回 通常为RESULT_CANCELED或RESULT_OK
	Intent data       //一个Intent对象,带有返回的数据
)

   其中onActivityResult的requestCode和startActivityForResult中的requestCode相对应.同时结合Intent意图实现拍照和截图,核心代码如下:(intent的参数设置省略)
    Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
    startActivityForResult(intent,TAKE_PHOTO);
    Intent intent = new Intent("com.android.camera.action.CROP"); 
    startActivityForResult(intent, CROP_PHOTO);
    2.使用Android拍照保存在系统相册,图库不能立刻显示最新照片.解决方法是发送系统内置的广播去刷新相册实现显示.代码如下:

Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intentBc.setData(imageUri);
this.sendBroadcast(intentBc);    

    可能你会使用下面这条广播扫描整个SD卡,但4.4已禁止这样的操作:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(...)))
    参考资料 http://blog.csdn.net/xiaanming/article/details/8990627
    3.当运行程序是可能会发现结果图像显示很小,当通过一个Intent意图触发时,Camera程序不会将全尺寸图像返回给主调活动,这样需要大量的内存,而移动设备内存会有一定限制.通常Camera将在返回的意图中返回一幅很小的缩略图,大图可能会导致OOM问题.参考:《Android多媒体开发高级编程 著:Shawn Van Every》
    针对大图像Android提供BitmapFactory类,允许通过各种资源加载Bitmap图像.调用BitmapFactory.Options类可以定义如何将Bitmap读入内存,当加载图像时,可设置BitmapFactory采样大小.并指定inSampleSize参数表明加载时结果Bitmap图像所占的比例.如inSampleSize=8表明产生一副大小为原始图像1/8的图像.参考下面代码:

if(resultCode==RESULT_OK) {
	DisplayMetrics dm = new DisplayMetrics();
	getWindowManager().getDefaultDisplay().getMetrics(dm);
	int width = dm.widthPixels; //宽度
	int height = dm.heightPixels ; //高度
	//加载图像尺寸而不是图像本身
	BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
	bmpFactoryOptions.inJustDecodeBounds = true; //bitmap为null 只是把图片的宽高放在Options里
     Bitmap bitmap = BitmapFactory.decodeFile(imageUri.toString(), bmpFactoryOptions);
	int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
	int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);
	//设置图片压缩比例 如果两个比例大于1 图像一边将大于屏幕
	if(heightRatio>1&&widthRatio>1) {
		if(heightRatio>widthRatio) {
			bmpFactoryOptions.inSampleSize = heightRatio;
		}
		else {
			bmpFactoryOptions.inSampleSize = widthRatio;
		}
	}
	//图像真正解码
	bmpFactoryOptions.inJustDecodeBounds = false;
	bitmap = BitmapFactory.decodeFile(imageUri.toString(), bmpFactoryOptions);
	showImage.setImageBitmap(bitmap); //将剪裁后照片显示出来
}

    4.使用nexus 4 剪裁图片后不能setImageBitmap显示在ImageView控件中,其中只有保存按钮,没有剪裁按钮.测试发现没有返回RESULT_OK.这个问题不能解决.Why?
    参考:Unable to Save Photo Edits
    最后希望文章对大家有所帮助,这是我学习Android图像处理部分的基础性文章与解决过程.下载地址:
http://download.csdn.net/detail/eastmount/8074833
参考资料和推荐博文:(都是非常不错的资料-.-)
    《Android第一行代码》著郭霖 参考8.3 调用摄像头和相册
    android拍照图片选取与图片剪裁 By:Lee_Allen  
    Android_照相机Camera_调用系统照相机返回data为空 By:strawberry2013    Android图片剪裁功能实心详解
By:小马

    Android开发 拍照、图片集保存照片技巧
    Android 拍照并显示在ImageView中(进阶)
By:leesa

    android调动系统的照相机并把照片显示在ImageView上
    cameraintent
data null in onActivityResult(int requestCode, int resultCode, Intentdata)

    Android高效加载大图、多图解决方案,有效避免程序OOM By:guolin
    Android相机、相册获取图片显示并保存到SD卡
By:唐韧_Ryan

    android、获取本地图片|直接获取照相图片
By:zcljy0318

(By:Eastmount 2014-10-23 晚10点
http://blog.csdn.net/eastmount/)

时间: 2014-10-23

[Android] 拍照、截图、保存并显示在ImageView控件中的相关文章

在GridView控件的TemplateField字段中有一DropDownList控件,该DropDownList控件有一事件处理程序。要求:用户选择某一条目(如c)后,c仍显示在DropDownList控件中。怎么做?

问题描述 各位高手: 我在GridView控件中添加一TemplateField字段,然后在该字段的HeaderTemplate中添加一DropDownList控件,再为该DropDownList控件添加一事件处理程序.假设该DropDownList控件有a.b.c.d这4个选项,现在想达到这样的效果:用户选择某一条目(如c)后,c仍显示在该DropDownList控件中.问题是:事件处理程序执行完毕后,DropDownList控件所显示的条目又回到第一个a,而不是c.为什么?请指教,谢谢! 解

imageview-安卓 ImageView控件,照片显示 拍照显示

问题描述 安卓 ImageView控件,照片显示 拍照显示 当我点击编辑的时候,显示的内容是从数据库中获取出来的 页面中有三个ImageView显示的是数据库中的三张照片 现在我想要实现这样的功能 点击一张照片,调用照相机功能拍照,拍摄的照片显示在该ImageView中 我奥怎么才能获取到调用照相机是哪个ImageView 解决方案 http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304970.html 声明一个ImageView变量,点击

android自定义带倒影的ImageView控件

http://xiaolifan.iteye.com/blog/1258520 今天给大家带来的是一个带倒影的ImageView控件,实现方法很简单,注释里面写的很详细,部分代码来自网络,我稍加了修改:  import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import andro

Android实现显示电量的控件代码_Android

下面介绍了Android实现显示电量的控件代码,具体代码如下: 1.目录结构,本人是使用安卓死丢丢. 2.运行界面,输入框中输入数值,点击刷新,会再电池中显示出相应的电量 3.绘制自定义电池控件,首先,新建一个类BatteryState继承View private Context mContext; private float width; private float height; private Paint mPaint; private float powerQuantity=0.5f;/

Android下拉刷新上拉加载控件(适用于所有View)_Android

     前面写过一篇关于下拉刷新控件的文章下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能.不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~     我做了一个大集合的demo,实现了ListView.GridView.ExpandableListView.ScrollView.WebView.ImageView.TextView的下拉刷新和上拉加载.后

Android下拉刷新上拉加载控件(适用于所有View)

前面写过一篇关于下拉刷新控件的文章下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能.不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~ 我做了一个大集合的demo,实现了ListView.GridView.ExpandableListView.ScrollView.WebView.ImageView.TextView的下拉刷新和上拉加载.后面会提供demo的

Android仿英语流利说取词放大控件的实现方法(附demo源码下载)_Android

本文实例讲述了Android仿英语流利说取词放大控件的实现方法.分享给大家供大家参考,具体如下: 1 取词放大控件 英语流利说是一款非常帮的口语学习app,在app的修炼页面长按屏幕,会弹出一个放大镜,当手指移到某个单词的附近,可以看到该英文单词会被选中,效果如下图所示: 2 代码示例 该控件挺有意思,于是我写了个简单的demo,完整实例代码点击此处本站下载.,程序运行后的效果如下: 3 实现原理 该控件的实现原理比较简单,下面介绍几个比较重要的类 ① WordView 在实习该控件的过程中,我

imageview-安卓中的ImageView控件的背景透明

问题描述 安卓中的ImageView控件的背景透明 请问如何在安卓中将ImageView控件动态加载的图片的背景去掉?image.setAlpha(0)不起作用? 解决方案 第一个问题: 图片背景透明是由图片本身决定的,一般使用png格式的图片,因为具有透明属性,而且需要事先用工具将背景弄成透明的才行. 当然,你实在是不想事先就用透明图,你也可以对bitmap进行处理,因为你可以将图片加载成为bitmap,而bitmap是可以进行色值的编辑的,bitmap是一个位图,你可以一位一位去进行色彩处理

imageview-Android中点击ImageView 如何知道 点击坐标是否在控件中的Bitmap上

问题描述 Android中点击ImageView 如何知道 点击坐标是否在控件中的Bitmap上 如题,imageview的onTouchEvent事件中获得点击坐标,但是view中的bitma并不是和imageview等大小的,而且用矩阵将Bitmap动态旋转.缩放了,想要知道点击的坐标是否位于bitmap上.目前的解决方案是,获取坐标点的Imageview的颜色值,看那是否登录0,但是Imageview点击获取颜色值有点卡,体验不好.我想应该可以用数学的方法来解决这个问题的.希望大神们帮助一