Android|Android Camera开发实现可复用的相机组件

本文实例为大家分享了Android Camera实现可复用相机组件的具体代码,供大家参考,具体内容如下
若自己的应用需要使用camera,有两种解决方案。
1. 使用Intent调用自带的Camera程序
2. 使用Camera API在程序中构造自己的Camera。
本文主要讲解第二种。
构造一个相机APP,通常需要六个步骤
1. 声明Manifest的相机权限
2. 创建一个相机预览类(继承SurfaceView)
3. 创建一个类实现相机拍照之后的回调函数
本文将一步步带你实现上述三个步骤。
1. 声明Manifest的相机权限。
应为我们需要写文件与调用相机,所以在你的manifest文件中加上。


2. 创建一个相机预览类
由于相机的预览是使用的SurfaceView,所以这里我们创建一个SurfaceView的子类。
为了让这个View所见即所得,我们将其设置为4/3的比例。重写它的onMeasure方法
代码如下:
package com.example.cameratutorial; import android.content.Context; import android.util.Log; import android.view.SurfaceView; /** * @author CTGU小龙同学 2014-6-21 */public class CameraSurfaceView extends SurfaceView {private static final String TAG = "CameraSurfaceView"; // 用四比三的比例public static double RATIO = 3.0 / 4.0; /*** @param context*/public CameraSurfaceView(Context context) {super(context); } @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); Log.d("Measured", "before width" + width + "height" + height); boolean isWidthLonger; int longSide; int shortSide; // 以短边为准确定一下长边if (width < height) {height = (int) (width / RATIO); isWidthLonger = false; } else {width = (int) (height / RATIO); isWidthLonger = true; } Log.d("Measured", "after width" + width + "height" + height); setMeasuredDimension(width, height); } }

【Android|Android Camera开发实现可复用的相机组件】3. 现在我们使用一个实现了SurfaceHolder.Callback, Camera.PictureCallback 的Fragment来把我们需要的组件都封装起来。
代码如下:
package com.example.cameratutorial; import java.io.*; import java.util.*; import android.app.Activity; import android.app.Fragment; import android.graphics.*; import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.*; import android.widget.RelativeLayout; import android.widget.Toast; /** * @author CTGU小龙同学 2014-6-21 */public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback {private Camera mCamera; // CameraPreview的holderprivate SurfaceHolder mSurfaceHolder; private CameraSurfaceView preview; private int mFrontCameraId = -1; private int mBackCameraId = -1; @Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { preview = new CameraSurfaceView(getActivity()); preview.getHolder().addCallback(this); RelativeLayout layout = new RelativeLayout(getActivity()); layout.addView(preview); return layout; } @Overridepublic void onAttach(Activity activity) {super.onAttach(activity); findAvailableCameras(); } @Overridepublic void onResume() { super.onResume(); Log.d("camera", "mFrontCameraId" + mFrontCameraId); Log.d("camera", "mbackCameraId" + mBackCameraId); if (mBackCameraId != -1) { mCamera = Camera.open(mBackCameraId); } else {Toast.makeText(getActivity(), "fialed to open camera", Toast.LENGTH_SHORT).show(); } } @Overridepublic void onPause() {super.onPause(); mCamera.stopPreview(); mCamera.release(); } /*** 获得可用的相机,并设置前后摄像机的ID*/private void findAvailableCameras() { Camera.CameraInfo info = new CameraInfo(); int numCamera = Camera.getNumberOfCameras(); for (int i = 0; i < numCamera; i++) {Camera.getCameraInfo(i, info); // 找到了前置摄像头if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {mFrontCameraId = info.facing; }// 招到了后置摄像头if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {mBackCameraId = info.facing; } } } /*** 当相机拍照时会回调该方法*/@Overridepublic void onPictureTaken(byte[] data, Camera camera) {final Bitmap bitmap; final String path; try {// /storage/emulated/0/Pictures/XXX.jpg path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/" + new Date().toLocaleString() + ".jpg"; Log.d("Path", path); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); camera.stopPreview(); final int displayOrientation = getCorrectOrientation(); new Thread(new Runnable() { @Overridepublic void run() {FileOutputStream fos; Matrix matrix = new Matrix(); matrix.postRotate(displayOrientation); Bitmap rotaBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); try {fos = new FileOutputStream(path); rotaBitmap.compress(CompressFormat.JPEG, 100, fos); fos.close(); } catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace(); } }}).start(); } catch (Exception e) { }camera.startPreview(); } /*** 让预览跟照片符合正确的方向。
* 因为预览默认是横向的。如果是一个竖向的应用,就需要把预览转90度
* 比如横着时1280*960的尺寸时,1280是宽.
* 竖着的时候1280就是高了
* 这段代码来自官方API。意思就是让拍出照片的方向和预览方向正确的符合设备当前的方向(有可能是竖向的也可能使横向的)* */private int getCorrectOrientation() {android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mBackCameraId, info); int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) {case Surface.ROTATION_0:degrees = 0; break; case Surface.ROTATION_90:degrees = 90; break; case Surface.ROTATION_180:degrees = 180; break; case Surface.ROTATION_270:degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror} else { // back-facingresult = (info.orientation - degrees + 360) % 360; }Log.d("orientationResult", result + ""); return result; } public void takePicture() {mCamera.takePicture(null, null, this); } @Overridepublic void surfaceCreated(SurfaceHolder holder) {mSurfaceHolder = holder; startPreView(); } private void startPreView() {try {mCamera.setPreviewDisplay(mSurfaceHolder); setPreviewSize(); setDisplayOrientation(); mCamera.startPreview(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace(); } } private void setDisplayOrientation() {int displayOrientation = getCorrectOrientation(); mCamera.setDisplayOrientation(displayOrientation); } /*** 我们用4比3的比例设置预览图片*/private void setPreviewSize() {Camera.Parameters params = mCamera.getParameters(); List sizes = params.getSupportedPreviewSizes(); for (Size size : sizes) {Log.d("previewSize", "width:" + size.width + " height " + size.height); }for (Size size : sizes) {if (size.width / 4 == size.height / 3) {params.setPreviewSize(size.width, size.height); Log.d("previewSize", "SET width:" + size.width + " height " + size.height); break; }} // params一定要记得写回CameramCamera.setParameters(params); } private void setPictureSize() {Camera.Parameters params = mCamera.getParameters(); List sizes = params.getSupportedPictureSizes(); for (Size size : sizes) {Log.d("picSize", "width:" + size.width + " height " + size.height); }for (Size size : sizes) {if (size.width / 4 == size.height / 3) {params.setPictureSize(size.width, size.height); break; }} } @Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mCamera.release(); } }

4. 程序的Mainactivity以及相应的布局文件
package com.example.cameratutorial; import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final CameraFragment fragment=(CameraFragment) getFragmentManager().findFragmentById(R.id.camera_fragment); Button button=(Button) findViewById(R.id.TakePic); button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {fragment.takePicture(); }}); } }

布局文件

这样,我们一个可以复用的相机组件就完成了
下一篇文章应该是关于如何实现触摸对焦测光的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    推荐阅读