android image clipping

Keywords: Android github Mobile

From: http://blog.csdn.net/zhaokaiqiang 1992/article/details/43022023

When making APP, if there is a user system function, it can't escape this requirement, that is, to set the user's avatar, and to set the avatar, which includes two ways: taking photos and selecting from the album. After the selection, the image is usually required to be tailored so that the user can set the avatar. Today's article is about how to fulfill this requirement.


Let's first analyze the requirements. For photography and selection from albums, you can send specific Intent to the system, call up the corresponding system program, and then in onActivity Result, get our data. There are two ways to tailor images. One is to process them by yourself, such as using third-party open source projects, such as Cropper.( https://github.com/edmodo/cropper To fulfill our needs, another way, we can directly use the cutting function provided by the system to achieve image clipping.


Before we implement the code, let's rationalize our thinking. If it's a photo taken from an album, in onActivity Result, we can get two forms of data, one is Bitmap, the other is uri. If the Bitmap object is too big, it may directly crash our program, so if all the pictures in the album are below 300px, the use of bitmap is allowed and safe, but it is basically impossible in our mobile phone. So I recommend using URI directly, no matter how big or small it is, because when you get uri, you get a picture pointer and do whatever you want.~


It's not too much of a problem to get pictures directly from the album, but if you want to use the pictures taken for processing, it may be a little more troublesome. After using Intent to call Photo APP, we can also get bitmap or URI in onActivity Result, depending on what flag we set in intent. However, if you get the Bitmap directly, it may not be the result you want to get. It may not return the original image, but the blurred thumbnail. This is the strategy Android system has made to reduce memory usage, but we can't use this thumbnail directly. So, when we get the picture from the photograph, we should also use uri. Type.


Well, in either way, we get the uri of the image we're dealing with, so what happens next? The uri is currently sent as data to Activeness for clipping using Intent. After clipping is completed, in on Activity Result, the clipped bitmap object is set to ImageView, then saved and uploaded to the server.


After understanding the whole process, we can start writing code.

There are two ways to wake up an album: Intent.ACTION_PICK and Intent.ACTION_GET_CONTENT. The code is as follows. Both ways can get uri data of the picture.

  1. //Mode 1: Open the gallery directly and select only the pictures in the gallery.  
  2.                         Intent i = new Intent(Intent.ACTION_PICK,  
  3.                                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI);  
  4.                         //In mode 2, the user will first select the APP that receives the request, and the image can be selected directly from the file system.  
  5.                         Intent intent = new Intent(Intent.ACTION_GET_CONTENT,  
  6.                                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI);  
  7.                         intent.setType("image/*");  
  8.                         startActivityForResult(intent, PICK_FROM_FILE);  

If we want to get it from a photograph, we can create a uri with a file object, then bind it together, so that when the photograph is successful, we can get the picture according to uri after returning, and save the result of the photograph in the file path. Here is the code implementation.

  1. Intent intent = new Intent(  
  2.                                 MediaStore.ACTION_IMAGE_CAPTURE);  
  3.                         imgUri = Uri.fromFile(new File(Environment  
  4.                                 .getExternalStorageDirectory(), "avatar_"  
  5.                                 + String.valueOf(System.currentTimeMillis())  
  6.                                 + ".png"));  
  7.                         intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);  
  8.                         startActivityForResult(intent, PICK_FROM_CAMERA);  

ok, what should we do when we get uri? Now it's time to open the tailoring interface again.~

The Intent that opens the tailoring interface is Intent intent = new Intent("com.android.camera.action.CROP");

For the meaning of these parameters in intent, please refer to the following figure

  1. Additional Options Data Type Description
  2. crop String Sends Cutting Signal
  3. Proportion in the direction of aspectX int X
  4. Proportion in the direction of aspectY int Y
  5. outputX int The width of the clipping area
  6. outputY int The height of the clipping area
  7. scale boolean Reserved Proportion
  8. return-data boolean Whether to Return Data in Bitmap
  9. data Parcelable
  10. Circle Crop String Circle Cutting Area?   
  11. MediaStore.EXTRA_OUTPUT ("output") URI points the URI to the corresponding file:///..., as shown in the code example.

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 returns in this way: (Bitmap)extras.getParcelable("data"). Note: If the final image you want to get is very large, then this method will cause you trouble, so you need to control the output X and output Y to keep in a smaller size.  

If you set return-data to "false", you will not receive any Bitmap in the Intent data of onActivityResult. Instead, you need to associate MediaStore.EXTRA_OUTPUT with a Uri, which is used to store Bitmap.  

With that in mind, it should be clear to look at the following code.

  1. private void doCrop() {  
  2.   
  3.         final ArrayList<CropOption> cropOptions = new ArrayList<CropOption>();  
  4.         Intent intent = new Intent("com.android.camera.action.CROP");  
  5.         intent.setType("image/*");  
  6.         List<ResolveInfo> list = getPackageManager().queryIntentActivities(  
  7.                 intent, 0);  
  8.         int size = list.size();  
  9.   
  10.         if (size == 0) {  
  11.             Toast.makeText(this"can't find crop app", Toast.LENGTH_SHORT)  
  12.                     .show();  
  13.             return;  
  14.         } else {  
  15.             intent.setData(imgUri);  
  16.             intent.putExtra("outputX"300);  
  17.             intent.putExtra("outputY"300);  
  18.             intent.putExtra("aspectX"1);  
  19.             intent.putExtra("aspectY"1);  
  20.             intent.putExtra("scale"true);  
  21.             intent.putExtra("return-data"true);  
  22.   
  23.             // only one  
  24.             if (size == 1) {  
  25.                 Intent i = new Intent(intent);  
  26.                 ResolveInfo res = list.get(0);  
  27.                 i.setComponent(new ComponentName(res.activityInfo.packageName,  
  28.                         res.activityInfo.name));  
  29.                 startActivityForResult(i, CROP_FROM_CAMERA);  
  30.             } else {  
  31.                 // many crop app  
  32.                 for (ResolveInfo res : list) {  
  33.                     final CropOption co = new CropOption();  
  34.                     co.title = getPackageManager().getApplicationLabel(  
  35.                             res.activityInfo.applicationInfo);  
  36.                     co.icon = getPackageManager().getApplicationIcon(  
  37.                             res.activityInfo.applicationInfo);  
  38.                     co.appIntent = new Intent(intent);  
  39.                     co.appIntent  
  40.                             .setComponent(new ComponentName(  
  41.                                     res.activityInfo.packageName,  
  42.                                     res.activityInfo.name));  
  43.                     cropOptions.add(co);  
  44.                 }  
  45.   
  46.                 CropOptionAdapter adapter = new CropOptionAdapter(  
  47.                         getApplicationContext(), cropOptions);  
  48.   
  49.                 AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  50.                 builder.setTitle("choose a app");  
  51.                 builder.setAdapter(adapter,  
  52.                         new DialogInterface.OnClickListener() {  
  53.                             public void onClick(DialogInterface dialog, int item) {  
  54.                                 startActivityForResult(  
  55.                                         cropOptions.get(item).appIntent,  
  56.                                         CROP_FROM_CAMERA);  
  57.                             }  
  58.                         });  
  59.   
  60.                 builder.setOnCancelListener(new DialogInterface.OnCancelListener() {  
  61.                     @Override  
  62.                     public void onCancel(DialogInterface dialog) {  
  63.   
  64.                         if (imgUri != null) {  
  65.                             getContentResolver().delete(imgUri, nullnull);  
  66.                             imgUri = null;  
  67.                         }  
  68.                     }  
  69.                 });  
  70.   
  71.                 AlertDialog alert = builder.create();  
  72.                 alert.show();  
  73.             }  
  74.         }  
  75.     }  

A large part of the code above is dealing with multiple APPs that can accept tailored intent requests. If you only want to use the default first APP, you can delete the logic.

After that, we can do this in onActivity Result:

  1. @Override  
  2.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  3.   
  4.         if (resultCode != RESULT_OK) {  
  5.             return;  
  6.         }  
  7.         switch (requestCode) {  
  8.         case PICK_FROM_CAMERA:  
  9.             doCrop();  
  10.             break;  
  11.         case PICK_FROM_FILE:  
  12.             imgUri = data.getData();  
  13.             doCrop();  
  14.             break;  
  15.         case CROP_FROM_CAMERA:  
  16.             if (null != data) {  
  17.                 setCropImg(data);  
  18.             }  
  19.             break;  
  20.         }  
  21.     }  

Wherever you choose, you need to go into the tailoring. After the tailoring is finished, we call setCropImg(), and set the result of the tailoring to ImageView, as follows

  1. private void setCropImg(Intent picdata) {  
  2.         Bundle bundle = picdata.getExtras();  
  3.         if (null != bundle) {  
  4.             Bitmap mBitmap = bundle.getParcelable("data");  
  5.             mImageView.setImageBitmap(mBitmap);  
  6.             saveBitmap(Environment.getExternalStorageDirectory() + "/crop_"  
  7.                     + System.currentTimeMillis() + ".png", mBitmap);  
  8.         }  
  9.     }  

    What is saveBitmap for? Of course, save the clipped Bitmap! Like the following

  1. public void saveBitmap(String fileName, Bitmap mBitmap) {  
  2.         File f = new File(fileName);  
  3.         FileOutputStream fOut = null;  
  4.         try {  
  5.             f.createNewFile();  
  6.             fOut = new FileOutputStream(f);  
  7.             mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);  
  8.             fOut.flush();  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.         } finally {  
  12.             try {  
  13.                 fOut.close();  
  14.                 Toast.makeText(this"save success", Toast.LENGTH_SHORT).show();  
  15.             } catch (IOException e) {  
  16.                 e.printStackTrace();  
  17.             }  
  18.         }  
  19.   
  20.     }  

All right, now save it and upload it to the server. It's finished.~

Remember the weighting limit

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.WRITE_SETTINGS" /> 

Code download: https://github.com/ZhaoKaiQiang/CropImageDemo

Posted by ItsWesYo on Mon, 08 Apr 2019 01:33:30 -0700