Camera Development (focusing, portrait taking, photo storage, continuous photo taking, etc)

Source: Internet
Author: User

Recently, the project used the camera function, so I thought about Encapsulating some universal camera calls, the materials obtained from Baidu and Google really prove the truth of "a huge copy of the world's articles", and most of their photo taking functions are flawed, such as focusing, duplicate photos, photo storage, and horizontal/vertical screen conversion. A lot of problems, and the scalability and reusability of the program are not flattering, the layout level is chaotic.

Finally, I had no choice but to open the camera Camera class of the API documentation, start from the basics, and then make improvements on my own. Here I also tell you the truth that the API documentation is the starting point for learning, because it will tell you the principle and reason of the entire implementation, you can have an overall understanding of the entire framework. After reading the API documentation, you can get twice the result with half the effort, the following is the formal implementation.

1. Implementation Process

This figure is organized from the API documentation (preferably in English). From this figure, we can see that there are six steps, the difficulty of which is to create a camera preview class.


Ii. Permission statement

If you don't want to talk about this, add the permission declaration code. If you don't understand it, check it online.

        <uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-feature android:name="android.hardware.camera.autofocus" /><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

3. Check the camera and obtain the camera instance

Create a cameracheck class. There are two main methods. The Code is as follows:

Public class cameracheck {public static Boolean checkcamera (context mcontext) {If (mcontext. getpackagemanager (). hassystemfeature (packagemanager. feature_camera) {return true;} else {toast. maketext (mcontext, "The camera does not exist! ", Toast. length_short ). show (); Return false ;}}/** a safe way to get an instance of the camera object. */public static camera getcamerainstance (context mcontext) {Camera c = NULL; If (checkcamera (mcontext) {try {c = camera. open () ;}catch (exception e) {c = NULL ;}} return C; // returns NULL if camera is unavailable }}

The first method is used to check whether the camera exists. This method is from the API documentation.

Mcontext. getpackagemanager (). hassystemfeature (packagemanager.Feature_camera)

Hassystemfeature (string name) method returns whether the device supports the name function;

The getcamerainstance method is used to return the camera instance. by calling this method, mcontext can obtain the camera resource. Only after obtaining the camera resource can the camera be operated.

 

4. Create a camera preview class (important)

We need to preview the scene before taking a picture. Here we need to use the surfaceview control. For the surfaceview control, let's take a brief look (don't worry, sharpen the knife without mistake ).

Surfaceview is a subclass of view, so it has all the methods and attributes of view, which we can see from the name above, such as the rendering method, size and other attributes; it has one more surface than view. surface is a class used to draw, while surfaceview can control the size and position of surface painting;

Some may ask, why do we need to draw such a class? Isn't there an ondraw () method? Compared with the ondraw () method, it has many advantages:

(1) When the UI thread is updated frequently, the encapsulated surface can be used for frequent updates, because the surface can be used to draw the UI interface using the background thread, while the ondraw () it is difficult to do this by using other plotting methods (unless you call handler frequently to update the main interface, this is a lot of trouble !);

(2) surfaceview can be used to draw 2D or 3D images, draw some dynamic curves, and so on. It will display much faster than normal, because it is drawn through hardware acceleration.

(3) It can be used to draw images using hardware data.

Therefore, we can know from the above points that it is taken for granted to accept the camera preview. So how does it work? To create a surfaceview inheritance class, you generally need to implement the following methods:

(1) surfacecreated (surfaceholderholder): called when this class is created. Initialization is generally required here, And surfacehodler is used to set the surface size and position;

(2) surfacechanged (surfaceholderholder, int format, int width, int height) is called when the surface size is changed. drawing is implemented here;

(3) surfacedestroyed (surfaceholderholder) is called when the surface is destroyed. Resources are usually released here;

(4) Implement the surfacehodler. Callback callback method and automatically call the class itself after surfaceview is created;

Before implementation, Let's first look at our needs. The features we want to implement: preview, take photos, auto focus, touch focus, continuous photos, and photo storage. Next we will create a surfaceview class camerapreview, which inherits surfaceview and implements the surfaceholder. Callback interface.

Therefore, we need to create a camer instance in the surfacecreated method. This instance can be called in this class. The implementation code is as follows:

/*** Automatically call this method during creation */@ overridepublic void surfacecreated (surfaceholder holder) {If (mcamera = NULL) {mcamera = cameracheck. getcamerainstance (mcontext);} Try {If (mcamera! = NULL) {mcamera. setpreviewdisplay (holder) ;}} catch (ioexception e) {If (null! = Mcamera) {mcamera. Release (); mcamera = NULL; ispreview = false;} e. printstacktrace ();}}

This code is mcamera. setpreviewdisplay (holder) indicates creating a preview Hodler. In surfacechanged, The startpreview () method is called to draw the preview window. The Code is as follows:

/*** Automatically called when the surface size changes */@ overridepublic void surfacechanged (surfaceholder holder, int format, int width, int height) {If (mholder. getsurface () = NULL) {return;} Try {setcameraparms (); mcamera. setpreviewdisplay (holder); mcamera. startpreview (); reautofocus ();} catch (exception e) {log. D (TAG, "error starting camera preview:" + E. getmessage ());}}

Two of the key methods are not implemented. setcameraparms (), reautofocus (), and setcameraparms () are used to set parameters for preview images, the key is the size of the preview image and the size of the saved image. The reason why many online apps make the photos very small is that they have not set the Photo size, the size of the photo depends on the size supported by the mobile phone. Reautofocus () is an automatic focus method, and the function of dynamically obtaining reautofocus () is an implementation of automatic focus;

Let's first take a look at the implementation of the setcameraparms () method:

private void setCameraParms(){Camera.Parameters myParam = mCamera.getParameters();List<Camera.Size> mSupportedsizeList =myParam.getSupportedPictureSizes();if(mSupportedsizeList.size() > 1) {Iterator<Camera.Size> itos = mSupportedsizeList.iterator();while (itos.hasNext()){Camera.Size curSize = itos.next();int curSupporSize=curSize.width * curSize.height;int fixPictrueSize= setFixPictureWidth  * setFixPictureHeight;if( curSupporSize>fixPictrueSize && curSupporSize <= maxPictureSize) {setFixPictureWidth  = curSize.width;setFixPictureHeight = curSize.height;}}}myParam.setJpegQuality(100);mCamera.setParameters(myParam);if (myParam.getMaxNumDetectedFaces() > 0){       mCamera.startFaceDetection();}}

Use myparam. getsupportedpicturesizes (); to obtain the enumeration of all sizes supported by the mobile phone, and set the maximum fixed size. The maximum value is maxpicturesize = 5000000.

Reautofocus () is implemented as follows:

<span style="white-space:pre"></span>/** * Call the camera to Auto Focus */public void reAutoFocus() {if (isSupportAutoFocus) {mCamera.autoFocus(new AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {}});}}

Use the callback function autofocus for automatic focus

5. Take a photo

One difficulty of the photo taking method is the conversion and storage of portrait and portrait screen photos. Most of the information on the Internet is the default portrait screen photos. Once the portrait screen is changed, the preview will fail, there are also problems with the stored photos. To solve this problem, we need to monitor the changes in the direction sensor at all times to get the current rotation angle, you can obtain the current angle by calling the orientationeventlistener system listening class. The custom myorientationdetector code is as follows:

/*** Listener for direction change * @ author ZW. yan **/public class myorientationdetector extends orientationeventlistener {int orientation; Public myorientationdetector (context) {super (context) ;}@ override public void onorientationchanged (INT orientation) {log. I ("myorientationdetector", "onorientationchanged:" + orientation); this. orientation = orientation; log. D ("myorientationdetector", "the current sensor direction is" + orientation);} public int getorientation () {return orientation ;}}

In the preview class, we define the camera method takephone (). The Code is as follows:

/*** Adjust the orientation of the photo and set the orientation of the photo */private void takephoto () {cameraorientation = new myorientationdetector (mcontext); If (mcamera! = NULL) {int orientation = cameraorientation. getorientation (); camera. parameters cameraparameter = mcamera. getparameters (); cameraparameter. setrotation (90); cameraparameter. set ("rotation", 90); If (orientation >=45) & (orientation <135) {cameraparameter. setrotation (180); cameraparameter. set ("rotation", 180);} If (orientation >=135) & (orientation <225) {cameraparameter. setrotation (270); cameraparameter. set ("rotation", 270);} If (orientation >=225) & (orientation <315) {cameraparameter. setrotation (0); cameraparameter. set ("rotation", 0);} mcamera. setparameters (cameraparameter); mcamera. takepicture (shuttercallback, picturecallback, mpicture );}}

The image rotation angle is automatically adjusted within the angle range. The specific rotation method is code, so that the stored image can be displayed normally.

6. Save Images

When taking a photo, you need to save the image, but it does not affect the next image taking. Therefore, we need to adopt the asynchronous thread method, and we can use the asynctask class, call the following code when taking the photo:

Public class savepicturetask extends asynctask <byte [], String, string >{@ suppresslint ("simpledateformat") @ overrideprotected string doinbackground (byte []... params) {file picturefile = fileutil. getoutputmediafile (media_type_image, mcontext); If (picturefile = NULL) {toast. maketext (mcontext, "Please insert a memory card! ", Toast. length_short ). show (); return NULL;} Try {fileoutputstream Fos = new fileoutputstream (picturefile); FOS. write (Params [0]); FOS. flush (); FOS. close ();} catch (filenotfoundexception e) {log. D (TAG, "file not found:" + E. getmessage ();} catch (ioexception e) {log. D (TAG, "Error accessing File:" + E. getmessage () ;}return null ;}}

This is the basic I/O operation on the file asynchronous thread. You can see the corresponding API documentation.

Below I will post the entire class:

/*** Sufaceview preview class, in which surfaceholder. callback is used to monitor changes to the surface. * This callback method is automatically called when the surface changes * by the caller surfaceholder. addcallback to bind this method * @ author ZW. yan **/public class camerapreview extends surfaceview implementssurfaceholder. callback {private string tag = "camerapreview";/*** surface controller, used to control preview and other operations */private surfaceholder mholder; /* ** camera instance */private camera mcamera = NULL;/* Image Processing */public static Fina L int media_type_image = 1;/*** preview status flag */private Boolean ispreview = false;/*** set a fixed maximum size */private int maxpicturesize = 5000000; /*** whether automatic focus is supported. By default, */private Boolean issupportautofocus = false is not supported./*** obtain the current context */private context mcontext; /*** the orientation of the current sensor. When the orientation changes, it will automatically receive notifications from the sensor management class */myorientationdetector cameraorientation; /*** set the image width most suitable for the current mobile phone */INT setfixpicturewidth = 0;/*** set the currently most suitable image height */INT setfixpictureheight = 0; @ suppresswarnings ("deprecation") Public camerapreview (context) {super (context); this. mcontext = context; issupportautofocus = context. getpackagemanager (). hassystemfeature (packagemanager. feature_camera_autofocus); mholder = getholder (); // compatible with APIs lower than Android 3.0. If it exceeds 3.0, you do not need to set this method if (build. version. sdk_int <build. version_codes.honeycomb) {mholder. settype (surfaceholder. surf Ace_type_push_buffers);} mholder. addcallback (this); // bind the current callback method}/*** automatically call this method during creation */@ overridepublic void surfacecreated (surfaceholder holder) {If (mcamera = NULL) {mcamera = cameracheck. getcamerainstance (mcontext);} Try {If (mcamera! = NULL) {mcamera. setpreviewdisplay (holder) ;}} catch (ioexception e) {If (null! = Mcamera) {mcamera. release (); mcamera = NULL; ispreview = false;} e. printstacktrace () ;}}/*** automatically called when the surface size changes */@ overridepublic void surfacechanged (surfaceholder holder, int format, int width, int height) {If (mholder. getsurface () = NULL) {return;} Try {setcameraparms (); mcamera. setpreviewdisplay (holder); mcamera. startpreview (); reautofocus ();} catch (exception e) {log. D (TAG, "error starting camera Preview: "+ E. getmessage () ;}} private void setcameraparms () {Camera. parameters myparam = mcamera. getparameters (); List <camera. size> msupportedsizelist = myparam. getsupportedpicturesizes (); If (msupportedsizelist. size ()> 1) {iterator <camera. size> itos = msupportedsizelist. iterator (); While (itos. hasnext () {Camera. size cursize = itos. next (); int cursupporsize = cursize. width * cursize. height; int fixpictru Esize = setfixpicturewidth * setfixpictureheight; If (cursupporsize> fixpictruesize & cursupporsize <= maxpicturesize) {setfixpicturewidth = cursize. width; setfixpictureheight = cursize. height ;}} myparam. set0000quality (100); mcamera. setparameters (myparam); If (myparam. getmaxnumdetectedfaces ()> 0) {mcamera. startfacedetection () ;}@overridepublic void surfacedestroyed (surfaceholder holder) {mcamera. stopp Review (); mcamera. release (); mcamera = NULL;}/*** call the camera to auto focus */Public void reautofocus () {If (issupportautofocus) {mcamera. autofocus (New autofocuscallback () {@ overridepublic void onautofocus (Boolean success, camera) {}}) ;}/ *** auto focus, then take a photo */Public void takepicture () {If (mcamera! = NULL) {mcamera. autofocus (SUCCESS) ;}} private autofocuscallback = new autofocuscallback () {public void onautofocus (Boolean success, camera) {// todo auto-generated method stubif (SUCCESS) {log. I (TAG, "autofocuscallback: success... "); takephoto ();} else {log. I (TAG, "autofocuscallback: fail... "); If (issupportautofocus) {takephoto () ;}}};/*** adjust the photo direction and set the photo direction */priv Ate void takephoto () {cameraorientation = new myorientationdetector (mcontext); If (mcamera! = NULL) {int orientation = cameraorientation. getorientation (); camera. parameters cameraparameter = mcamera. getparameters (); cameraparameter. setrotation (90); cameraparameter. set ("rotation", 90); If (orientation >=45) & (orientation <135) {cameraparameter. setrotation (180); cameraparameter. set ("rotation", 180);} If (orientation >=135) & (orientation <225) {cameraparameter. setrotation (270); camerapa Rameter. set ("rotation", 270);} If (orientation >=225) & (orientation <315) {cameraparameter. setrotation (0); cameraparameter. set ("rotation", 0);} mcamera. setparameters (cameraparameter); mcamera. takepicture (shuttercallback, callback, mpicture) ;}} private shuttercallback = new shuttercallback () {@ overridepublic void onshutter () {// todo auto-generated method stub}; private PICT Urecallback picturecallback = new picturecallback () {@ overridepublic void onpicturetaken (byte [] arg0, camera arg1) {// todo auto-generated method stub }}; private picturecallback mpicture = new picturecallback () {@ overridepublic void onpicturetaken (byte [] data, camera) {New savepicturetask(cmd.exe cute (data); mcamera. startpreview (); // preview again}; public class savepicturetask extends asynctask <byte [], String, string >{@ suppresslint ("simpledateformat") @ overrideprotected string doinbackground (byte []... params) {file picturefile = fileutil. getoutputmediafile (media_type_image, mcontext); If (picturefile = NULL) {toast. maketext (mcontext, "Please insert a memory card! ", Toast. length_short ). show (); return NULL;} Try {fileoutputstream Fos = new fileoutputstream (picturefile); FOS. write (Params [0]); FOS. flush (); FOS. close ();} catch (filenotfoundexception e) {log. D (TAG, "file not found:" + E. getmessage ();} catch (ioexception e) {log. D (TAG, "Error accessing File:" + E. getmessage () ;}return null ;}@ overridepublic Boolean ontouchevent (motionevent event) {reautofocus (); Return false ;}}

File layout and calling are as follows:

public class CameraActivity extends Activity{    private CameraPreview mPreview;public static final int MEDIA_TYPE_IMAGE = 1;public static final int MEDIA_TYPE_VIDEO = 2;private String TAG="CameraActivity";private FrameLayout preview;private ImageButton captureButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);  this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);setContentView(R.layout.camera_preview);        mPreview = new CameraPreview(this);        preview = (FrameLayout) findViewById(R.id.camera_preview);        preview.addView(mPreview);        captureButton = (ImageButton) findViewById(R.id.button_capture);captureButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPreview.takePicture();}});}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();}}
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#000">  <FrameLayout    android:id="@+id/camera_preview"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_weight="1"    />  <ImageButton    android:id="@+id/button_capture"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_gravity="center"    android:src="@drawable/camera_icon"    android:background="#00000000"    /></LinearLayout>

The final result is as follows:



Note: There are some classes that are not described in detail. For details, refer to the Code download link below. If you do not understand anything, you can send an email. the email address is [email protected].

Reprinted please indicate the source, Code: (don't go! Please leave your comment)









Camera Development (focusing, portrait taking, photo storage, continuous photo taking, etc)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.