前段时间写了如何获取相册和拍照之后的照片并且进行显示和上传,这一次是如何进行圆形图像制作,经常看我写的笔记的人会知道,我很懒。那么我就懒的自定义了,目前需求就用原生的就好了,大神的轮子,我会在后面进行推荐。这篇笔记是依赖于:Android调用相册、相机(兼容6.0、7.0、8.0) 文章撰写的,所以不会基本操作的,请先去看看那个。
[系统自带的裁剪效果]
一、布局设置
由于是圆形头像,所以,我们引用一个举世闻名的项目哈:CircleImageView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btn_get_pic_form_photo_album" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_margin="10dp" android:text="调用相册" /> <Button android:id="@+id/btn_get_Permission" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_margin="10dp" android:text="动态权限申请" /> <Button android:id="@+id/btn_get_pic_from_camera" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_margin="10dp" android:text="调用相机" /> <de.hdodenhof.circleimageview.CircleImageView android:id="@+id/iv_test" android:layout_width="96dp" android:layout_height="96dp" android:layout_centerInParent="true" android:src="@drawable/ic_launcher_background" app:civ_border_color="#999999" app:civ_border_width="2dp" /> </RelativeLayout> |
布局没有太大变化,就是把之前的ImageView修改为CircleImageView控件
二、.java 文件
这里增加了两个方法
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
privatevoidphotoClip(Uri uri){ // 调用系统中自带的图片剪裁 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setDataAndType(uri, "image/*"); // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 150); intent.putExtra("outputY", 150); intent.putExtra("return-data", true); startActivityForResult(intent, 3); } |
该方法,传入我们拿到的照片的 uri 进行激活 Android 系统的裁剪界面。我是在 onActivityResult 内进行调用该方法。
方法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public String saveImage(String name, Bitmap bmp) { File appDir = new File(Environment.getExternalStorageDirectory().getPath()); if (!appDir.exists()) { appDir.mkdir(); } String fileName = name + ".jpg"; File file = new File(appDir, fileName); try { FileOutputStream fos = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); return file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return null; } |
该方法 传入获取照片的 bitmap 和裁剪之后的照片名称,生成文件的保存路径,韩小呆将其保存在了本地的根目录了。
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
package com.example.hxd.pictest; import android.Manifest; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.SystemClock; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import com.bumptech.glide.Glide; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import java.util.Objects; import java.util.logging.Logger; import de.hdodenhof.circleimageview.CircleImageView; import pub.devrel.easypermissions.EasyPermissions; public classMainActivityextendsAppCompatActivityimplementsView.OnClickListener, EasyPermissions.PermissionCallbacks{ private CircleImageView ivTest; private File cameraSavePath;//拍照照片路径 private Uri uri; private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; private String photoName = System.currentTimeMillis() + ".jpg"; @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnGetPicFromCamera = findViewById(R.id.btn_get_pic_from_camera); Button btnGetPicFromPhotoAlbum = findViewById(R.id.btn_get_pic_form_photo_album); Button btnGetPermission = findViewById(R.id.btn_get_Permission); ivTest = findViewById(R.id.iv_test); btnGetPicFromCamera.setOnClickListener(this); btnGetPicFromPhotoAlbum.setOnClickListener(this); btnGetPermission.setOnClickListener(this); cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + photoName); } @Override publicvoidonClick(View v){ int id = v.getId(); switch (id) { case R.id.btn_get_pic_from_camera: goCamera(); break; case R.id.btn_get_pic_form_photo_album: goPhotoAlbum(); break; case R.id.btn_get_Permission: getPermission(); break; } } //获取权限 privatevoidgetPermission(){ if (EasyPermissions.hasPermissions(this, permissions)) { //已经打开权限 Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show(); } else { //没有打开相关权限、申请权限 EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions); } } privatevoidphotoClip(Uri uri){ // 调用系统中自带的图片剪裁 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是宽高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪图片宽高 intent.putExtra("outputX", 150); intent.putExtra("outputY", 150); intent.putExtra("return-data", true); startActivityForResult(intent, 3); } //激活相册操作 privatevoidgoPhotoAlbum(){ Intent intent = new Intent(); intent.setAction(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, 2); } //激活相机操作 privatevoidgoCamera(){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(cameraSavePath); } intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); MainActivity.this.startActivityForResult(intent, 1); } @Override publicvoidonRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){ super.onRequestPermissionsResult(requestCode, permissions, grantResults); //框架要求必须这么写 EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } //成功打开权限 @Override publicvoidonPermissionsGranted(int requestCode, @NonNull List<String> perms){ Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show(); } //用户未同意权限 @Override publicvoidonPermissionsDenied(int requestCode, @NonNull List<String> perms){ Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show(); } @Override protectedvoidonActivityResult(int requestCode, int resultCode, Intent data){ String photoPath; if (requestCode == 1 && resultCode == RESULT_OK) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { photoPath = String.valueOf(cameraSavePath); photoClip(Uri.fromFile(cameraSavePath)); } else { photoPath = uri.getEncodedPath(); photoClip(uri); } Log.d("拍照返回图片路径:", photoPath); Glide.with(MainActivity.this).load(photoPath).into(ivTest); } else if (requestCode == 2 && resultCode == RESULT_OK) { photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData()); Log.d("相册返回图片路径:", photoPath); photoClip(data.getData()); Glide.with(MainActivity.this).load(photoPath).into(ivTest); } else if (requestCode == 3 && resultCode == RESULT_OK) { Bundle bundle = data.getExtras(); if (bundle != null) { //在这里获得了剪裁后的Bitmap对象,可以用于上传 Bitmap image = bundle.getParcelable("data"); //设置到ImageView上 ivTest.setImageBitmap(image); //也可以进行一些保存、压缩等操作后上传 String path = saveImage("头像", image); Log.d("裁剪路径:", path); } } super.onActivityResult(requestCode, resultCode, data); } public String saveImage(String name, Bitmap bmp){ File appDir = new File(Environment.getExternalStorageDirectory().getPath()); if (!appDir.exists()) { appDir.mkdir(); } String fileName = name + ".jpg"; File file = new File(appDir, fileName); try { FileOutputStream fos = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); return file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return null; } } |
当代码写成了这样,我以为就可以完事了,但是后来拿出来我的小米4和小米8se 测试的时候,我就懵逼了,出现了如下结果:
描述一下:
1、相册选择照片之后,只要进行裁剪就会出现“保存时发生错误,保存失败”;
2、就是拍照之后进行裁剪无效果。
三、解决bug
1、将 photoClip() 方法内添加如下代码,其他代码不进行变动
1 2 3 4 |
uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); |
这里的 uritempFile 是个 Uri 。
2、将裁剪的返回成功的返回方法内添加如下代码:
1 2 3 4 5 6 7 8 9 10 |
<span style="font-family: arial, helvetica, sans-serif;">Picasso.with(EditMyInfoActivity.this).load(uritempFile).into(ivHead); File file = null; try { file = new File(new URI(uritempFile.toString())); } catch (URISyntaxException e) { e.printStackTrace(); } //照片路径 String path = Objects.requireNonNull(file).getPath(); </span> |
然后,就可以完美的运行了。
四、推荐几款裁剪框架
1、[uCrop]()---薄荷,哔哩哔哩 在使用
地址:https://github.com/Yalantis/uCrop
2、[android-crop]()---网易新闻,芒果TV 在使用
地址:https://github.com/jdamcd/android-crop
https://github.com/Yalantis/uCrop
3、PhotoCrop---快手 使用
地址:https://github.com/albinmathew/PhotoCrop
4、CropBitmap--->一位很牛x的大佬搞出来的
地址:https://github.com/zhongruiAndroid/CropBitmap
—————END—————