android 开启摄像头以及选取相册照片剪裁图片并使用比例压缩大小

        之前搜索了各种网上的开启摄像头拍照和选取相册的方式,发现大部分都不太兼容、适合。因此在这里总结一下切实可用的方法(参考第一行代码)

        拍照使用的是FileProvider,这是为了保证uri安全机制而使用的一个类。使用此类在最新安卓版本中不需要访问SD卡中内容。

--工具包

1.CameraUtil(相机相关工具类)


import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;

import com.frz.marryapp.activity.ChoosePhotoActivity;
import com.frz.marryapp.base.GlobalApplication;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class CameraUtil {

    public static final int TAKE_PHOTO = 1;

    public static final int CHOOSE_PHOTO = 2;

    public static final int CROP_PHOTO = 3;

    public static boolean IS_LARGER_VERSION_19 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    /**
     * 对于4.4版本通过FileProvider获取到的Uri
     * @param activity 放入当前的活动
     * @return 返回拍照后的对应文件uri
     */
    public static Uri getPhotoUri(Activity activity, String providerAuthority){
        //创建File对象,用于存储拍照后的图片
        Uri imageUri;
        File outputImage = new File(activity.getExternalCacheDir(), "output_image.jpg");
        try{
            if(outputImage.exists()){
                outputImage.delete();
            }
            outputImage.createNewFile();
        }catch (IOException e){
            e.printStackTrace();
        }
        if(Build.VERSION.SDK_INT >= 24){
            imageUri = FileProvider.getUriForFile(activity,
                    providerAuthority, outputImage);
        }else{
            imageUri = Uri.fromFile(outputImage);
        }
        return imageUri;


    }

    /**
     * 在权限通过后,可以调用此方法打开相册
     * @param activity 传入当前活动
     */
    public static void openAlbum(Activity activity){
        Intent intent;
        if(IS_LARGER_VERSION_19){
            //4.4版本及以上建议使用这个打开相册
            intent = new Intent("android.intent.action.OPEN_DOCUMENT");
        }else{
            intent = new Intent("android.intent.action.GET_CONTENT");
        }
        intent.setType("image/*");
        activity.startActivityForResult(intent, CHOOSE_PHOTO);
    }

    /**
     * 传入uri返回图片路径,这里不适用FileProvider提供的方式,而是适用SD卡获取
     * @param uri 传入获取到的Intent数据
     * @param activity 传入当前活动
     * @return 返回图片路径
     */
    public static String handleImage(Uri uri, Activity activity){
        String imagePath;
        if(IS_LARGER_VERSION_19){
            //4.4版本以上使用这个而方法处理图片
            imagePath = handleImageNewWay(uri, activity);
        }else{
            imagePath = handleImageOldWay(uri, activity);
        }
        return imagePath;
    }

    private static String handleImageOldWay(Uri uri, Activity activity) {
        String imagePath = getImagePath(uri, null, activity);
        return imagePath;
    }

    @TargetApi(19)
    private static String handleImageNewWay(Uri uri, Activity activity) {
        String imagePath = null;
        if(DocumentsContract.isDocumentUri(activity, uri)){
            //如果是document类型的uri,则通过document id处理
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id = docId.split(":")[1];//解析出数字格式的id
                String selection = MediaStore.Images.Media._ID + "=" + id;
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, activity);
            }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null, activity);
            }
        }else if("content".equalsIgnoreCase(uri.getScheme())){
            //如果content类型的uri,则使用普通方式处理
            imagePath = getImagePath(uri, null, activity);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
            //如果是file类型的Uri,直接截取图片路径即可
            imagePath = uri.getPath();
        }
        return imagePath;
    }

    private static String getImagePath(Uri uri, String selection, Activity activity) {
        String path = null;
        //通过Uri和selection来获取真实的图片路径
        Cursor cursor = activity.getContentResolver().query(uri, null, selection, null, null);
        if(cursor != null){
            if(cursor.moveToFirst()){
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        return path;
    }

    /**
     * 通过provider获得的Uri,相反想获取路径通过此方法获取
     * @param context 当前context上下文,传入活动也可
     * @param uri 通过FileProvider转换而成的封装过的uri
     * @return 返回路径
     */
    public static String getPathByUri(Context context, Uri uri) {

        try {
            List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
            if (packs != null) {
                String fileProviderClassName = FileProvider.class.getName();
                for (PackageInfo pack : packs) {
                    ProviderInfo[] providers = pack.providers;
                    if (providers != null) {
                        for (ProviderInfo provider : providers) {
                            if (uri.getAuthority().equals(provider.authority)) {
                                if (provider.name.equalsIgnoreCase(fileProviderClassName)) {
                                    Class<FileProvider> fileProviderClass = FileProvider.class;
                                    try {
                                        Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class, String.class);
                                        getPathStrategy.setAccessible(true);
                                        Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
                                        if (invoke != null) {
                                            String PathStrategyStringClass = FileProvider.class.getName() + "$PathStrategy";
                                            Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
                                            Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                                            getFileForUri.setAccessible(true);
                                            Object invoke1 = getFileForUri.invoke(invoke, uri);
                                            if (invoke1 instanceof File) {
                                                String filePath = ((File) invoke1).getAbsolutePath();
                                                return filePath;
                                            }
                                        }
                                    } catch (NoSuchMethodException e) {
                                        e.printStackTrace();
                                    } catch (InvocationTargetException e) {
                                        e.printStackTrace();
                                    } catch (IllegalAccessException e) {
                                        e.printStackTrace();
                                    } catch (ClassNotFoundException e) {
                                        e.printStackTrace();
                                    }
                                    break;
                                }
                                break;
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 剪裁图片功能
     * @param activity 传入当前活动
     * @param sourceUri 传入需要剪裁图片的uri
     * @param targetPath 传入需要保存的"文件"路径
     * @param width 传入需要剪裁成的宽度
     * @param height 传入需要剪裁成的高度
     */
    public static void cropImg(Activity activity, Uri sourceUri, String targetPath, int width, int height){
        Intent intent = new Intent("com.android.camera.action.CROP");
        if(IS_LARGER_VERSION_19){
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intent.setDataAndType(sourceUri, "image/*");
        intent.putExtra("crop", "true"); // crop为true是设置在开启的intent中设置显示的view可以剪裁
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        intent.putExtra("return-data", false);
        File file = new File(targetPath);
        if(file.exists()){
            file.delete();
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true); // no face detection
        activity.startActivityForResult(intent, CameraUtil.CROP_PHOTO);
    }

}

2.BitmapUtil(图片处理相关工具类)


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.util.Log;

import java.io.IOException;

public class BitmapUtil {

    /**
     * 此方法用于获取图片选取后旋转角度获取
     * @param filepath 文件路径
     * @return 返回此时照片旋转角度
     */
    public static int getImageDegree(String filepath){
        int degree = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            switch (orientation){
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        }catch (IOException e){
            Log.d("错误", "不能创建出ExifInterface");
        }
        return degree;
    }

    /**
     * 更正图片旋转
     * @param bitmap 目标图片
     * @param degree 需要旋转的角度
     * @return
     */
    public static Bitmap resetImage(Bitmap bitmap, int degree){
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     *
     * @param imgPath map的路径
     * @param sampleSize map的缩放大小,宽和高都同比例缩放
     * @return 返回压缩后的bitmap
     */
    public static Bitmap compressBitmapBySampleSize(String imgPath, int sampleSize){
        BitmapFactory.Options options = new BitmapFactory.Options();
/*        options.inJustDecodeBounds = true;//只去读图片的头信息,不去解析真实的位图
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, options);*/
        options.inSampleSize = sampleSize;
        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, options);
        return bitmap;
    }

/**
     * 使用Matrix将Bitmap压缩到指定大小
     * @param imgPath 图片路径
     * @param w 要压缩的图片宽
     * @param h 要压缩的图片高
     * @return
     */
    public static Bitmap resizeBitmap(String imgPath, int w, int h)
    {
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        float scaleWidth = ((float) w) / width;
        float scaleHeight = ((float) h) / height;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);

        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width,
                height, matrix, true);//使用bitmap,从(x,y)点开始,截取宽width,高height,根据matrix进行缩放,filter=true表示对其进行剪裁操作
        return resizedBitmap;
    }


}

MainActivity


import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn1, btn2;

    private ImageView img1, img2;

    private Uri imageUri;

    private String targetCropPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListener();
    }

    private void initView() {
        btn1 = (Button) findViewById(R.id.btn1);
        btn2 = (Button) findViewById(R.id.btn2);
        img1 = (ImageView) findViewById(R.id.img1);
        img2 = (ImageView) findViewById(R.id.img2);
    }

    private void initListener() {
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn1:
                take_photo();
                break;
            case R.id.btn2:
                choose_photo();
                break;
            default:
                break;
        }
    }

    private void choose_photo() {
        //权限确认
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }else{
            CameraUtil.openAlbum(this);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    CameraUtil.openAlbum(this);
                }else{
                    Toast.makeText(this, "您拒绝赋予此权限", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    private void take_photo() {
        //启动相机程序
        imageUri = CameraUtil.getPhotoUri(this, "com.frz.marryapp.activity.fileprovider");
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, CameraUtil.TAKE_PHOTO);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        targetCropPath = getExternalCacheDir() + File.separator + "temp.jpg";
        switch (requestCode){
            case CameraUtil.TAKE_PHOTO:
                if(resultCode == RESULT_OK){
                    //将拍摄的照片显示出来
                    //正数为顺时针旋转
                    String imagePath = CameraUtil.getPathByUri(this, imageUri);
                    Bitmap bitmap1 = BitmapFactory.decodeFile(imagePath);
                    bitmap1 = BitmapUtil.resetImage(bitmap1, BitmapUtil.getImageDegree(imagePath));
                    img1.setImageBitmap(bitmap1);
                    CameraUtil.cropImg(this, imageUri, targetCropPath, 500, 500);
                }
                break;
            case CameraUtil.CHOOSE_PHOTO:
                if(resultCode == RESULT_OK){
                    String imagePath = CameraUtil.handleImage(data.getData(), this);
                    Bitmap bitmap1 = BitmapFactory.decodeFile(imagePath);
                    bitmap1 = BitmapUtil.resetImage(bitmap1, BitmapUtil.getImageDegree(imagePath));
                    img1.setImageBitmap(bitmap1);
                    CameraUtil.cropImg(this, data.getData(), targetCropPath, 500, 500);
                }
                break;
            case CameraUtil.CROP_PHOTO:
                if(resultCode == RESULT_OK){
                    Bitmap bitmap = BitmapFactory.decodeFile(targetCropPath);
                    bitmap = BitmapUtil.resetImage(bitmap, BitmapUtil.getImageDegree(targetCropPath));
                    img2.setImageBitmap(bitmap);
                }
                break;
        }

    }
}

 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="before"/>
        <ImageView
            android:id="@+id/img1"
            android:layout_width="match_parent"
            android:layout_height="400dp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="after"/>

        <ImageView
            android:id="@+id/img2"
            android:layout_width="match_parent"
            android:layout_height="400dp" />

        <Button
            android:id="@+id/btn1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="拍照"/>

        <Button
            android:id="@+id/btn2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="选取照片"/>

    </LinearLayout>

</ScrollView>

效果:

照片点击确定后,自动伸张为500X500,如果选取的区域过小,其分辨率将会很低

猜你喜欢

转载自blog.csdn.net/a568283992/article/details/81179224
今日推荐