在公司开发过程中,测试时发现有台手机的系统相机拍完照片后按确定键没有反应,回调不了数据给我的app,一开始以为是代码问题,后来看了下,开源中国的app也是用系统相机,也是不行,微信也是用系统相机,没测(估计也是这鸟样),如果在遇到这个问题,我只能呵呵呵了,要么忽略这台手机(这台手机的系统相机有bug,解决这个方法是让这台手机装个好点的相机),要么就是自己写一个相机,app里面调用。
于是,我就开始了自定义相机的研究。。。
android使用自定义相机
http://blog.csdn.net/gf771115/article/details/19438409
http://blog.csdn.net/wwj_748/article/details/8927784
package com.wwj.finger; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.Intent; import android.graphics.PixelFormat; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.os.Bundle; import android.os.Environment; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; /** * Android手指拍照 * * @author wwj * @date 2013/4/29 */ public class MainActivity extends Activity { private View layout; private Camera camera; private Camera.Parameters parameters = null; Bundle bundle = null; // 声明一个Bundle对象,用来存储数据 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 显示界面 setContentView(R.layout.activity_main); layout = this.findViewById(R.id.buttonLayout); SurfaceView surfaceView = (SurfaceView) this .findViewById(R.id.surfaceView); surfaceView.getHolder() .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceView.getHolder().setFixedSize(176, 144); //设置Surface分辨率 surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮 surfaceView.getHolder().addCallback(new SurfaceCallback());//为SurfaceView的句柄添加一个回调函数 } /** * 按钮被点击触发的事件 * * @param v */ public void btnOnclick(View v) { if (camera != null) { switch (v.getId()) { case R.id.takepicture: // 拍照 camera.takePicture(null, null, new MyPictureCallback()); break; } } } /** * 图片被点击触发的时间 * * @param v */ public void imageClick(View v) { if (v.getId() == R.id.scalePic) { if (bundle == null) { Toast.makeText(getApplicationContext(), R.string.takephoto, Toast.LENGTH_SHORT).show(); } else { Intent intent = new Intent(this, ShowPicActivity.class); intent.putExtras(bundle); startActivity(intent); } } } private final class MyPictureCallback implements PictureCallback { @Override public void onPictureTaken(byte[] data, Camera camera) { try { bundle = new Bundle(); bundle.putByteArray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换 saveToSDCard(data); // 保存图片到sd卡中 Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_SHORT).show(); camera.startPreview(); // 拍完照后,重新开始预览 } catch (Exception e) { e.printStackTrace(); } } } /** * 将拍下来的照片存放在SD卡中 * @param data * @throws IOException */ public static void saveToSDCard(byte[] data) throws IOException { Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间 String filename = format.format(date) + ".jpg"; File fileFolder = new File(Environment.getExternalStorageDirectory() + "/finger/"); if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录 fileFolder.mkdir(); } File jpgFile = new File(fileFolder, filename); FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流 outputStream.write(data); // 写入sd卡中 outputStream.close(); // 关闭输出流 } private final class SurfaceCallback implements Callback { // 拍照状态变化时调用该方法 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { parameters = camera.getParameters(); // 获取各项参数 parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式 parameters.setPreviewSize(width, height); // 设置预览大小 parameters.setPreviewFrameRate(5); //设置每秒显示4帧 parameters.setPictureSize(width, height); // 设置保存的图片尺寸 parameters.setJpegQuality(80); // 设置照片质量 } // 开始拍照时调用该方法 @Override public void surfaceCreated(SurfaceHolder holder) { try { camera = Camera.open(); // 打开摄像头 camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象 camera.setDisplayOrientation(getPreviewDegree(MainActivity.this)); camera.startPreview(); // 开始预览 } catch (Exception e) { e.printStackTrace(); } } // 停止拍照时调用该方法 @Override public void surfaceDestroyed(SurfaceHolder holder) { if (camera != null) { camera.release(); // 释放照相机 camera = null; } } } /** * 点击手机屏幕是,显示两个按钮 */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: layout.setVisibility(ViewGroup.VISIBLE); // 设置视图可见 break; } return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮 if (camera != null && event.getRepeatCount() == 0) { // 拍照 //注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后 //,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络 camera.takePicture(null, null, new MyPictureCallback()); } } return super.onKeyDown(keyCode, event); } // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度 public static int getPreviewDegree(Activity activity) { // 获得手机的方向 int rotation = activity.getWindowManager().getDefaultDisplay() .getRotation(); int degree = 0; // 根据手机的方向计算相机预览画面应该选择的角度 switch (rotation) { case Surface.ROTATION_0: degree = 90; break; case Surface.ROTATION_90: degree = 0; break; case Surface.ROTATION_180: degree = 270; break; case Surface.ROTATION_270: degree = 180; break; } return degree; } }
运行后发现
相机无论如何设置setPreviewSize,都是没效果的。。。呵呵呵呵
后来在找了一篇文章:
http://blog.csdn.net/yanzi1225627/article/details/33028041
里面说这些方法已经失效了,要吧相机作为背景全屏,拍完照之后要把图片转账个90度,原因是拍出的照片数据一直都是横线的。。
自定义相机还是要深入才能写出个好的。