Android(安卓)照相机实现方式
在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中。
基本实现:
准备工作:设置 调用相机的回调码 和 设置 调用照相机拍照后保存图片的位置,名称,及后缀名(图片类型)
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
- @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的权限:
123 | <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 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 | 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中显示html标签或者带图片
- android universalimageloader 几点改进
- 浅谈Android五大布局——LinearLayout、FrameLayout和AbsoulteLa
- Android(安卓)关于手指拖动onScroll、onFling...[geoway]
- Android之相机的使用
- Android中获取网络图片的三种方法
- SimpleCropView 裁剪图片
- 超炫的android 3d ui,目前正在内测中 期待
- [置顶] android利用zbar二维码扫描-(解决中文乱码及扫描区域定义