android中如何压缩图片

为什么需要压缩?

android中的图片是以Bitmap形式存在的,bitmap的大小和数量会直接影响到手机内存情况。不同大小的手机显示的图片也会不一样,跟分辨率、手机内存、显示的大小都有关系,所以很多时候我们需要对位图进行一些压缩的操作。

计算bitmap大小

一个像素点占用字节

四种压缩格式

[图片上传失败…(image-e55c37-1535879147605)]

ARGB代表的意思是

A(透明度)
R(red红色)
G(green绿色)
B(blue蓝色)

  • ALPHA_8
    8位Alpha位图一个像素占用一个字节,只有透明度。A=8
  • ARGB_4444
    16位的ARGB位图,ARGB各占用4位总共16位,2个字节。
  • ARGB_8888
    16位的ARGB位图,ARGB各占用8位总共36位,4个字节。
  • RGB_565
    16位RGB位图没有透明度,2个字节。

1. 质量压缩方式

质量压缩是在不改变图片大小的前提下,改变图片的位深以透明度,来达到压缩的目的。所以通过这种方式压缩的话,实际上我们内存加载进来的bitmap大小也是不会改变的。

但是这种方式会改变图片的文件大小,代码中可以看到通过了byteArray来判断大小,所以适合去传递二进制的图片数据,比如微信分享图片,要传入二进制数据过去,限制32kb之内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static Bitmap compressByQuality(Bitmap src, long maxByteSize, boolean recycle) {
if (isEmptyBitmap(src) || maxByteSize <= 0) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int quality = 100;
src.compress(CompressFormat.JPEG, quality, baos);
while (baos.toByteArray().length > maxByteSize && quality > 0) {
baos.reset();
src.compress(CompressFormat.JPEG, quality -= 5, baos);
}
if (quality < 0) {
return null;
}
byte[] bytes = baos.toByteArray();
if (recycle && !src.isRecycled()) {
src.recycle();
}
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}

2. 采样率压缩

采样率压缩主要是通过BitmapFactory.Options类的inJustDecodeBunds标识为true,然后返回的bitmap就是一个Null对象,这样可以节约内存空间的开销。

但是这个bitmap的options是包含bitmap的宽高、MimeType参数。我们可以根据这些图片参数去设置options的 inSampleSize参数,通过这个参数我们可以实现图片大小的压缩。

主要压缩步骤

  1. BitmapFactory.Options的 inJustDecodeBunds为true并加载图片

  2. 从BitmapFactory.Options 中取出图片的原始宽高信息,对应outWidth和outHeight

  1. 根据采样率的规格并结合目标计算出View的所需大小计算出inSampleSize

  2. BitmapFactory.Options 的 inJustDecodeBunds 参数设置为false,然后重新加载图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private Bitmap decodeSampleBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile(imagePath, options);
return bm;
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = height / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}

3.缩放法压缩(martix)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 缩放图片
*
* @param src 源图片
* @param scaleWidth 缩放宽度倍数
* @param scaleHeight 缩放高度倍数
* @param recycle 是否回收
* @return 缩放后的图片
*/
public static Bitmap scale(Bitmap src, float scaleWidth, float scaleHeight, boolean recycle) {
if (isEmptyBitmap(src)) {
return null;
}
Matrix matrix = new Matrix();
matrix.setScale(scaleWidth, scaleHeight);
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src
.getHeight(), matrix, true);
if (recycle && !src.isRecycled()) {
src.recycle();
}
return ret;
}

4. RGB_565压缩法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* rgb 565压缩
* @param bm
* @param path
* @return
*/
private Bitmap rgb565(Bitmap bm, String path) {
BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inPreferredConfig = Bitmap.Config.RGB_565;
bm = BitmapFactory.decodeFile(path, options2);
return bm;
}

5 . createScaledBitmap方式压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 缩放图片
*
* @param src 源图片
* @param newWidth 新宽度
* @param newHeight 新高度
* @param recycle 是否回收
* @return 缩放后的图片
*/
public static Bitmap scale(Bitmap src, int newWidth, int newHeight, boolean recycle) {
if (isEmptyBitmap(src)) {
return null;
}
Bitmap ret = Bitmap.createScaledBitmap(src, newWidth, newHeight, true);
if (recycle && !src.isRecycled()) {
src.recycle();
}
return ret;
}