Reprint Please specify source: http://blog.csdn.net/zhaokaiqiang1992
When doing the app, if there is a user system function, then generally can not escape this demand, is to set the user profile picture, and set the Avatar, but also from the photo and choose two ways from the album, and after the choice, the general will require the image to be cropped, let the user set the avatar. Today's article is about how to accomplish this requirement.
Let's analyze the requirements first. About taking pictures and selecting from albums, you can send a specific intent to the system, evoke the corresponding system program, and then in Onactivityresult, get our data. About image clipping, there are two ways to do it yourself, such as using third-party open source projects such as Cropper (Https://github.com/edmodo/cropper) to complete our needs, and the other, we can directly take advantage of the system provides the cutting function, Realize the cropping of the image.
Before the code is implemented, let's start with the idea. If it is a photo taken from the album, in Onactivityresult, we can get two forms of data, one is bitmap, one is URI. If the bitmap object is too large, it may be directly to the process of the collapse of our program, so if the picture in the album is 300px below the picture, the use of bitmap is allowed, is also safe, but this in our phone is basically impossible. So, I recommend that you use URIs no matter how large or small, because getting to the URI is the equivalent of getting a pointer to the picture, what do you want to do?
There won't be a lot of problems with getting pictures directly in a photo album, but if you want to work with pictures of photos, it might be a bit of a hassle. After using intent to invoke the photo app, we can also get bitmap or URI in Onactivityresult, depending on what flag we set in intent. However, if you get direct access to the photos returned by the bitmap, it may not be the result you want, it is possible to return not the original image, but a vague thumbnail, this is the Android system in order to reduce memory use of the strategy, but we hold this thumbnail image is not directly used, so, We should also use the URI method when taking pictures from the photo.
Well, either way, we get the URI of the picture we want to work with, and then what? The current is to use this URI as data using intent sent to the activity in the cropping, and then after the crop is finished, in the Onactivityresult, the bitmap object after the clip is set to ImageView, and then saved up, Upload to the server.
Once we've learned the whole process, we can start writing code.
if you want to evoke a photo album, there are two ways of Intent.action_pick, there is one more Intent. Action_get_content, the code is as follows, both of which can get the URI data of the picture
Mode 1, directly open the library, can only select pictures of the gallery Intent i = new Intent (Intent.action_pick,mediastore.images.media.external_content_uri);//Mode 2 , the user is asked to select the app that receives the request, and the image can be selected directly from the file system intent Intent = new Intent (intent.action_get_content, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); Intent.settype ("image/*"); Startactivityforresult (Intent, Pick_ From_file);
if we want to get from the photo, then we can use the following way, first create a URI with a file object, and then help top up, so that the photo is successful, after returning, we can get the picture according to the URI, and the file path to save the result of the photo, the following is the code implementation
Intent Intent = new Intent (mediastore.action_image_capture); Imguri = Uri.fromfile (New File ( Environment.getexternalstoragedirectory (), "Avatar_" + string.valueof (System.currenttimemillis ()) + ". png"); Intent.putextra (Mediastore.extra_output, Imguri); Startactivityforresult (Intent, Pick_from_camera);
OK, after getting to the URI, what should we do? Now the cutting interface is open again ~
the intent that opens the cropping interface is Intent Intent = New Intent ("Com.android.camera.action.CROP");
Please refer to the meanings of these parameters in intent
Additional Options data type description cropstring send clipping signal proportional aspectyinty direction on aspectxintx direction proportional outputxint width outputyint clipping area high Scaleboolean whether to preserve proportions Return-databo Olean do you want to keep the data in bitmap return dataparcelable the corresponding bitmap data circlecropstring the circular cropping area? The Mediastore.extra_output ("OUTPUT") URI points the URI to the corresponding file:///..., as detailed in the code example
The more important are the mediastore.extra_output and return-data options.
If you set Return-data to "true", you will get an action associated with the internal data and Bitmap return it in this way: (Bitmap) extras.getparcelable ("Data"). Note: If you finally want to get the picture very large, then this method will bring you trouble, so you have to control Outputx and outputy keep in smaller size.
If you set Return-data to "false", you will not receive any bitmap in Onactivityresult intent data, instead you will need to associate Mediastore.extra_output to a URI, This URI is used to store the bitmap.
With that in view, let's look at the following code very clearly.
private void DoCrop () {final arraylist<cropoption> cropoptions = new arraylist<cropoption> (); Intent Intent = New Intent ("Com.android.camera.action.CROP"); Intent.settype ("image/*"); list<resolveinfo> list = Getpackagemanager (). Queryintentactivities (Intent, 0); int size = List.size (); if (size = = 0 {Toast.maketext (this, "can ' t find crop app", Toast.length_short). Show (); return;} else {intent.setdata (Imguri); Intent.putextra ("Outputx"); Intent.putextra ("outputy", +) Intent.putextra (" Aspectx ", 1); Intent.putextra (" Aspecty ", 1); Intent.putextra (" scale ", true); Intent.putextra (" Return-data ", true);// Only Oneif (size = = 1) {Intent i = new Intent (Intent); ResolveInfo res = list.get (0); I.setcomponent (new ComponentName (Res.activityinfo.packagename,res.activityinfo.name) ); Startactivityforresult (i, Crop_from_camera);} else {//many crop appfor (ResolveInfo res:list) {final Cropoption co = new cropoption (); co.title = Getpackagemanager (). Getapplicationlabel (res.activityInfo.applicAtioninfo); Co.icon = Getpackagemanager (). Getapplicationicon (res.activityInfo.applicationInfo); co.appintent = new Intent (Intent); Co.appIntent.setComponent (new ComponentName (Res.activityinfo.packagename,res.activityinfo.name)) ; Cropoptions.add (co);} Cropoptionadapter adapter = new Cropoptionadapter (Getapplicationcontext (), cropoptions); Alertdialog.builder Builder = new Alertdialog.builder (this), Builder.settitle ("Choose a App"); Builder.setadapter ( Adapter,new Dialoginterface.onclicklistener () {public void OnClick (dialoginterface dialog, int item) { Startactivityforresult (Cropoptions.get (item). Appintent,crop_from_camera);}); Builder.setoncancellistener (New Dialoginterface.oncancellistener () {@Overridepublic void OnCancel (dialoginterface Dialog) {if (Imguri! = null) {getcontentresolver (). Delete (Imguri, NULL, NULL); Imguri = null;}}); Alertdialog alert = Builder.create (); Alert.show ();}}}
The above code, a large part of the process has a number of applications that can accept the clipping intent request, if you only want to use the default first app, then these logic you can delete.
After saying these things, we can do this in Onactivityresult:
@Overrideprotected void Onactivityresult (int requestcode, int resultcode, Intent data) {if (ResultCode! = RESULT_OK) {Retu RN;} Switch (requestcode) {case pick_from_camera:docrop (); Break;case Pick_from_file:imguri = Data.getdata ();d ocrop (); Break;case crop_from_camera:if (null! = data) {setcropimg (data);} Break;}}
no matter where you choose, you need to go into the crop, and then after the end of the crop, we call setcropimg (), the result set after cropping is ready, as follows
private void Setcropimg (Intent picdata) {Bundle bundle = Picdata.getextras (); if (null! = bundle) {Bitmap Mbitmap = bundle. Getparcelable ("Data"); Mimageview.setimagebitmap (Mbitmap); Savebitmap (Environment.getexternalstoragedirectory () + "/crop_" + system.currenttimemillis () + ". png", Mbitmap);}}
What's savebitmap doing? Of course, the bitmap saved up after the cut! Just like this .
public void Savebitmap (String fileName, Bitmap mbitmap) {file F = new File (fileName); FileOutputStream FOut = null;try {f.createnewfile (); fOut = new FileOutputStream (f); Mbitmap.compress ( Bitmap.CompressFormat.PNG, FOut); Fout.flush ();} catch (Exception e) {e.printstacktrace ();} finally {try {fout.close (); Toast.maketext (This, "Save Success", Toast.length_short). Show (); catch (IOException e) {e.printstacktrace ();}}}
OK, now save up, you can upload to the server, completed ~
Remember to add permission
< uses-permission android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
< uses-permission android:name="Android.permission.WRITE_SETTINGS" />
Code Download: Https://github.com/ZhaoKaiQiang/CropImageDemo
Reference article:
How to crop large images using Android Mediastore
Android Big picture clipping Ultimate solution (top: Principle analysis)
Android Big picture clipping Ultimate Solution (medium: from album)
Android Big picture clipping ultimate solution (bottom: Take photo)
"Android Development experience" setting up your avatar and cropping it is just that simple?