One, foreword

Recently, my former colleague and gay friend Dai Lao asked me for my old demo that could take photos without any delay. He looked through my demo project folder and found it was a bit real

In addition, programmers do not like to see the features of the code they wrote before, so they decided to encapsulate this function, for the convenience of others, of course, but also for their own convenience

The origin of this function is still the card swiping attendance machine we made before. When checking attendance, we need to take attendance pictures, so we need to take photos

At first, I just used the conventional Camera takePicture method to get photos, but it would appear in the actual application and the speed of taking photos would be slow

At that time I also went to the scene to see the usage, director complained that the film is slow with me and show me for a moment, is indeed a caton, of course, it is easy to understand, I reluctantly explained to her that you don’t use mobile phones will also pause, need to focus on mobile phones, this is so

The person in charge told me that such and such attendance machine took pictures without stopping ah, very fast, my first reaction is that it should be a Windows machine

It turned out to be an Android machine, so I was lost in thought

I don’t know about any of us, but it was a pretty good idea to copy it, and that’s where we started exploring android cameras


As I wrote in the title, in order to achieve my stuck shooting, I use the SurfaceView+Camera mode, through the Camera preview to the SurfaceView, and then through the Camera setPreviewCallback function to call the current frame of the picture, there will be no stuck

Second, the effect drawing

After clicking Take a picture, you can get the BitMap object of the current frame and save it to the local path

Three, function realization

(a) how to use

Let’s start by looking at the layout file a SurfaceView for displaying the camera’s image in real time and a text field for ImageView for displaying and saving the image

<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context=".MainActivity"> <SurfaceView android:id="@+id/surfaceview" android:layout_width="320dp" android:layout_height="240dp" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" Android :layout_height="wrap_content"> <Button android:id="@+id/btn_take_photo" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_pic_dir" Android :text=" " android:textSize="14sp" android:textColor="#000000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:background="#000000" android:id="@+id/img_pic" android:layout_width="160dp" android:layout_height="120dp" /> </LinearLayout> </LinearLayout>Copy the code

Using the encapsulated CameraTakeManager, you pass in three parameters: the Activity object, the surfaceView control object, and a custom callback

The two functions onSuccess of the callback return the image and BitMap object to save

OnFail Returns failure information

manager = new CameraTakeManager(this, previewView, new CameraTakeListener() { @Override public void onSuccess(File bitmapFile, Bitmap mBitmap) { imgPic.setImageBitmap(mBitmap); Tvpicdir.settext (" image path: "+ bitmapfile.getPath ()); } @Override public void onFail(String error) { LogUtil.e(error); }});Copy the code

By clicking the button used to get the photo, enter the CameraTakeManager callback

@OnClick({R.id.btn_take_photo}) public void onClick(View view) { switch (view.getId()) { case R.id.btn_take_photo: /** click takePhoto */ manager.takephoto (); break; }}Copy the code

(2) the code of implementation

A custom SurfaceViewCallback class implements the SurfaceHolder.callback interface

Start by opening a preview of the camera in the surfaceChanged callback

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (previewing) {
            mCamera.stopPreview();
            previewing = false;
        }

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
            previewing = true;
            setCameraDisplayOrientation(activity, mCurrentCamIndex, mCamera);
        } catch (Exception e) {
        }
    }
Copy the code

The Camera setPreviewCallback function is implemented in the surfaceCreated callback to get the callback for each frame of the Camera

CanTake variable is used to determine whether the current frame needs to be photographed. When it is true, the image of the current frame is taken, a bitmap is generated, and a picture file is compressed and saved locally, and the data is called back to the interface

Realize the camera function

@Override public void surfaceCreated(SurfaceHolder holder) { if (! hasSurface) { hasSurface = true; mCamera = openFrontFacingCameraGingerbread(); If (mCamera == null){listener.onFail(" No camera available "); return; } mCamera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] bytes, Camera camera) { if (canTake) { getSurfacePic(bytes, camera); canTake = false; }}}); }}Copy the code

Four, conclusion

Here even if completed, skills are not fine, I hope you give more suggestions, I will be the first time to improve, remember to give me praise oh

At the end of the post github source address github.com/Giftedcat/C…