Android 照相机实现方式
2016-03-02 10:19
525 查看
在android 中实现照相机的方式一般有两种
1、调用系统的相机
2、自定义相机
1、调用系统照相机程序拍照
1.定义所需要的权限
2.我们需要定义调用系统相机App的Intent,当然是通过设定IntentFilter中的Action来打开我们想要的activity了。
MediaStore.ACTION_IMAGE_CAPTURE
- 这个Action将打开拍照的系统相机。返回一个Image
MediaStore.ACTION_VIDEO_CAPTURE
- 这个Action将打开录像的系统相机。返回一个Video
3.API规定我们传入拍照得到图片的存储位置的Uri。否则Bimmap将以一个压缩后的形式返回到我们当前Activity.
intent.putExtra(MediaStore.EXTRA_OUTPUT,
fileUri); // 设置图片地址名称 会把拍照的图片存储到我们传入的Uri对应的File里面。
4.我们调用startActivityForResult(intent)来启动这样一个系统相机app之后,然后在当前应用Activity的onActivityResult()中接受到返回拍照成功或者失败的消息,做相应处理。
5.“压缩处理”(Android应用中加载大图片),并显示到ImageView中。
基本实现:
准备工作:设置 调用相机的回调码 和 设置 调用照相机拍照后保存图片的位置,名称,及后缀名(图片类型)
在button监听器中调用相机:
[java] view
plain copy
//调用系统照相机拍照
bt4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri u=Uri.fromFile(sdcardTempFile);
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
intent.putExtra(MediaStore.EXTRA_OUTPUT, u);
intent.putExtra("return-data", true);
startActivityForResult(intent, n);
}
});
[java] view
plain copy
回调函数中接收图片:
[java] view
plain copy
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
System.out.println("requestCode"+requestCode);
switch (requestCode){
case 2:
Uri tuku_uri = data.getData();
System.out.println(tuku_uri.getPath());
ContentResolver tuku_cr = this.getContentResolver();
try {
bmp = BitmapFactory.decodeStream(tuku_cr.openInputStream(tuku_uri));
MCShareLaunchShareHelper.shareContentWithBitmap("测试分享本地图片", bmp, "your share url", "", MoxunActivity.this);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case 3:
try {
Uri uri = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), sdcardTempFile.getAbsolutePath(), null, null));
System.out.println(uri.getPath());
ContentResolver cr = this.getContentResolver();
bmp = BitmapFactory.decodeStream(cr.openInputStream(uri));
MCShareLaunchShareHelper.shareContentWithBitmap("测试照相机图片", bmp, "your share url", "", MoxunActivity.this);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//方法二
//if (requestCode == MyApp.CAMERA_RECODE) {
// try {
// bmp=BitmapFactory.decodeFile(sdcardTempFile.getAbsolutePath());
// img.setImageBitmap(bmp);
// picCount++;
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// break;
// }
// }
}
2、自定义相机
基本实现方式:
1.检查相机是否存在,并获取相机Camera。
2.创建一个相机图像预览类:extends SurfaceView 并 implements SurfaceHolder (我定义:MySurfaceView)3.把这个预览类放入一个自定义布局layout里面,并且可以在layout里添加自己的其他按钮4.设置对应的拍照按钮然后听事件
5.捕获照片和保存图片
6.释放掉我们使用的相机Camera,不然之后其他应用将无法使用它。
计算机解析图片的方式和Android中大图片Bitmap的压缩显示处理
这个问题有点老生长谈了,平时我们经常遇到一些图片资源,我们把它加载到内存发现抛出内存不够用的异常,即OOM,当然加载图片时出现的OOM情况有很多种,比如单张图片没有做压缩,导致图片占用内存过大而发生内存溢出,也有多张图片一次性加载进来,导致的内存溢出。
通常单张大图,我们加载进来往往会经过一个图片的压缩处理的过程,而如果多张图片加载,我们可能就需要一些缓存机制,再加上一些算法来保证程序不出现OOM。
我们这里想要讲的知识点跟单张大图比较有关系
首先,我们知道一个图片,它是由很多像素点来表示的,而像素点的个数只跟图片的分辨率有关,而跟图片所占的内存空间大小无关。比如我们的桌面壁纸:1280 * 768 的分辨率,那么它就有 1280 * 768 = 983040个像素点,这意味着什么呢?我们知道我们要表示一个像素点的颜色,最经常我们需要RGB三种颜色来表示,而R:0~255,相当于两个FF的位置,就是8位,这样的话RGB合起来,一个像素点的表示就需要24位(这就是我们平衡听到的24位图),而加上透明度的8位,就是平时说的32位图。那么一张图片,它加载到内存中的话,它会占用多大的空间呢?
计算方法:(像素点 * 一个像素所占用的byte数) / 1024 / 1024 (MB)
以1280 * 768 的分辨率,32位图为例:所占内存大小: ((1280 * 768 * (32 / 8)) / 1024)/1024=3.75(MB)
说了这么多,那么我们再来说下Android系统的规定吧,Android系统严格规定了每个应用所能分配的最大的内存为多少,我们知道有一个VM值(在我们创建模拟器的时候),这个VM值里面便是我们所说的堆空间(Heap Size),当你的应用占用的空间已经超出我们定义的堆空间大小,那么不好意思,OOM
这样的话,我们明白了图片的大小占据原理,还有尽量不要超出这个堆空间,那么OK,现在问题变得简单了。如果我们有一种方式可以在图片加载进来之前,知道图片的大小,然后改变它的长、宽,这样的话,分辨率便变小了,这样出来的乘积也就变小了。比如:我们的屏幕只有320 * 240, 这时候你加载大分辨的图片进来最多也只能显示成这样,所以我们常采用的是对图片进行压缩处理。这里有个概念叫压缩比:
长:1024 / 320 = 3.2 约等于 3
宽:768 / 240 = 3.2
那这样我们如果把图片压缩成这样大小的,最后的图片加载进来的大小便是
((320 * 240 * (32 / 8)) / 1024)/1024=0.29(MB)
Android提供了Camera来控制拍照,步骤如下:
(1)调用Camera的open()方法打开相机。
(2)调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象。
(3)调用Camera.Parameters对象对照相的参数进行设置。
(4)调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置。
(5)调用Camerade的startPreview()的方法开始预览取景,在之前需要调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。
(6)调用Camera的takePicture()方法进行拍照。
(7)程序结束时,要调用Camera的stopPreview()方法停止预览,并且通过Camera.release()来释放资源。
需要赋予Camera的权限:
下面上代码:
1、调用系统的相机
2、自定义相机
1、调用系统照相机程序拍照
1.定义所需要的权限
2.我们需要定义调用系统相机App的Intent,当然是通过设定IntentFilter中的Action来打开我们想要的activity了。
MediaStore.ACTION_IMAGE_CAPTURE
- 这个Action将打开拍照的系统相机。返回一个Image
MediaStore.ACTION_VIDEO_CAPTURE
- 这个Action将打开录像的系统相机。返回一个Video
3.API规定我们传入拍照得到图片的存储位置的Uri。否则Bimmap将以一个压缩后的形式返回到我们当前Activity.
intent.putExtra(MediaStore.EXTRA_OUTPUT,
fileUri); // 设置图片地址名称 会把拍照的图片存储到我们传入的Uri对应的File里面。
4.我们调用startActivityForResult(intent)来启动这样一个系统相机app之后,然后在当前应用Activity的onActivityResult()中接受到返回拍照成功或者失败的消息,做相应处理。
5.“压缩处理”(Android应用中加载大图片),并显示到ImageView中。
基本实现:
准备工作:设置 调用相机的回调码 和 设置 调用照相机拍照后保存图片的位置,名称,及后缀名(图片类型)
private int n=3; private File sdcardTempFile = new File("/mnt/sdcard/", "tmp_pic_" + SystemClock.currentThreadTimeMillis() + ".jpg");
在button监听器中调用相机:
[java] view
plain copy
//调用系统照相机拍照
bt4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri u=Uri.fromFile(sdcardTempFile);
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
intent.putExtra(MediaStore.EXTRA_OUTPUT, u);
intent.putExtra("return-data", true);
startActivityForResult(intent, n);
}
});
[java] view
plain copy
回调函数中接收图片:
[java] view
plain copy
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
System.out.println("requestCode"+requestCode);
switch (requestCode){
case 2:
Uri tuku_uri = data.getData();
System.out.println(tuku_uri.getPath());
ContentResolver tuku_cr = this.getContentResolver();
try {
bmp = BitmapFactory.decodeStream(tuku_cr.openInputStream(tuku_uri));
MCShareLaunchShareHelper.shareContentWithBitmap("测试分享本地图片", bmp, "your share url", "", MoxunActivity.this);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case 3:
try {
Uri uri = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), sdcardTempFile.getAbsolutePath(), null, null));
System.out.println(uri.getPath());
ContentResolver cr = this.getContentResolver();
bmp = BitmapFactory.decodeStream(cr.openInputStream(uri));
MCShareLaunchShareHelper.shareContentWithBitmap("测试照相机图片", bmp, "your share url", "", MoxunActivity.this);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//方法二
//if (requestCode == MyApp.CAMERA_RECODE) {
// try {
// bmp=BitmapFactory.decodeFile(sdcardTempFile.getAbsolutePath());
// img.setImageBitmap(bmp);
// picCount++;
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// break;
// }
// }
}
2、自定义相机
基本实现方式:
1.检查相机是否存在,并获取相机Camera。
2.创建一个相机图像预览类:extends SurfaceView 并 implements SurfaceHolder (我定义:MySurfaceView)3.把这个预览类放入一个自定义布局layout里面,并且可以在layout里添加自己的其他按钮4.设置对应的拍照按钮然后听事件
5.捕获照片和保存图片
6.释放掉我们使用的相机Camera,不然之后其他应用将无法使用它。
计算机解析图片的方式和Android中大图片Bitmap的压缩显示处理
这个问题有点老生长谈了,平时我们经常遇到一些图片资源,我们把它加载到内存发现抛出内存不够用的异常,即OOM,当然加载图片时出现的OOM情况有很多种,比如单张图片没有做压缩,导致图片占用内存过大而发生内存溢出,也有多张图片一次性加载进来,导致的内存溢出。
通常单张大图,我们加载进来往往会经过一个图片的压缩处理的过程,而如果多张图片加载,我们可能就需要一些缓存机制,再加上一些算法来保证程序不出现OOM。
我们这里想要讲的知识点跟单张大图比较有关系
首先,我们知道一个图片,它是由很多像素点来表示的,而像素点的个数只跟图片的分辨率有关,而跟图片所占的内存空间大小无关。比如我们的桌面壁纸:1280 * 768 的分辨率,那么它就有 1280 * 768 = 983040个像素点,这意味着什么呢?我们知道我们要表示一个像素点的颜色,最经常我们需要RGB三种颜色来表示,而R:0~255,相当于两个FF的位置,就是8位,这样的话RGB合起来,一个像素点的表示就需要24位(这就是我们平衡听到的24位图),而加上透明度的8位,就是平时说的32位图。那么一张图片,它加载到内存中的话,它会占用多大的空间呢?
计算方法:(像素点 * 一个像素所占用的byte数) / 1024 / 1024 (MB)
以1280 * 768 的分辨率,32位图为例:所占内存大小: ((1280 * 768 * (32 / 8)) / 1024)/1024=3.75(MB)
说了这么多,那么我们再来说下Android系统的规定吧,Android系统严格规定了每个应用所能分配的最大的内存为多少,我们知道有一个VM值(在我们创建模拟器的时候),这个VM值里面便是我们所说的堆空间(Heap Size),当你的应用占用的空间已经超出我们定义的堆空间大小,那么不好意思,OOM
这样的话,我们明白了图片的大小占据原理,还有尽量不要超出这个堆空间,那么OK,现在问题变得简单了。如果我们有一种方式可以在图片加载进来之前,知道图片的大小,然后改变它的长、宽,这样的话,分辨率便变小了,这样出来的乘积也就变小了。比如:我们的屏幕只有320 * 240, 这时候你加载大分辨的图片进来最多也只能显示成这样,所以我们常采用的是对图片进行压缩处理。这里有个概念叫压缩比:
长:1024 / 320 = 3.2 约等于 3
宽:768 / 240 = 3.2
那这样我们如果把图片压缩成这样大小的,最后的图片加载进来的大小便是
((320 * 240 * (32 / 8)) / 1024)/1024=0.29(MB)
Android提供了Camera来控制拍照,步骤如下:
(1)调用Camera的open()方法打开相机。
(2)调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象。
(3)调用Camera.Parameters对象对照相的参数进行设置。
(4)调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置。
(5)调用Camerade的startPreview()的方法开始预览取景,在之前需要调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。
(6)调用Camera的takePicture()方法进行拍照。
(7)程序结束时,要调用Camera的stopPreview()方法停止预览,并且通过Camera.release()来释放资源。
需要赋予Camera的权限:
1 2 3 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.CAMERA"/> |
1 2 3 | package com.lyj.camera; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.PixelFormat; import android.hardware.Camera; import android.hardware.Camera.AutoFocusCallback; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.PictureCallback; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.widget.ImageButton; import android.widget.ImageView; public class MyCameraActivity extends Activity implements SurfaceHolder.Callback { private ImageView back, position;//返回和切换前后置摄像头 private SurfaceView surface; private ImageButton shutter;//快门 private SurfaceHolder holder; private Camera camera;//声明相机 private String filepath = "";//照片保存路径 private int cameraPosition = 1;//0代表前置摄像头,1代表后置摄像头 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);//没有标题 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置全屏 this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照过程屏幕一直处于高亮 //设置手机屏幕朝向,一共有7种 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); //SCREEN_ORIENTATION_BEHIND: 继承Activity堆栈中当前Activity下面的那个Activity的方向 //SCREEN_ORIENTATION_LANDSCAPE: 横屏(风景照) ,显示时宽度大于高度 //SCREEN_ORIENTATION_PORTRAIT: 竖屏 (肖像照) , 显示时高度大于宽度 //SCREEN_ORIENTATION_SENSOR 由重力感应器来决定屏幕的朝向,它取决于用户如何持有设备,当设备被旋转时方向会随之在横屏与竖屏之间变化 //SCREEN_ORIENTATION_NOSENSOR: 忽略物理感应器——即显示方向与物理感应器无关,不管用户如何旋转设备显示方向都不会随着改变("unspecified"设置除外) //SCREEN_ORIENTATION_UNSPECIFIED: 未指定,此为默认值,由Android系统自己选择适当的方向,选择策略视具体设备的配置情况而定,因此不同的设备会有不同的方向选择 //SCREEN_ORIENTATION_USER: 用户当前的首选方向 setContentView(R.layout.main); back = (ImageView) findViewById(R.id.camera_back); position = (ImageView) findViewById(R.id.camera_position); surface = (SurfaceView) findViewById(R.id.camera_surface); shutter = (ImageButton) findViewById(R.id.camera_shutter); holder = surface.getHolder();//获得句柄 holder.addCallback(this);//添加回调 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//surfaceview不维护自己的缓冲区,等待屏幕渲染引擎将内容推送到用户面前 //设置监听 back.setOnClickListener(listener); position.setOnClickListener(listener); shutter.setOnClickListener(listener); } //响应点击事件 OnClickListener listener = new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.camera_back: //返回 MyCameraActivity.this.finish(); break; case R.id.camera_position: //切换前后摄像头 int cameraCount = 0; CameraInfo cameraInfo = new CameraInfo(); cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数 for(int i = 0; i < cameraCount; i ) { Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息 if(cameraPosition == 1) { //现在是后置,变更为前置 if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置 camera.stopPreview();//停掉原来摄像头的预览 camera.release();//释放资源 camera = null;//取消原来摄像头 camera = Camera.open(i);//打开当前选中的摄像头 try { camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } camera.startPreview();//开始预览 cameraPosition = 0; break; } } else { //现在是前置, 变更为后置 if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置 camera.stopPreview();//停掉原来摄像头的预览 camera.release();//释放资源 camera = null;//取消原来摄像头 camera = Camera.open(i);//打开当前选中的摄像头 try { camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } camera.startPreview();//开始预览 cameraPosition = 1; break; } } } break; case R.id.camera_shutter: //快门 camera.autoFocus(new AutoFocusCallback() {//自动对焦 @Override public void onAutoFocus(boolean success, Camera camera) { // TODO Auto-generated method stub if(success) { //设置参数,并拍照 Parameters params = camera.getParameters(); params.setPictureFormat(PixelFormat.JPEG);//图片格式 params.setPreviewSize(800, 480);//图片大小 camera.setParameters(params);//将参数设置到我的camera camera.takePicture(null, null, jpeg);//将拍摄到的照片给自定义的对象 } } }); break; } } }; /*surfaceHolder他是系统提供的一个用来设置surfaceView的一个对象,而它通过surfaceView.getHolder()这个方法来获得。 Camera提供一个setPreviewDisplay(SurfaceHolder)的方法来连接*/ //SurfaceHolder.Callback,这是个holder用来显示surfaceView 数据的接口,他必须实现以下3个方法 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub //当surfaceview创建时开启相机 if(camera == null) { camera = Camera.open(); try { camera.setPreviewDisplay(holder);//通过surfaceview显示取景画面 camera.startPreview();//开始预览 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub //当surfaceview关闭时,关闭预览并释放资源 camera.stopPreview(); camera.release(); camera = null; holder = null; surface = null; } //创建jpeg图片回调数据对象 PictureCallback jpeg = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { // TODO Auto-generated method stub try { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); //自定义文件保存路径 以拍摄时间区分命名 filepath = "/sdcard/Messages/MyPictures/" new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) ".jpg"; File file = new File(filepath); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩的流里面 bos.flush();// 刷新此缓冲区的输出流 bos.close();// 关闭此输出流并释放与此流有关的所有系统资源 camera.stopPreview();//关闭预览 处理数据 camera.startPreview();//数据处理完后继续开始预览 bitmap.recycle();//回收bitmap空间 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; } |
相关文章推荐
- android studio 下载地址
- android 键盘按键监听
- Android 笔记10
- 随手记----Android仿iOS音量调节的效果
- java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@412d723
- Android基于蓝牙的聊天demo
- Android实现渐变title栏
- 今天学习Android软键盘
- android学习笔记(一)---shape属性
- 老罗Android(19)AsyncTask下载图片例子
- Android 多线程
- 在Mac环境下安装AndroidStudio
- SAX,DOM,Pull的比较
- Android Fragment分页显示的实现
- Android 仿美团网,探索ListView的A-Z字母排序功能实现选择城市
- Pull解析和生成XML
- Android给页面添加横线和竖线
- EditText属性整理
- Activity四种启动模式及应用
- Android数据输入测试的checklist