Camera 拍照

    xiaoxiao2025-04-16  4

    1、背景

    同样这篇文章是为了练习代码的抽取能力,其实Camera的拍照后我们会获取到原始照片的数据,这些数据我们可以进行处理;比如加个滤镜,美白等等;这就是我们的美白相机了,但对于图片的处理,我们最好在底层处理;然后把处理的图片数据再转换成图片,最后展示给用户,美白相机的大体流程就是这样的,不过今天主要练习代码的抽取能力;虽然上次已经写过了,只有经过反复的训练,我们才能对怎样抽取代码,并进行封装得心用手;

    2、方法(来自疯狂Androud讲义)

    Android应用提供了Camera来控制拍照,使用Camera进行拍照比较简单,按如下步骤进行即可。 1:调用Camera的open()方法打开相机。该方法默认打开后置摄像头。如果需要打开指定摄像头,可以为该方法传入声响头ID. 2:调用Camera的getParameters()方法获取拍照参数,该方法返回一个Camera.Parameters对象。 3:调用Camera.Parameters对象方法设置拍照参数; 4:调用Camera的startPreview()方法开始预览取景,在预览取景之前调用Camera的setPreviewDisplay(SurfaceViewHolder holder)方法设置使用哪个SurfaceView来显示取景图片。 5:调用Camera的takePicture()方法进行拍照。 6:结束程序时,调用Camera的stopPreview()结束取景预览,并调用release()方法释放资源;

    3、实例

    该实例通过预览,当我们点击拍照后,会弹出一个对话框,让用户输入图片的名字;

    1、MainActivity布局:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center_horizontal" android:layout_marginBottom="8dp" > <Button android:id="@+id/btn_capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/normal_capture" /> </LinearLayout> </RelativeLayout>

    2、对话框布局:

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="5dp" > <TextView android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="文件名:" android:textSize="20sp" /> <EditText android:id="@+id/et_filename" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <ImageView android:id="@+id/iv_picture" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" /> </LinearLayout>

    3、MainActivity代码:

    public class MyActivity01 extends Activity implements SurfaceHolder.Callback,OnClickListener{ private SurfaceView surfaceView; private Button ib_capture; private Camera mCamera; private int screenWidth; private int screenHeight; private boolean isPreview = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); } private void initData() { DisplayMetrics outMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(outMetrics);; screenWidth = outMetrics.widthPixels; screenHeight = outMetrics.heightPixels; } private void initView() { surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView); surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceView.getHolder().addCallback(this); ib_capture = (Button) this.findViewById(R.id.btn_capture); ib_capture.setOnClickListener(this); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { initCamera(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if(null != mCamera){ if(isPreview) mCamera.stopPreview(); mCamera.release(); mCamera = null; } } @Override public void onClick(View v) { if(null != mCamera){ mCamera.autoFocus(new MyAutoFocusCallback()); } } private void initCamera() { if(!isPreview){ mCamera = Camera.open(); mCamera.setDisplayOrientation(90); } if(null != mCamera && !isPreview){ try { //设置surfaceView的取景画面 mCamera.setPreviewDisplay(surfaceView.getHolder()); Parameters mParameters = mCamera.getParameters(); //设置预览照片的大小 mParameters.setPreviewSize(screenWidth, screenHeight); //设置预览照片时每秒显示多少帧的最大值、最小值 mParameters.setPreviewFpsRange(4, 10); //设置图片格式JPEG mParameters.setPictureFormat(ImageFormat.JPEG); //设置照片的质量 mParameters.setJpegQuality(88); //设置照片的大小 mParameters.setPictureSize(screenWidth, screenHeight); //开始预览 mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } isPreview = true; } @Override protected void onDestroy() { super.onDestroy(); if(null != mCamera){ if(isPreview) mCamera.stopPreview(); mCamera.release(); mCamera = null; } } private final class MyAutoFocusCallback implements AutoFocusCallback{ @Override public void onAutoFocus(boolean success, Camera camera) { if(success){ camera.takePicture(new ShutterCallback() { @Override public void onShutter() { //按下快门瞬间执行此处代码 } }, new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { //此处代码可以决定是否需要保存原始照片信息 } }, new MyPictureCallback()); } } } private final class MyPictureCallback implements PictureCallback{ //通过该方法获取JPEG照片,通过对话框的形式提示给用户,并让用户给起名,然后保存; @Override public void onPictureTaken(byte[] data, Camera camera) { final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); View view = View.inflate(MainActivity.this, R.layout.dialog_view, null); ImageView mImageView = (ImageView) view.findViewById(R.id.iv_picture); final EditText et_filename = (EditText) view.findViewById(R.id.et_filename); mImageView.setImageBitmap(bitmap); new AlertDialog.Builder(MainActivity.this) .setView(view) .setPositiveButton("保存", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String fileName = et_filename.getText().toString().trim(); if(null != fileName || !"".equals(fileName)){ try { File file = new File(Environment.getExternalStorageDirectory(),fileName+".jpeg"); OutputStream outStream = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, outStream ); outStream.close(); } catch (Exception e) { e.printStackTrace(); } }else{ Toast.makeText(MainActivity.this, "文件名为空,保存失败!!!", Toast.LENGTH_LONG).show(); } } }) .setNegativeButton("取消", null) .show(); mCamera.stopPreview(); mCamera.startPreview(); isPreview = true; } } }

    我们通过initView()、initData()等方法来把我们的代码逻辑清晰, 当大量的代码都放在MainActivity中时,依旧效果不是很好。 我们通过分析可以发现在MainActivity中Came的设置占据了大量代码,比如:Camera的initCamera()以及Camera拍照时设置的回调方法;所以我们可以把这些方法抽取出来,放到CameraEngine中:

    4、CameraEngine类:

    public class CameraEngine { private MainActivity context; private Camera mCamera; private int screenWidth; private int screenHeight; private boolean isPreview = false; public CameraEngine(Context context){ this.context = (MainActivity) context; initData(); } public void initData(){ DisplayMetrics outMetrics = new DisplayMetrics(); context.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);; screenWidth = outMetrics.widthPixels; screenHeight = outMetrics.heightPixels; } public void onDestroy(){ if(null != mCamera){ if(isPreview) mCamera.stopPreview(); mCamera.release(); mCamera = null; } } public void initCamera(SurfaceView surfaceView){ if(!isPreview){ mCamera = Camera.open(); mCamera.setDisplayOrientation(90); } if(null != mCamera && !isPreview){ try { //设置surfaceView的取景画面 mCamera.setPreviewDisplay(surfaceView.getHolder()); Parameters mParameters = mCamera.getParameters(); //设置预览照片的大小 mParameters.setPreviewSize(screenWidth, screenHeight); //设置预览照片时每秒显示多少帧的最大值、最小值 mParameters.setPreviewFpsRange(4, 10); //设置图片格式JPEG mParameters.setPictureFormat(ImageFormat.JPEG); //设置照片的质量 mParameters.setJpegQuality(88); //设置照片的大小 mParameters.setPictureSize(screenWidth, screenHeight); //开始预览 mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } isPreview = true; } public void autoFocus(){ if(null != mCamera){ mCamera.autoFocus(new MyAutoFocusCallback()); } } private final class MyAutoFocusCallback implements AutoFocusCallback{ @Override public void onAutoFocus(boolean success, Camera camera) { if(success){ camera.takePicture(new ShutterCallback() { @Override public void onShutter() { //按下快门瞬间执行此处代码 } }, new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { //此处代码可以决定是否需要保存原始照片信息 } }, new MyPictureCallback()); } } } private final class MyPictureCallback implements PictureCallback{ //通过该方法获取JPEG照片,通过对话框的形式提示给用户,并让用户给起名,然后保存; @Override public void onPictureTaken(byte[] data, Camera camera) { final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); View view = View.inflate(context, R.layout.dialog_view, null); ImageView mImageView = (ImageView) view.findViewById(R.id.iv_picture); final EditText et_filename = (EditText) view.findViewById(R.id.et_filename); mImageView.setImageBitmap(bitmap); new AlertDialog.Builder(context) .setView(view) .setPositiveButton("保存", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String fileName = et_filename.getText().toString().trim(); if(null != fileName || !"".equals(fileName)){ try { File file = new File(Environment.getExternalStorageDirectory(),fileName+".jpeg"); OutputStream outStream = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, outStream ); outStream.close(); } catch (Exception e) { e.printStackTrace(); } }else{ Toast.makeText(context, "文件名为空,保存失败!!!", Toast.LENGTH_LONG).show(); } } }) .setNegativeButton("取消", null) .show(); mCamera.stopPreview(); mCamera.startPreview(); isPreview = true; } } }

    5、抽取之后的MainActivity代码:

    public class MainActivity extends Activity implements SurfaceHolder.Callback,OnClickListener{ private SurfaceView surfaceView; private Button ib_capture; private CameraEngine cameraEngine; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cameraEngine = new CameraEngine(this); initView(); } private void initView() { surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView); surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceView.getHolder().addCallback(this); ib_capture = (Button) this.findViewById(R.id.btn_capture); ib_capture.setOnClickListener(this); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { cameraEngine.initCamera(surfaceView); } @Override public void surfaceDestroyed(SurfaceHolder holder) { cameraEngine.onDestroy(); } @Override public void onClick(View v) { cameraEngine.autoFocus(); } @Override protected void onDestroy() { super.onDestroy(); cameraEngine.onDestroy(); } }

    是不是很简单,MainActivity还可以更进一步的抽取;剩下的就交给你们了;

    转载请注明原文地址: https://ju.6miu.com/read-1298127.html
    最新回复(0)