1. 程式人生 > >Android Camera開發 給攝像頭預覽介面加個ZoomBar(附完整程式碼下載)

Android Camera開發 給攝像頭預覽介面加個ZoomBar(附完整程式碼下載)

               

廢話不說了,就是加個seekbar,拖動的話能夠調節焦距,讓畫面變大或縮小。下面是核心程式:

一,camera的佈局檔案

<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=".StandardCamera" />
    <RelativeLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content" >        <FrameLayout
            android:layout_width="wrap_content"            android:layout_height="wrap_content" >
            <SurfaceView                android:id="@+id/previewSV"                android:layout_width="fill_parent"                android:layout_height="wrap_content" />        </FrameLayout>
                <LinearLayout        android:id="@+id/zoomLayout"        android:layout_width="wrap_content"        android:layout_height="40dp"        android:layout_centerInParent="true"        android:layout_centerHorizontal="true"                        android:orientation="horizontal" >        <TextView            android:id="@+id/textView1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="-"            android:textColor="#ffffff"             android:textSize="30dip"/>        <SeekBar            android:id="@+id/seekbar_zoom"            android:layout_width="300dp"            android:layout_height="wrap_content"            android:layout_gravity="center_vertical"           android:progressDrawable="@drawable/seekbar_style"            android:thumb="@drawable/ic_launcher"            android:thumbOffset="0dp" />        <TextView            android:id="@+id/textView2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"             android:text="+"            android:textColor="#ffffff"            android:textSize="30dip" />    </LinearLayout>    </RelativeLayout>        <ImageButton        android:id="@+id/photoImgBtn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:background="@drawable/photo_img_btn" /></LinearLayout>


其中裡面巢狀的LinearLayout就是那個ZoomBar,最外面我用了相對佈局,發現相對佈局用起來還是很好用的。為了方便以後擴充套件,Camera的SurfaceView用的幀佈局。注意SeekBar的幾個引數,其中的progressDrawable是指那個橫條的形狀,可以直接用個圖片,也可以寫個xml檔案。這裡用的是xml,當然用圖片很簡單。seekbar_style.xml檔案如下:

<?xml version="1.0" encoding="UTF-8"?>   <layer-list xmlns:android="http://schemas.android.com/apk/res/android">     <item android:id="@android:id/background">           <shape>               <corners android:radius="5dip" />               <gradient                       android:startColor="#ff9d9e9d"                       android:centerColor="#ff5a5d5a"                       android:centerY="0.75"                       android:endColor="#ff747674"                       android:angle="270"               />           </shape>       </item>  </layer-list>   


下面的android:thumb是滑動的那個手柄,本來我是寫了一個xml檔案,名字為thumb.xml如下:

<?xml version="1.0" encoding="UTF-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <!-- 按下狀態 -->    <item android:state_focused="true" android:state_pressed="true"><shape android:shape="oval">            <gradient android:angle="0" android:centerColor="#FF00FF00" android:endColor="#000000" android:gradientRadius="8" android:startColor="#FFFF0000" android:type="radial" />            <size android:height="20dip" android:width="20dip"></size>        </shape></item></selector>

無奈啥也顯示不出來,索性直接找了個粗糙的圖片,見諒哈!

二,整個程式的主程式碼:

package yan.guoqi.camera;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.List;import yan.guoqi.rectphoto.R;import android.app.Activity;import android.content.Context;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.Parameters;import android.hardware.Camera.PictureCallback;import android.hardware.Camera.PreviewCallback;import android.hardware.Camera.ShutterCallback;import android.os.Bundle;import android.util.Log;import android.view.Display;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;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;public class StandardCamera extends Activity implements SurfaceHolder.Callback, PreviewCallbackprivate static final String tag="StandardCamera"private boolean isPreview = falseprivate SurfaceView mPreviewSV = null; //棰勮SurfaceView private SurfaceHolder mySurfaceHolder = nullprivate ImageButton mPhotoImgBtn = nullprivate Camera myCamera = nullprivate Bitmap mBitmap = nullprivate AutoFocusCallback myAutoFocusCallback = nullboolean flag = true;  private SeekBar mZoomBar = 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);  initView();  mySurfaceHolder = mPreviewSV.getHolder();  mySurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);  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)    {     Log.i(tag, "myAutoFocusCallback: success...");    }    else    {     Log.i(tag, "myAutoFocusCallback: 澶辮觸浜�?.");    }   }  };    //新增ZoomBar  mZoomBar = (SeekBar)findViewById(R.id.seekbar_zoom);  mZoomBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {      public void onStopTrackingTouch(SeekBar seekBar) {    // TODO Auto-generated method stub       }      public void onStartTrackingTouch(SeekBar seekBar) {    // TODO Auto-generated method stub       }      public void onProgressChanged(SeekBar seekBar, int progress,     boolean fromUser) {    // TODO Auto-generated method stub    Parameters p = myCamera.getParameters();    p.setZoom(progress);    myCamera.setParameters(p);   }  }); } public void initView(){  mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);  WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);  Display display = wm.getDefaultDisplay();        LayoutParams lpSV = mPreviewSV.getLayoutParams();        lpSV.width = display.getWidth();        lpSV.height = (int) ((float)display.getHeight()*0.75);        mPreviewSV.setLayoutParams(lpSV);   mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);  LayoutParams lp = mPhotoImgBtn.getLayoutParams();  lp.width = 240;  lp.height = 240;    mPhotoImgBtn.setLayoutParams(lp);      mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());  mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener()); } public void surfaceChanged(SurfaceHolder holder, int format, int width,int height)  {  // TODO Auto-generated method stub    Log.i(tag, "SurfaceHolder.Callback:surfaceChanged!");  initCamera(); } public void surfaceCreated(SurfaceHolder holder)  {  // TODO Auto-generated method stub    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錛歋urface Destroyed");  if(null != myCamera)  {   myCamera.setPreviewCallback(null);    myCamera.stopPreview();    isPreview = false;    myCamera.release();   myCamera = null;       } } public void initCamera(){  if(isPreview){   myCamera.stopPreview();  }  if(null != myCamera){      Camera.Parameters myParam = myCamera.getParameters();   myParam.setPictureFormat(PixelFormat.JPEG);//璁劇疆鎷嶇収鍚庡瓨鍌ㄧ殑鍥劇墖鏍煎紡      //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);     List<String> focuseMode = (myParam.getSupportedFocusModes());   for(int i=0; i<focuseMode.size(); i++){    Log.i(tag, focuseMode.get(i));    if(focuseMode.get(i).contains("continuous")){     myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);    }    else{     myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);    }   }   //設定mZoomBar的最大值   mZoomBar.setMax(myParam.getMaxZoom());   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()  {  public void onPictureTaken(byte[] data, Camera camera) {   // TODO Auto-generated method stub   Log.i(tag, "myRawCallback:onPictureTaken...");  } }; PictureCallback myJpegCallback = new PictureCallback()  {  public void onPictureTaken(byte[] data, Camera camera) {   // TODO Auto-generated method stub   Log.i(tag, "myJpegCallback:onPictureTaken...");   if(null != data){    mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);//data鏄瓧鑺傛暟鎹紝灝嗗叾瑙f瀽鎴愪綅鍥�    myCamera.stopPreview();    isPreview = false;   }   Matrix matrix = new Matrix();   matrix.postRotate((float)90.0);   Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false);   if(null != rotaBitmap)   {    saveJpeg(rotaBitmap);   }   myCamera.startPreview();   isPreview = true;  } }; public class PhotoOnClickListener implements OnClickListener{  public void onClick(View v) {   // TODO Auto-generated method stub   if(isPreview && myCamera!=null){    myCamera.takePicture(myShutterCallback, null, myJpegCallback);    }  } } 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);  try {   FileOutputStream fout = new FileOutputStream(jpegName);   BufferedOutputStream bos = new BufferedOutputStream(fout);   //   Bitmap newBM = bm.createScaledBitmap(bm, 600, 800, false);   bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);   bos.flush();   bos.close();  } catch (IOException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } } 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) {   // TODO Auto-generated method stub   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));    v.setBackgroundDrawable(v.getBackground());   }   return false;  } } @Override public void onBackPressed() {  // TODO Auto-generated method stub  super.onBackPressed();  StandardCamera.this.finish(); } class UpdateThread implements Runnable{  public void run() {   // TODO Auto-generated method stub   while(flag){    if(myCamera!=null && isPreview)     myCamera.autoFocus(myAutoFocusCallback); //鑷姩鑱氱劍    myCamera.setOneShotPreviewCallback(StandardCamera.this); //onPreviewFrame閲屼細鎺ュ彈鍒版暟鎹�?   myCamera.stopPreview(); //鍋滄棰勮    flag = false;    try {     Thread.sleep(1000);    } catch (InterruptedException e) {     // TODO Auto-generated catch block     e.printStackTrace();    }   }  } } public void onPreviewFrame(byte[] data, Camera camera) {  // TODO Auto-generated method stub }}

需要注意的有以下幾點:

1,為了讓程式適用不同的手機,onCreate函式裡用如下程式碼初始化SurfaceView的大小,避免以前寫死的方法:

 public void initView(){
  mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);
  WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
  Display display = wm.getDefaultDisplay();
        LayoutParams lpSV = mPreviewSV.getLayoutParams();
        lpSV.width = display.getWidth();
        lpSV.height = (int) ((float)display.getHeight()*0.75);
        mPreviewSV.setLayoutParams(lpSV);

   mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
  LayoutParams lp = mPhotoImgBtn.getLayoutParams();
  lp.width = 240;
  lp.height = 240;  
  mPhotoImgBtn.setLayoutParams(lp);    
  mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
  mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
 }

2,關於ZoomBar的程式碼片段很簡短,如下:


   mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
  LayoutParams lp = mPhotoImgBtn.getLayoutParams();
  lp.width = 240;
  lp.height = 240;  
  mPhotoImgBtn.setLayoutParams(lp);    
  mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
  mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
 }
  //新增ZoomBar
  mZoomBar = (SeekBar)findViewById(R.id.seekbar_zoom);
  mZoomBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
   
   public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub
    
   }
   
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    // TODO Auto-generated method stub
    Parameters p = myCamera.getParameters();
    p.setZoom(progress);
    myCamera.setParameters(p);
   }
  });

3,在initCamera函式裡,查詢camera支援的聚焦模式,如果帶連續視訊聚焦則使用連續視訊聚焦,否則使用自動聚焦:


   mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
  LayoutParams lp = mPhotoImgBtn.getLayoutParams();
  lp.width = 240;
  lp.height = 240;  
  mPhotoImgBtn.setLayoutParams(lp);    
  mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
  mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
 }
List<String> focuseMode = (myParam.getSupportedFocusModes());
   for(int i=0; i<focuseMode.size(); i++){
    Log.i(tag, focuseMode.get(i));
    if(focuseMode.get(i).contains("continuous")){
     myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
    }
    else{
     myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
    }
   }

4,同樣在initCamera函式裡,設定ZoomBar的最大值:
//設定mZoomBar的最大值
   mZoomBar.setMax(myParam.getMaxZoom());

後續將寫專文分析Camera4.0的原始碼,並且模仿到自己的程式碼中!