前段时间,项目的一个需求涉及图片压缩之后上传。要求是压缩之后的图片要和原图尺寸一致,压缩后的大小控制在< 600KB,并且重新加载的时候不能卡顿更不能OOM,在此做一下记录。

质量压缩

使用方式:

public String compressAndImage(Bitmap image) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    //压缩比重,图片存储在磁盘上的大小会根据这个值变化。值越小存储在磁盘的图片文件越小,取值
    //区间为0-100,小于0时会抛异常
    int options = 100;
    image.compress(Bitmap.CompressFormat.JPEG, options, os);
    // Compress by loop
    while (os.toByteArray().length / 1024 > 500) {
        os.reset();
        if (options > 10) {
            options -= 10;
            image.compress(Bitmap.CompressFormat.JPEG, options, os);
        } else {
            options = 1;
            image.compress(Bitmap.CompressFormat.JPEG, options, os);
            break;
        }
    }
    File file = new File("图片路径");
    // Generate compressed image file
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(os.toByteArray());
    fos.flush();
    fos.close();
    return file.getAbsolutePath();
}

Bitmap.CompressFormat.PNG无效。

采样率压缩

使用方式:

public Bitmap handleImageToBitmap() {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        //此时只是为了获取当inJustDecodeBounds设置为true的时候,
        // BitmapFactory通过decodeResource或者decodeFile解码图片时,
        // 返回的Bitmap对象为null,这样可以避免Bitmap的内存分配,
        // 但是它可以获取Bitmap的宽度、高度
        BitmapFactory.decodeFile("文件路径", options);

        options.inJustDecodeBounds = false;
        //采样率,这个值决定了压缩后的图片大小
        options.inSampleSize = 2;

        return BitmapFactory.decodeFile("文件路径", options);
}

采样率压缩改变了图片的尺寸大小,减少了图片的像素点数,使得加载进内存的对象也变小了,当然对应图片保存到磁盘上所占空间也会变小。这些都取决于采样率的设定。一般这种压缩方式在做缩略图时用的较多。另附上做缩略图时,采样率(options.inSampleSize)的值设置方式:

public static int handleSampleSize(BitmapFactory.Options options, int aimsWidth, int aimsHeight) {
        int height = options.outHeight;//获取原始图片的高度
        int width = options.outWidth;//获取原始图片的宽度
        //inSampleSize小于等于1会按照1处理
        //inSampleSize只能设置为2的平方,不是2的平方则最终会减小到最近的2的平方数,如设置7会按4进行压缩。
        int inSampleSize = 1;//设置初始采样率

        if (height > aimsHeight || width > aimsWidth) {
            final int heightRatio = Math.round((float) height / (float) aimsHeight);
            final int widthRatio = Math.round((float) width / (float) aimsWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

尺寸压缩

即通过压缩图片尺寸而改变图片的大小。

public static Bitmap zoomCompress(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.setScale(0.5f, 0.5f);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
}

RGB_565压缩

在Android中,图片在内存是以Bitmap对象存在的,Bitmap所占内存计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数

图片的压缩格式共有以下四种:

ALPHA_8:表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度
ARGB_4444:表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节
ARGB_8888:表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节
RGB_565:表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节

ARGB_4444压缩出来的画质很差,所以对透明度没有要求的话可以采用RGB_565的方式进行压缩:

public static Bitmap rgbCompress(String imgPath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(imgPath, options);
}

也可以采用ARGB_8888,只不过压缩出来大小变化可能会很小。

第三方

鲁班压缩------接近微信朋友圈的压缩方法

放一张作者提供的效果对比图:

Glide图片压缩 android android图片压缩到200-300kb_图片压缩

具体使用方法上面链接里有,就不多做叙述。这种方案适合那种,要求图片压缩后尺寸不变、体积要变小加载进内存的对象也要变小的需求,亲测效果还不错,而且压缩出来的图片也不会模糊,压缩出来的格式是JPEG

总结

使用每种压缩方式都要根据自己的需要来选择,有时候可能需要其中两种方式组合使用。对于第三方的选择上要慎重,毕竟使用第三方会增大apk的体积,能用系统提供的方法解决就尽量不用第三方。

最后如果文章有错误,请大家评论指正。希望我的分享能帮到大家!