当前位置:   article > 正文

Android 系统自带图片裁剪功能(适配7.0、8.0、对了还有小米手机)_安卓非常小体积图片裁剪工具

安卓非常小体积图片裁剪工具

前段时间写了如何获取相册和拍照之后的照片并且进行显示和上传,这一次是如何进行圆形图像制作,经常看我写的笔记的人会知道,我很懒。那么我就懒的自定义了,目前需求就用原生的就好了,大神的轮子,我会在后面进行推荐。这篇笔记是依赖于:Android调用相册、相机(兼容6.0、7.0、8.0)
文章撰写的,所以不会基本操作的,请先去看看那个。

先上效果哈:


##一、布局设置
由于是圆形头像,所以,我们引用一个举世闻名的项目哈:CircleImageView
 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <Button
  9. android:id="@+id/btn_get_pic_form_photo_album"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:layout_alignParentStart="true"
  13. android:layout_margin="10dp"
  14. android:text="调用相册" />
  15. <Button
  16. android:id="@+id/btn_get_Permission"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_centerHorizontal="true"
  20. android:layout_margin="10dp"
  21. android:text="动态权限申请" />
  22. <Button
  23. android:id="@+id/btn_get_pic_from_camera"
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:layout_alignParentEnd="true"
  27. android:layout_margin="10dp"
  28. android:text="调用相机" />
  29. <de.hdodenhof.circleimageview.CircleImageView
  30. android:id="@+id/iv_test"
  31. android:layout_width="96dp"
  32. android:layout_height="96dp"
  33. android:layout_centerInParent="true"
  34. android:src="@drawable/ic_launcher_background"
  35. app:civ_border_color="#999999"
  36. app:civ_border_width="2dp" />
  37. </RelativeLayout>

布局没有太大变化,就是把之前的ImageView修改为CircleImageView控件

##二、.java 文件
这里增加了两个方法
######方法一

  1. private void photoClip(Uri uri) {
  2. // 调用系统中自带的图片剪裁
  3. Intent intent = new Intent("com.android.camera.action.CROP");
  4. intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  5. intent.setDataAndType(uri, "image/*");
  6. // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
  7. intent.putExtra("crop", "true");
  8. // aspectX aspectY 是宽高的比例
  9. intent.putExtra("aspectX", 1);
  10. intent.putExtra("aspectY", 1);
  11. // outputX outputY 是裁剪图片宽高
  12. intent.putExtra("outputX", 150);
  13. intent.putExtra("outputY", 150);
  14. intent.putExtra("return-data", true);
  15. startActivityForResult(intent, 3);
  16. }

该方法,传入我们拿到的照片的 uri 进行激活 Android 系统的裁剪界面。我是在 onActivityResult 内进行调用该方法。

######方法二

  1. public String saveImage(String name, Bitmap bmp) {
  2. File appDir = new File(Environment.getExternalStorageDirectory().getPath());
  3. if (!appDir.exists()) {
  4. appDir.mkdir();
  5. }
  6. String fileName = name + ".jpg";
  7. File file = new File(appDir, fileName);
  8. try {
  9. FileOutputStream fos = new FileOutputStream(file);
  10. bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
  11. fos.flush();
  12. fos.close();
  13. return file.getAbsolutePath();
  14. } catch (IOException e) {
  15. e.printStackTrace();
  16. }
  17. return null;
  18. }

 

该方法 传入获取照片的 bitmap 和裁剪之后的照片名称,生成文件的保存路径,韩小呆将其保存在了本地的根目录了。 

完整代码

  1. package com.example.hxd.pictest;
  2. import android.Manifest;
  3. import android.content.Intent;
  4. import android.graphics.Bitmap;
  5. import android.net.Uri;
  6. import android.os.Build;
  7. import android.os.Bundle;
  8. import android.os.Environment;
  9. import android.os.SystemClock;
  10. import android.provider.MediaStore;
  11. import android.support.annotation.NonNull;
  12. import android.support.v4.content.FileProvider;
  13. import android.support.v7.app.AppCompatActivity;
  14. import android.util.Log;
  15. import android.view.View;
  16. import android.widget.Button;
  17. import android.widget.ImageView;
  18. import android.widget.Toast;
  19. import com.bumptech.glide.Glide;
  20. import java.io.File;
  21. import java.io.FileOutputStream;
  22. import java.io.IOException;
  23. import java.util.List;
  24. import java.util.Objects;
  25. import java.util.logging.Logger;
  26. import de.hdodenhof.circleimageview.CircleImageView;
  27. import pub.devrel.easypermissions.EasyPermissions;
  28. public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {
  29. private CircleImageView ivTest;
  30. private File cameraSavePath;//拍照照片路径
  31. private Uri uri;
  32. private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
  33. private String photoName = System.currentTimeMillis() + ".jpg";
  34. @Override
  35. protected void onCreate(Bundle savedInstanceState) {
  36. super.onCreate(savedInstanceState);
  37. setContentView(R.layout.activity_main);
  38. Button btnGetPicFromCamera = findViewById(R.id.btn_get_pic_from_camera);
  39. Button btnGetPicFromPhotoAlbum = findViewById(R.id.btn_get_pic_form_photo_album);
  40. Button btnGetPermission = findViewById(R.id.btn_get_Permission);
  41. ivTest = findViewById(R.id.iv_test);
  42. btnGetPicFromCamera.setOnClickListener(this);
  43. btnGetPicFromPhotoAlbum.setOnClickListener(this);
  44. btnGetPermission.setOnClickListener(this);
  45. cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + photoName);
  46. }
  47. @Override
  48. public void onClick(View v) {
  49. int id = v.getId();
  50. switch (id) {
  51. case R.id.btn_get_pic_from_camera:
  52. goCamera();
  53. break;
  54. case R.id.btn_get_pic_form_photo_album:
  55. goPhotoAlbum();
  56. break;
  57. case R.id.btn_get_Permission:
  58. getPermission();
  59. break;
  60. }
  61. }
  62. //获取权限
  63. private void getPermission() {
  64. if (EasyPermissions.hasPermissions(this, permissions)) {
  65. //已经打开权限
  66. Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show();
  67. } else {
  68. //没有打开相关权限、申请权限
  69. EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions);
  70. }
  71. }
  72. private void photoClip(Uri uri) {
  73. // 调用系统中自带的图片剪裁
  74. Intent intent = new Intent("com.android.camera.action.CROP");
  75. intent.setDataAndType(uri, "image/*");
  76. // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
  77. intent.putExtra("crop", "true");
  78. // aspectX aspectY 是宽高的比例
  79. intent.putExtra("aspectX", 1);
  80. intent.putExtra("aspectY", 1);
  81. // outputX outputY 是裁剪图片宽高
  82. intent.putExtra("outputX", 150);
  83. intent.putExtra("outputY", 150);
  84. intent.putExtra("return-data", true);
  85. startActivityForResult(intent, 3);
  86. }
  87. //激活相册操作
  88. private void goPhotoAlbum() {
  89. Intent intent = new Intent();
  90. intent.setAction(Intent.ACTION_PICK);
  91. intent.setType("image/*");
  92. startActivityForResult(intent, 2);
  93. }
  94. //激活相机操作
  95. private void goCamera() {
  96. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  97. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  98. uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
  99. intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  100. } else {
  101. uri = Uri.fromFile(cameraSavePath);
  102. }
  103. intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
  104. MainActivity.this.startActivityForResult(intent, 1);
  105. }
  106. @Override
  107. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  108. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  109. //框架要求必须这么写
  110. EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
  111. }
  112. //成功打开权限
  113. @Override
  114. public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
  115. Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show();
  116. }
  117. //用户未同意权限
  118. @Override
  119. public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
  120. Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show();
  121. }
  122. @Override
  123. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  124. String photoPath;
  125. if (requestCode == 1 && resultCode == RESULT_OK) {
  126. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  127. photoPath = String.valueOf(cameraSavePath);
  128. photoClip(Uri.fromFile(cameraSavePath));
  129. } else {
  130. photoPath = uri.getEncodedPath();
  131. photoClip(uri);
  132. }
  133. Log.d("拍照返回图片路径:", photoPath);
  134. Glide.with(MainActivity.this).load(photoPath).into(ivTest);
  135. } else if (requestCode == 2 && resultCode == RESULT_OK) {
  136. photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
  137. Log.d("相册返回图片路径:", photoPath);
  138. photoClip(data.getData());
  139. Glide.with(MainActivity.this).load(photoPath).into(ivTest);
  140. } else if (requestCode == 3 && resultCode == RESULT_OK) {
  141. Bundle bundle = data.getExtras();
  142. if (bundle != null) {
  143. //在这里获得了剪裁后的Bitmap对象,可以用于上传
  144. Bitmap image = bundle.getParcelable("data");
  145. //设置到ImageView上
  146. ivTest.setImageBitmap(image);
  147. //也可以进行一些保存、压缩等操作后上传
  148. String path = saveImage("头像", image);
  149. Log.d("裁剪路径:", path);
  150. }
  151. }
  152. super.onActivityResult(requestCode, resultCode, data);
  153. }
  154. public String saveImage(String name, Bitmap bmp) {
  155. File appDir = new File(Environment.getExternalStorageDirectory().getPath());
  156. if (!appDir.exists()) {
  157. appDir.mkdir();
  158. }
  159. String fileName = name + ".jpg";
  160. File file = new File(appDir, fileName);
  161. try {
  162. FileOutputStream fos = new FileOutputStream(file);
  163. bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
  164. fos.flush();
  165. fos.close();
  166. return file.getAbsolutePath();
  167. } catch (IOException e) {
  168. e.printStackTrace();
  169. }
  170. return null;
  171. }
  172. }

当代码写成了这样,我以为就可以完事了,但是后来拿出来我的小米4和小米8se 测试的时候,我就懵逼了,出现了如下结果:

描述一下:
1、相册选择照片之后,只要进行裁剪就会出现“保存时发生错误,保存失败”;
2、就是拍照之后进行裁剪无效果。

#三、解决bug
###1、将 photoClip() 方法内添加如下代码,其他代码不进行变动

  1. uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");
  2. intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
  3. intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
  4. intent.putExtra("noFaceDetection", true);

这里的 uritempFile 是个 Uri 。

###2、将裁剪的返回成功的返回方法内添加如下代码:

  1. Picasso.with(EditMyInfoActivity.this).load(uritempFile).into(ivHead);
  2. File file = null;
  3. try {
  4. file = new File(new URI(uritempFile.toString()));
  5. } catch (URISyntaxException e) {
  6. e.printStackTrace();
  7. }
  8. //照片路径
  9. String path = Objects.requireNonNull(file).getPath();

然后,就可以完美的运行了。
##三、推荐一篇自定义裁剪的博文
Android 高仿微信头像截取 打造不一样的自定义控件----作者: 家喻户晓的 张鸿洋

##四、推荐几款裁剪框架
1、uCrop—薄荷,哔哩哔哩 在使用

2、android-crop—网易新闻,芒果TV 在使用


3、PhotoCrop—快手 使用


4、CropBitmap—>出自一位牛x的群友

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/174267
推荐阅读
相关标签
  

闽ICP备14008679号