前些天参加面试时,被问到的一个问题是:Android里面压缩图片有什么方法。当时只用了瀑布流照片墙的一些方法来回答,还是不够清楚,答得不太满意。现在就来总结一下Android中压缩图片的一些基本知识和流程。

一、引言

在移动开发中,图片压缩是一个非常重要的方面,因为设备内存有限,如果不对图片进行处理的话,可能会引起OOM;在瀑布流等图片经典demo中也使用了相应的处理,压缩图片等等。

现在先来了解一下Android图片的存在方式:
1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 增大的倍数是很可观的

检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap: bitmap.getByteCount()

二、常用的图片压缩方法

**

1. BitmapFactory的decodeFile方法

**

特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩

首先,在处理图片的方法中,官方demo中推荐的也是这种方法。
结合现实场景来看,我们通常会将图片固定大小成缩略图,使用的就是decodeFile方法,然后通过传递进去 BitmapFactory.Option类型的参数取缩略图。

Option类在百度地图sdk或者其它地方中也看到过,可以说是参数或者限定的集和吧。在Option中,有两个重要的地方,一是inSampleSize表示采样率长宽压缩的比例,另外的就是inJustDecodeBounds,就是表示只包括一些解码边界信息即图片大小信息等等。举个具体的例子来说,还是以官方demo为主来讲吧:
inSampleSize表示缩略图大小为原始图片大小的几分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。
而inJustDecodeBounds设置为true的时候,就是提取图片大小信息,不返回实际的bitmap也不给其分配内存空间,但记得用完后就要把它设为false;

/** * 计算压缩比率 */    public static int calculateInSampleSize(BitmapFactory.Options options,                                            int reqWidth) {        // 源图片的宽度        final int width = options.outWidth;        int inSampleSize = 1;        if (width > reqWidth) {            // 计算出实际宽度和目标宽度的比率            final int widthRatio = Math.round((float) width / (float) reqWidth);            inSampleSize = widthRatio;        }        return inSampleSize;    } /** * 官方文档的用法改写,这是一个系列的 * http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html * @param pathName * @param reqWidth * @return */    public static Bitmap decodeSampledBitmapFromResource(String pathName,                                                         int reqWidth) {        // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小        final BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(pathName, options);        // 调用上面定义的方法计算inSampleSize值        options.inSampleSize = calculateInSampleSize(options, reqWidth);        // 使用获取到的inSampleSize值再次解析图片        options.inJustDecodeBounds = false;        return BitmapFactory.decodeFile(pathName, options);    }

简要总结:
该方法就是对Bitmap形式的图片进行压缩, 也就是通过设置采样率, 减少Bitmap的像素, 从而减少了它所占用的内存。一般过程就是:
使用2的次幂来设置inSampleSize值可以使解码器执行地更加迅速、更加高效。但是,如果你想在内存或者硬盘上缓存一个调整过大小的图片,通常还是解码到合适的图片尺寸更加节省空间。

要使用这个方法,首先要使用inJustDecodeBounds为true来解码尺寸信息,将options传递过去使用新的inSampleSize值再次解码并且要将inJustDecodeBounds值设置为false。最后通过BitmapFactory.decode**的方法压缩。

2. 将图片保存到本地时进行压缩, 即将图片从Bitmap形式变为File形式时进行压缩,

特点是: File形式的图片确实被压缩了, 只对File格式进行质量压缩。注意:如果读取压缩后的file为Bitmap时,它占用的内存并没有改变

public static void compressBmpToFile(Bitmap bmp,File file){        ByteArrayOutputStream baos = new ByteArrayOutputStream();        int options = 80;//设置开始的compress系数        bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);        while (baos.toByteArray().length / 1024 > 100) {             baos.reset();            options -= 10;            bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);        }        try {            FileOutputStream fos = new FileOutputStream(file);            fos.write(baos.toByteArray());            fos.flush();            fos.close();        } catch (Exception e) {            e.printStackTrace();        }    }

方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100K以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700, 计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(), 图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的.

该方法的官方文档也解释说, 它会让图片重新构造, 但是有可能图像的位深(即色深)和每个像素的透明度会变化,JPEG only supports opaque(不透明), 也就是说以jpeg格式压缩后, 原来图片中透明的元素将消失.所以这种格式很可能造成失真

既然它是改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩的file为Bitmap时, 它占用的内存并不会少.

所以呢,这种方法比较适用上传服务器时的图片压缩

更多相关文章

  1. android扫描sdcard中的音视频及图片等文件
  2. Android单点触控技术,对图片进行平移,缩放,旋转操作
  3. (六)android recovery 升级UI显示之资源文件
  4. FontAwesome-用TextView显示图片
  5. .9图片的制作(draw9patch.bat工具的使用)
  6. Android(安卓)studio进阶之多语言/图片--国际化
  7. 【Android(安卓)Training - 09】高效地显示Bitmap图片 [ Lesson
  8. android图片旋转处理
  9. android基于gpuimage和photoview的图片编辑(滤镜,饱和度,裁剪)

随机推荐

  1. 解决:Failed to fectch URl https://dl-ss
  2. Android 对话框(Dialog)大全 建立你自己
  3. Android 进阶——Material Design新控件
  4. Maven开发Android指南 4 与Eclipse整合(m2
  5. Android的滑动手势处理
  6. Android开发——工欲善其事必先利其器
  7. android应用程序fps meter[帧数显示]的分
  8. ISurfaceComposer接口有13个成员函数
  9. Android 日志系统logcat内核代码分析
  10. ubuntu环境:下载、编译模拟器平台android