Android Camera Development (four): The preview interface is lit in the dark, just take a picture of the rectangular region (with full source code)

Source: Internet
Author: User

Zajia previously wrote a demo about just taking pictures of specific areas. It's just a little more humble. In the coordinates of the conversion is not very rigorous, and did not complete the preview interface around the effect of the dark, deeply regret. I'm going to make this up today.

Before the code is first confessed, there are two modes of conversion. The first is to convert the rectangular area on the screen to the base. Give me a sample example. A rectangle in the middle of the screen is 100dip*100dip. Be sure to use DIP units, otherwise the size of the rectangular box on the screen will not be the same on different phones.

Convert the dip to PX first. Then, according to the width and height of the screen to calculate the rectangular region, to the Surfaceview upper layer of view, called Maskview (Mask), let Maskview to draw. And then take a picture. The size of the screen rectangle and the size of the screen are converted to the picturesize of the image that was finally taken. Get a picture of the rectangular area in the picture, and then intercept the save. Another mode is to know in advance the desired length of the image, as I just want to intercept 400*400 (px) size of the picture.

Use this as a benchmark to calculate the length and width of the rect that is rendered on the screen, and then let Maskview draw.

Which mode to use, select on demand. This article demonstrates the sample in the first mode. The following code:

Encapsulation is based on the Zajia of the previous article. First, wrap a maskview to draw the effect of a dark light around you, or you can add a scroll bar. This is not a thing.

First, Maskview.java

Package Org.yanzi.ui;import Org.yanzi.util.displayutil;import Android.content.context;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.paint.style;import Android.graphics.point;import Android.graphics.rect;import Android.util.attributeset;import Android.util.log;import Android.widget.imageview;public class MaskView extends ImageView {private static final String TAG = "Yanzi";p rivate paint mlinepaint;private paint mareapaint;private Rect mcente  Rrect = null;private Context Mcontext;public Maskview (context context, AttributeSet Attrs) {Super (context, attrs);//TODO Auto-generated constructor Stubinitpaint (); mcontext = context; Point p= displayutil.getscreenmetrics (mcontext); widthscreen = P.x;heightscreen = p.y;} private void Initpaint () {//Draw paintmlinepaint = new paint (paint.anti_alias_flag) for the rectangle boundary of the middle transparent area; Mlinepaint.setcolor ( Color.Blue); Mlinepaint.setstyle (Style.stroke); Mlinepaint.setstrokewidth (5f); Mlinepaint.setalpha (30);//Draw AroundShadow Area Mareapaint = new Paint (paint.anti_alias_flag); Mareapaint.setcolor (Color.gray); Mareapaint.setstyle (Style.FILL) ; Mareapaint.setalpha (180);} public void Setcenterrect (Rect r) {log.i (TAG, "Setcenterrect ..."); this.mcenterrect = R;postinvalidate ();} public void Clearcenterrect (Rect r) {this.mcenterrect = null;} int Widthscreen, heightscreen; @Overrideprotected void OnDraw (canvas canvas) {//TODO auto-generated method Stublog.i (TAG , "OnDraw ..."), if (Mcenterrect = = null) return;//draws the surrounding shaded area canvas.drawrect (0, 0, Widthscreen, Mcenterrect.top, Mareapaint ); Canvas.drawrect (0, Mcenterrect.bottom + 1, widthscreen, Heightscreen, Mareapaint); Canvas.drawrect (0, Mcenterrect.top, Mcenterrect.left-1, Mcenterrect.bottom + 1, mareapaint); Canvas.drawrect (MCenterRect.right + 1, mCente Rrect.top, Widthscreen, Mcenterrect.bottom + 1, mareapaint);//Draw target Transparent area canvas.drawrect (Mcenterrect, mlinepaint); Super.ondraw (canvas);}}
A description such as the following:

1, in order to let this maskview have a better adaptation type, the inside set variable mcenterrect, the coordinates of this matrix is already converted good. The size of the screen to fit, in full screen screen width high as a coordinate system, no need to change.

2, of course, this maskview is full screen, here to change the playcamera_v1.0.0 in a small problem, I will change its layout for example, the following:

<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 =". Cameraactivity "> <framelayout android:layout_width=" match_parent "android:layout_height=" Match_par            Ent "> <org.yanzi.camera.preview.camerasurfaceview android:id=" @+id/camera_surfaceview " Android:layout_width= "0dip" android:layout_height= "0dip"/> <org.yanzi.ui.maskview and Roid:id= "@+id/view_mask" android:layout_width= "match_parent" android:layout_height= "Match_parent"/&    Gt        </FrameLayout> <imagebutton android:id= "@+id/btn_shutter" android:layout_width= "Wrap_content" android:layout_height= "Wrap_content" android:layout_alignparentbottom= "true" Android:layout_centerhoriz Ontal= "true" Android:layout_Marginbottom= "10dip" android:background= "@drawable/btn_shutter_background"/></relativelayout> 
the place to change is to let Framelayout directly fullscreen. Do not set it to wrap_content, assuming it is wrap. The size of the Surfaceview is adjusted in the code, and Maskview is set to wrap, it will feel that the Maskview is 0. In addition, let framelayout full screen. When switching between 16:9 and 4:3, you can adjust the size of the preview layout by setting the Surfaceview margin, so the preview's parent layout framelayout must be full-screen.

3. About the +1-1 in the code that draws the shadow area. Try not to be wrong in these small places, as written in this article. The order is to first draw the top, bottom, left, and right four areas of the shadow.

Draw the surrounding shaded area canvas.drawrect (0, 0, Widthscreen, Mcenterrect.top, Mareapaint); Canvas.drawrect (0, Mcenterrect.bottom + 1, Widthscreen, Heightscreen, Mareapaint); Canvas.drawrect (0, Mcenterrect.top, mcenterrect.left-1, MCenterRect.bottom  + 1, mareapaint); Canvas.drawrect (Mcenterrect.right + 1, mcenterrect.top, Widthscreen, Mcenterrect.bottom + 1, Mareapaint);

two, in the Cameraactivity.java package two functions:

/** the width and height of the middle rectangle of the picture after the photo is generated * @param the width of the rectangle on the W screen, in px * @param the height of the rectangle on the H screen. Unit px * @return */private point createcenterpicturerect (int W, int. h) {int wscreen = Displayutil.getscreenmetrics (this). X;i NT Hscreen = Displayutil.getscreenmetrics (this). Y;int wsavepicture = Camerainterface.getinstance (). doGetPrictureSize (). Y; Because the picture is rotated, here the wide-height transposition int hsavepicture = Camerainterface.getinstance (). Dogetpricturesize (). x; Because the picture is rotated. So here the wide-height transposition float wrate = (float) (wsavepicture)/(float) (wscreen), float hrate = (float) (hsavepicture)/(float) (hscreen); Float rate = (wrate <= hrate)? Wrate:hrate;//is also able to calculate int wrectpicture = (int) (w * wrate) at the minimum rate, int hrectpicture = (int) (h * hrate); return new Point (Wrec Tpicture, hrectpicture);} /** * Generates a rectangle in the middle of the screen * @param the width of the target rectangle, px * @param h The height of the target rectangle, unit px * @return */private Rect createcenterscreenrect (int w, int  h) {int x1 = displayutil.getscreenmetrics (This). X/2 – W/2;int y1 = Displayutil.getscreenmetrics (this). Y/2-H/2;int x2 = x1 + W;int y2 = y1 + h;return new Rect (x1, y1, x2, y2);} 
Each is a point that creates the width and height of the middle rectangle of the picture, creating a rectangular area in the middle of the screen. The input parameters of the two functions are the width and height of the mid-screen rectangle of the PX unit.

Here is a condition: the rectangle is centered on the center of the screen, otherwise the calculation formula should be properly transformed .

third, after opening the preview, you can let Maskview draw

@Overridepublic void camerahasopened () {//TODO auto-generated method Stubsurfaceholder holder = Surfaceview.getsurfaceholder (); Camerainterface.getinstance (). Dostartpreview (holder, previewrate); if (Maskview! = null) {Rect Screencenterrect = Createcenterscreenrect (displayutil.dip2px (this, dst_center_rect_width), displayutil.dip2px (This, DST_CENTER_RECT_ HEIGHT)); Maskview.setcenterrect (Screencenterrect);}}
Here's a note: Because the Camera.open is placed in a separate line thread. Open after the callback to Camerahasopened () here, that this function is run on the main thread and child threads? The answer is also in the child thread, that is, the callback of the child thread is run in the child thread.

That is why. When the Maskview is encapsulated, the set matrix is refreshed with postinvalidate ().

public void Setcenterrect (Rect r) {log.i (TAG, "Setcenterrect ..."); this.mcenterrect = R;postinvalidate ();}

Finally, we'll tell the camera's callback.

Private class Btnlisteners implements onclicklistener{@Overridepublic void OnClick (View v) {//TODO auto-generated method Stubswitch (V.getid ()) {case R.id.btn_shutter:if (rectpicturesize = = null) {rectpicturesize = Createcenterpicturerect ( DISPLAYUTIL.DIP2PX (Cameraactivity.this, Dst_center_rect_width), displayutil.dip2px (CameraActivity.this, DST_ center_rect_height));} Camerainterface.getinstance (). Dotakepicture (rectpicturesize.x, rectpicturesize.y); break;default:break;}}
above is the camera listening, in camerainterface to rewrite a dotakepicture function:

int dst_rect_width, dst_rect_height;public void dotakepicture (int w, int h) {if (ispreviewing && (Mcamera! = null)) {LOG.I (TAG, "Rectangle photo size: Width =" + W + "H =" + h);D st_rect_width = W;dst_rect_height = H;mcamera.takepicture (Mshuttercallba CK, NULL, mrectjpegpicturecallback);}}
Here comes a mrectjpegpicturecallback, which corresponds to the class:

/** * Capture the rect of the specified area */picturecallback mrectjpegpicturecallback = new Picturecallback ()//callback for JPEG image data, one of the most important callbacks {public void Onpicturetaken (byte[] data, Camera camera) {//TODO auto-generated method stublog.i (TAG, "Myjpegcallback:o Npicturetaken ... "); Bitmap B = null;if (null! = data) {b = bitmapfactory.decodebytearray (data, 0, data.length);//data is byte data, Parse it into bitmap Mcamera.stoppreview (); ispreviewing = false;} After saving the picture to SDCARDIF (null! = b) {//Set Focus_mode_continuous_video), the Myparam.set ("rotation", 90) fails.

The picture can't actually rotate, so here to rotate under bitmap rotabitmap = Imageutil.getrotatebitmap (b, 90.0f); int x = Rotabitmap.getwidth ()/2-dst_rect_ Width/2;int y = rotabitmap.getheight ()/2-dst_rect_height/2; LOG.I (TAG, "rotabitmap.getwidth () =" + rotabitmap.getwidth () + "rotabitmap.getheight () =" + Rotabitmap.getheight ()); Bitmap Rectbitmap = Bitmap.createbitmap (Rotabitmap, x, Y, Dst_rect_width, dst_rect_height); Fileutil.savebitmap (Rectbitmap); if (rotabitmap.isrecycled ()) {rotabitmap.recycle (); rotabitmap = null;} if (rectbitmap.isrecycled ()) {rectbitmap.recycle (); rectbitmap = null;}} Go back to preview Mcamera.startpreview (); ispreviewing = True;if (!b.isrecycled ()) {b.recycle (); b = null;}};


Precautions:

1, in order to let the cut out of the area and the screen shows the full consistency, here first to meet the previewsize aspect ratio, picturesize aspect ratio, screen preview Surfaceview aspect ratio of the same ratio, This is a prerequisite . . Then, when you convert the width of the screen rectangle to a rectangular area of the picture:

/** the width and height of the middle rectangle of the picture after the photo is generated
* @param the width of the rectangle on the W screen, unit px
* @param the height of the rectangle on the H screen, unit px
* @return
*/
Private point Createcenterpicturerect (int w, int h) {

int wscreen = Displayutil.getscreenmetrics (this). x;
int hscreen = Displayutil.getscreenmetrics (this). Y;
int wsavepicture = Camerainterface.getinstance (). Dogetpricturesize (). Y; Because the picture is rotated, the width and height transposition here
int hsavepicture = Camerainterface.getinstance (). Dogetpricturesize (). x; Because the picture is rotated. So here's the wide-height transposition.
float wrate = (float) (wsavepicture)/(float) (wscreen);
float hrate = (float) (hsavepicture)/(float) (hscreen);
Float rate = (wrate <= hrate)?

wrate:hrate;//can also be calculated according to the minimum ratio

int wrectpicture = (int) (w * wrate);
int hrectpicture = (int) (h * hrate);
return new Point (Wrectpicture, hrectpicture);

}

in principle wrate should be equal to hrate ...!!

。!!!

!!

2, I have updated the getproppreviewsize and getproppicturesize in Camparautil. Once inferred from width, this is changed to a height inference.

Since the type of 800*480 (width * height) is obtained when reading the reference, it is generally slightly smaller, so the height is inferred. And this high at last displayed and saved by the rotation and became wide.

Public Size getproppicturesize (list<camera.size> list, float th, int minheight) {collections.sort (list, sizecomparator); int i = 0;for (Size s:list) {if (s.height >= minheight) && equalrate (s, th)) {log.i (TAG, " Picturesize:w = "+ S.width +" H = "+ S.height); i++;} if (i = = List.size ()) {i = 0;//if not found, select the smallest Size}return list.get (i);}
Let's take a look at the effect. I set the screen to display a rectangle size of 200dip*200dip, the camera preview is the proportion of the screen on its own initiative to find the height of the preview size is not less than 400,picturesize height is not less than 1300.

Set previewsize and Picturesizesize picturesize = Camparautil.getinstance (). Getproppicturesize ( Mparams.getsupportedpicturesizes (), previewrate, 1300); Mparams.setpicturesize (Picturesize.width, Picturesize.height); Size previewsize = Camparautil.getinstance (). Getproppreviewsize (Mparams.getsupportedpreviewsizes (), PreviewRate, Mparams.setpreviewsize (Previewsize.width, previewsize.height);

to see the simple interception is not to change the image resolution. Note that the concept of true resolution is not equal to XXX * xxx, the larger the picture, the less clear. The rectangular area can be moved and stretched later. Take a picture of a specific area anywhere in the demo. -------------------------------This article is original, reproduced please indicate the author: yanzi1225627code Download Link:csdn:http://download.csdn.net/detail/yanzi1225627/7557539





Android Camera Development (four): The preview interface is lit in the dark, just take a picture of the rectangular region (with full source code)

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.