当前位置: 代码迷 >> Android >> android camera(二)
  详细解决方案

android camera(二)

热度:41   发布时间:2016-05-01 17:54:09.0
android camera(2)

先说说我的测试机器:nexus s。以下的结果都是通过nexus s上测试通过。

还是先上代码:

package com.TestCamera1;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.List;import android.app.Activity;import android.content.Context;import android.content.pm.ActivityInfo;import android.content.res.Configuration;import android.graphics.Bitmap;import android.graphics.Bitmap.CompressFormat;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.graphics.PixelFormat;import android.hardware.Camera;import android.hardware.Camera.CameraInfo;import android.hardware.Camera.PictureCallback;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.Display;import android.view.KeyEvent;import android.view.Surface;import android.view.SurfaceHolder;import android.view.View;import android.view.SurfaceHolder.Callback;import android.view.View.OnClickListener;import android.view.SurfaceView;import android.view.Window;import android.view.WindowManager;import android.widget.Button;public class TestCamera1Activity extends Activity {    /** Called when the activity is first created. */	private SurfaceHolder surfaceHolder;    private Camera camera;    private int cameraId;    private SurfaceView surfaceView;    private Button btn;    private boolean flag;    private Camera.PreviewCallback previewCallBack;    //////////////////////////////照相实现函数    private PictureCallback jpeg=new PictureCallback(){    	public void onPictureTaken(byte[] data,Camera camera){    		if(data!=null){    			Log.i("take photo","ok!");    			    			Bitmap bm=BitmapFactory.decodeByteArray(data, 0, data.length);    			String picDirStr=Environment.getExternalStorageDirectory()+"/";    			File picDir=new File(picDirStr);    			if(!picDir.exists()){    				picDir.mkdir();    			}    			String picName=picDirStr+System.currentTimeMillis()+".jpg";    			File myCaptureFile=new File(picName);   			    			try{    				BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(myCaptureFile));    				bm.compress(Bitmap.CompressFormat.JPEG, 50, bos);    				bos.flush();    				bos.close();//保存图片    				camera.startPreview();//重新打开预览图,进行下一次的拍照准备,必须等到onPictureCallback函数调用才能调用    				Log.i("pic", "ok!");    			}catch(Exception e){    				Log.i("pic", e.toString());    			}    		}else{    			Log.i("take pic", "faile!");    		}    	}    };    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                          btn=(Button)findViewById(R.id.button1);               surfaceView = (SurfaceView) findViewById(R.id.preview_view);        surfaceHolder = surfaceView.getHolder();               surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        surfaceView.getHolder().addCallback(new SurfaceViewCallback());                btn.setOnClickListener(new OnClickListener(){			@Override			public void onClick(View v) {				// TODO Auto-generated method stub								camera.takePicture(null, null, jpeg);							}        });    }    private final class SurfaceViewCallback implements SurfaceHolder.Callback {    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {        // TODO Auto-generated method stub    	  Camera.Parameters parameters = camera.getParameters();    	         // 选择合适的预览尺寸       	        List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();    	        Camera.Size cameraSize=(Camera.Size)sizeList.get(1);    	        parameters.setPreviewSize(cameraSize.width, cameraSize.height);    	        parameters.setPreviewFrameRate(5);    	        parameters.setPictureFormat(PixelFormat.JPEG);           	        parameters.set("jpeg-quality", 100);    	        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {    	            camera.setDisplayOrientation(90);    	            flag=true;    	            Log.i("por","1");    	           }    	           if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {    	            parameters.set("orientation", "landscape");    	            parameters.set("rotation", 0);    	            flag=false;    	            Log.i("orientation", "1");    	           }    	            	        camera.setParameters(parameters);    	        try {    	            camera.setPreviewDisplay(surfaceHolder);    	        } catch (IOException e) {    	            System.out.println(e.getMessage());    	        }    	        camera.startPreview();    }    public void surfaceCreated(SurfaceHolder arg0) {        // TODO Auto-generated method stub        camera = Camera.open();                  }    public void surfaceDestroyed(SurfaceHolder arg0) {        // TODO Auto-generated method stub        if (camera != null) {            camera.stopPreview();        }        camera.release();        camera = null;    }    }   }
   这次只要是增加了一个函数camera.takePicture(null, null, jpeg);和一个回调函数PictureCallback jpeg=new PictureCallback(){ public void onPictureTaken(byte[] data,Camera camera){}。当照相进行预览就可以进行拍照,我的拍照时机就是button控件被按下,调用takePicture();当开始拍照时,会依次调用shutter的onShutter()方法,raw的方法,jpeg的方法.三个参数的作用是shutter--拍照瞬间调用,raw--获得没有压缩过的图片数据,jpeg---返回jpeg的图片数据当你不需要对照片进行处理,可以直接用null代替.

注意,当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览。
拍完照之后就是保存照片了,图片数据就是保存在参数data数组里面,这个比较简单就不详诉了!
   


拍个照片看上去很简单,但是其中却存在各种问题。

1·预览图旋转问题。

当旋转手机时,SurfaceView 预览图像反转或旋转90度,这个是因为照相机是默认横屏,当你竖屏的时候照相机的镜头并没有对应翻转过来。
解决方法1:
解决:在拍照过程中应该设置为将内容始终横屏显示,这样,在拍照程序中SurfaceView的内容就不会旋转90度或180度了。
在AndroidManifest.xml中设置android:screenOrientation="landscape"。代码如下:
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
还有在onCreate函数加入 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  
解决方法2:
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {   camera.setDisplayOrientation(90);//将镜头旋转90度。   flag=true;   Log.i("por","1");}if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {    parameters.set("orientation", "landscape");    parameters.set("rotation", 0);    flag=false;    Log.i("orientation", "1");//由于镜头默认是横屏的,所以这里可以为空
}
为什么我不采取第一种方法呢?因为相机默认是翻转了90度,即是水平放置 等价于DefaultDisplayRotation的状态永远是1,即是ROTATION_90(加入这段    int rotation = TestCamera1Activity.this.getWindowManager().getDefaultDisplay().getRotation();可以看到  )。不管你手机怎么翻转,surfaceChanged只会响应一次,因为强制了横屏了,surfaceview当然不会改变了。因为被强制了横屏,觉得有点受限制不爽。所以选择第二种。其实我们只需要获得镜头的方向,然后旋转对应的角度,那么预览图就正常了。由google sdk上可以看到有这四种方向ORIENTATION_UNDEFINED   ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT , ORIENTATION_SQUARE。我这里只对两种方向进行判断。     

2.预览图像被拉伸变形问题

是因为preview的size与surfaceview的size比例不一样,同时你还要注意自己手机支持的preview的大小,上一篇已经说了不是任意的size都接受的。网上有各种办法,但是不知道能不能用。我没有自己试验就不多说了,因为我的demo的surfaceview比较小,看不出拉伸的。我提出的解决方案是:根据你设定的preview修改surfaceview的大小。


3.照片旋转问题

如果是竖屏找出来的照片,虽然预览是没有旋转,但是最后成像的时候还是会旋转的,其中原因网上有概述http://jefry.iteye.com/blog/1337492。那么我的解决方法是用Matrix类对照片进行旋转,重新生成新的一幅bitmap,这里就不给出代码,可以在网上搜“android 图片旋转”。我这里出了点小问题,就是OOM问题,在createBitmap的时候内存溢出了,我猜测是因为图片太大了。至于解决方案留给大家思考了

最后回应第一篇最后留下的猜想,那就是会导致图片的拉伸,我猜错了~


附上android camera(2)的demo http://download.csdn.net/detail/bin381/4442510
下集预告:自动对焦

  相关解决方案