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
下集预告:自动对焦

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值