先说说我的测试机器: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
下集预告:自动对焦