這個代碼幾乎涉及到了攝像頭開發的所有方面,(除了previewcallback,這塊東西我會結合android攝像頭自動識别人臉/火災來談),且力求精簡,是雜家的心血阿!相對之前改進之處有:
1,精簡。隻有一個imagebutton用來實作按下拍照。拍照後自動儲存,進入預覽界面。 不像原來的要三個按鍵:預覽/拍照/儲存。
2,聚焦方面實作不間斷循環聚焦。 不像之前的,要按一下按鍵聚焦一次。
3,imagebutton增加了按下的效果。按之前示例如下:
,點選後背景變暗,有種風車旋轉的感覺。
4,增加了查詢攝像頭picturesizes和previewsize的代碼,調試程式時應先查詢出自己的參數然後配置。不同的手機參數不同。另外,預覽surfaceview的高我設為800px,如果手機螢幕太小,這個參數要改。
5,改進了之前的按back傳回按鍵退出程式後,再次進入程式camera沒有釋放,緻使程式挂掉的問題。
6,改進了預覽時手機橫豎屏切換時,程式挂掉的毛病。但這裡的布局還是采用預設的豎屏。
7,在實作循環聚焦的同時,保留了autofocus()接口。可以測試出,在使用focus_mode_continuous_video聚焦模式下,autofocus不發揮作用。如果不支援不間斷聚焦,setfocusmode就改成focus_mode_auto!!!
8,注釋更加良好。
廢話不說了請看源碼:
第一部分:manifinest.xml
[html] view
plaincopy
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="yan.guoqi.rectphoto"
android:versioncode="1"
android:versionname="1.0" >
<uses-sdk
android:minsdkversion="8"
android:targetsdkversion="15" />
<!-- 增加檔案存儲和通路攝像頭的權限 -->
<uses-permission android:name="android.permission.mount_unmount_filesystems" />
<uses-permission android:name="android.permission.write_external_storage" />
<uses-permission android:name="android.permission.camera" />
<uses-feature android:name="android.hardware.camera" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/apptheme" >
<activity
android:name=".rectphoto"
android:label="@string/title_activity_rect_photo" >
<intent-filter>
<action android:name="android.intent.action.main" />
<category android:name="android.intent.category.launcher" />
</intent-filter>
</activity>
</application>
</manifest>
第二部分:布局檔案
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<textview
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bestwish"
tools:context=".rectphoto" />
<framelayout
android:layout_height="wrap_content" >
<surfaceview
android:id="@+id/previewsv"
android:layout_width="fill_parent"
android:layout_height="800px" />
</framelayout>
<imagebutton
android:id="@+id/photoimgbtn"
android:background="@drawable/photo_img_btn"
android:layout_gravity="center" />
</linearlayout>
第三部分:rectphoto.java主程式
[java] view
package yan.guoqi.rectphoto;
import java.io.bufferedoutputstream;
import java.io.file;
import java.io.fileoutputstream;
import java.io.ioexception;
import android.app.activity;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.colormatrixcolorfilter;
import android.graphics.matrix;
import android.graphics.pixelformat;
import android.hardware.camera;
import android.hardware.camera.autofocuscallback;
import android.hardware.camera.picturecallback;
import android.hardware.camera.shuttercallback;
import android.os.bundle;
import android.util.log;
import android.view.motionevent;
import android.view.surfaceholder;
import android.view.surfaceview;
import android.view.view;
import android.view.view.onclicklistener;
import android.view.view.ontouchlistener;
import android.view.viewgroup.layoutparams;
import android.view.window;
import android.view.windowmanager;
import android.widget.imagebutton;
public class rectphoto extends activity implements surfaceholder.callback{
private static final string tag="yan";
private boolean ispreview = false;
private surfaceview mpreviewsv = null; //預覽surfaceview
private surfaceholder mysurfaceholder = null;
private imagebutton mphotoimgbtn = null;
private camera mycamera = null;
private bitmap mbitmap = null;
private autofocuscallback myautofocuscallback = null;
@override
public void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
//設定全屏無标題
requestwindowfeature(window.feature_no_title);
int flag = windowmanager.layoutparams.flag_fullscreen;
window mywindow = this.getwindow();
mywindow.setflags(flag, flag);
setcontentview(r.layout.activity_rect_photo);
//初始化surfaceview
mpreviewsv = (surfaceview)findviewbyid(r.id.previewsv);
mysurfaceholder = mpreviewsv.getholder();
mysurfaceholder.setformat(pixelformat.translucent);//translucent半透明 transparent透明
mysurfaceholder.addcallback(this);
mysurfaceholder.settype(surfaceholder.surface_type_push_buffers);
//自動聚焦變量回調
myautofocuscallback = new autofocuscallback() {
public void onautofocus(boolean success, camera camera) {
// todo auto-generated method stub
if(success)//success表示對焦成功
{
log.i(tag, "myautofocuscallback: success...");
//mycamera.setoneshotpreviewcallback(null);
}
else
//未對焦成功
log.i(tag, "myautofocuscallback: 失敗了...");
}
};
mphotoimgbtn = (imagebutton)findviewbyid(r.id.photoimgbtn);
//手動設定拍照imagebutton的大小為120×120,原圖檔大小是64×64
layoutparams lp = mphotoimgbtn.getlayoutparams();
lp.width = 120;
lp.height = 120;
mphotoimgbtn.setlayoutparams(lp);
mphotoimgbtn.setonclicklistener(new photoonclicklistener());
mphotoimgbtn.setontouchlistener(new myontouchlistener());
}
/*下面三個是surfaceholder.callback建立的回調函數*/
public void surfacechanged(surfaceholder holder, int format, int width,int height)
// 當surfaceview/預覽界面的格式和大小發生改變時,該方法被調用
{
// todo auto-generated method stub
log.i(tag, "surfaceholder.callback:surfacechanged!");
initcamera();
public void surfacecreated(surfaceholder holder)
// surfaceview啟動時/初次執行個體化,預覽界面被建立時,該方法被調用。
mycamera = camera.open();
try {
mycamera.setpreviewdisplay(mysurfaceholder);
log.i(tag, "surfaceholder.callback: surfacecreated!");
} catch (ioexception e) {
// todo auto-generated catch block
if(null != mycamera){
mycamera.release();
mycamera = null;
e.printstacktrace();
}
public void surfacedestroyed(surfaceholder holder)
//銷毀時被調用
// todo auto-generated method stub
log.i(tag, "surfaceholder.callback:surface destroyed");
if(null != mycamera)
{
mycamera.setpreviewcallback(null); /*在啟動previewcallback時這個必須在前不然退出出錯。
這裡實際上注釋掉也沒關系*/
mycamera.stoppreview();
ispreview = false;
mycamera.release();
mycamera = null;
//初始化相機
public void initcamera(){
if(ispreview){
mycamera.stoppreview();
if(null != mycamera){
camera.parameters myparam = mycamera.getparameters();
// //查詢螢幕的寬和高
// windowmanager wm = (windowmanager)getsystemservice(context.window_service);
// display display = wm.getdefaultdisplay();
// log.i(tag, "螢幕寬度:"+display.getwidth()+" 螢幕高度:"+display.getheight());
myparam.setpictureformat(pixelformat.jpeg);//設定拍照後存儲的圖檔格式
// //查詢camera支援的picturesize和previewsize
// list<size> picturesizes = myparam.getsupportedpicturesizes();
// list<size> previewsizes = myparam.getsupportedpreviewsizes();
// for(int i=0; i<picturesizes.size(); i++){
// size size = picturesizes.get(i);
// log.i(tag, "initcamera:攝像頭支援的picturesizes: width = "+size.width+"height = "+size.height);
// }
// for(int i=0; i<previewsizes.size(); i++){
// size size = previewsizes.get(i);
// log.i(tag, "initcamera:攝像頭支援的previewsizes: width = "+size.width+"height = "+size.height);
//
//設定大小和方向等參數
myparam.setpicturesize(1280, 960);
myparam.setpreviewsize(960, 720);
//myparam.set("rotation", 90);
mycamera.setdisplayorientation(90);
myparam.setfocusmode(camera.parameters.focus_mode_continuous_video);
mycamera.setparameters(myparam);
mycamera.startpreview();
mycamera.autofocus(myautofocuscallback);
ispreview = true;
/*為了實作拍照的快門聲音及拍照儲存照片需要下面三個回調變量*/
shuttercallback myshuttercallback = new shuttercallback()
//快門按下的回調,在這裡我們可以設定類似播放“咔嚓”聲之類的操作。預設的就是咔嚓。
public void onshutter() {
// todo auto-generated method stub
log.i(tag, "myshuttercallback:onshutter...");
};
picturecallback myrawcallback = new picturecallback()
// 拍攝的未壓縮原資料的回調,可以為null
public void onpicturetaken(byte[] data, camera camera) {
log.i(tag, "myrawcallback:onpicturetaken...");
picturecallback myjpegcallback = new picturecallback()
//對jpeg圖像資料的回調,最重要的一個回調
log.i(tag, "myjpegcallback:onpicturetaken...");
if(null != data){
mbitmap = bitmapfactory.decodebytearray(data, 0, data.length);//data是位元組資料,将其解析成位圖
mycamera.stoppreview();
ispreview = false;
//設定focus_mode_continuous_video)之後,myparam.set("rotation", 90)失效。圖檔竟然不能旋轉了,故這裡要旋轉下
matrix matrix = new matrix();
matrix.postrotate((float)90.0);
bitmap rotabitmap = bitmap.createbitmap(mbitmap, 0, 0, mbitmap.getwidth(), mbitmap.getheight(), matrix, false);
//儲存圖檔到sdcard
if(null != rotabitmap)
{
savejpeg(rotabitmap);
//再次進入預覽
//拍照按鍵的監聽
public class photoonclicklistener implements onclicklistener{
public void onclick(view v) {
if(ispreview && mycamera!=null){
mycamera.takepicture(myshuttercallback, null, myjpegcallback);
/*給定一個bitmap,進行儲存*/
public void savejpeg(bitmap bm){
string savepath = "/mnt/sdcard/rectphoto/";
file folder = new file(savepath);
if(!folder.exists()) //如果檔案夾不存在則建立
folder.mkdir();
long datatake = system.currenttimemillis();
string jpegname = savepath + datatake +".jpg";
log.i(tag, "savejpeg:jpegname--" + jpegname);
//file jpegfile = new file(jpegname);
fileoutputstream fout = new fileoutputstream(jpegname);
bufferedoutputstream bos = new bufferedoutputstream(fout);
// //如果需要改變大小(預設的是寬960×高1280),如改成寬600×高800
// bitmap newbm = bm.createscaledbitmap(bm, 600, 800, false);
bm.compress(bitmap.compressformat.jpeg, 100, bos);
bos.flush();
bos.close();
log.i(tag, "savejpeg:存儲完畢!");
log.i(tag, "savejpeg:存儲失敗!");
/*為了使圖檔按鈕按下和彈起狀态不同,采用過濾顔色的方法.按下的時候讓圖檔顔色變淡*/
public class myontouchlistener implements ontouchlistener{
public final float[] bt_selected=new float[]
{ 2, 0, 0, 0, 2,
0, 2, 0, 0, 2,
0, 0, 2, 0, 2,
0, 0, 0, 1, 0 };
public final float[] bt_not_selected=new float[]
{ 1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0 };
public boolean ontouch(view v, motionevent event) {
if(event.getaction() == motionevent.action_down){
v.getbackground().setcolorfilter(new colormatrixcolorfilter(bt_selected));
v.setbackgrounddrawable(v.getbackground());
else if(event.getaction() == motionevent.action_up){
v.getbackground().setcolorfilter(new colormatrixcolorfilter(bt_not_selected));
return false;
public void onbackpressed()
//無意中按傳回鍵時要釋放記憶體
super.onbackpressed();
rectphoto.this.finish();
}
源碼下載下傳連結: http://download.csdn.net/detail/yanzi1225627/5060323