zoukankan      html  css  js  c++  java
  • android 通过uri获取bitmap图片并压缩

    很多人在调用图库选择图片时会在onActivityResult中用Media.getBitmap来获取返回的图片,如下:

                            Uri mImageCaptureUri = data.getData();
                            Bitmap photoBmp = null;
                            if (mImageCaptureUri != null) {
                                photoBmp = MediaStore.Images.Media.getBitmap(ac.getContentResolver(), mImageCaptureUri);
                            }
    

    但是Media.getBitmap这个方法获取已知uri图片的方式并不可取,咱来看看Media.getBitmap()方法的源码:

    public static final Bitmap getBitmap(ContentResolver cr, Uri url)
            throws FileNotFoundException, IOException {
        InputStream input = cr.openInputStream(url);
        Bitmap bitmap = BitmapFactory.decodeStream(input);
        input.close();
        return bitmap;
    }
    

    其实它很简单很粗暴,返回的是原始大小的bitmap,当图库选择的图片很大时程序极有可能会报OOM。

    为了避免OOM,咱们需要改进该方法,在 BitmapFactory.decodeStream 之前压缩图片,以下是我改进后的代码:

    在onActivityResult中调用

        Uri mImageCaptureUri = data.getData();
    
        Bitmap photoBmp = null;
    
        if (mImageCaptureUri != null) {
    
        photoBmp = getBitmapFormUri(ac, mImageCaptureUri);
    
        }
    
    /**
         * 通过uri获取图片并进行压缩
         *
         * @param uri
         */
        public static Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException {
            InputStream input = ac.getContentResolver().openInputStream(uri);
            BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
            onlyBoundsOptions.inJustDecodeBounds = true;
            onlyBoundsOptions.inDither = true;//optional
            onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
            BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
            input.close();
            int originalWidth = onlyBoundsOptions.outWidth;
            int originalHeight = onlyBoundsOptions.outHeight;
            if ((originalWidth == -1) || (originalHeight == -1))
                return null;
            //图片分辨率以480x800为标准
            float hh = 800f;//这里设置高度为800f
            float ww = 480f;//这里设置宽度为480f
            //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int be = 1;//be=1表示不缩放
            if (originalWidth > originalHeight && originalWidth > ww) {//如果宽度大的话根据宽度固定大小缩放
                be = (int) (originalWidth / ww);
            } else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的话根据宽度固定大小缩放
                be = (int) (originalHeight / hh);
            }
            if (be <= 0)
                be = 1;
            //比例压缩
            BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
            bitmapOptions.inSampleSize = be;//设置缩放比例
            bitmapOptions.inDither = true;//optional
            bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
            input = ac.getContentResolver().openInputStream(uri);
            Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
            input.close();
    
            return compressImage(bitmap);//再进行质量压缩
        }
    
     /**
         * 质量压缩方法
         *
         * @param image
         * @return
         */
        public static Bitmap compressImage(Bitmap image) {
    
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
            int options = 100;
            while (baos.toByteArray().length / 1024 > 100) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩
                baos.reset();//重置baos即清空baos
                //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流
                image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
                options -= 10;//每次都减少10
            }
            ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
            Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
            return bitmap;
        }
    

    OOM的问题解决了,但是又碰到另外一个问题,用三星手机拍照或者选择照片后返回来的图片居然转了90度。。苦逼的android程序员。。接着改。。

    讲onActivityResult中的代码进行改进:

              Uri originalUri = null;
                    File file = null;
                    if (null != data && data.getData() != null) {
                        originalUri = data.getData();
                        file = getFileFromMediaUri(ac, originalUri);
                    }
               Bitmap photoBmp = getBitmapFormUri(ac, Uri.fromFile(file));
                int degree = getBitmapDegree(file.getAbsolutePath());
                /**
                 * 把图片旋转为正的方向
                 */
                Bitmap newbitmap = rotateBitmapByDegree(photoBmp, degree);
    
    /**
         * 通过Uri获取文件
         * @param ac
         * @param uri
         * @return
         */
        public static File getFileFromMediaUri(Context ac, Uri uri) {
            if(uri.getScheme().toString().compareTo("content") == 0){
                ContentResolver cr = ac.getContentResolver();
                Cursor cursor = cr.query(uri, null, null, null, null);// 根据Uri从数据库中找
                if (cursor != null) {
                    cursor.moveToFirst();
                    String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 获取图片路径
                    cursor.close();
                    if (filePath != null) {
                        return new File(filePath);
                    }
                }
            }else if(uri.getScheme().toString().compareTo("file") == 0){
                return new File(uri.toString().replace("file://",""));
            }
                return null;
            }
    
    /**
         * 读取图片的旋转的角度
         *
         * @param path 图片绝对路径
         * @return 图片的旋转角度
         */
        public static 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 旋转后的图片
         */
        public static 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;
        }
    

    好了,问题搞定!

  • 相关阅读:
    团队博客----用户需求调研报告
    结对开发----买书问题
    团队开发----NABC分析
    js 中中括号,大括号使用详解
    FileZilla Server 防火墙端口开启设置 windows 2008 win
    在其他的电脑上配置绿色Jre+tomcat运行环境
    工资发给平庸,高薪给予责任。奖金发给成绩,股权分给态度,荣誉颁给理想!
    SSH框架(四) struts2+spring3.0的登陆示例
    SSH框架(三) struts2的登陆示例
    SSH (Struts2+Spring3.0+Hibernate3)框架(二) 框架的配置
  • 原文地址:https://www.cnblogs.com/popqq520/p/5404738.html
Copyright © 2011-2022 走看看