一、Android中使用的图片压缩库
Android和IOS 中图片处理使用了一个叫做skia的开源图形处理引擎。他位于android源码的/external/skia 目录。我们平时在java层使用一个图片处理的函数实际上底层就是调用了这个开源引擎中的相关的函数。
二、Android 中常用的压缩方式
Android中常用压缩方法分为2种:一种是降采样率压缩,另外一种是质量压缩
代码:
1.降采样率压缩的一般写法:

  public static Bitmap obtainImageFromPath(String path, int width, int height) {BitmapFactory.Options o = new BitmapFactory.Options();o.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, o);o.inSampleSize = calculateSampleSize(o, width, height);o.inJustDecodeBounds = false;return BitmapFactory.decodeFile(path, o);}private static int calculateSampleSize(BitmapFactory.Options o, int reqWidth, int reqHeight) {int sampleSize = 1;if (o.outWidth > reqWidth || o.outHeight > reqHeight) {final int halfWidth = o.outWidth / 2;final int halfHeight = o.outHeight / 2;while ((halfHeight / sampleSize) >= reqHeight&& (halfWidth / sampleSize) >= reqWidth) {sampleSize *= 2;}}return sampleSize;}

2.质量压缩的一般写法:

bitmap.compress(Bitmap.CompressFormat.JPEG, 20, new FileOutputStream("sdcard/result.jpg"));

三、libjpeg
我们使用质量压缩的话它的底层就是用skia引擎进行处理,加入我们调用bitmap.compress(Bitmap.CompressFormat.JPEG,…..) 他实际会 使用一个libjpeg.so 的动态库进行编码压缩。
android在进行jpeg压缩编码的时候,考虑到了效率问题使用了定长编码方式进行编码(因为当时的手机性能都比较低),而IOS使用了变长编码的算法——哈夫曼算法。而且IOS对skia引擎也做了优化。所有我们看到同样的图片在ios上压缩会好一点。

四、优化思路
上文我们知道之所以在android机进行质量压缩没有IOS上压缩好的原因,那么我们也就应该有了相应的优化思路。我们的思路如下:
1、下载开源的libjpeg,进行移植、编译得到libjpeg.so
2、使用jni编写一个函数用来图片压缩
3、在函数中添加一个开关选项,可以让我们选择是否使用哈夫曼算法。
4、打包,搞成sdk供我们以后使用。

五、实现
1、下载libjpeg 编译
使用git clone最新的android分支

git clone git://git.linaro.org/people/tomgall/libjpeg-turbo/libjpeg-turbo.git -b linaro-android

2、编译
记得配置好ndk,设置环境变量

1、把文件名变成 jni
mv libjpeg-turbo jni
2、编译
ndk-build APP_ABI=armeabi-v7a,armeabi

3、使用AndroidStudio创建一个项目,记得勾选c++ support

4、加入编译好的 动态库,和头文件并且在在配置文件中引用

5、编写代码:

#include "compress.h"
#include "lang.h"#include <android/bitmap.h>
#include <setjmp.h>
#include <jpeglib.h>#include <stdlib.h>#define true 1
#define false 0typedef u_int8_t BYTE;struct my_error_mgr {struct jpeg_error_mgr pub;jmp_buf setjmp_buffer;
};typedef struct my_error_mgr *my_error_ptr;METHODDEF(void)my_error_exit(j_common_ptrcinfo) {my_error_ptr myerr = (my_error_ptr) cinfo->err;(*cinfo->err->output_message)(cinfo);LOGW("jpeg_message_table[%d]:%s",myerr->pub.msg_code, myerr->pub.jpeg_message_table[myerr->pub.msg_code]);longjmp(myerr->setjmp_buffer, 1);
}int generateJPEG(BYTE *data, int w, int h, jint quality, const char *name, boolean optimize);const char *jstringToString(JNIEnv *env, jstring jstr);JNIEXPORT jintJNICALL
Java_com_blueberry_compress_ImageCompress_nativeCompressBitmap(JNIEnv *env, jclass type,jobject bitmap, jint quality,jstring dstFile_,jboolean optimize) {AndroidBitmapInfo androidBitmapInfo;BYTE *pixelsColor;int ret;BYTE *data;BYTE *tmpData;const char *dstFileName = jstringToString(env, dstFile_);//解码Android Bitmap信息if ((ret = AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo)) < 0) {LOGD("AndroidBitmap_getInfo() failed error=%d", ret);return ret;}if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelsColor)) < 0) {LOGD("AndroidBitmap_lockPixels() failed error=%d", ret);return ret;}LOGD("bitmap: width=%d,height=%d,size=%d , format=%d ",androidBitmapInfo.width, androidBitmapInfo.height,androidBitmapInfo.height * androidBitmapInfo.width,androidBitmapInfo.format);BYTE r, g, b;int color;int w, h, format;w = androidBitmapInfo.width;h = androidBitmapInfo.height;format = androidBitmapInfo.format;data = (BYTE *) malloc(androidBitmapInfo.width * androidBitmapInfo.height * 3);tmpData = data;// 将bitmap转换为rgb数据for (int i = 0; i < h; ++i) {for (int j = 0; j < w; ++j) {//只处理 RGBA_8888if (format == ANDROID_BITMAP_FORMAT_RGBA_8888) {color = (*(int *) (pixelsColor));// 这里取到的颜色对应的 A B G R  各占8位b = (color >> 16) & 0xFF;g = (color >> 8) & 0xFF;r = (color >> 0) & 0xFF;*data = r;*(data + 1) = g;*(data + 2) = b;data += 3;pixelsColor += 4;} else {return -2;}}}AndroidBitmap_unlockPixels(env, bitmap);//进行压缩ret = generateJPEG(tmpData, w, h, quality, dstFileName, optimize);free((void *) dstFileName);free((void *) tmpData);return ret;
}int generateJPEG(BYTE *data, int w, int h, int quality, const char *name, boolean optimize) {int nComponent = 3;struct jpeg_compress_struct jcs;//自定义的errorstruct my_error_mgr jem;jcs.err = jpeg_std_error(&jem.pub);jem.pub.error_exit = my_error_exit;if (setjmp(jem.setjmp_buffer)) {return 0;}//为JPEG对象分配空间并初始化jpeg_create_compress(&jcs);//获取文件信息FILE *f = fopen(name, "wb");if (f == NULL) {return 0;}//指定压缩数据源jpeg_stdio_dest(&jcs, f);jcs.image_width = w;jcs.image_height = h;jcs.arith_code = false;jcs.input_components = nComponent;jcs.in_color_space = JCS_RGB;jpeg_set_defaults(&jcs);jcs.optimize_coding = optimize;//为压缩设定参数,包括图像大小,颜色空间jpeg_set_quality(&jcs, quality, true);//开始压缩jpeg_start_compress(&jcs, true);JSAMPROW row_point[1];int row_stride;row_stride = jcs.image_width * nComponent;while (jcs.next_scanline < jcs.image_height) {row_point[0] = &data[jcs.next_scanline * row_stride];jpeg_write_scanlines(&jcs, row_point, 1);}if (jcs.optimize_coding) {LOGI("使用了哈夫曼算法完成压缩");} else {LOGI("未使用哈夫曼算法");}//压缩完毕jpeg_finish_compress(&jcs);//释放资源jpeg_destroy_compress(&jcs);fclose(f);return 1;
}const char *jstringToString(JNIEnv *env, jstring jstr) {char *ret;const char *tempStr = (*env)->GetStringUTFChars(env, jstr, NULL);jsize len = (*env)->GetStringUTFLength(env, jstr);if (len > 0) {ret = (char *) malloc(len + 1);memcpy(ret, tempStr, len);ret[len] = 0;}(*env)->ReleaseStringUTFChars(env, jstr, tempStr);return ret;
}

6、最后测试

我测试发现确实有些改善,使用同样的压缩等级,采用哈夫曼算法的话,会压缩的更小一些。

7、最后
代码地址:
https://github.com/blueberryCoder/Compress

Android使用libjpeg实现图片压缩相关推荐

  1. 使用libjpeg进行图片压缩(哈夫曼算法,无损压缩)

    Huffman算法也是一种无损压缩算法,但与LZW压缩算法不同,Huffman需要得到每种字符出现概率的先验知识.通过计算字符序列中每种字符出现的频率,为每种字符进行唯一的编码设计,使得频率高的字符占 ...

  2. Android性能优化之图片压缩优化

    1 分类 Android图片压缩结合多种压缩方式,常用的有尺寸压缩.质量压缩.采样率压缩以及通过JNI调用libjpeg库来进行压缩. 参考此方法:Android-BitherCompress 备注: ...

  3. 使用libjpeg进行图片压缩

    简介 由于工作原因,boss下达的任务就大概说了对图片进行压缩寻找比较合理的方式,还举了一个项目中的坑,就是系统原生的Bitmap.compress设置质量参数为100生成图片会变大的坑.所以我打算用 ...

  4. Android性能优化之图片压缩综合解决方案

    在Android中我们经常会遇到图片压缩的场景,比如给服务端上传图片,包括个人信息的用户头像,有时候人脸识别也需要捕获图片等等.这种情况下,我们都需要对图片做一定的处理,比如大小,尺寸等的压缩. 常见 ...

  5. Android 最详细的图片压缩攻略(建议收藏)

    以下内容来自公众号code小生,关注每日干货及时送达 作者:Mr.Louis https://blog.csdn.net/weixin_44005563 前言 最近在研究图片压缩原理,看了大量资料,从 ...

  6. Android 超清大尺寸图片压缩转Base64中卡顿/速度优化问题整理(在子线程压缩Bitmap卡的主线程进度条走不动了。。。)

    最近遇到需求是前后端传输图片使用的是Base64,但是前端(Android 端)图片很大(尺寸很大4480 × 2520,质量也很大7-10M),需要压缩到一定尺寸(1280 × 960,当然还可以压 ...

  7. 图片压缩android bitmap compress(图片压缩)

    本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~ 有些场景中,须要照相并且上传到服务,但是由于图片的巨细太大,那么就 上传就 会很慢(在有些网络情况下),而且很耗流量,要想速度 ...

  8. bitmap的六种压缩方式,Android图片压缩(转)

    转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/51955467 android中图片是以bitmap形式存在的,那么bitm ...

  9. bitmap的六种压缩方式,Android图片压缩

    转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/51955467 android中图片是以bitmap形式存在的,那么bitm ...

最新文章

  1. 这就是为什么我们需要在React的类组件中绑定事件处理程序
  2. Linux基础知识99问(一)
  3. Quartz 框架快速入门(一)
  4. ACM常见错误提示及可能的解决办法
  5. linux下面破解rar压缩包密码
  6. python爬虫用什么软件写_python爬虫怎么写
  7. 论文阅读 | DasiamRPN
  8. java 求最大公因数_求最大公约数的三种算法(java实现)
  9. 平流式沉淀池表面负荷怎么计算_推荐收藏关于斜管(板)沉淀池的知识点汇总,及常见问题解决!...
  10. 8 年经验面试官解读程序员的技能瓶颈,以及突破瓶颈的忠告 | CSDN 博文精选
  11. Lesson 3.5 - Maya Commands: getAttr
  12. arm poky linux,opencv移植在4412和imx6(yocto 3.14.28 arm-poky-linux-gnueabi )上
  13. cai计算机辅助教程,拓展:计算机辅助教学(CAI)的基本模式
  14. 三对角矩阵解算——TDMA解法(C++)
  15. init mysql db error_Python mysql curs错误
  16. SQL Server基础操作(此随笔仅作为本人学习进度记录六 !--程序块和循环)
  17. oauth2 ldap sso
  18. 【Linux】进程状态的理解
  19. (二、八、十、十六)进制转换
  20. 电脑桌面便签提醒事项到期后怎么清除时间设置?

热门文章

  1. 会员中心—1—登录与注册
  2. Named Route ‘***‘ has a default child route. When navigating to this named route
  3. HP DL580 G8 做RAID
  4. python图像计数_检测并计数图像中的对象
  5. 利用随机森林进行特征选择
  6. WhatsApp:硅谷屌丝现世逆袭
  7. 猿创征文|后端开发工程师提升开发效率神器推荐
  8. unity自定义组件
  9. Google hacking使用总结
  10. 本地化 A NOTE 桌面便签软件 ---最佳开源软件之一