Android自定义照相机的实例
程序员文章站
2022-10-10 12:28:16
android自定义照相机实现
近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开...
android自定义照相机实现
近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能。
创建一个项目:fingertakepicture
首先来搞一下界面:
<framelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/framelayout1" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- 显示预览图形 --> <surfaceview android:id="@+id/surfaceview" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 相对布局,放置两个按钮 --> <relativelayout android:id="@+id/buttonlayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" > <!-- 拍照按钮 --> <button android:id="@+id/takepicture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentright="true" android:layout_alignparentbottom="true" android:background="@drawable/btn_tabkepicture_selector" android:onclick="btnonclick" /> <imageview android:id="@+id/scalepic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentleft="true" android:layout_alignparentbottom="true" android:layout_marginleft="5dp" android:background="@drawable/img_showpic_selector" android:onclick="imageclick" /> </relativelayout> </framelayout>
界面效果(无法把预览给截屏下来滴):
权限设置少不了:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.wwj.finger" android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="4" android:targetsdkversion="15" /> <uses-permission android:name="android.permission.camera" /> <!-- 在sdcard中创建与删除文件权限 --> <uses-permission android:name="android.permission.mount_unmount_filesystems" /> <!-- 往sdcard写入数据权限 --> <uses-permission android:name="android.permission.write_external_storage" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name=".mainactivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name=".showpicactivity" android:label="@string/app_name" android:theme="@style/apptheme" android:configchanges="orientation|keyboardhidden" ></activity> </application> </manifest>
主activity:
package com.wwj.finger; 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.intent; import android.graphics.pixelformat; import android.hardware.camera; import android.hardware.camera.picturecallback; import android.os.bundle; import android.os.environment; import android.view.keyevent; import android.view.motionevent; import android.view.surface; import android.view.surfaceholder; import android.view.surfaceholder.callback; import android.view.surfaceview; import android.view.view; import android.view.viewgroup; import android.widget.toast; /** * android手指拍照 * * @author wwj * @date 2013/4/29 */ public class mainactivity extends activity { private view layout; private camera camera; private camera.parameters parameters = null; bundle bundle = null; // 声明一个bundle对象,用来存储数据 @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); // 显示界面 setcontentview(r.layout.activity_main); layout = this.findviewbyid(r.id.buttonlayout); surfaceview surfaceview = (surfaceview) this .findviewbyid(r.id.surfaceview); surfaceview.getholder() .settype(surfaceholder.surface_type_push_buffers); surfaceview.getholder().setfixedsize(176, 144); //设置surface分辨率 surfaceview.getholder().setkeepscreenon(true);// 屏幕常亮 surfaceview.getholder().addcallback(new surfacecallback());//为surfaceview的句柄添加一个回调函数 } /** * 按钮被点击触发的事件 * * @param v */ public void btnonclick(view v) { if (camera != null) { switch (v.getid()) { case r.id.takepicture: // 拍照 camera.takepicture(null, null, new mypicturecallback()); break; } } } /** * 图片被点击触发的时间 * * @param v */ public void imageclick(view v) { if (v.getid() == r.id.scalepic) { if (bundle == null) { toast.maketext(getapplicationcontext(), r.string.takephoto, toast.length_short).show(); } else { intent intent = new intent(this, showpicactivity.class); intent.putextras(bundle); startactivity(intent); } } } private final class mypicturecallback implements picturecallback { @override public void onpicturetaken(byte[] data, camera camera) { try { bundle = new bundle(); bundle.putbytearray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换 savetosdcard(data); // 保存图片到sd卡中 toast.maketext(getapplicationcontext(), r.string.success, toast.length_short).show(); camera.startpreview(); // 拍完照后,重新开始预览 } catch (exception e) { e.printstacktrace(); } } } /** * 将拍下来的照片存放在sd卡中 * @param data * @throws ioexception */ public static void savetosdcard(byte[] data) throws ioexception { date date = new date(); simpledateformat format = new simpledateformat("yyyymmddhhmmss"); // 格式化时间 string filename = format.format(date) + ".jpg"; file filefolder = new file(environment.getexternalstoragedirectory() + "/finger/"); if (!filefolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录 filefolder.mkdir(); } file jpgfile = new file(filefolder, filename); fileoutputstream outputstream = new fileoutputstream(jpgfile); // 文件输出流 outputstream.write(data); // 写入sd卡中 outputstream.close(); // 关闭输出流 } private final class surfacecallback implements callback { // 拍照状态变化时调用该方法 @override public void surfacechanged(surfaceholder holder, int format, int width, int height) { parameters = camera.getparameters(); // 获取各项参数 parameters.setpictureformat(pixelformat.jpeg); // 设置图片格式 parameters.setpreviewsize(width, height); // 设置预览大小 parameters.setpreviewframerate(5); //设置每秒显示4帧 parameters.setpicturesize(width, height); // 设置保存的图片尺寸 parameters.setjpegquality(80); // 设置照片质量 } // 开始拍照时调用该方法 @override public void surfacecreated(surfaceholder holder) { try { camera = camera.open(); // 打开摄像头 camera.setpreviewdisplay(holder); // 设置用于显示拍照影像的surfaceholder对象 camera.setdisplayorientation(getpreviewdegree(mainactivity.this)); camera.startpreview(); // 开始预览 } catch (exception e) { e.printstacktrace(); } } // 停止拍照时调用该方法 @override public void surfacedestroyed(surfaceholder holder) { if (camera != null) { camera.release(); // 释放照相机 camera = null; } } } /** * 点击手机屏幕是,显示两个按钮 */ @override public boolean ontouchevent(motionevent event) { switch (event.getaction()) { case motionevent.action_down: layout.setvisibility(viewgroup.visible); // 设置视图可见 break; } return true; } @override public boolean onkeydown(int keycode, keyevent event) { switch (keycode) { case keyevent.keycode_camera: // 按下拍照按钮 if (camera != null && event.getrepeatcount() == 0) { // 拍照 //注:调用takepicture()方法进行拍照是传入了一个picturecallback对象——当程序获取了拍照所得的图片数据之后 //,picturecallback对象将会被回调,该对象可以负责对相片进行保存或传入网络 camera.takepicture(null, null, new mypicturecallback()); } } return super.onkeydown(keycode, event); } // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度 public static int getpreviewdegree(activity activity) { // 获得手机的方向 int rotation = activity.getwindowmanager().getdefaultdisplay() .getrotation(); int degree = 0; // 根据手机的方向计算相机预览画面应该选择的角度 switch (rotation) { case surface.rotation_0: degree = 90; break; case surface.rotation_90: degree = 0; break; case surface.rotation_180: degree = 270; break; case surface.rotation_270: degree = 180; break; } return degree; } }
用来显示图片的activity:
package com.wwj.finger; import android.app.activity; import android.content.intent; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.graphics.matrix; import android.os.bundle; import android.widget.imageview; public class showpicactivity extends activity { private imageview ivpic = null; // 显示图片控件 /** * activity在创建的时候回调的函数 主要用来初始化一些变量 */ @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.showpic); ivpic = (imageview) findviewbyid(r.id.ivpic); setimagebitmap(getimageformbundle()); } /** * 将mainactivity传过来的图片显示在界面当中 * * @param bytes */ public void setimagebitmap(byte[] bytes) { bitmap camerabitmap = byte2bitmap(); // 根据拍摄的方向旋转图像(纵向拍摄时要需要将图像选择90度) matrix matrix = new matrix(); matrix.setrotate(mainactivity.getpreviewdegree(this)); camerabitmap = bitmap .createbitmap(camerabitmap, 0, 0, camerabitmap.getwidth(), camerabitmap.getheight(), matrix, true); ivpic.setimagebitmap(camerabitmap); } /** * 从bundle对象中获取数据 * * @return */ public byte[] getimageformbundle() { intent intent = getintent(); bundle data = intent.getextras(); byte[] bytes = data.getbytearray("bytes"); return bytes; } /** * 将字节数组的图形数据转换为bitmap * * @return */ private bitmap byte2bitmap() { byte[] data = getimageformbundle(); // 将byte数组转换成bitmap对象 bitmap bitmap = bitmapfactory.decodebytearray(data, 0, data.length); return bitmap; } }
这是小巫那个创新项目的一小部分,已经完美实现简单的照相机功能了,保存图片不会像有些网友提供的代码给定一个特定的文件名,不能保存多张图片,还特定把一些方法封装了一下,有需要的朋友好好看看吧。