Android性能优化——图片压缩的终极选择libjpeg-turbo
文章目录
- 概述
- 需求分析
- 各种压缩方式
- libjepg-turbo+jnigraphics
- 介绍
- 编译
- 使用
- 引用文章
概述
之前在网络上搜索Android图片压缩,能看到各种各样的关于图片压缩的文章,本没有必要再写一篇,但是最近的一个需求真是折腾了我很久,本来以为很简单的事情,愣是搞了好几天。这里记录下我完成的整个过程,作为一个笔记供以后查阅。如果读友觉得有帮助,就?下
需求分析
需求(额呵,这个肯定不是客户的需求):在即时通讯发消息的场景中,需要发送的图片保持清晰度的同时压缩一定的比例,最好不要超过1M。
衍生需求(一看就是后台小哥的臆想):上传到服务器的图片要适当的压缩,不然服务器撑不住。
附加需求:(无力吐槽)最好能做个sdk供调用
分析下:就是个图片压缩嘛,简单
private Bitmap compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);int options = 100;//循环判断如果压缩后图片是否大于100kb,大于继续压缩while (baos.toByteArray().length / 1024 > 100) {baos.reset();image.compress(Bitmap.CompressFormat.JPEG, options, baos);//每次都减少10options -= 10;}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());return BitmapFactory.decodeStream(isBm, null, null);}
试了试,好像不行,图片压缩了之后会失真,而且用起来不是那么顺手
上述代码中Bitmap.CompressFormat.JPEG可以更换为CompressFormat.PNG和CompressFormat.WEBP
PNG 格式是无损的,它无法再进行质量压缩,options 这个参数就没有作用了,会被忽略,图片并不会缩小
CompressFormat.WEBP ,这个格式是 google 推出的图片格式,它会比 JPEG 更加省空间,但是IOS好像兼容有些问题,还是JPEG靠谱
到网上搜搜,我的天,各种图片压缩的文章,看得的我眼花缭乱。
这里放个原图,然后继续分析
原图大小:116 KB
各种压缩方式
质量压缩
采样率压缩
按比例大小压缩
libjepg-turbo+jnigraphics
介绍
翻译一下官网的描述
libjpeg-turbo是一种jpeg图像编解码器,它使用simd指令(mmx、sse2、avx2、neon、altivec)加速x86、x86-64、ARM和PowerPC系统上的Baseline JPEG(标准型)压缩和解压缩,以及x86和x86-64系统上的渐进式progressive JPEG(渐进式)压缩。在这些系统中,libjpeg-turbo的速度通常是libjpeg的2-6倍,其他的都是相同的。在其他类型的系统上,libjpeg-turbo由于其高度优化的哈夫曼编码例程,仍然可以在很大程度上超过libjpeg 。在许多情况下,libjpeg-turbo的性能与专有的高速JPEG编解码器的性能相当。
libjpeg-turbo最初基于libjpeg/simd,这是 Miyasaka Masaru 开发的libjpeg v6b的MMX(多媒体扩展)加速衍生产品。
2009年,在TigerVnc和VirtualGL项目中对编解码器进行了大量改进,2010年初,libjpeg turbo被拆分成了一个独立的项目,其目标是为更广泛的用户和开发人员提供高速的jpeg压缩/解压缩技术。
编译
github编译教程:https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/BUILDING.md
刚开始我也是用linux编译,使用像下面的编译脚本可以编译成功
#!/bin/bash
NDK_PATH=/home/shuai/Android/android-ndk-r13
TOOLCHAIN=gcc
ANDROID_VERSION=17
cd libjpeg-turbo-2.0.2cmake -G "Unix Makefiles" \-DANDROID_ABI=armeabi-v7a \-DANDROID_ARM_MODE=arm \-DANDROID_PLATFORM=android-${ANDROID_VERSION} \-DANDROID_TOOLCHAIN=${TOOLCHAIN} \-DCMAKE_ASM_FLAGS="--target=arm-linux-androideabi${ANDROID_VERSION}" \-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=android/arm-v7a \-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=android/arm-v7a \make
后来发现,可以直接在android studio中直接编译通过,真是开心的像廋了10斤一样
新建带jni的Android项目,将libjpeg-turbo整个项目直接拷贝到jni目录下,然后在CmakeLists.txt中加入这个
cmake_minimum_required(VERSION 3.4.1)
add_library(native-jpegSHAREDnative-jpeg.cpp)
# 编译子项目(源码路径)
ADD_SUBDIRECTORY(libjpeg-turbo-2.0.2)find_library(log-liblog)
target_link_libraries(native-jpeg${log-lib})
build之后妥妥可以拿到动态和静态库
同样的方法,我又编译了libpng的代码
具体请参考:https://github.com/ddssingsong/NdkImage,下载项目直接运行,里面还有使用demo
使用
打造一个图片压缩框架
// 压缩bitmap
extern "C"
JNIEXPORT void JNICALL
Java_com_dds_ndkimage_NativeImageUtils_compressBitmap(JNIEnv *env, jclass type, jobject bitmap,jint q,jstring p_) {if (bitmap == NULL) {LOGE("bitmap is null");return;}const char *path = env->GetStringUTFChars(p_, 0);AndroidBitmapInfo info;// 获取bitmap中信息AndroidBitmap_getInfo(env, bitmap, &info);// 获取图片中的像素信息uint8_t *pixels;AndroidBitmap_lockPixels(env, bitmap, (void **) (&pixels));int w = info.width;int h = info.height;int color;//data中可以存放图片的所有内容uint8_t *data = (uint8_t *) malloc((size_t) (w * h * 3));uint8_t *temp = data;uint8_t r, g, b;//bytefor (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {color = *(int *) pixels;//取出rgbr = (uint8_t) ((color >> 16) & 0xFF);// #00rrggbb 16 0000rr 8 00rrggg = (uint8_t) ((color >> 8) & 0xFF);b = (uint8_t) (color & 0xFF);*data = b;*(data + 1) = g;*(data + 2) = r;data += 3;//指针跳过4个字节pixels += 4;}}//把得到的新的图片的信息存入一个新文件 中jpegcompress::write_JPEG_file(temp, w, h, q, path);//释放内存free(temp);AndroidBitmap_unlockPixels(env, bitmap);env->ReleaseStringUTFChars(p_, path);
}
void jpegcompress::write_JPEG_file(uint8_t *data, int w, int h, jint q, const char *path) {//3.1、创建jpeg压缩对象jpeg_compress_struct jcs;//错误回调jpeg_error_mgr error;jcs.err = jpeg_std_error(&error);//创建压缩对象jpeg_create_compress(&jcs);//3.2、指定存储文件 write binaryFILE *f = fopen(path, "wb");jpeg_stdio_dest(&jcs, f);//3.3、设置压缩参数jcs.image_width = (JDIMENSION) (w);jcs.image_height = (JDIMENSION) h;//bgrjcs.input_components = 3;jcs.in_color_space = JCS_RGB;jpeg_set_defaults(&jcs);//开启哈夫曼功能jcs.optimize_coding = true;jpeg_set_quality(&jcs, q, 1);//4 开始压缩jpeg_start_compress(&jcs, 1);// 5 循环写入每一行数据int row_stride = w * 3;//一行的字节数JSAMPROW row[1];while (jcs.next_scanline < jcs.image_height) {//取一行数据uint8_t *pixels = data + jcs.next_scanline * row_stride;row[0] = pixels;jpeg_write_scanlines(&jcs, row, 1);}//6 压缩完成jpeg_finish_compress(&jcs);//7 释放jpeg对象fclose(f);jpeg_destroy_compress(&jcs);
}
详见:https://github.com/ddssingsong/NdkImage
引用文章
Android 中图片压缩分析https://www.cnblogs.com/qcloud1001/p/7827133.html)https://www.cnblogs.com/qcloud1001/p/7827133.html
Android性能优化——图片压缩的终极选择libjpeg-turbo相关推荐
- 性能优化——图片压缩、加载和格式选择
本文首发于政采云前端团队博客:性能优化--图片压缩.加载和格式选择 https://www.zoo.team/article/images-compress 前言 相信大家都听说过 "258 ...
- android性能优化透明,Android性能优化-图片篇
(1)drawable目录详解(mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi) 1.1.图片在各个目录中要如何存放?(必须理解) android的drawable目录有: drawab ...
- [Android 性能优化系列]内存之终极篇--降低你的内存消耗
原文地址:http://developer.android.com/training/articles/memory.html 拒绝在 Bitmap 上浪费你的内存 当你加载一张 Bitmap 的时候 ...
- 【Android 内存优化】Android 原生 API 图片压缩原理 ( 哈夫曼编码开关 | 哈夫曼编码原理 | libjpeg-turbo 函数库 )
文章目录 一. 哈夫曼编码开关 二. 哈夫曼编码原理 三. libjpeg-turbo 函数库 四. libjpeg-turbo 函数库下载 [Android 内存优化]图片文件压缩 ( Androi ...
- Android 性能优化之——高性能使用图片全面总结
Android 性能优化之--高性能使用图片全面总结 移动设备的系统资源有限,所以应用应该尽可能的降低内存的使用.在应用运行过程中,Bitmap (图片)往往是内存占用最大的一个部分,Bitmap 图 ...
- Android 性能优化——之图片的优化
Android 性能优化--之图片的优化 在Android性能优化中,我们会发现占内存最大的和对性能影响最大的往往是图片资源,其次是控件资源.相对来说,其他的资源的影响会小一点.这里我就先对图片资源的 ...
- 【Android 内存优化】Android 原生 API 图片压缩原理 ( Bitmap_compress 方法解析 | Skia 二维图形库 | libjpeg 函数库 | libpng 函数库 )
文章目录 一. 图片质量压缩方法 二. Skia 二维图形库 三. libjpeg.libpng 函数库引入 在博客 [Android 内存优化]图片文件压缩 ( Android 原生 API 提供的 ...
- 【Android 内存优化】Android 原生 API 图片压缩原理 ( 图片质量压缩方法 | 查找 Java 源码中的 native 方法对应的 C++ 源码 )
文章目录 一. 图片质量压缩方法 二. 查找对应的 Native 方法源码 三. 分析 Bitmap.cpp 中动态注册 Native 方法 在博客 [Android 内存优化]图片文件压缩 ( An ...
- Android 性能优化
为什么80%的码农都做不了架构师?>>> 原文作者:鸿洋 原文地址:点我跳转原文 一般情况下,我们谈性能优化基本上会从以下几个方面: App启动速度优化 UI流畅度优化 内存优 ...
最新文章
- poj3508(高精度模拟减法)
- 2020 蚂蚁面试指南!
- Pet Shop4解密配置文件
- 如何抓取html请求,请求获取网页的response,获取网页的html 怎么那么慢
- Spring框架----Spring框架的基本概念
- 华为 MateBook 笔记本 Linux 版正式开售
- idea配置jfinal_JFinal 开箱评测,这次我是认真的
- Linux安装yum教程
- ftp工具哪个好,推荐8个超级好用而且免费的ftp工具,支持中文版windows系统的。
- SecureCRT免费安装教程
- 计算机网络-域名与IP地址详解
- java delete()_Java File delete()用法及代码示例
- 程序员找工作-----人力资源面试题
- java/kafka的使用,生产者 ,发布/发送消息,自定义数据/json数据,实战。
- Swing中如何实现二级联动下拉列表
- 多模态情感识别数据集和模型(下载地址+最新综述2021.8)
- win10图标变白纸_同是Office365,为什么你的软件图标还是旧版的?
- 《zw版·Halcon-delphi系列原创教程》 邮票艺术品自动分类脚本
- Android 11.0 根据包名授予WRITE_SETTINGS权限
- 窄告:超越搜索引擎关键词模式的精准营销