Android 拍照后图片处理

安卓拍照或选择的图片自动旋转处理

在安卓开发中,经常使用相机或是选择照片的功能,但是在部分手机上拍照或选择图片后,发现图片被自动旋转了。那我们怎么处理呢?相信这个不难,很多人都能轻易想到。下面是如果是H5调用原生相机获取照片,需要原生将图片存储后继续返回Uri路径。

处理步骤如下:

  1. 根据拍照或选择照片的Uri获取图片Path 
  2. 根据图片Path获取其EXIF信息,包括图片旋转的角度
  3. 将URI转换成Bitmap对象
  4. 对Bitmap对象做旋转处理
  5. 将旋转的Bitmap存储,然后获取存储后的Uri

1、根据Uri获取图片绝对路径

    /**
     * 根据Uri返回文件绝对路径
     * 兼容了file:///开头的 和 content://开头的情况
     * @param context
     * @param uri
     * @return
     */
    public static String getRealFilePathFromUri(final Context context, final Uri uri) {
        if (null == uri) {
            return null;
        }
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
            Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }

2、根据图片Path获取其EXIF信息,包括图片旋转的角度

     /**
     * 读取图片的旋转的角度
     *
     * @param path
     *            图片绝对路径
     * @return 图片的旋转角度
     */
    private int getBitmapDegree(String path) {
        int degree = 0;//被旋转的角度
        try {
            // 从指定路径下读取图片,并获取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 获取图片的旋转信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            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) {
            e.printStackTrace();
        }
        return degree;
    }

3、将URI转换成Bitmap对象

a) 获取图片的宽高

public static int[] getImageWidthHeight(Context context, Uri uri) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        //最关键在此,把options.inJustDecodeBounds = true;
        //这里再decodeFile(),返回的bitmap为空,但此时调用options.outHeight时,已经包含了图片的高了

        options.inJustDecodeBounds = true;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
                FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
                parcelFileDescriptor.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Bitmap bitmap = BitmapFactory.decodeFile(FileUtil.getRealFilePathFromUri(context, uri), options); // 此时返回的bitmap为null
        }
        //options.outHeight为原始图片的高
        return new int[]{options.outWidth, options.outHeight};
    }

b)获取Bitmap图片

     /**
     * 图片等比例压缩
     *
     * @param uri
     * @param reqWidth  期望的宽
     * @param reqHeight 期望的高
     * @return
     */
    public static Bitmap decodeSampledBitmap(Context context, Uri uri, int reqWidth,
                                             int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        //bitmap is null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
                FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);

                // Calculate inSampleSize
                int inSampleSize = calculateInSampleSize(options, reqWidth,
                        reqHeight);
                Log.i(TAG, "decodeSampledBitmap: inSampleSize = " + inSampleSize);
                options.inSampleSize = inSampleSize;

                // Decode bitmap with inSampleSize set
                options.inJustDecodeBounds = false;
                return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            Bitmap bitmap = BitmapFactory.decodeFile(FileUtil.getRealFilePathFromUri(context, uri), options);
            // Calculate inSampleSize
            int inSampleSize = calculateInSampleSize(options, reqWidth,
                    reqHeight);
            Log.i(TAG, "decodeSampledBitmap: inSampleSize = " + inSampleSize);
            options.inSampleSize = inSampleSize;
            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(FileUtil.getRealFilePathFromUri(context, uri), options);
        }
        return null;
    }

4 、对Bitmap对象做旋转处理

    /**
     * 将图片按照某个角度进行旋转
     * @param bm 需要旋转的图片
     * @param degree 旋转角度
     * @return 旋转后的图片
     */
    private Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
        Bitmap returnBm = null;

        // 根据旋转角度,生成旋转矩阵
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        try {
            // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
        }
        if (returnBm == null) {
            returnBm = bm;
        }
        if (bm != returnBm) {
            bm.recycle();
        }
        return returnBm;
    }

5、将旋转的Bitmap存储,然后获取存储后的Uri

private Uri saveBitmapToFile(Uri singleUri,Bitmap bitmap){

        try {
            String path = singleUri.toString();
            String fileName = path.substring(singleUri.toString().lastIndexOf("/"))+".JPEG";
            File filesDir = context.getExternalFilesDir(Environment.DIRECTORY_DCIM);
            File file = new File(filesDir,fileName);
            FileOutputStream fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
            fos.flush();
            fos.close();
            return Uri.fromFile(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

将图片角度测量和旋转转图片已经储封装工具类如下:

package com.bobfintech.module_webview.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;

import androidx.appcompat.app.AppCompatActivity;
import androidx.exifinterface.media.ExifInterface;

import com.bobfintech.by_base.utils.BitmapUtil;
import com.bobfintech.by_base.utils.FileUtil;
import com.bobfintech.by_lib.utils.LogUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * author : wdx
 * time    : 2021/1/4
 * 计算图片角度
 **/
public class BitmapDegreeHandle {
    private static BitmapDegreeHandle instance;
    private Context context;
    private BitmapHandlerListener mListener;
    private Thread mHandleThead;

    private BitmapDegreeHandle(Context context){
        this.context = context;
    }

    public static BitmapDegreeHandle init(Context context){

        if (instance == null){
            synchronized (BitmapDegreeHandle.class){
                if (instance == null){
                    instance = new BitmapDegreeHandle(context);
                }
            }
        }
        return instance;
    }
    public BitmapDegreeHandle build(BitmapHandlerListener handle){
        this.mListener = handle;
        return instance;
    }
    public void handle(final Uri[]uris){
        mHandleThead = new Thread(new Runnable() {
            @Override
            public void run() {
                instance.unifyAllUriHandle(uris);
            }
        });
        mHandleThead.start();
    }
    /**
     * 读取图片的旋转的角度
     *
     * @param path
     *            图片绝对路径
     * @return 图片的旋转角度
     */
    private int getBitmapDegree(String path) {
        int degree = 0;//被旋转的角度
        try {
            // 从指定路径下读取图片,并获取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 获取图片的旋转信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            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) {
            e.printStackTrace();
        }
        return degree;
    }
    /**
     * 将图片按照某个角度进行旋转
     * @param bm 需要旋转的图片
     * @param degree 旋转角度
     * @return 旋转后的图片
     */
    private Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
        Bitmap returnBm = null;

        // 根据旋转角度,生成旋转矩阵
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        try {
            // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
        }
        if (returnBm == null) {
            returnBm = bm;
        }
        if (bm != returnBm) {
            bm.recycle();
        }
        return returnBm;
    }

    private Uri saveBitmapToFile(Uri singleUri,Bitmap bitmap){

        try {
            String path = singleUri.toString();
            String fileName = path.substring(singleUri.toString().lastIndexOf("/"))+".JPEG";
            File filesDir = context.getExternalFilesDir(Environment.DIRECTORY_DCIM);
            File file = new File(filesDir,fileName);
            FileOutputStream fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
            fos.flush();
            fos.close();
            return Uri.fromFile(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    private Uri singleUriHandle(Uri singleUri){
        String path = FileUtil.getRealFilePathFromUri(context, singleUri);
        LogUtils.i("evan", "*********path*******  " + path);
        if (TextUtils.isEmpty(path)) {
            return singleUri;
        }
        int degree = getBitmapDegree(path);
        LogUtils.i("evan", "*********degree*******  " + degree);
        if (degree ==0){
            return singleUri;
        }

        int[] imageWidthHeight = BitmapUtil.getImageWidthHeight(context, singleUri);
        int w = imageWidthHeight[0];
        int h = imageWidthHeight[1];

        Bitmap bitmap = BitmapUtil.decodeSampledBitmap(context, singleUri,  w, h);

        if (bitmap == null) {
            return singleUri;
        }
        Bitmap resutBitmap = rotateBitmapByDegree(bitmap, degree);

        Uri resultUri = saveBitmapToFile(singleUri, resutBitmap);
        LogUtils.i("evan", "*********resultUri*******  " + resultUri);
        if (resultUri == null){
            return singleUri;
        }
        return resultUri;
    }

    private void unifyAllUriHandle(final Uri[] results ){
        final Uri[] mUri = new Uri[results.length];
        try {
            for(int i=0;i<mUri.length;i++){
                Uri uri = singleUriHandle(results[i]);
                mUri[i] = uri;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ((AppCompatActivity)context).runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mListener.onSuccess(mUri);
                }
            });
            if (mHandleThead !=null){
                mHandleThead =null;
            }
        }

    }

    public interface BitmapHandlerListener{
        void onSuccess(Uri[]results);
    }
}

在打开相机或打开相册获取Uri后调用如下:

 Uri[] results = pathList.toArray(new Uri[pathList.size()]);
 BitmapDegreeHandle.init(this).build(new BitmapDegreeHandle.BitmapHandlerListener() {
      @Override
      public void onSuccess(Uri[] results) {
         if (!isFinishing()){
            uploadMessage.onReceiveValue(results);
         }
         uploadMessage = null;
     }
 }).handle(results);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值