图片压缩

  图片压缩的方式大概有以下几种:更换图片格式、质量压缩、采样率压缩、缩放压缩、调用jpeg压缩。

设置图片格式

  安卓目前支持的图片格式有png、jpeg、webp三种格式。
1 . png:无损压缩图片格式,支持Alpha通道,Android切图素材多采用此格式;
2 . jpeg:有损压缩图片格式,不支持背景透明,适用于照片等色彩丰富的大图压缩,不适合logo;
3 . webp:是一种同时提供了有损压缩和无损压缩的图片格式,派生自视频编码格式VP8,从谷歌官网来看,无损webp平均比png小26%,有损的webp平均比jpeg小25%~34%,无损webp支持Alpha通道,有损webp在一定的条件下同样支持,有损webp在Android4.0(API 14)之后支持,无损和透明在Android4.3(API18)之后支持。采用webp能够在保持图片清晰度的情况下,可以有效减小图片所占有的磁盘空间大小;

质量压缩

  图片质量并不会改变图片在内存中的大小,仅仅会减小图片所占用的磁盘空间的大小,因为质量压缩不会改变图片的分辨率,而图片在内存中的大小是根据(width * height * 一个像素所占用的字节数)来计算的,宽高没变的话,在内存中占用的大小自然不会变。质量压缩的原理是通过改变图片的位深和透明度来减小图片占用的磁盘空间大小的,所以不适合作为缩略图,可以用于想保持图片质量的同时减小图片所占用的磁盘空间大小。
  此外,由于png格式的图片是无损压缩,所以设置quality属性无效。

采样率压缩

  采样率压缩是通过设置BitmapFactory.Options.inSampleSize属性来减小图片的分辨率,进而减小图片所占用的磁盘空间和内存大小的。
  设置的BitmapFactory.Options.inSampleSize属性会导致压缩的图片的宽高都为1/inSampleSize,整体大小变为原始图片的inSampleSize平方分之一。以下为所需要注意的点:
1 . inSampleSize小于等于1的时候会按照1来处理;
2 . inSampleSize只能设置为2的平方,不是2的平方则最终会减小到最近的2的平方数。如设置7会按照4来进行压缩,设置15会按照8来进行压缩;

File sdFile = Environment.getExternalStorageDirectory();
File originFile = new File(sdFile, "originImg.jpg");
BitmapFactory.Options options = new BitmapFactory.Options();
//设置此参数是仅仅读取图片的宽高到options中,不会将整张图片读到内存中,防止oom
options.inJustDecodeBounds = true;
Bitmap emptyBitmap = BitmapFactory.decodeFile(originFile.getAbsolutePath(), options);

options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
Bitmap resultBitmap = BitmapFactory.decodeFile(originFile.getAbsolutePath(), options);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
try {
    FileOutputStream fos = new FileOutputStream(new File(sdFile, "resultImg.jpg"));
    fos.write(bos.toByteArray());
    fos.flush();
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

尺寸缩放压缩

  通过减少图片的像素来降低图片的磁盘空间大小和内存大小,可以用于缓存缩略图。

File sdFile = Environment.getExternalStorageDirectory();
File originFile = new File(sdFile, "originImg.jpg");
Bitmap bitmap = BitmapFactory.decodeFile(originFile.getAbsolutePath());
//设置缩放比
int radio = 8;
Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / radio, bitmap.getHeight() / radio, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
RectF rectF = new RectF(0, 0, bitmap.getWidth() / radio, bitmap.getHeight() / radio);
//将原图画在缩放之后的矩形上
canvas.drawBitmap(bitmap, null, rectF, null);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
result.compress(Bitmap.CompressFormat.JPEG, 100, bos);
try {
    FileOutputStream fos = new FileOutputStream(new File(sdFile,"sizeCompress.jpg"));
    fos.write(bos.toByteArray());
    fos.flush();
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

JNI调用JPEG库

  Android的图片引擎使用的是阉割版的skia引擎,去掉了图片压缩中的哈夫曼算法 -- 一种耗CPU但是能在保持图片清晰度的情况下很大程度降低图片的磁盘空间大小的算法,这就是为什么ios拍出的1M的照片比Android5M的还要清晰的原因。

后续补充

总结

1 . 使用webp格式的图片可以在保持清晰度的情况下减小图片的磁盘大小,是一种推荐的图片格式;
2 . 质量压缩可以减小图片占用的磁盘空间,不会减小在内存中的大小;
3 . 采样率压缩可以通过改变分辨率来减小图片所占用的磁盘空间和内存空间大小,但是采样率只能设置2的n次方,可能图片的最优比例在2的某两个n次方数值中间;
4 . 尺寸压缩同样也是通过改变分辨率来减小图片所占用的磁盘空间和内存空间大小,缩放的尺寸没什么限制;
5 . jni调用jpeg库来弥补安卓系统skia框架的不足,也是比较优秀的解决方式;

  尺寸压缩和采样率压缩的区别:
  采样率的压缩比例会受到限制,尺寸压缩不会,但是采样率压缩的清晰度会比尺寸压缩的清晰度要好一些

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--------------------last line for now------------------