Android Custom Camera Detailed _android

Source: Internet
Author: User

Almost every app will use the camera function, the following small series to share the content of the cloud Habitat Community Platform for your reference, interested friends to study together!

Two ways to start a camera

1. Direct Boot System camera

<code class= "Hljs avrasm" > Intent Intent = new Intent (); 
Intent.setaction (mediastore.action_image_capture); 
StartActivity (Intent);</code>

Or specify a name to return the picture Mcurrentphotofile

<code class= "Hljs avrasm" > 
Intent Intent = new Intent (mediastore.action_image_capture);
Intent.putextra (Mediastore.extra_output,uri.fromfile (Mcurrentphotofile));
Startactivityforresult (Intent, Camera_with_data);</code>

2. Custom Launch camera

Today, for example, the second type. The effect chart is as follows

General steps for customizing a camera

To create a layout that shows the camera screen, Android has chosen for us Surfaceview through Surfaceview#getholder () to get links to camera and Surfaceview Surfaceholder Camame.open () Open the camera via surfaceholder link camera and Surfaceview

Code demos for general steps

<code class= "Hljs java" >public class Camerasurfaceview extends Surfaceview implements Surfaceholder.callback, Camera.autofocuscallback {private static final String TAG = "Camerasurfaceview"; private context mcontext; private SURFAC
Eholder Holder;
Private Camera Mcamera;
private int mscreenwidth;
private int mscreenheight; Public Camerasurfaceview {This (context, null);} public Camerasurfaceview AttributeSet attrs) {This [context, attrs, 0];} public Camerasurfaceview (context context, AttributeSet attrs, int defstyl EATTR) {Super (context, attrs, defstyleattr); mcontext = context; Getscreenmetrix (context); Initview ();} private void Get
Screenmetrix (Context context) {WindowManager WM = (windowmanager) context.getsystemservice (Context.window_service);
Displaymetrics outmetrics = new Displaymetrics ();
Wm.getdefaultdisplay (). Getmetrics (Outmetrics);
Mscreenwidth = Outmetrics.widthpixels;
Mscreenheight = Outmetrics.heightpixels; } private void InitviEW () {holder = Getholder ();//Get Surfaceholder reference holder.addcallback (this); Holder.settype (surfaceholder.surface_type_ Push_buffers/settings type} @Override public void surfacecreated (Surfaceholder holder) {log.i (TAG, "surfacecreated"); if (mCa Mera = = null) {Mcamera = Camera.open ();//Turn on camera try {mcamera.setpreviewdisplay (holder);//Camera screen appears on surface} catch (Ioexcep
tion e) {e.printstacktrace ();}} @Override public void surfacechanged (surfaceholder holder, int format, int width, int height) {log.i (TAG, "Surfacechang
Ed ");
Mcamera.startpreview (); @Override public void surfacedestroyed (Surfaceholder holder) {log.i (TAG, surfacedestroyed); Mcamera.stoppreview ()
//Stop preview mcamera.release ();//Release camera resource mcamera = NULL;
Holder = null; @Override public void Onautofocus (Boolean success, Camera Camera) {if (success) {LOG.I (TAG, Onautofocus success=) +suc
Cess); }}}</code>

Add camera and auto focus limit

<code class= "Hljs xml" ><uses-permission android:name= "Android.permission.CAMERA" >
< Uses-feature android:name= "Android.hardware.camera.autofocus" ></uses-feature></uses-permission> </code>

Put the Camerasurfaceview in the layout file, which suggests that the outermost layer is framelayout and will be used later. So, we have a camera without photographic function. First, carefully observe the camera display screen, the picture is not serious deformation? That's because we haven't set any parameters for the camera yet. Before previewing, set the camera resolution, preview resolution, and picture resolution to the aspect ratio to be consistent. So the picture will not deform. This is a more difficult to understand the part, want to understand deeply also need the reader to practice.

<code class= "Hljs java" > private void Setcameraparams (Camera Camera, int width, int height) {log.i (TAG, "setcamerap
Arams width= "+width+" height= "+height);
Camera.parameters Parameters = Mcamera.getparameters ();
Get the Picturesize list supported by the camera list<camera.size> picturesizelist = parameters.getsupportedpicturesizes (); for (Camera.size size:picturesizelist) {log.i (TAG, "picturesizelist size.width=" + size.width + "size.height=" + Size.)
height);
/** Select the appropriate resolution from the list * * Camera.size picsize = getpropersize (Picturesizelist, ((float) height/width));
if (null = = Picsize) {log.i (TAG, "null = = Picsize"); picsize = Parameters.getpicturesize ();}
LOG.I (TAG, "picsize.width=" + picsize.width + "picsize.height=" + picsize.height);
According to the selected picturesize reset Surfaceview size float w = picsize.width;
float h = picsize.height;
Parameters.setpicturesize (Picsize.width,picsize.height);
This.setlayoutparams ((int) (height* (h/w)), height) (new framelayout.layoutparams); Get the Previewsize list supported by the camera List<camera.size> previewsizelist = parameters.getsupportedpreviewsizes (); for (Camera.size size:previewsizelist) {log.i (TAG, "previewsizelist size.width=" + size.width + "size.height=" + Size.)
height);
Camera.size presize = Getpropersize (Previewsizelist, ((float) height)/width); if (null!= presize) {log.i (TAG, "presize.width=" + presize.width + "presize.height=" + presize.height); parameters.setp
Reviewsize (Presize.width, presize.height); } parameters.setjpegquality (100); Set the photo quality if (Parameters.getsupportedfocusmodes (). Contains (android.hardware.Camera.Parameters.FOCUS_MODE_ Continuous_picture)) {Parameters.setfocusmode (Android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
;//continuous Focus mode} mcamera.cancelautofocus ();//Auto focus.
Mcamera.setdisplayorientation (90)//set Previewdisplay direction, the effect is to rotate the captured picture of how many degrees show mcamera.setparameters (parameters); /** * Select the appropriate resolution from the list * default w:h = 4:3 *<p> Note: Here the W corresponds to the screen's height * H corresponds to the screen's width</p></camera.size></ camera.size></code> * * priVate camera.size getpropersize (List picturesizelist, float screenratio) {log.i (TAG, "screenratio=" + screenratio); Camera.size result = null; for (Camera.size size:picturesizelist) {Float Currentratio = ((float) size.width)/size.height; if (CURRENTRATIO-SCR Eenratio = = 0 {result = size; if (Null = result) {for (camera.size size:picturesizelist) {Float Curratio = ((float) size.width)/size.height; if ( Curratio = = 4F/3) {//default w:h = 4:3 result = size; break;}} return result; }

In the screen is wide, out of the adjusted parameters. Execute Mcamera.startpreview () in the Surfacechanged method; Before calling Setcameraparams (Mcamera, Mscreenwidth, mscreenheight); It's OK. Finally in the androidmanifest.xml to set the direction of activity android:screenorientation= "portrait" code has a lot of comments, which also have my own debugging time log, you can debug yourself, Look at the effects of different parameters. Yesterday tuning parameters to get a little more, are tossing this function. Alas, a bitter tear.

As a camera, can't you take a picture? It's humiliating! Here's how to add a photo to our camera. The camera core code is just one sentence: mcamera.takepicture (null, NULL, JPEG);

You can see that the Takepicture method has three parameters, namely, Shuttercallback, Picturecallback, and Picturecallback. We only use picturecallback here.

<code class= "Hljs java" >//Photo instant call private Camera.shuttercallback shutter = new Camera.shuttercallback () {@Overrid
e public void Onshutter () {log.i (TAG, "shutter");}; Get picture data that is not compressed private camera.picturecallback raw = new Camera.picturecallback () {@Override public void Onpicturetaken (b
yte[] data, Camera Camera) {log.i (TAG, "raw");}; Create a JPEG picture callback data Object private camera.picturecallback JPEG = new Camera.picturecallback () {@Override public void Onpicturetake
N (byte[] data, Camera Camera) {bufferedoutputstream BOS = null;
Bitmap BM = NULL; try {//Get Picture BM = Bitmapfactory.decodebytearray (data, 0, data.length); if (Environment.getexternalstoragestate (). equals (environment.media_mounted))
{LOG.I (TAG, "environment.getexternalstoragedirectory () =" +environment.getexternalstoragedirectory ());
String FilePath = "/sdcard/dyk" +system.currenttimemillis () + ". jpg";//Photo save path File File = new file (FilePath); if (!file.exists ()) {file.createnewfile ();} BOS = new Bufferedoutputstream (New FileouTputstream (file)); Bm.compress (Bitmap.CompressFormat.JPEG, BOS); Compress the picture into the stream}else{Toast.maketext (Mcontext, "No Memory card detected"
Toast.length_short). Show (); } catch (Exception e) {e.printstacktrace ();} finally {try {bos.flush ();//output Bos.close ();//close bm.recycle ();//Recycle BITMA
P Space Mcamera.stoppreview ()//Close preview Mcamera.startpreview ()//Open Preview} catch (IOException e) {e.printstacktrace ();}} }};</code>

In the onpicturetaken of JPEG. We will store the photo information byte[] data parsed into bitmap, and then converted to JPG images saved in the SD card. Note Finally the last two sentences Mcamera.stoppreview ();//Close Preview Mcamera.startpreview ()/Open preview As mentioned above: When the Camera.takepiture method is invoked, camera closes the preview, and then calls Startpreview () to reopen the preview. If you don't open the preview again, you'll be stuck in the picture. To facilitate external calls to take pictures. Here I have exposed a method for external photography.

<code class= "HLJS cs" > public void Takepicture () {
//Set parameters and photographed
setcameraparams (Mcamera, Mscreenwidth, Mscreenheight);
When the Camera.takepiture method is invoked, camera closes the preview, and calls Startpreview () to reopen the preview
mcamera.takepicture (null, NULL, JPEG);
</code>

Add a button to the layout file and click the button to execute the Takepicture () method. Do not forget to add the write SD card limit right

<code class= "Hljs xml" ><uses-permission android:name= "Android.permission.WRITE_EXTERNAL_STORAGE" >< /uses-permission></code>

So far, a camera with the ability to take photos and save pictures is done. But, are we satisfied with this? I wouldn't have written this blog for these simple features. It's just a start.

The real start

Yesterday saw another app in the photo, the screen can actually show like the effect of the box, auxiliary point, picture bulabulabula~. Online search for a way to achieve, coupled with some of their own understanding, constitute this blog.

The layout file has not been posted above, now put it out to everyone first glance, some controls will be shown next

<code class= "Hljs xml" ><!--? XML version= "1.0" encoding= "Utf-8"?--> <framelayout android:layout_height = "Match_parent" android:layout_width= "match_parent" xmlns:android= "Http://schemas.android.com/apk/res/android" > <com.dyk.cameratest.view.camerasurfaceview android:id= "@+id/camerasurfaceview" android:layout_height= " Match_parent "android:layout_width=" match_parent "> <com.dyk.cameratest.view.rectoncamera android:layout_ height= "Match_parent" android:layout_width= "match_parent" > <relativelayout android:layout_height= "Match_" Parent "android:layout_width=" match_parent "> </relativelayout></com.dyk.cameratest.view.rectoncamera ></com.dyk.cameratest.view.camerasurfaceview></framelayout></code><button android: Background= "#88427ac7" android:id= "@+id/takepic" android:layout_alignparentbottom= "true" Android:layout_ Centerhorizontal= "true" android:layout_height= "50DP" android:layout_marginbottom= "20DP" android:layout_width= " 80DP "Android:text= "Photo" android:textcolor= "#aaa" ><code class= "Hljs xml" > </code></button> 

The outermost layer of the layout file is a framelayout, and we know that Framelayout is a self covering effect. The origin of this idea next is very simple. Programming is about thinking, thinking has, and the rest of it is the specifics of the implementation.

Custom Edges and boundaries

In order to separate from the Camerasurfaceview area, and then customize a rectoncamera specifically used to draw the edge of these things. One advantage of this is that it is easy to maintain and not put everything in one view.

Rectoncamera

<code class= "Hljs java" >package Com.dyk.cameratest.view;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import Android.graphics.Color;
Import Android.graphics.Paint;
Import Android.graphics.Point;
Import Android.graphics.RectF;
Import Android.util.AttributeSet;
Import Android.util.DisplayMetrics;
Import Android.util.Log;
Import android.view.MotionEvent;
Import Android.view.View;
Import Android.view.WindowManager;
/** * Created by DYK on 2016/4/7. * * public class Rectoncamera extends View {private static final String TAG = "Camerasurfaceview"; private int Mscreenwidt
H
private int mscreenheight;
Private Paint Mpaint;
Private RECTF MRECTF;
Round private point CenterPoint;
private int Radio; Public Rectoncamera {This (context, null);} public Rectoncamera (context, AttributeSet attrs) {T
His (context, attrs, 0); Public Rectoncamera (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); GETSCR Eenmetrix (context);
Initview (context); } private void Getscreenmetrix (context context) {WindowManager WM = (windowmanager) context.getsystemservice (
Context.window_service);
Displaymetrics outmetrics = new Displaymetrics ();
Wm.getdefaultdisplay (). Getmetrics (Outmetrics);
Mscreenwidth = Outmetrics.widthpixels;
Mscreenheight = Outmetrics.heightpixels; } private void Initview {mpaint = new Paint (); Mpaint.setantialias (true);//Anti-aliasing Mpaint.setdither (TRUE);
/Anti-jitter Mpaint.setcolor (color.red);
Mpaint.setstrokewidth (5);
Mpaint.setstyle (Paint.Style.STROKE);//Hollow int marginleft = (int) (mscreenwidth*0.15);
int margintop = (int) (mscreenheight * 0.25);
MRECTF = new RECTF (marginleft, MarginTop, Mscreenwidth-marginleft, mscreenheight-margintop);
CenterPoint = new Point (MSCREENWIDTH/2, MSCREENHEIGHT/2);
Radio = (int) (mscreenwidth*0.1); @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas); Mpaint.setcolor (color.red); Canvas.drawrect (
MRECTF, Mpaint); Mpaint.setcolor (Color.White);
LOG.I (TAG, "OnDraw"); Canvas.drawcircle (Centerpoint.x,centerpoint.y, radio,mpaint);//Outer Circle canvas.drawcircle (CENTERPOINT.X,CENTERPOINT.Y, Radio-20,mpaint); Inner Circle}} </code>

Here is a simple picture of a two-dimensional code scan, and a similar inner and outer circle of focus. So the problem is, the inner and outer circles of the focus change position with the fingers, and have the effect of focusing. Camerasurfaceview is not the same class as the focusing function, so focusing on the inner and outer circles is completely covered by the Camerasurfaceview. To handle this problem, an interface callback is required. This is the detail below the thought. Now, although the interface callback is determined, there is a problem that there is no object or reference in the Camerasurfaceview class and Rectoncamera class. Yes, this functionality can be achieved by holding Rectoncamera and camerasurfaceview activity together. The following are the specific implementation methods.

Move it

First of all, to change the position of the Rectoncamera with the slide of the finger must be to make a carbon copy ontouchevent () method

<code class= "HLJS cs" > @Override public
boolean ontouchevent (Motionevent event) {
switch ( Event.getaction ()) {case
Motionevent.action_down: Case
motionevent.action_move:
case MOTIONEVENT.ACTION_UP:
int x = (int) event.getx ();
int y = (int) event.gety ();
CenterPoint = new Point (x, y);
Invalidate ();
return true;
}
return true;
} </code>

Second, define the callback interface

<code class= "Hljs java" > Private iautofocus miautofocus;
/**-Focused Callback interface *
/public interface iautofocus{
void Autofocus ();
}
public void Setiautofocus (Iautofocus miautofocus) {
this.miautofocus = Miautofocus;
} </code>

Join before return in Ontouchevent ()

<code class= "HLJS cs" > if (miautofocus!= null) {
miautofocus.autofocus ();
} </code>

Now that our callback interface has been defined, we also need camerasurfaceview to expose a focus method so that the activity calls

<code class= "HLJS cs" > public void Setautofocus () {
mcamera.autofocus (this);
} </code>

The preparations have been completed and the following are the specific implementations of the activity:

<code class= "Hljs java" >public class mainactivity activity extends implements, rectoncamera.iautofocus{private Camerasurfaceview Mcamerasurfaceview; private Rectoncamera Mrectoncamera; private
Button takepicbtn;
Private Boolean isclicked;
@Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Requestwindowfeature (Window.feature_no_title); Full screen displays GetWindow (). SetFlags (Windowmanager.layoutparams.flag_fullscreen,windowmanager.layoutparams.flag_
fullscreen);
Setcontentview (R.layout.activity_main);
Mcamerasurfaceview = (Camerasurfaceview) Findviewbyid (R.id.camerasurfaceview);
Mrectoncamera = (Rectoncamera) Findviewbyid (R.id.rectoncamera);
Takepicbtn= (Button) Findviewbyid (r.id.takepic);
Mrectoncamera.setiautofocus (this);
Takepicbtn.setonclicklistener (this);
@Override public void OnClick (View v) {switch (V.getid ()) {case r.id.takepic:mcamerasurfaceview.takepicture ();
Default:break; @Override public void AUTofocus () {Mcamerasurfaceview.setautofocus ();}} </code>

As you can see, mainactivity implements the Iautofocus interface, and in the Iautofocus#autofocus () method of the replication, the Camerasurfaceview exposed method Setautofocus () is invoked. At this point, each slide in the Rectoncamera will change the position of the focus inside and outside the circle, and also increase the focus function. It would be better to have two or even more multitasking.

OK, so the Android custom camera tutorial is over and I hope it helps!

Recommended readings for cloud-dwelling communities:

Android Development get picture clipping from camera or album

Android Custom Camera Countdown photo

Related Article

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.