Skip to content

Commit 1ad6182

Browse files
authored
Update Bitmap的压缩机制.md
1 parent 6bf9c51 commit 1ad6182

File tree

1 file changed

+166
-3
lines changed

1 file changed

+166
-3
lines changed

Bitmap的压缩机制.md

Lines changed: 166 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,171 @@
11
Bitmap的压缩机制
2-
---
3-
> 按照一定的采样率去将要显示的图片缩小后,再加载入ImageView;
42

5-
从源码得知;
3+
> 参考:
4+
>
5+
> [Android压缩图片保持不失帧的方法](https://blog.csdn.net/jiaruihua_blog/article/details/12113521)
6+
>
7+
> [Bitmap的6种压缩方式](https://blog.csdn.net/harryweasley/article/details/51955467)
8+
9+
### Bitmap的数据大小
10+
11+
图片的长(width)x 图片的宽(height)x一个像素点所占用对字节数;
12+
13+
下列为常用的图片压缩格式:
14+
15+
![ ](https://img-blog.csdn.net/20160720113139490)
16+
17+
> A:透明度, R:红色,G:绿色,B:蓝色;
18+
19+
#### 格式解析
20+
21+
+ ALPHA_8 : 表示为 8位的 Alpha 使徒,即 A=8, 一个像素点占用一个字节,只有透明度的特性,没有颜色显示;
22+
+ ARGB_4444: 表示16位的 ARGB 的位图;即 A = 4,B = 4,G = 4,R = 4每个颜色的像素占4位,所以一个像素点的大小为16位,占2个字节;
23+
+ **该字段已在 API 13 中废弃,图片质量较差**
24+
+ ARGB_8888:表示32位的ARGB位图;即 A = 8,B = 8,G = 8,R = 8,一个像素点的大小为32位,显色度更高一点,占4个字节;
25+
+ RGB_565 :表示16位的RGB位图,R=5,G=6,B=5,没有透明度的设置,一个像素点的大小为16位,占2个字节;
26+
27+
### 压缩方式
28+
29+
#### 质量压缩
30+
31+
> 这是一种,不会减少图片的像素,通过改变图片的位深度(字节的长度)和 透明度等,来达到压缩图片的目的,但是由于图片的像素和长宽都不会改变,所以导致所占内存大小就是一样的;
32+
>
33+
> ##### 适用:(不适用于 png 等无损照片的操作)
34+
>
35+
> 传递二进制流的渠道,比如优化上传速度,微信分享图片的拉取,这类接受二进制流数据,但是又有一定的上限;
36+
>
37+
> 缺点:
38+
>
39+
> 压缩前后的图片,在内存中的大小没有变化;
40+
41+
实现代码:
42+
43+
```java
44+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
45+
//目前 quality 是从 edittext 中获取的;
46+
// 作用就是,通过这个值设定压缩的位深,位深随设定的值的减小而减小
47+
int quality =Integer.valueOf(editText.getText().toString());
48+
//调用 bitmap 的 compress (图片,设定压缩程度,字节输出)
49+
bit.compress(CompressFormat.JPEG, quality, baos);
50+
byte[] bytes = baos.toByteArray();
51+
bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
52+
//log测试确认
53+
Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() /1024 / 1024)+ "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight() + "bytes.length= " + (bytes.length / 1024) + "KB"+ "quality=" + quality);
54+
```
55+
56+
quality 变化后 位深的相应变化为:
57+
58+
![ ](https://img-blog.csdn.net/20160720132221751)
59+
60+
#### 采样率压缩
61+
62+
> 通过设定的缩放值:options.inSampleSize = n ,说明缩放倍数是 1/n^2,获取的宽高的 1/n 的像素点,从像素点的个数上,减少图片的大小;
63+
>
64+
> 读取策略:
65+
>
66+
> 先读取原图片的宽高,根据宽高和缩放值,再从原图片中获取相应的像素点,最后才把获取完毕的图片加入内存,在获取原图片的宽高的时候,是不会把图片加加入内存的,大大减少了 OOM 的机率;
67+
>
68+
> ##### 缺点:
69+
>
70+
> 压缩过后的图片由于像素点减少,容易失真;
71+
72+
实现代码:
73+
74+
```java
75+
BitmapFactory.Options newOpts = new
76+
BitmapFactory.Options();
77+
//设定inJustDecodeBounds 为 ture,保证第一次decodeFile的时候获取的 bitmap 是一个空对象,但是又获取到图片的宽高;
78+
newOpts.inJustDecodeBounds = true;
79+
Bitmap bitmap =
80+
BitmapFactory.decodeFile(path,newOpts);
81+
// false ,保证通过压缩方式,把图片按照取样率加载到内存中
82+
newOpts.inJustDecodeBounds = false;
83+
int w = newOpts.outWidth;
84+
int h = newOpts.outHeight;
85+
//计算出取样率
86+
newOpts.inSampleSize = be;
87+
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
88+
```
89+
90+
当设定的采样率为 2 时,压缩图片的结果:
91+
92+
![ ](https://img-blog.csdn.net/20160720134004311)
93+
94+
#### 缩放法压缩
95+
96+
> 在 Android中提供了 一个 3*3 矩阵 Matrix对图像进行缩放、旋转、平移、斜切等变换;
97+
>
98+
> 那么在不要求图片的保真程度的情况下,通过 对Matrix中属性值的设定,就就可以达到压缩图片的目的;
99+
>
100+
> matrix.setScale(0.5f, 0.5f);
101+
>
102+
> bitmap 的长度和宽度分别缩小了一半,图片缩小了 四分之一;
103+
104+
实现代码:
105+
106+
```java
107+
Matrix matrix = new Matrix();
108+
matrix.setScale(0.5f, 0.5f);
109+
//bitmap 的长度和宽度分别缩小了一半,图片缩小了 四分之一;
110+
bm = Bitmap.
111+
createBitmap(bit, 0, 0, bit.getWidth(),
112+
bit.getHeight(), matrix, true);
113+
```
114+
115+
效果:
116+
117+
![ ](https://img-blog.csdn.net/20160720145255625)
118+
119+
#### RGB_565法压缩
120+
121+
> 在舍弃了透明度的同时,由于是16位的像素点设定,比 32位的默认 ARBG_8888 占用内存更少;在不考虑透明度的情况下,可以使用 RGB_565 对 bitmap 图片读取到内存;可以很好保证图片的质量;
122+
123+
实现代码:
124+
125+
```java
126+
BitmapFactory.Options options2 =
127+
new BitmapFactory.Options();
128+
//设定优先加载到内存的数据格式
129+
options2.inPreferredConfig =
130+
Bitmap.Config.RGB_565;
131+
bm = BitmapFactory.decodeFile(
132+
Environment.getExternalStorageDirectory()
133+
.getAbsolutePath()
134+
+ "/DCIM/Camera/test.jpg", options2);
135+
```
136+
137+
压缩效果:
138+
139+
![ ](https://img-blog.csdn.net/20160720145726252)
140+
141+
#### Bitmap.createScaledBitmap自带API
142+
143+
> 通过自带的API调用,直接设定用户希望加载的大小限定(长宽);
144+
>
145+
> 缺点:
146+
>
147+
> 会导致图片很不清晰;
148+
149+
实现代码:
150+
151+
```java
152+
bm = Bitmap.createScaledBitmap(bit, 150, 150, true);
153+
```
154+
155+
实现效果:
156+
157+
![ ](https://img-blog.csdn.net/20160720150219297)
158+
159+
160+
161+
### 总结:
162+
163+
Bitmap所占用的内存 = 图片长度 x 图片宽度 x 一个像素点占用的字节数。
164+
165+
3个参数,任意减少一个的值,就达到了压缩的效果 ;无论是自定义实现压缩,也都是想方设法的改变这三个属性值;
166+
167+
168+
#### 从源码得知;
6169
Bitmap的四种加载方式:
7170
+ decodeFile : 从文件系统
8171
+ decodeResource: 资源

0 commit comments

Comments
 (0)