概述
文章目录
- 质量压缩法(改变图片位深和透明度)
- 采样率压缩法(改变图片分辨率)
- 缩放法
- RGB_565 法(色彩压缩法)
- 常见的色彩编码格式
- RGB_565 在 Android 中的使用:
- RGB_888 转换成 RGB_565
- RGB_565 转换成 RGB_888
系列文章:
- 【图像处理 】001 Android 中 Bitmap 压缩的几种方法浅析
- 【图像处理 】002 Android .9 图片相关处理
- 【图像处理 】003 图片处理工具类
决定 Bitmap 图片大小或者解码之后内存取决于:图片透明度,位深,图片采样率(分辨率),编码格式,图片本身宽高,下面我们围绕这几个因素来研究下:
质量压缩法(改变图片位深和透明度)
所谓质量压缩法:不减少图片本身的像素,它在保持像素的前提下改变图片的位深以及透明度,来达到压缩图片的目的,压缩后的文件大小会有所改变,但是导入成 bitmap 后所占内存是不会变化的,由于要保持像素不变,所以它无法无限压缩,达到一个极限值后就不会继续变小了。
所以这个方法,不适合缩略图,也不适合想通过压缩图片来减少内存的占用。它仅仅适用在想保证图片质量的前提下,同时减少文件大小的情况而已。
代码演示如下:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
while ( baos.toByteArray().length / 1024>32) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 10;
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
采样率压缩法(改变图片分辨率)
限制图片的采样率可以直接限制解码读取到图片的大小,即图片分辨率大小。但是采样率是整数,这就会造成我们不能根据图片实际宽高来精确的给出图片采样率。
所以我们一般都过下面的方式来计算图片分辨率
- 首先获取一张图片的大小和内存
- 根据获取到图片的宽高,结合我们需要的宽高,来重新计算图片的采样率
- 得到采样率之后,重新解码图片,就可以根据需要的大小来获取对应分辨率的图片
代码演示如下:
step1: 首先获取一张图片的大小
BitmapFactory.Options options = new BitmapFactory.Options();
// itmapFactory.Opitions的inJustDecodeBounds属性为true,就可以在不分配内存的情况下,
// 获取该图片的大小和类型。否则一旦图过大,在解码这个图片时,可能会出线内存泄漏
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
step2: 获取到高度和宽度之后,就可以按照我们的需要的高度和宽度,来计算图片的缩放比,得出图片的采样率
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
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 = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
step3: 得到采样率之后,重新解码图片,就可以根据需要的大小来获取对应分辨率的图片
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
缩放法
缩放法其实就是,通过设置好的 matrix , 然后再 createBitmap ,相当于将图片按照一定比例缩放。至于按照多大的比例,你可以按照经验值 进行 0.8 倍缩放,也可以循环缩放直到合适的尺寸。
演示代码如下:
ByteArrayOutputStream out = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 85, out);
float zoom = (float)Math.sqrt(size * 1024 / (float)out.toByteArray().length);
Matrix matrix = new Matrix();
matrix.setScale(zoom, zoom);
Bitmap result = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
out.reset();
result.compress(Bitmap.CompressFormat.JPEG, 85, out);
while(out.toByteArray().length > size * 1024){
System.out.println(out.toByteArray().length);
matrix.setScale(0.9f, 0.9f);
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
out.reset();
result.compress(Bitmap.CompressFormat.JPEG, 85, out);
}
RGB_565 法(色彩压缩法)
常见的色彩编码格式
图片默认的编码格式是 ARGB_8888 ,转换成 ARGB_565 可以减少一半内存消耗,可以解决一些 OOM 问题,但是 RGB_565 是没有透明度的,如果图片本身需要保留透明度,就只能使用 ARGB_8888。
其中 ARGB -----分别代表图片:Alpha 透明度和 red green blue 三原色。
常见的图片编码格式有:
在 Bitmap.Config 中,图片列举了下面几种编码格式:
- ARGB_8888:分别用 8 位来记录 4 个值,所以每个像素会占用 32 位,它表示 32 位位图。
- ARGB_4444:分别用 4 位来记录 4 个值,所以每个像素会占用 16 位,它表示 16 位位图。
- RGB_565:分别用 5 位、6 位和 5 位来记录 RGB 三色值,所以每个像素会占用 16 位,它表示 16 位位图。
- ALPHA_8:根据注释应该是不保存颜色值,只保存透明度(8位),每个像素会占用 8 位,它表示 8 位位图。
所以,如果我们以 ARGB_8888 作为基准来进行对比:
- ARGB_4444:内存占用减少一半,但是每个值图片失真度很严重,这个参数本身已经不推荐使用了。
- RGB_565:内存占用减少一半,舍弃了透明度,同时三色值也有部分损失,但是图片失真度很小。
- ALPHA_8:内存占用减少 3/4,没有颜色,只有透明度,即黑白。
综上,由于 ARGB_4444 已废除,而 ALPHA_8 需要在特殊条件下使用,一般用来做特殊需求的,所以我们大多数是用的还是 ARGB_8888和 RGB_565。
RGB_565 能够在保证图片质量的情况下大大减少内存的开销,是解决 oom 的一种方法。但是一定要注意 RGB_565 是没有透明度的,如果图片本身需要保留透明度,那么就不能使用 RGB_565。
RGB_565 是色彩压缩的一种方式,其通过不用透明率以及对 RGB 的相应位数进行省略。
一个彩色图像由 R G B 三个分量组成,一个 RGB565 的每一个像素点数据为 2Byte,即 16 位,那么从名字上就可看出来这 16 位中,高 5 位为 R 分量,中间 6 位为 G 分量,低 5 位为 B 分量。
RGB_565 在 Android 中的使用:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/DCIM/Camera/test.jpg",
options);
RGB_888 转换成 RGB_565
前者是 24 位,后者是 16 位,所以后者的占用内存大小是前者的 2/3, 其转换原理如下:
24ibt RGB888 R7 R6 R5 R4 R3 R2 R1 R0 G7 G6 G5 G4 G3 G2 G1 G0 B7 B6 B5 B4 B3 B2 B1 B0
16bit RGB656 R7 R6 R5 R4 R3 G7 G6 G5 G4 G3 G2 B7 B6 B5 B4 B3
RGB_565 转换成 RGB_888
转换原理:即为 RGB_888 的低位补零
16bit RGB565 -> 24bit RGB888 的转换:
16bit RGB656 R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0
24ibt RGB888 R4 R3 R2 R1 R0 0 0 0 G5 G4 G3 G2 G1 G0 0 0 B4 B3 B2 B1 B0 0 0 0
24ibt RGB888 R4 R3 R2 R1 R0 R2 R1 R0 G5 G4 G3 G2 G1 G0 G1 G0 B4 B3 B2 B1 B0 B2 B1 B0
最后
以上就是粗犷猎豹为你收集整理的【图像处理 】001 Android 中 Bitmap 压缩的几种方法浅析的全部内容,希望文章能够帮你解决【图像处理 】001 Android 中 Bitmap 压缩的几种方法浅析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复