|
1 | 1 | Bitmap的压缩机制
|
2 |
| ---- |
3 |
| -> 按照一定的采样率去将要显示的图片缩小后,再加载入ImageView; |
4 | 2 |
|
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 | + |
| 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 | + |
| 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 | + |
| 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 | + |
| 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 | + |
| 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 | + |
| 158 | + |
| 159 | + |
| 160 | + |
| 161 | +### 总结: |
| 162 | + |
| 163 | +Bitmap所占用的内存 = 图片长度 x 图片宽度 x 一个像素点占用的字节数。 |
| 164 | + |
| 165 | +3个参数,任意减少一个的值,就达到了压缩的效果 ;无论是自定义实现压缩,也都是想方设法的改变这三个属性值; |
| 166 | + |
| 167 | + |
| 168 | +#### 从源码得知; |
6 | 169 | Bitmap的四种加载方式:
|
7 | 170 | + decodeFile : 从文件系统
|
8 | 171 | + decodeResource: 资源
|
|
0 commit comments