Android 自定义相机及分析源码
android 自定义相机及分析源码
使用android 系统相机的方法:
要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下
<intent-filter> <action android:name="android.intent.action.image_capture" /> <category android:name="android.intent.category.default" /> </intent-filter>
action的作用就是声明action的类型,便于intent的使用,category的作用就是注册,没有它。相关操作将不起作用。
一种方式是简单粗暴的实现,如下
intent intent=new intent(mediastore.action_image_capture); startactivityforresult(intent, req_1); //然后在 onactivityresult方法中实现数据的获取,此处是展示在了一个imageview上 if(resultcode==result_ok){ if(requestcode==req_1){ bundle bundle=data.getextras(); bitmap bitmap=(bitmap) bundle.get("data"); imageview.setimagebitmap(bitmap); }
小总结:这样的好处是简单快捷,但是在现在的android智能机中,好多相片都是很大的,这里获得的仅仅是一个缩略图罢了
另外一种方式是稍微温婉一点了,而且效果也更好一点,好处就在于它是先将照片信息存储到本地一个临时文件中,然后让imageview去相关路径下进行读取,这样就可以获得清晰度很高的图片了。如下
/* * 此方法的存在意义就是不在onactivityresult方法的data中获取我们拍照的缩略图,而是从我们的文件输出目录下直接查看原图 * 这样的好处就是可以对大容量的照片进行便捷的准确的操作 */ public void onstartcarema2(view view){ intent intent=new intent(mediastore.action_image_capture); //见你给你路径传递回需要的处理方法中 uri uri=uri.fromfile(new file(myfilepath)); //设置文件的输出路径 intent.putextra(mediastore.extra_output, uri); startactivityforresult(intent, req_2); } //然后在onactivityresult方法中进行相关的处理就可以了 else if(requestcode==req_2){ fileinputstream fis=null; try { fis=new fileinputstream(myfilepath); bitmap bitmap=bitmapfactory.decodestream(fis); imageview.setimagebitmap(bitmap); } catch (filenotfoundexception e) { // todo auto-generated catch block e.printstacktrace(); }finally{ try { fis.close(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } } } //记得最后一定要关闭相关的流操作。否则会引起相关的异常的。
开发自定义的相机
由于开发自定义的相机要进行相关的权限的生命,所以一定不要忘记在清单文件中做相关的处理,如下
<uses-permission android:name="android.permission.write_external_storage"/> <uses-permission android:name="android.permission.camera"/>
然后有以下几个步骤:
- 创建camera,并完成初始化camera,开始预览,释放资源三个方法
- 与activity的surfaceview进行绑定。
- 在系统的onpause(),onresume()方法中进行相关状态设置
- 对camera进行参数设置,作用就是对照片类型和状态进行相关的设置
- 将拍得的照片进行展示,一般会新开一个activity,用imageview进行承载,我们还可以在此activity上添加textview,实现水印效果等其他的美化操作
- 另外,如果想加入自动聚焦的功能,就可以在surfaceview上添加onclicklistener(),对屏幕进行侦听,调用mycamera.autofocus(null);方法即可
以上就是整个思路
接下来就是使用系统camera的代码展示
(可以直接copy相关代码块,添加到你的应用中去,实现camera这一功能。)
首先是mainactivity
布局
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".mainactivity" > <button android:id="@+id/startcarema" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" android:text="startcarema" android:onclick="onstartcarema" /> <button android:id="@+id/startcarema2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" android:text="startcarema2" android:onclick="onstartcarema2" /> <button android:id="@+id/customcarema" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" android:text="customcarema" android:onclick="oncustomcarema" /> <imageview android:id="@+id/imageview" android:layout_width="match_parent" android:layout_height="match_parent" /> </linearlayout>
代码
package com.example.camerademo; import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.ioexception; import android.app.activity; import android.content.intent; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.net.uri; import android.os.bundle; import android.os.environment; import android.provider.mediastore; import android.view.view; import android.widget.button; import android.widget.imageview; public class mainactivity extends activity { //为下面的获取请求所用 private static int req_1=1; private static int req_2=2; button btn_startcareme,btn_startcarema2,btn_customcarema; imageview imageview; //定义照片存储的路径 private string myfilepath; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); btn_startcareme=(button) findviewbyid(r.id.startcarema); btn_startcarema2=(button) findviewbyid(r.id.startcarema2); btn_customcarema=(button) findviewbyid(r.id.customcarema); imageview=(imageview) findviewbyid(r.id.imageview); //初始化不同手机的sd卡的路径 myfilepath=environment.getexternalstoragedirectory().getpath(); myfilepath=myfilepath+"/"+"temperature.png"; } public void oncustomcarema(view view){ intent intent=new intent(this,customcarema.class); startactivity(intent); } public void onstartcarema(view view){ intent intent=new intent(mediastore.action_image_capture); startactivityforresult(intent, req_1); } /* * 此方法的存在意义就是不在onactivityresult方法的data中获取我们拍照的缩略图,而是从我们的文件输出目录下直接查看原图 * 这样的好处就是可以对大容量的照片进行便捷的准确的操作 */ public void onstartcarema2(view view){ intent intent=new intent(mediastore.action_image_capture); //见你给你路径传递回需要的处理方法中 uri uri=uri.fromfile(new file(myfilepath)); //设置文件的输出路径 intent.putextra(mediastore.extra_output, uri); startactivityforresult(intent, req_2); } @override protected void onactivityresult(int requestcode, int resultcode, intent data) { // todo auto-generated method stub super.onactivityresult(requestcode, resultcode, data); if(resultcode==result_ok){ if(requestcode==req_1){ bundle bundle=data.getextras(); bitmap bitmap=(bitmap) bundle.get("data"); imageview.setimagebitmap(bitmap); }else if(requestcode==req_2){ fileinputstream fis=null; try { fis=new fileinputstream(myfilepath); bitmap bitmap=bitmapfactory.decodestream(fis); imageview.setimagebitmap(bitmap); } catch (filenotfoundexception e) { // todo auto-generated catch block e.printstacktrace(); }finally{ try { fis.close(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } } } } }
接下来是自定义相机的代码
主界面布局
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <button android:id="@+id/capture" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dp" android:text="capture" android:onclick="oncapture" /> <surfaceview android:id="@+id/preview" android:layout_width="match_parent" android:layout_height="match_parent" /> </linearlayout>
resultactivity的布局
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <textview android:layout_width="match_parent" android:layout_height="wrap_content" android:text="capture result" android:textsize="28dp" android:textcolor="#bfaacd" android:gravity="center" /> <imageview android:id="@+id/picture" android:layout_width="match_parent" android:layout_height="match_parent" android:scaletype="center" /> </linearlayout>
代码
首先是customcamera类,
package com.example.camerademo; import java.io.file; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; import android.app.activity; import android.content.intent; import android.graphics.imageformat; import android.hardware.camera; import android.os.bundle; import android.view.surfaceholder; import android.view.surfaceview; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; @suppresswarnings("unused") public class customcarema extends activity implements surfaceholder.callback{ private camera mycamera; private surfaceview preview; private surfaceholder myholder; //myholder勇于展现surfaceview的图像 private camera.picturecallback mypicturecallback=new camera.picturecallback() { @override public void onpicturetaken(byte[] data, camera arg1) { //将拍照得到的数据信息存储到本地 file tempfile=new file("/sdcard/temp.png"); try { fileoutputstream fos=new fileoutputstream(tempfile); fos.write(data); fos.close(); //然后将这个照片的数据信息传送给要进行展示的activity即可 intent intent=new intent(customcarema.this,resultactivity.class); intent.putextra("picturepath", tempfile.getabsolutepath()); startactivity(intent); //拍照结束之后销毁当前的activity,进入到图片展示界面 customcarema.this.finish(); } catch (filenotfoundexception e) { // todo auto-generated catch block e.printstacktrace(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } }; @override protected void oncreate(bundle savedinstancestate) { // todo auto-generated method stub super.oncreate(savedinstancestate); setcontentview(r.layout.customcarema); preview=(surfaceview) findviewbyid(r.id.preview); myholder=preview.getholder(); myholder.addcallback(this); //实现点击屏幕自动聚焦的功能,此处并不需要拍照,故只是聚焦 preview.setonclicklistener(new onclicklistener() { @override public void onclick(view arg0) { // todo auto-generated method stub mycamera.autofocus(null); } }); } @override protected void onresume() { super.onresume(); if(mycamera==null){ mycamera=getcamera(); if(myholder != null ){ setstartpreview(mycamera, myholder); } } } @override protected void onpause() { // todo auto-generated method stub super.onpause(); releasecamera(); } /** * 释放相机的资源 */ private void releasecamera(){ if(mycamera !=null ){ mycamera.setpreviewcallback(null); mycamera.stoppreview(); mycamera.release(); mycamera=null; } } /** * 拍照的一些参数设置,点击此按钮之后会触发拍照的会掉,进而实现拍照的效果 * @param view */ public void oncapture(view view){ camera.parameters parameters=mycamera.getparameters(); //设置照片的类型 parameters.setpictureformat(imageformat.jpeg); parameters.setpicturesize(800, 600); //设置为自动聚焦 parameters.setfocusmode(camera.parameters.focus_mode_auto); //设置为自动聚焦是不够的,因为我们先得到的是最为清晰的图片,所以要在聚焦成功的时候才进行拍照 mycamera.autofocus(new camera.autofocuscallback() { @override public void onautofocus(boolean success, camera camera) { // todo auto-generated method stub if(success){ mycamera.takepicture(null, null, mypicturecallback); } } }); } /** * 获取系统的一个camera对象 */ private camera getcamera(){ camera camera=null; try{ camera=camera.open(); }catch(exception e){ e.printstacktrace(); } return camera; } /** * 开始预览相机的内容,其实就是讲surfaceholder与之绑定 */ private void setstartpreview(camera camera,surfaceholder holder){ //直接调用系统方式绑定预览 try { camera.setpreviewdisplay(holder); //由于系统默认使用横屏预览,,所以要进行设置 camera.setdisplayorientation(90); camera.startpreview(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } @override public void surfacechanged(surfaceholder holder, int arg1, int arg2, int arg3) { // todo auto-generated method stub mycamera.stoppreview(); setstartpreview(mycamera, myholder); } @override public void surfacecreated(surfaceholder holder) { // todo auto-generated method stub setstartpreview(mycamera, myholder); } @override public void surfacedestroyed(surfaceholder arg0) { // todo auto-generated method stub releasecamera(); } }
然后是结果界面代码:
package com.example.camerademo; import java.io.fileinputstream; import java.io.filenotfoundexception; import android.app.activity; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.graphics.matrix; import android.os.bundle; import android.widget.imageview; public class resultactivity extends activity { @override protected void oncreate(bundle savedinstancestate) { // todo auto-generated method stub super.oncreate(savedinstancestate); setcontentview(r.layout.resultactivity); string path=getintent().getstringextra("picturepath"); imageview imageview=(imageview) findviewbyid(r.id.picture); //由于这样稚嫩获得横屏,所以我们要使用流的形式来转换 // bitmap bitmap=bitmapfactory.decodefile(path); // imageview.setimagebitmap(bitmap); fileinputstream fis; try { fis = new fileinputstream(path); bitmap bitmap=bitmapfactory.decodestream(fis); matrix matrix=new matrix(); matrix.setrotate(90); bitmap=bitmap.createbitmap(bitmap, 0,0, bitmap.getwidth() ,bitmap.getheight(),matrix,true); imageview.setimagebitmap(bitmap); } catch (filenotfoundexception e) { // todo auto-generated catch block e.printstacktrace(); } } }
以上代码中已经做了下关的代码注释
总结:
安卓6.0以上版本记得加动态权限,不然会报空指针哦,还有点击拍照事件那里 别忘了加进去,不然拍照没反应
以上就是android 自定义相机的实例详解,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
上一篇: HP 541笔记本电脑改XP的方法
下一篇: 小程序实现列表多个批量倒计时