- 浏览: 2738982 次
- 来自: 深圳
-
文章分类
最新评论
-
Wangwei86609:
非常好的规则引擎框架,支持决策树和多线程运行规则https:/ ...
规则引擎 -
comet0515:
dist.lib是什么文件?提示找不到
Jenkins(Hudson)+Findbugs/PMD/Checkstyle的配置要点 -
comet0515:
不是maven工程能不能用checkstyle插件?job是一 ...
HUDSON/Jenkins -
comet0515:
不是maven工程能不能用checkstyle插件?job是一 ...
Jenkins(Hudson)+Findbugs/PMD/Checkstyle的配置要点 -
comet0515:
不是maven工程能不能用checkstyle插件?job是一 ...
Jenkins(Hudson)+Findbugs/PMD/Checkstyle的配备要点
Android--相机预览及拍照临时文件/SurfaceView
如果做游戏或者视频相关开发的时候,将会用到SurfaceView。对于SurfaceView,首先需要了解一下它自己的位置:
extendsView
↳ |
||
|
↳ |
android.view.SurfaceView |
由手册可知:
SurfaceView是View类的继承类,这个View里内嵌了一个专门用于绘制的Surface,这个可以类似的理解成为一个在View里的Canvas。你可以控制这个Surface的格式和尺寸。Surfaceview类则控制这个Surface在屏幕上的正确位置。
《Android高级编程》里这样说:
在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。
对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的。
当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。
1. 何时应该使用SurfaceView
SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。
SurfaceView封装的Surface支持所有标准的Canvas方法进行绘图,同时也支持完全的OpenGL ES 库。
使用OpenGL,你可以在Surface上绘制任何支持2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。
对于显示动态的3D图像来说,例如,那些使用Google Earth 功能的应用程序,或者那些提供沉浸体验的交互式游戏,Surface特别有用。它还是实时显示摄像头预览的最佳选择。
2. 创建一个新的SurfaceView控件
创建一个新的SurfaceView控件需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。
SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它SurfaceHolder对象的引用,其中包含了当前有效的Surface。
一个典型的SurfaceView 设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。
3. 使用SurfaceView创建3D控件
Android完全支持OpenGL ES 3D 渲染框架,其中包含了对设备的硬件加速的支持。SurfaceView控件提供了一个表面,可以在它上面渲染你的OpenGL场景。
那么我们在使用的时候可以这样使用:
被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
可以直接从内存或硬件设备比如相机等取得图像数据,是个非常重要的绘图容器。
它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。
如何去使用一个SurfaceView:
首先继承SurfaceView并实现SurfaceHolder.Callback接口。因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始。可以被直接复制到显存从而显示出来,这使得显示速度会非常快,而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。
需要重写的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在surface的大小发生改变时激发
(2)public void surfaceCreated(SurfaceHolder holder){}
//在创建时激发,一般在这里调用画图的线程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {}
//销毁时激发,一般在这里将画图的线程停止、释放。
整个过程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。
关于SurfaceHolder:
这里用到了一个类SurfaceHolder,可以把它当成surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
几个需要注意的方法:
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。
(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。
下面给出一个应用的实例,本实例实现的是相机的预览和拍照功能,其中,为了节省存储空间,当退出应用程序时,拍照文件会自动删除,这里把它作为临时文件保存。
下面是它的实现截图:
由于是在模拟器中运行,所以显示的是无内存卡。
下面给出实现本实例的源码:
1.首先,我们需要做权限的声明
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.给出布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="@drawable/white" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/myTextView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="@drawable/blue" android:text="@string/hello" /> <SurfaceView android:id="@+id/mSurfaceView1" android:visibility="visible" android:layout_width="320px" android:layout_height="240px"> </SurfaceView> <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:id="@+id/myButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/str_button1"/> <Button android:id="@+id/myButton2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/str_button2"/> <Button android:id="@+id/myButton3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/str_take_picture"/> </LinearLayout> <ImageView android:id="@+id/myImageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
3.主程序代码
package irdc.ex07_15; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import android.app.Activity; /* 延含学习 */ //import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.PixelFormat; /* 引用Camera类 */ import android.hardware.Camera; /* 引用PictureCallback为取得拍照后的事件 */ import android.hardware.Camera.PictureCallback; import android.hardware.Camera.ShutterCallback; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; /* 使Activity实现SurfaceHolder.Callback */ public class EX07_15 extends Activity implements SurfaceHolder.Callback { /* 建立私有Camera对象 */ private Camera mCamera01; private Button mButton01, mButton02, mButton03; /* 当成review照下来的相片之用 */ private ImageView mImageView01; private TextView mTextView01; private static String TAG = "HIPPO_DEBUG"; private SurfaceView mSurfaceView01; private SurfaceHolder mSurfaceHolder01; //private int intScreenX, intScreenY; /* 默认相机预览模式为false */ private boolean bIfPreview = false; /* 将照下来的图片保存在此 */ private String strCaptureFilePath = "/sdcard/camera_snap.jpg"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* 使应用程序全屏运行,不使用title bar */ requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); /* 判断存储卡是否存在 */ if(!checkSDCard()) { /* 提醒User未安装存储卡 */ mMakeTextToast ( getResources().getText(R.string.str_err_nosd).toString(), true ); } /* 取得屏幕解析像素 */ DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //intScreenX = dm.widthPixels; //intScreenY = dm.heightPixels; //Log.i(TAG, Integer.toString(intScreenX)); /* 延含学习 */ //import android.content.pm.ActivityInfo; //this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mTextView01 = (TextView) findViewById(R.id.myTextView1); mImageView01 = (ImageView) findViewById(R.id.myImageView1); /* 以SurfaceView作为相机Preview之用 */ mSurfaceView01 = (SurfaceView) findViewById(R.id.mSurfaceView1); /* 绑定SurfaceView,取得SurfaceHolder对象 */ mSurfaceHolder01 = mSurfaceView01.getHolder(); /* Activity必须实现SurfaceHolder.Callback */ mSurfaceHolder01.addCallback(EX07_15.this); /* 额外的设置预览大小设定,在此不使用 */ //mSurfaceHolder01.setFixedSize(320, 240); /* * 以SURFACE_TYPE_PUSH_BUFFERS(3) * 作为SurfaceHolder显示类型 * */ mSurfaceHolder01.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mButton01 = (Button)findViewById(R.id.myButton1); mButton02 = (Button)findViewById(R.id.myButton2); mButton03 = (Button)findViewById(R.id.myButton3); /* 开启相机及Preview */ mButton01.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub /* 自定义初始化开启相机函数 */ initCamera(); } }); /* 停止Preview及相机 */ mButton02.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub /* 自定义重置相机,并关闭相机预览函数 */ resetCamera(); } }); /* 拍照 */ mButton03.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub /* 当存储卡存在才允许拍照,保存临时图像文件 */ if(checkSDCard()) { /* 自定义拍照函数 */ takePicture(); } else { /* 存储卡不存在的显示提示 */ mTextView01.setText ( getResources().getText(R.string.str_err_nosd).toString() ); } } }); } /* 告订初始相机函数 */ private void initCamera() { if(!bIfPreview) { /* 若相机非?预览模式,则开启相机 */ try { /* * The Heap 是应用程序?手机里执行所配置的空间 * 当超过预设的16 MB(每几个应用程序)时就会导致 "Out of memory"的错误 * 目前看来是Cupcake(AVD 1.5)?会发生 * Connect E from ICameraClient 0x.... * new client (0x...) sttempting to connect - rejected * */ mCamera01 = Camera.open(); } catch(Exception e) { Log.e(TAG, e.getMessage()); } } if (mCamera01 != null && !bIfPreview) { try { Log.i(TAG, "inside the camera"); mCamera01.setPreviewDisplay(mSurfaceHolder01); /* 建立Camera.Parameters对象 */ Camera.Parameters parameters = mCamera01.getParameters(); /* 设定相片格式为JPEG */ parameters.setPictureFormat(PixelFormat.JPEG); //parameters.setPreviewSize(w, h); List<Camera.Size> s=parameters.getSupportedPreviewSizes(); try { if(s!=null) { for(int i=0;i<s.size();i++) { Log.i(TAG,""+(((Camera.Size)s.get(i)).height)+"/"+(((Camera.Size)s.get(i)).width)); } } parameters.setPreviewSize(320, 240); //parameters.setPreviewSize(176, 144); /* ?2.0模拟器中,设置不支持的PreviewSize将造成Exception */ s=parameters.getSupportedPictureSizes(); try { if(s!=null) { for(int i=0;i<s.size();i++) { Log.i(TAG,""+(((Camera.Size)s.get(i)).height)+"/"+(((Camera.Size)s.get(i)).width)); } } /* ?2.0模拟器中,设置不支持的PictureSize将造成Exception */ parameters.setPictureSize(512, 384); //parameters.setPictureSize(213, 350); /* 将Camera.Parameters设定予Camera */ mCamera01.setParameters(parameters); /* setPreviewDisplay唯几的参数为SurfaceHolder */ mCamera01.setPreviewDisplay(mSurfaceHolder01); /* 立即运行Preview */ mCamera01.startPreview(); bIfPreview = true; Log.i(TAG, "startPreview"); } catch (Exception e) { Log.i(TAG, e.toString()); e.printStackTrace(); } } catch (Exception e) { Toast.makeText ( EX07_15.this, "initCamera error.", Toast.LENGTH_LONG ).show(); e.printStackTrace(); } } catch (IOException e) { // TODO Auto-generated catch block mCamera01.release(); mCamera01 = null; Log.i(TAG, e.toString()); e.printStackTrace(); } } } /* 拍照撷取影像 */ private void takePicture() { if (mCamera01 != null && bIfPreview) { /* 调用takePicture()方法拍照 */ mCamera01.takePicture(shutterCallback, rawCallback, jpegCallback); } } /* 相机重置 */ private void resetCamera() { if (mCamera01 != null && bIfPreview) { mCamera01.stopPreview(); /* 延含学习,释放Camera对象 */ //mCamera01.release(); //mCamera01 = null; Log.i(TAG, "stopPreview"); bIfPreview = false; } } private ShutterCallback shutterCallback = new ShutterCallback() { public void onShutter() { // Shutter has closed } }; private PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { // TODO Handle RAW image data } }; private PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { // TODO Handle JPEG image data /* onPictureTaken传入的第几个参数即为相片的byte */ Bitmap bm = BitmapFactory.decodeByteArray(_data, 0, _data.length); /* 创建文件 */ File myCaptureFile = new File(strCaptureFilePath); try { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile)); /* 采用压缩转档方法 */ bm.compress(Bitmap.CompressFormat.JPEG, 80, bos); /* 调用flush()方法,更新BufferStream */ bos.flush(); /* 结束OutputStream */ bos.close(); /* 将拍照下来且保存完毕的图文件,显示出来 */ mImageView01.setImageBitmap(bm); /* 显示完图片,立即重置相机,并关闭预览 */ resetCamera(); /* 再重新启动相机继续预览 */ initCamera(); } catch (Exception e) { Log.e(TAG, e.getMessage()); Log.e(TAG, e.toString()); } } }; /* 自定义文件函数 */ private void delFile(String strFileName) { try { File myFile = new File(strFileName); if(myFile.exists()) { myFile.delete(); } } catch (Exception e) { Log.e(TAG, e.toString()); e.printStackTrace(); } } public void mMakeTextToast(String str, boolean isLong) { if(isLong==true) { Toast.makeText(EX07_15.this, str, Toast.LENGTH_LONG).show(); } else { Toast.makeText(EX07_15.this, str, Toast.LENGTH_SHORT).show(); } } private boolean checkSDCard() { /* 判断存储卡是否存在 */ if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { return true; } else { return false; } } @Override public void surfaceChanged(SurfaceHolder surfaceholder, int format, int w, int h) { // TODO Auto-generated method stub Log.i(TAG, "Surface Changed1"); } @Override public void surfaceCreated(SurfaceHolder surfaceholder) { // TODO Auto-generated method stub Log.i(TAG, "Surface Changed2"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceholder) { // TODO Auto-generated method stub /* 当Surface不存在,就需要删除图片 */ try { delFile(strCaptureFilePath); mCamera01.stopPreview(); mCamera01.release(); mCamera01 = null; Log.i(TAG, "Surface Destroyed"); } catch(Exception e) { e.printStackTrace(); } } @Override protected void onPause() { // TODO Auto-generated method stub try { resetCamera(); mCamera01.release(); } catch(Exception e) { e.printStackTrace(); } super.onPause(); } }
相关推荐
SurfaceView是Android系统提供的一种用于显示多媒体数据(如视频或相机预览)的视图组件。它拥有自己的Surface,可以直接与硬件进行交互,从而提供流畅的动画和低延迟的视频播放。SurfaceView通常用于处理高性能的...
本项目“Android-surfaceview-camera”专注于利用SurfaceView来实现一个自定义的相机应用。下面将详细介绍SurfaceView与Camera在Android开发中的应用及核心知识点。 1. **SurfaceView介绍** SurfaceView是Android...
本系列会包括Android Camera预览,拍照,视频录制,播放,滤镜及渲染等,还会对相机系统原理做深入分析。 一、相机预览 序号 项目名称 内容简介 1 GLSurfacePreview GLSurfaceView OpenGL相机预览,直接绘制...
在Android开发中,自定义相机预览界面的拉伸问题是一个常见的挑战,尤其是在处理不同设备和屏幕方向变化时。本文将深入探讨这个问题,并提供解决方案。 首先,理解问题的根本原因至关重要。当我们在Android应用中...
在Android平台上,开发一款应用程序来实现通过Camera与SurfaceView选择摄像头并进行即时预览涉及到多个关键知识点。以下是对这些技术的详细解释: 1. **Camera API**:Android提供了Camera类,用于与设备上的摄像头...
在这个项目中,可能会使用`SurfaceView`作为相机预览的显示窗口,通过`Camera.setPreviewDisplay(SurfaceHolder)`方法将相机预览设置到`SurfaceView`上。 接着,为了实现头像轮廓的绘制,我们需要进行人像识别和...
android camera mirror 前置后置相机视频预览时左右镜像,实现镜子效果 基于以下网址实现的android studio项目源代码包,可以直接打开使用 https://blog.csdn.net/mbrose/article/details/80167781 代码做了一...
在Android开发中,实时显示摄像头视频是一个常见的需求,如创建相机应用、视频聊天或游戏等。`SurfaceView`是Android提供的一种用于高效显示多媒体数据的视图组件,尤其适合处理像视频流这样的实时数据。本篇文章将...
总之,通过`Camera2` API,我们可以实现对Android相机的精细控制,包括实时预览和拍照功能。在`Android Studio`中,结合`TextureView`和`CameraCaptureSession`,我们可以轻松地创建一个应用程序,允许用户查看相机...
本文将详细介绍这两个知识点,包括如何启动系统相机应用以及如何利用SurfaceView进行相机预览和拍照。 首先,调用系统摄像头是通过Intent来实现的。在MainActivity类中,我们可以创建一个Intent对象,指定其ACTION_...
在Android平台上,自定义相机是一项常见的需求,它允许开发者创建具有独特功能和界面设计的拍照应用。本教程将深入探讨如何在Android应用中实现自定义相机功能,包括使用Camera API和CameraX库。 首先,我们要了解...
在Android应用开发中,`SurfaceView` 和 `Camera` API 的结合使用是实现摄像头功能的常见方式,特别是在需要实时预览和拍照的场景下。本文将深入探讨如何利用`SurfaceView`来创建一个可重复预览和拍照的功能,主要...
// 创建相机预览会话并设置预览数据流 } ``` 接下来,创建一个CameraCaptureSession来处理预览帧。你需要定义一个CaptureRequest.Builder,并设置预览的目标Surface: ```java private void ...
在这个类中,我们将使用`SurfaceView`来显示相机预览,并通过`Camera.open()`方法获取相机实例。 3. 初始化和设置相机预览 在Activity的布局文件中加入`CameraPreview`,然后在`onCreate()`方法中初始化并设置相机...
在Android应用开发中,自定义SurfaceView来实现拍照、视频录制以及高级功能是一个常见的需求。本文将深入探讨如何使用SurfaceView来创建一个功能完善的拍照应用,包括删除、浏览照片以及自动对焦等功能。 首先,...
`android-Camera-Code.zip`是一个实用的Android相机应用示例,涵盖了基本的相机预览、拍照和参数设置。通过学习和分析这个示例,开发者可以快速掌握Android相机功能的开发,为自己的应用添加丰富的相机特性。同时,...
SurfaceView创建了一个独立的窗口,其内容在单独的线程中绘制,这使得它非常适合用于显示实时的视频流,如相机预览。通过重写SurfaceHolder的回调方法,我们可以监听Surface的创建、改变和销毁,以便及时更新相机...
Android 7 自定义相机预览及拍照功能需要使用 Android 的 Camera 类或 CameraManager 类, SurfaceView 控件,并解决权限问题。开发者需要根据实际情况选择合适的实现方式,並解决可能出现的技术问题。
首先,要理解“不预览拍照”,意味着在启动相机时,我们不需要显示实际的相机预览画面。这通常是通过使用Camera API或Camera2 API来完成的,但不创建用于显示预览的SurfaceTexture或SurfaceView。在Camera API中,...
- 设置预览Surface:相机预览需要一个Surface来显示图像,通常是`SurfaceView`或`TextureView`。通过`Camera.setPreviewDisplay()`方法设置预览显示。 - 启动预览:调用`Camera.startPreview()`开始预览。 - 拍照...