libjpeg哈夫曼算法压缩图片
之前的博客提到过关于图片压缩的方法: Android 图片压缩,Bitmap优化
Android原生的压缩方法,不在乎两种:通过设置simpleSize根据图片尺寸压缩图片;通过Bitmap.compress方法通过压缩图片质量,去压缩。但是我们当我们对图片质量和图片文件大小同时存在要求时,我们发现无论怎么去设置参数,我们所做的效果总是不能尽如人意,而且同样大小的图片,效果却总是比iOS的效果差很多。
其实归根到底的是iOS和Android的压缩算法存在一些差异。
Android所用的是skia的压缩算法,它在google的很多地方,比如chrome、Android等都有使用,而Bitmap的压缩算法就是通过这个实现。而Skia是libjpeg进行了封装,google在实现skia时对其中一个地方进行了修改:通过哈夫曼算法来进行图片压缩,但是采用这个算法的时候,机器可能会出现性能问题,于是并没有调动这个方法。
[plain] view plain copy
- boolean optimize_coding
- TRUE causes the compressor to compute optimal Huffman coding tables
- for the image. This requires an extra pass over the data and
- therefore costs a good deal of space and time. The default is
- FALSE, which tells the compressor to use the supplied or default
- Huffman tables. In most cases optimal tables save only a few percent
- of file size compared to the default tables. Note that when this is
- TRUE, you need not supply Huffman tables at all, and any you do
- supply will be overwritten.
接下来,我们就自己去编译生成libjpeg的动态库,然后调用。
github中android libjpeg的源文件地址:https://github.com/libjpeg-turbo/libjpeg-turbo
这个我们需要自己去编译,但是已经有人帮我们编译好了,压缩算法也已经实现,因此,我们去下载然后编译即可:https://github.com/bither/bither-android-lib
首先将上面下载好的已经编译好的libjpeg放到jni目录下,将下图内容都放到jni目录中:
安装好ndk以后,直接输入ndk-build即可。
接下来就会编译生成arm下的动态库,使用的时候必须在项目中新建一个包net.bither.util,然后加入下面这个类方法,也就是使用了libjpeg开启哈夫曼算法的压缩算法:
[java] view plain copy
- /*
- * Copyright 2014 http://Bither.net
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package net.bither.util;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.Config;
- import android.graphics.Canvas;
- import android.graphics.Rect;
- import android.util.Log;
- public class NativeUtil {
- private static int DEFAULT_QUALITY = 95;
- public static void compressBitmap(Bitmap bit, String fileName,
- boolean optimize) {
- compressBitmap(bit, DEFAULT_QUALITY, fileName, optimize);
- }
- public static void compressBitmap(Bitmap bit, int quality, String fileName,
- boolean optimize) {
- Log.d("native", "compress of native");
- // if (bit.getConfig() != Config.ARGB_8888) {
- Bitmap result = null;
- result = Bitmap.createBitmap(bit.getWidth() / 3, bit.getHeight() / 3,
- Config.ARGB_8888);// 缩小3倍
- Canvas canvas = new Canvas(result);
- Rect rect = new Rect(0, 0, bit.getWidth(), bit.getHeight());// original
- rect = new Rect(0, 0, bit.getWidth() / 3, bit.getHeight() / 3);// 缩小3倍
- canvas.drawBitmap(bit, null, rect, null);
- saveBitmap(result, quality, fileName, optimize);
- result.recycle();
- // } else {
- // saveBitmap(bit, quality, fileName, optimize);
- // }
- }
- private static void saveBitmap(Bitmap bit, int quality, String fileName,
- boolean optimize) {
- compressBitmap(bit, bit.getWidth(), bit.getHeight(), quality,
- fileName.getBytes(), optimize);
- }
- private static native String compressBitmap(Bitmap bit, int w, int h,
- int quality, byte[] fileNameBytes, boolean optimize);
- static {
- System.loadLibrary("jpegbither");
- System.loadLibrary("bitherjni");
- }
- }
注意包名和方法名都是不能变的,因为在编译的时候已经被确定。
如果我们想要去修改方法名放入自己的项目中怎么办。那我们就需要去修改一下bitherlibjni.c这个文件。
例如我想把这个方法放在com.example.test中的ImageUtils中,
我们只需要把c文件中的
jstring Java_net_bither_util_NativeUtil_compressBitmap(JNIEnv* env, jobject thiz, jobject bitmapcolor, int w, int h, int quality, jbyteArray fileNameStr, jboolean optimize) {修改为
jstring Java_com_example_test_ImageUtils_compressBitmap(JNIEnv* env, jobject thiz, jobject bitmapcolor, int w, int h, int quality, jbyteArray fileNameStr, jboolean optimize) {这个对会ndk开发的同学应该都知道,接下来我们重新运行ndk-build就可以重新替换so文件然后调用我们自己的libjpeg了。
但是,目前libjpeg是很多年前的了。github上这个库只支持arm架构的cpu,如果我们想用这个库的话,只能通过在加载so文件的时候对其进行trycatch处理,来防止x86等其他cpu架构的机器加载so文件报错。
压缩效果对比:
原图:
bitmap压缩:
libjpeg压缩:
github下载地址:https://github.com/xiaoqiAndroid/LibJpegCompress/tree/master
更多相关文章
- android反编译和防止反编译的方法
- Android研究院之ListView原理学习与优化总结
- 自制Gallery打开指定文件夹里的图片
- 你不应该错过的 Android(安卓)全方位面试总结
- Zygote家的大儿子 —— SystemServer
- 【笔记】Retrofit的使用以及原理
- Android(安卓)WebView JS不能调用Java对象的问题
- android利用BitMap获得图片的像素数据
- Android系统移植与调试之------->如何修改开机动画的两种方式剖