Let's start with the idea that we have a picture-cutting application in the Android system, so we just need to pass the photos we got to the picture-cutting application and then return the clipped photos to our own screen.
In the process of developing some apps, we may be involved in the processing of avatars, such as from the phone or photo albums to get the Avatar, tailored to their own needs of the avatar, set or upload avatar. Some of the relevant information on the Internet is also numerous, but in practical applications often have a variety of problems, there is no perfect solution. As a result of the recent project needs, the study, it seems that there is no problem.
Here we only talk about getting, tailoring, and setting up, and uploading the process is added to your business needs. First previous flowchart:
This picture is drawn with Google Drive's drawing tools and has to marvel at how powerful Google can be in online editing tools. Okay, I'm Google's brain residue! Back to the theme, this is my idea of design, and then a detailed analysis:
1, the way to get pictures is nothing more than two kinds, the first is camera shooting, the second is from the local album to get.
2, I created a folder on the SD card, which has two URIs, one is used to save the original picture when the photo, one is to save the cropped picture. Before I thought about using the same URI to save the picture, but in practice encountered a problem, when the camera does not cut, then the next time from the SD card to take photos saved large image, not only lost the previously cropped pictures, but also because of loading large graphics led to memory crashes. Based on this consideration, I chose two URIs to save the picture separately.
3, when the camera is taken, we use intent to call the system camera, and set the output to Sdcard\xx\photo_file.jpg, the following is the code fragment:
Call system camera
Intent Intentcamera = new Intent (mediastore.action_image_capture);
Save the photo to the Photo_file URI, not in the album
Intentcamera.putextra (Mediastore.extra_output, Imagephotouri);
Startactivityforresult (Intentcamera, Photo_request_carema);
In the callback, we need to trim the photo_file.jpg call System tool and set the output settings to Sdcard\xx\crop_file.jpg, which is the following code fragment:
Case Photo_request_carema:
if (ResultCode = = RESULT_OK) {
//Remove picture from camera's saved URI, call system clipping tool
if (ImagePhoto Uri!= null) {
Croputils.cropimageuri (this, Imagephotouri, Imageuri, Ibusericon.getwidth (), Ibusericon.getheigh T (), photo_request_cut);
else {
Toastutils.show (this, "photo not photographed");
}
Else if (ResultCode = result_canceled) {
toastutils.show (this, "Cancel Photo");
else {
Toastutils.show (this, "Photo failed");
} break
;
Invokes the system's clipping processing picture and saves it to the Imageuri public
static void Cropimageuri (activity activity, Uri Orguri, Uri Desuri, int width, int h eight, int requestcode) {
Intent Intent = new Intent ("Com.android.camera.action.CROP");
Intent.setdataandtype (Orguri, "image/*");
Intent.putextra ("Crop", "true");
Intent.putextra ("Aspectx", 1);
Intent.putextra ("Aspecty", 1);
Intent.putextra ("Outputx", width);
Intent.putextra ("outputy", height);
Intent.putextra ("scale", true);
Saves the clipped picture to the target URI
Intent.putextra (Mediastore.extra_output, Desuri);
Intent.putextra ("Return-data", false);
Intent.putextra ("OutputFormat", Bitmap.CompressFormat.JPEG.toString ());
Intent.putextra ("Nofacedetection", true);
Activity.startactivityforresult (Intent, Requestcode);
}
Finally, we need to remove the CROP_ in the callback File.jpg, because the picture has been compressed, so do not worry about the memory problem, here I provide two methods, the first is directly to get the original picture of the bitmap, the second is to get the original picture and make a circle, I believe most people are interested in the latter, haha! The following is a code fragment:
Case Photo_request_cut:
if (ResultCode = = RESULT_OK) {
Bitmap Bitmap = Decodeuriiasbimap (This,imagecropuri)
} else if (ResultCode = = result_canceled) {
toastutils.show (this, "Cancel clipping picture");
else {
Toastutils.show (this, "Cut failed");
} break
;
Gets the picture in the Bitmap format from the Uri
private static Bitmap Decodeuriasbitmap (context context, Uri Uri) {
Bitmap Bitmap;
try {
bitmap = Bitmapfactory.decodestream (Context.getcontentresolver (). Openinputstream (URI));
catch (FileNotFoundException e) {
e.printstacktrace ();
return null;
return
bitmap;
}
Gets the circular picture public static Bitmap Getroundedcornerbitmap (Bitmap Bitmap) {if (Bitmap = null) {return null;
Bitmap output = Bitmap.createbitmap (Bitmap.getwidth (), Bitmap.getheight (), Bitmap.Config.ARGB_8888);
Canvas Canvas = new Canvas (output);
Final Paint Paint = new Paint ();
/* antialiasing/Paint.setantialias (TRUE);
Paint.setfilterbitmap (TRUE);
Paint.setdither (TRUE);
Guaranteed to be square, and draw int width from center = bitmap.getwidth ();
int height = bitmap.getheight ();
int W;
int deltax = 0;
int deltay = 0;
if (width <= height) {w = width;
DeltaY = height-w;
else {w = height;
DeltaX = width-w;
Final Rect Rect = new Rect (DeltaX, DeltaY, W, W);
Final RECTF RECTF = new RECTF (rect);
Paint.setantialias (TRUE);
Canvas.drawargb (0, 0, 0, 0);
Circle, all with only one int radius = (int) (MATH.SQRT (w * w * 2.0d)/2);
Canvas.drawroundrect (RECTF, radius, radius, paint);
Paint.setxfermode (New Porterduffxfermode (PorterDuff.Mode.SRC_IN)); Canvas.drawbitmap(Bitmap, rect, rect, paint);
return output;
}
4, album acquisition, this is also the hardest place. Under Android 4.4, the picture URI obtained from the photo album can call the system clipping tool perfectly, or the intent that is brought into the clipping picture directly from the selected album, and the effect is perfect. However, in Android 4.4 and above, the URI obtained cannot invoke the system clipping tool at all, causing the program to crash directly. I also studied for a long time, only to find that the URI of the two is very different, Google official documents let developers use Intent.action_get_content to replace the previous action, and even if you still use the previous action, will return a new type of URI , my personal guess is that Google has all the content to be shared into a unified URI, if it is wrong, please correct me! Figured this out, after the problem becomes simple, I encapsulate this new type of URI once, get to think "file:\\ ..." standard absolute road strength, incoming system tailoring tool, really successful, just this encapsulation process and difficult, consult a lot of data, finally still got. The following is a specific step:
First, call the system photo album, the following is a code fragment:
Call System album
Intent photopickerintent = new Intent (intent.action_get_content);
Photopickerintent.settype ("image/*");
Startactivityforresult (Photopickerintent, photo_request_gallery);
Second, in the callback, the URI is encapsulated, and the system clipping tool is invoked to set the output to Crop_file.jpg, and the call to the System clipping tool code is posted in the step of capturing the camera, where the wheel is not duplicated, the code that encapsulates the URI is highlighted, and the following code fragment:
case photo_request_gallery:if (ResultCode = = RESULT_OK) {//After the successful selection from the album, you need to take the picture from the URI
Absolute path, and then call the clipping Uri Newuri = Uri.parse ("file:///" + croputils.getpath (this, Data.getdata ())); if (Newuri!= null) {Croputils.cropimageuri (this, Newuri, Imageuri, Ibusericon.getwidth (), Ibusericon.getheig
HT (), photo_request_cut);
else {toastutils.show (this, "not getting photo album");
} else if (ResultCode = result_canceled) {toastutils.show (this, select Cancel from album);
else {toastutils.show (this, select from album failed);
} break;
@SuppressLint ("Newapi") public static String GetPath (final context, final URI Uri) {Final Boolean iskitkat = Bu Ild. VERSION. Sdk_int >= build.version_codes.
KitKat;
Documentprovider if (Iskitkat && documentscontract.isdocumenturi (context, URI)) {//Externalstorageprovider
if (Isexternalstoragedocument (URI)) {final String docId = Documentscontract.getdocumentid (URI);
Final string[] split = Docid.split (":");
Final String type = split[0];
if ("PRIMARY". Equalsignorecase (Type)) {return environment.getexternalstoragedirectory () + "/" + split[1]; }//Downloadsprovider else if (isdownloadsdocument (URI)) {final String id = documentscontract.getdocumenti
D (URI); Final Uri Contenturi = Contenturis.withappendedid (Uri.parse ("Content://downloads/public_downloads"), Long.valueOf (
ID));
Return Getdatacolumn (context, Contenturi, NULL, NULL); }//Mediaprovider else if (ismediadocument (URI)) {final String docId = doCumentscontract.getdocumentid (URI);
Final string[] split = Docid.split (":");
Final String type = split[0];
Uri Contenturi = null;
if ("image". Equals (Type)) {Contenturi = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
else if ("video". Equals (Type)) {Contenturi = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
else if ("Audio". Equals (Type)) {Contenturi = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Final String selection = "_id=?";
Final string[] Selectionargs = new String[]{split[1]};
Return Getdatacolumn (context, Contenturi, Selection,selectionargs); }//Mediastore (and general) else if ("content". Equalsignorecase (Uri.getscheme ())) {return Getdatacolumn (con
Text, URI, NULL, NULL);
}//File else if ("file". Equalsignorecase (Uri.getscheme ())) {return Uri.getpath ();
return null; }/** * Get the value of the ' data column ' for this Uri. This is useful to * Mediastore Uris, and other File-basEd Contentproviders.
* * @param context.
* @param uri the URI to query.
* @param selection (Optional) Filter used in the query.
* @param Selectionargs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path. * * private static String Getdatacolumn (context context, Uri uri,string selection, string[] selectionargs) {Cursor curs
or = null;
Final String column = "_data";
Final string[] projection = {column};
try {cursor = Context.getcontentresolver (). Query (URI, projection,selection, Selectionargs, NULL);
if (cursor!= null && cursor.movetofirst ()) {final int column_index = cursor.getcolumnindexorthrow (column);
Return cursor.getstring (Column_index);
Finally {if (cursor!= null) cursor.close ();
return null;
/** * @param uri the URI to check.
* @return Whether The Uri authority is externalstorageprovider. * Private Static Boolean IsexterNalstoragedocument (Uri Uri) {return "com.android.externalstorage.documents". Equals (Uri.getauthority ());}
/** * @param uri the URI to check.
* @return Whether The Uri authority is downloadsprovider. */Private static Boolean isdownloadsdocument (Uri uri) {return "com.android.providers.downloads.documents". Equals (URI
. getauthority ());
/** * @param uri the URI to check.
* @return Whether The Uri authority is mediaprovider. */Private static Boolean ismediadocument (Uri uri) {return "com.android.providers.media.documents". Equals (
Uri.getauthority ());
}
Subsequent system clipping tool calls are consistent with the capture step, see code on.
5, all steps completed, in the Nexus 5 equipment in the latest system test through, in Millet, Samsung and other equipment in the performance is also perfect. If there is a flaw in your equipment, be sure to post feedback to me, thank you!
The end of the article with a complete example of a netizen, gave me a lot of references
Package Com.only.android.app;
Import Java.io.File;
Import android.app.Activity;
Import Android.app.AlertDialog;
Import Android.content.DialogInterface;
Import android.content.Intent;
Import Android.graphics.Bitmap;
Import Android.graphics.BitmapFactory;
Import Android.net.Uri;
Import Android.os.Bundle;
Import Android.os.SystemClock;
Import Android.provider.MediaStore;
Import Android.view.View;
Import Android.widget.Button;
Import Android.widget.ImageView;
Import COM.ONLY.ANDROID.R; public class Copyofimagescaleactivity extends activity implements View.onclicklistener {/** when the The created.
* * Private Button selectimagebtn;
Private ImageView ImageView;
Private File Sdcardtempfile;
Private Alertdialog Dialog;
private int crop = 180;
@Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
Setcontentview (R.layout.imagescale); SELECTIMAGEBTN = (Button) Findviewbyid (r.id.selectimageBTN);
ImageView = (ImageView) Findviewbyid (R.id.imageview);
Selectimagebtn.setonclicklistener (this);
Sdcardtempfile = new File ("/mnt/sdcard/", "Tmp_pic_" + systemclock.currentthreadtimemillis () + ". jpg"); @Override public void OnClick (View v) {if (v = = selectimagebtn) {if (dialog = null) {Dialog = new Alertdialog.builder (this). Setitems (new string[] {camera, photo album}, new Dialoginterface.onclicklistener () {@O Verride public void OnClick (Dialoginterface dialog, int which) {if (which = 0) {int
ent intent = new Intent ("Android.media.action.IMAGE_CAPTURE");
Intent.putextra ("Output", Uri.fromfile (Sdcardtempfile));
Intent.putextra ("Crop", "true");
Intent.putextra ("Aspectx", 1);//cropping frame proportional Intent.putextra ("Aspecty", 1);
Intent.putextra ("Outputx", crop);//Output picture size Intent.putextra ("outputy", crop); StartActivityForresult (Intent, 101);
else {Intent Intent = new Intent ("Android.intent.action.PICK");
Intent.setdataandtype (MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
Intent.putextra ("Output", Uri.fromfile (Sdcardtempfile));
Intent.putextra ("Crop", "true");
Intent.putextra ("Aspectx", 1);//cropping frame proportional Intent.putextra ("Aspecty", 1);
Intent.putextra ("Outputx", crop);//Output picture size Intent.putextra ("outputy", crop);
Startactivityforresult (Intent, 100);
The}}). Create ();
} if (!dialog.isshowing ()) {dialog.show (); }} @Override protected void Onactivityresult (int requestcode, int resultcode, Intent Intent) {if (resu
Ltcode = = RESULT_OK) {Bitmap bmp = Bitmapfactory.decodefile (Sdcardtempfile.getabsolutepath ());
Imageview.setimagebitmap (BMP); }
}
}
Finally a word, although the function has been realized, but the actual code can be further optimized, interested in the children can be improved.