zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

【Android 内存优化】Android 原生 API 图片压缩原理 ( 哈夫曼编码开关 | 哈夫曼编码原理 | libjpeg-turbo 函数库 )

Android内存编码原理API 优化 图片 原生
2023-09-27 14:29:04 时间



【Android 内存优化】图片文件压缩 ( Android 原生 API 提供的图片压缩功能能 | 图片质量压缩 | 图片尺寸压缩 ) 简要介绍了 图片文件压缩格式 , 以及 Android 提供的图片质量 , 尺寸压缩原生 API ;


【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 ) 主要使用了上述 Android 原生 API 压缩图片功能进行图片压缩 ;


【Android 内存优化】Android 原生 API 图片压缩原理 ( 图片质量压缩方法 | 查找 Java 源码中的 native 方法对应的 C++ 源码 ) 中主要查找 Bitmap.java 对应的 Native 层的 C++ 类 Bitmap.cpp 源码文件 , 并分析了其动态注册 Native 方法的过程 ;


【Android 内存优化】Android 原生 API 图片压缩原理 ( Bitmap_compress 方法解析 | Skia 二维图形库 | libjpeg 函数库 | libpng 函数库 ) 博客中分析了 Bitmap.cpp 中的 Bitmap_compress 方法 ;






一、 哈夫曼编码开关



上一篇博客 【Android 内存优化】Android 原生 API 图片压缩原理 ( Bitmap_compress 方法解析 | Skia 二维图形库 | libjpeg 函数库 | libpng 函数库 ) 分析到了 实际的图片压缩方法是由 Skia 图形库执行的 , Skia 图形库根据不同的压缩格式 , 选择不同的函数库进行压缩 , 如果压缩格式是 JPEG 格式 , 那么使用 libjpeg 库进行图片压缩 , 如果压缩格式是 PNG 库 , 那么使用 libpng 库进行压缩 ;


1. 哈夫曼编码 : 在 libjpeg 中提供了图片哈夫曼编码功能 , 该功能非常消耗 CPU 性能 , 因此早期的 Android 版本禁用了该功能 , 在 7.0 之后的版本 , 此时 Android 设备上的 CPU 性能很高 , 这时才将哈夫曼编码功能打开 ; ( SkImageDecoder_libjpeg.cpp 代码参考 )


2. 打开哈夫曼编码 : 将 jpeg_compress_struct 结构体的 optimize_coding 成员设置成 TRUE ; 作用是 通知 libjpeg-turbo 为图像计算最佳的哈夫曼编码表 , 该操作可以 提高图片压缩比例 , 代价是编码速度较慢 ;


3. 源码参考 :

SkImageDecoder_libjpeg.cppSkJPEGImageEncoder 类 ( SkImageEncoder 对应的 JPEG 格式图片压缩实现类 ) 中的 onEncode 方法 , 在 7.0 以后的版本 , 打开图片压缩哈夫曼编码功能 ;

// 该类是 SkImageEncoder 的子类 , 在 Bitmap.cpp 中使用的就是
class SkJPEGImageEncoder : public SkImageEncoder {
protected:
    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
		// ... 
		jpeg_compress_struct    cinfo;
		// ... 
        // 打开哈夫曼编码 
        // 通知 libjpeg-turbo 为图像计算最佳的哈夫曼编码表
        // 该功能可以提高压缩比例 , 代价是编码速度较慢
        cinfo.optimize_coding = TRUE;
        // ... 
        return true;
    }
};

源码位置 7.0.0/external/skia/src/images/SkImageDecoder_libjpeg.cpp ( 7.0.0 以后的源码才添加了上述功能 )





二、 哈夫曼编码原理



在 libjpeg 编码中 , 如果没有开启哈夫曼编码 , 采用的是定长的编码方式 , 如果打开了哈夫曼编码 , 采用的就是变长哈夫曼编码 , 可以大幅度压缩数据大小 ;


简介 : 哈夫曼编码是字符编码 , 适用于数据文件压缩场景 , 能大幅度压缩文件大小 ;


哈夫曼编码原理 : 每个数据的编码长度可变 , 文件中出现较多的字符使用短编码 , 出现较少的字符使用长编码 , 另外额外维护一张哈夫曼编码表 , 用于维护字符与编码的对应关系 , 总体的文件大小会降低 20% 至 90% ;





三、 libjpeg-turbo 函数库



使用哈夫曼编码进行图片压缩 , 能最大幅度压缩图片大小 , 但是 Android 原生编码中只有 7.0 以后的系统才打开了哈夫曼编码功能 , 目前的主流应用都要向下兼容到 android-17 平台版本 , 对应的系统版本是 Android 4.2 Jelly Bean , 这里就需要引入第三方库 libjpeg-turbo 函数库 , 进行哈夫曼编码图片压缩 , 该函数库是由 C 语言开发 , 需要在 Ubuntu 中进行交叉编译成 ARM 架构的函数库 ( 动态库 / 静态库 ) , 然后导入到 Android Studio 中使用 ;


Android 源码中有 libjpeg-turbo 库 , 但是Java 框架中提供的 Bitmap.java 只能调用 Bitmap.cpp 中的代码 , Bitmap.cpp 中通过 Skia 2D 图形库调用 libjpeg 库 , 在该 C++ 代码中是固定的 , 开发者无法修改框架层的源码 , 因此该函数库无法被开发者调用到 ;


NDK 交叉编译开发参考 : Android NDK 开发 专栏





四、 libjpeg-turbo 函数库下载



1. libjpeg-turbo 相关资源链接 :


① libjpeg-turbo 官方网站 : https://libjpeg-turbo.org/

② GitHub 地址 : libjpeg-turbo/libjpeg-turbo

③ libjpeg-turbo 文档 : 文档地址



2. 下载发布版本 :


在 Android 工程中使用该函数库 , 尽量下载发布的稳定版本 , 最好不要直接下载开发中的 DEBUG 版本 , 可能存在 BUG ;

如下图 , 找到 release 发布版本界面 , 下载最新的发布版本 ; 或者直接点击 libjpeg-turbo/libjpeg-turbo 项目的 Release 发布版本地址 进入该界面 ;

在这里插入图片描述


进入 Release 界面后 , 查看到目前最新的发布版本是 2.0.5 版本 , 直接下载该源码 ; 之后需要到 Ubuntu 中进行交叉编译 ;

在这里插入图片描述


下载这个 Source code (tar.gz) 源码 , 到 Ubuntu 中进行交叉编译 ; ( 也可以直接点击上述连接下载 )

在这里插入图片描述