Bitmap之压缩方案

本文深入探讨Bitmap的压缩方案,包括基础知识如色彩模式、内存占用计算,以及采样率、尺寸、质量压缩。重点解析哈夫曼压缩的原理,背景和代码逻辑,阐述其在早期因性能限制被Skia图像处理引擎屏蔽,但随着手机性能提升,未来可能重新启用的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在Bitmap的内存管理中,介绍了Bitmap的压缩、缓存、复用等问题。其中的压缩方案是采样率压缩,这里再介绍几种其它的压缩方案,首先是原生的质量压缩,尺寸压缩,其次是哈夫曼压缩,也叫鲁班压缩或微信压缩。只有先知道原生压缩的原理,我们才能更好的优化改良,以及更好的理解哈夫曼压缩,而这种方案也是本文的分析重点。

1.基础知识

1.1色彩模式

ARGB:指的是一种色彩模式,里面A代表Alpha,R表示red, G表示green,B表示blue

自然界中所有的可见颜色都是由红、绿、蓝组成的,所以红、绿、蓝又称三原色,每个原色都存储着所表示颜色的信息值

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

1.2四种模式的区别

bitmap在内存中存在四种色彩的存储模式,它们的本质区别体现在每种模式下的bitmap的每个像素点,在内存中大小和组成成分的区别

1.3具体对比
  • ALPHA_8: A ->8bit->一个字节,即8bit,一个像素总共占一个字节
  • ARGB_8888: A->8bit->一个字节,R->8bit->一个字节,G->8bit->一个字节,B->8bit->一个字节,一个像素总共占用四个字节,8 + 8+ 8 + 8 = 32bit = 4byte
  • ARGB_4444: A->4bit,R->4bit,G->4bit,B->4bit,一个像素总共占用两个字节,4 + 4 + 4 + 4 = 16bit = 2byte
  • RGB_565: R->5bit,G->6bit,B->5bit,一个像素总共占用两个字节,5+ 6 + 5 = 16bit = 2byte
1.4bitmap内存占用大小计算方式

一张bitmap内存占用大小 = 像素点数 * 每个像素点内存占用大小 = width * height * 每个像素点占用内存大小

tips

  • 我们知道了决定了bitmap内存占用的因素,只有改变这些因素才能改变bitmap的内存占用大小,Bitmap的压缩方案也是基于改变这些因素,来减小内存的占用
  • bitmap的内存占用大小与在本地磁盘大小是不同的概念
1.5图片存在的形式
  • 以File的形式存在于SD卡/磁盘中
  • 以Stream的形式存在于内存中
  • 以Bitmap的形式存在于内存中
1.6BitampFactory加载Bitmap对象的方式
  • decodeFile 从文件中加载Bitmap对象
  • decodeResource从资源中加载Bitmap对象
  • decodeStream从输入流加载Bitmap对象
  • decodeByteArray 从字节数组中加载Bitmap对象

2.压缩方案

2.1采样率压缩
/**
     * 采样率压缩
     * @param bitmap
     * @param file
     */
    public void compressInSampleSize(Bitmap bitmap, File file) {
   
        BitmapFactory.Options options = new BitmapFactory.Options();
        //正常的做法是通过ImageView的宽高,和图片自身的宽高计算采样率
        //inJustDecodeBounds为true的时候不会真正的加载图片,只是解析图片原始宽高信息并不会去
        //真正加载图片,轻量级操作
        //options.inJustDecodeBounds = true;
        //BitmapFactory.decodeFile(stringName, options);
        //通过计算获取采样率inSampleSize
        //options.inSampleSize = calculateInSampleSize(options, 150, 100);
        
        //这里只是为了为了通过采用率压缩图片,不需要根据ImageView的宽高,和图片自身的宽高计算采样率
        //直接赋值采样率为8,获得采样率后,再设置inJustDecodeBounds为false,真正的加载图片
        //采样率数值越高,图片像素越低
        int inSampleSize = 8;
        options.inSampleSize = inSampleSize;
        options.inJustDecodeBounds = false;
        BitmapFactory.decodeFile(stringName, options);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把压缩后的数据保存到baos中
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 不进行质量压缩

        try {
   
            if (file.exists()) {
   
                file.delete();
            } else {
   
                file.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baos.toByteArray());
            fos.flush();
            fos.close();
        } catch (Exception e) {
   
            e.printStackTrace();
        }
    }

    /**
     * 获取采样率
     * @param options
     * @param reqWidth 需要显示/控件定义的宽度
     * @param reqHeight 需要显示/控件定义的高度
     * @return
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, 
    					int reqHeight) {
   
        int width = options.outWidth;
        int height = options.outHeight;

        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
   
            int halfWidth = width / 2;
            int halfHeight = height / 2;
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) 
            >= reqWidth) {
   
                inSampleSize *=2;
            }
        }

        return inSampleSize;
    }
2.2尺寸压缩
/**
     * 2. 尺寸压缩
     * 通过减少单位尺寸的像素值,真正意义上的降低像素
     * 通过缩放图片像素来达到减少图片占用内存大小的效果
     * 使用场景:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值