Android Bitmap尺寸压缩和质量压缩

作者:陆金龙    发表时间:2017-10-22 12:04   


Bitmap尺寸压缩

    在图片显示或处理时,经常需要创建Bitmap对象。由于Bitmap占用内存是跟图片的像素点数量直接相关的,因此图片尺寸的大小对内存的占用有很大的影响。如2560x3840尺寸的照片,如果ARGB_4444格式直接加载到Bitmap,占用内存中2560x3840x2/(1024x1024)=18.75M,如果以ARGB_8888格式直接加载则占用内存37M。Android虚拟机默认分配给应用的内存为16M,这样很容易就发生OOM(OutOfMemory)错误。

    在满足显示要求的前提下,应尽量减小Bitmap的宽高尺寸。

    从图片文件读取为Bitmap对象,可根据需要显示的大小,计算出采样率,然后创建出合适尺寸的Bitmap对象,尽可能减小对内存的占用。

     //*
     * 根据采样率从文件获取位图图片
     *
     * @param srcPath      文件路径
     * @param inSampleSize 采样率 图片的采样率: 数值越高,图片像素越低。
     * @return 通过采样率进行尺寸压缩的位图对象
     
    public static Bitmap getBitmap(String srcPath, int inSampleSize) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inSampleSize = inSampleSize;
        opts.inPurgeable = true;// 同时设置才会有效
        opts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
        Bitmap resizeBmp = BitmapFactory.decodeFile(srcPath, opts);
        return resizeBmp;
    }
 
     //*
     * 根据需要显示的宽度获取合适大小的位图
     *
     * @param srcPath      文件路径
     * @param width  图片需要显示的宽度
     * @return 通过采样率进行尺寸压缩的位图对象
     
    public static Bitmap getBitmap(String imagePath, int width) {
        // 获取采样率
       BitmapFactory.Options options = new BitmapFactory.Options(); 
       options.inJustDecodeBounds = true; // 只获取图片的大小信息,不将整张图片载入在内存中,避免内存溢出 
       BitmapFactory.decodeFile(imagePath, options); 
       inSampleSize = (int)Math.ceil(options.outWidth/width); // 计算像素压缩比例 
       
       // 加载原图
       options.inJustDecodeBounds = false; 
       options.inSampleSize = inSampleSize; // 设置为刚才计算的压缩比例 
       opts.inPurgeable = true;// 同时设置才会有效
       opts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
       Bitmap  resizeBmp = BitmapFactory.decodeFile(imagePath, options); // 解码文件
       return resizeBmp;
    }
 
    注:
    
     * BitmapFactory.Options.inPurgeable; 
     *  
     * 如果 inPurgeable 设为True的话表示使用BitmapFactory创建的Bitmap 
     * 用于存储Pixel的内存空间在系统内存不足时可以被回收, 
     * 在应用需要再次访问Bitmap的Pixel时(如绘制Bitmap或是调用getPixel), 
     * 系统会再次调用BitmapFactory decoder重新生成Bitmap的Pixel数组。  
     * 为了能够重新解码图像,bitmap要能够访问存储Bitmap的原始数据。 
     *  
     * 在inPurgeable为false时表示创建的Bitmap的Pixel内存空间不能被回收, 
     * 这样BitmapFactory在不停decodeByteArray创建新的Bitmap对象, 
     * 不同设备的内存不同,因此能够同时创建的Bitmap个数可能有所不同, 
     * 200个bitmap足以使大部分的设备重新OutOfMemory错误。 
     * 当isPurgable设为true时,系统中内存不足时, 
     * 可以回收部分Bitmap占据的内存空间,这时一般不会出现OutOfMemory 错误

Bitmap质量压缩

   在图片文件上传时,不希望图片太大,占用过多浏览,可以对图片适当进行质量压缩,另存为文件再上传。

   //*
     * 质量压缩减小图片文件的存储大小
     *
     * @param bmp
     * @param file
     
    public static void compressBitmap(Bitmap bmp, File file) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  
 
      //*
     * 质量压缩减小图片文件的存储大小
     *
     * @param bmp
     * @param file
     * @param quantity 压缩质量 1-100,  100为不压缩 ,值越小 压缩越厉害
     
    public static void compressBitmap(Bitmap bmp, File file, int quantity) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, quantity, baos);//如果需要透明 使用Bitmap.CompressFormat.PNG
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }