2013新春奉送 Android摄像头开发完美demo--- 循环聚焦 缩放大小 旋转picture 查询支持的pict

               

补充:我已在对此代码进行了全面的升级,升级后代码结构更加利于维护扩展,全面适配所有手机,参见博文。此文中的资源也不要再下载了,请下载升级后的代码,如有问题请留言反馈,谢谢。---------------------------2014-6-23】    


【后注:】下载代码的注意,我的手机是4.3寸的屏,华为U9200.如果不能运行的请修改参数。看本篇的第四条。

 

    除夕之夜,程序员还在编代码。http://blog.csdn.net/yanzi1225627/article/details/7926994这是我几个月前写的代码,现在看来真是垃圾不堪阿。变量名字不规范,整个架构拉杂,几乎没有注释,程序不稳键,没有安全退出,导致摄像头下次不可用。

     这个代码几乎涉及到了摄像头开发的所有方面,(除了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

<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_width="wrap_content"        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:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="@drawable/photo_img_btn"        android:layout_gravity="center" /></LinearLayout>
第三部分:RectPhoto.java主程序

 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.Callbackprivate static final String tag="yan"private boolean isPreview = falseprivate SurfaceView mPreviewSV = null; //预览SurfaceView private SurfaceHolder mySurfaceHolder = nullprivate ImageButton mPhotoImgBtn = nullprivate Camera myCamera = nullprivate Bitmap mBitmap = nullprivate 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启动时/初次实例化,预览界面被创建时,该方法被调用。 {  // 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: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) {   // TODO Auto-generated method stub   Log.i(tag, "myRawCallback:onPictureTaken...");  } }; PictureCallback myJpegCallback = new PictureCallback()  //对jpeg图像数据的回调,最重要的一个回调 {  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是字节数据,将其解析成位图    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);   }   //再次进入预览   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);    }  } } /*给定一个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);  try {   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:存储完毕!");  } catch (IOException e) {   // TODO Auto-generated catch block   Log.i(tag, "saveJpeg:存储失败!");   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();  RectPhoto.this.finish(); }}

源码下载链接: http://download.csdn.net/detail/yanzi1225627/5060323

 

欢迎android爱好者加群248217350,备注:yanzi

注:代码不能正常运行的请看上面第4条,修改相关参数。
----------------------------------------------------------------------------------------本文系原创,转载请注明作者:yanzi1225627





           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值