图片压缩

来源:互联网 发布:qq飞车白银帝王数据 编辑:程序博客网 时间:2024/06/16 09:31

0x01-从图库中选择图片

这点不难,通过隐式意图跳转到图库,然后在onActivityResult中拿到返回结果 
这里面需要注意以下几点: 
1、选择图库中的照片在6.0之后个别手机需要权限,如华为;你会发现图库可以跳转进去,但是选中图片之后会报没有相关权限,这里主要是存储权限,华为手机比较特殊,需要去申请运行时权限。 
2、onActivityResult中返回的是一个Uri,需要根据Uri翻查图片的真实路径,在Android4.4之后对图库做了调整,需要通过不同的方式进行查询;正常情况下Uri是以content开头但是有一种情况是特例,比如小米云相册(这个现在不知道是否已经统一),返回的Uri是file开头的,需要单独处理。代码如下:

Intent intent = new Intent(Intent.ACTION_PICK, null);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");startActivityForResult(intent, REQUEST_CODE_NATIVE_PHOTO);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
public static String getPhotoPath(Context context, Uri uri) {        String filePath = "";        if (uri != null) {            Log.d(TAG, uri.toString());            String scheme = uri.getScheme();            if (TextUtils.equals("content", scheme)) {// android 4.4以上版本处理方式                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT                        && DocumentsContract.isDocumentUri(context, uri)) {                    String wholeID = DocumentsContract.getDocumentId(uri);                    String id = wholeID.split(":")[1];                    String[] column = { MediaStore.Images.Media.DATA };                    String sel = MediaStore.Images.Media._ID + "=?";                    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,                            column, sel, new String[] { id }, null);                    if (cursor != null && cursor.moveToFirst()) {                        int columnIndex = cursor.getColumnIndex(column[0]);                        filePath = cursor.getString(columnIndex);                        cursor.close();                    }                } else {// android 4.4以下版本处理方式                    String[] filePathColumn = { MediaStore.Images.Media.DATA };                    Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);                    if (cursor != null && cursor.moveToFirst()) {                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);                        filePath = cursor.getString(columnIndex);                        Log.d(TAG, "filePath" + filePath);                        cursor.close();                    }                }            } else if (TextUtils.equals("file", scheme)) {// 小米云相册处理方式                filePath = uri.getPath();            }        }        return filePath;    }
  • 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
  • 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

0x02-尺寸压缩之inSampleSize

这个都知道是为了防止加载图片时内存溢出,需要先计算采样率,然后再去加载图片这里要说的也有两点: 
1、inSampleSize只能是2的次方,如计算结果是7会按4进行压缩,计算结果是15会按8进行压缩。 
2、存在两种算法: 
算法一:图片长与目标长比,图片宽与目标宽比,取最大值(不过也有人取最小值,怕压缩的太多吗?取最小值会遇到的问题举个例子,满屏加载长截图的时候,图片宽与屏幕宽为1:1,这样inSampleSize就为1,没有压缩那么很容易就内存溢出了),不管怎么都欠妥;因为如果手机是横屏拍摄,或者是拍摄的全景图,那么图片宽与目标宽的比例会很增大,这样压缩的比例会偏大。

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {        final int width = options.outWidth;        final int height = options.outHeight;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            //计算图片高度和我们需要高度的最接近比例值            final int heightRatio = Math.round((float) height / (float) reqHeight);            //宽度比例值            final int widthRatio = Math.round((float) width / (float) reqWidth);            //取比例值中的较大值作为inSampleSize            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;        }        return inSampleSize;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

算法二:取目标长宽的最大值来计算,这样会减少过度的尺寸压缩,

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {        final int width = options.outWidth;        final int height = options.outHeight;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            //使用需要的宽高的最大值来计算比率            final int suitedValue = reqHeight > reqWidth ? reqHeight : reqWidth;            final int heightRatio = Math.round((float) height / (float) suitedValue);            final int widthRatio = Math.round((float) width / (float) suitedValue);            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;//用最大        }        return inSampleSize;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

0x03-质量压缩之quality

发现很多人有一个错误认识,本人曾经也不例外,就是误以为,这个比例是文件压缩前后大小的比值,因此会用目标大小/目前文件大小,来计算这个quality,其实这是错误的。因为这完全是两码事,比如压缩前是1.5M,目标大小是1M,好大概计算一下是60左右,压完了之后你可能会发现图片只有100多k;好像没有可以直接算出来这个比例的方法,常见的都是尝试式的算法,如从100开始,每次减少6,压缩一次比较一次,直到满足条件,当然这个可以自己调整。

ByteArrayOutputStream baos = new ByteArrayOutputStream();int option = 100;bitmap.compress(Bitmap.CompressFormat.JPEG, option, baos);while (baos.toByteArray().length / 1024 > maxSize&&option>6) {    baos.reset();    option -= 6;    bitmap.compress(Bitmap.CompressFormat.JPEG, option, baos);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

0x04-图片的旋转角度之ExifInterface

图片的旋转角度在很多人做压缩的时候都会加上一笔,这个说实话我没有太多的研究,因为我用的手机不管怎么弄旋转角度都是0;如我们竖着拍照,图库里面的照片是竖着显示的;横着拍照,之后发现图库里面的照片是横着显示的(宽>高的形式展示),但是旋转角度都是0;然后我又把其中一张照片编辑一下 让它旋转一下保存,发现之后的旋转角度依然是0。可能是我的手机的问题,也可能是这个旋转角度会在个别手机上有体现。废话不多说贴上代码

private int getImageSpinAngle(String path) {        int degree = 0;        try {            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;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

0x05-延伸

介绍一些github知名的压缩算法,luban算法 
https://github.com/Curzibn/Luban.git 
https://github.com/shaohui10086/AdvancedLuban 
当然这都是从参数上的优化,star很多问题也很多,说明并非所有需求都适用,最重要的还是能够满足项目需求的算法才是最好的。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 门牙牙齿蛀掉了怎么办 吃了辣的牙齿痛怎么办 牙颈部楔状缺损怎么办 牙齿磨了很疼怎么办 小孩牙有窟窿疼怎么办 西瓜吃多了尿不停怎么办 吃了个西瓜不停拉肚子怎么办 例假完了又来了怎么办 肾上面有个肿瘤怎么办 膀胱壁毛糙增厚怎么办 痔疮手术后尿不出来怎么办 小牛肚一天不尿怎么办 小孩拉肚一直不好怎么办 尿涨但是尿很少怎么办 十四岁尿血医生说是肾炎怎么办 吃肉反胃想吐怎么办 母牛排尿带血尿发烧怎么办 4岁发烧40度怎么办 狗狗拉肚子咳漱哮喘怎么办 拉肚子拉脱水人无力怎么办 孕中期拉稀拉水怎么办 吃坏肚子拉稀水怎么办 手上起小疙瘩疼怎么办 手上长东西很痛怎么办 七八十斤猪拉稀怎么办 宝宝扁桃体化脓反复发烧怎么办 骑单车后膝盖痛怎么办 孩子一运动就喘怎么办 小孩晚上咳嗽很厉害怎么办 1岁宝宝夜里咳嗽怎么办 咳嗽咳的胸疼怎么办 儿童又咳又喘怎么办 咳嗽咳到胸口痛怎么办 咳嗽咳得肋骨疼怎么办 孕妇咳嗽咳得胸口疼怎么办 怀孕偏左侧宫腔怎么办 晨起活动后咳嗽怎么办 运动后乳房坠痛怎么办 嗓子痒咳嗽怎么办夜间最为难受 小孩鼻炎引起的咳嗽怎么办 跑完800米喉咙痒怎么办