Android 系统自带图片裁剪功能(适配7.0、8.0、对了还

作者: 吾乃韩小呆 | 来源:发表于2018-09-17 18:58 被阅读123次

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

    先上效果哈:


    系统自带的裁剪效果

    一、布局设置

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

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns: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 文件

    这里增加了两个方法

    方法一
      private void photoClip(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 内进行调用该方法。

    方法二
      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 和裁剪之后的照片名称,生成文件的保存路径,韩小呆将其保存在了本地的根目录了。

    完整代码

    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 class MainActivity extends AppCompatActivity implements View.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
        protected void onCreate(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
        public void onClick(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;
            }
        }
    
        //获取权限
        private void getPermission() {
            if (EasyPermissions.hasPermissions(this, permissions)) {
                //已经打开权限
                Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show();
            } else {
                //没有打开相关权限、申请权限
                EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions);
            }
    
        }
    
    
        private void photoClip(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);
    
    
        }
    
    
        //激活相册操作
        private void goPhotoAlbum() {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_PICK);
            intent.setType("image/*");
            startActivityForResult(intent, 2);
        }
    
        //激活相机操作
        private void goCamera() {
            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
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            //框架要求必须这么写
            EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
        }
    
    
        //成功打开权限
        @Override
        public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
    
            Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show();
        }
    
        //用户未同意权限
        @Override
        public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
            Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        protected void onActivityResult(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 测试的时候,我就懵逼了,出现了如下结果:


    bug

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

    三、解决bug

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

    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、将裁剪的返回成功的返回方法内添加如下代码:

      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();
    

    然后,就可以完美的运行了。

    三、推荐一篇自定义裁剪的博文

    Android 高仿微信头像截取 打造不一样的自定义控件----作者: 家喻户晓的 张鸿洋

    四、推荐几款裁剪框架

    1、uCrop---薄荷,哔哩哔哩 在使用

    uCrop

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

    android-crop

    3、PhotoCrop---快手 使用

    PhotoCrop

    4、CropBitmap--->一位很牛x的大佬搞出来的

    CropBitmap

    相关文章

      网友评论

        本文标题:Android 系统自带图片裁剪功能(适配7.0、8.0、对了还

        本文链接:https://www.haomeiwen.com/subject/uwgrnftx.html