android平台移植jpeg-turbo库达到减小jpeg编码体积的目的
来源:互联网 发布:移动数据打开没有网络 编辑:程序博客网 时间:2024/06/06 02:03
我目前所从事的工作是做公司社交类APP的消息服务模块,其中有一个需求就是压缩传输的图片的体积,因为现在一般的手机拍摄的照片体积都在2M左右,所以想办法减小传输过程中的体积是非常有必要的。
一般的处理过程是这样:设定一个固定的分辨率大小,比如960*960,图片解码成bitmap对象后,如果图片的宽或者高超出了960,那么就对宽和高进行等比例缩放,使得长的那一边刚好等于960,然后再进行jpeg编码。
经过这个过程的处理,一般2M左右的图片就会变为100K左右,这个已经是一个不错的结果了,但是既然交给我们平台架构中心来做这件事,肯定要做出一点不同的效果出来。
我的研究成果如下:
Android平台所使用的jpeg编解码库其实是一个叫IJG的组织开发的一个C库,Android的图形库SKIA对其进行了封装,但是SKIA对jpeg库进行封装的时候没有将其中的两个选项暴露出来:optimize encoding选项和progressive选项,而这两个选项都可以减小编码后的体积,并且progressive选项产生的progressive jpeg的用户体验是好于baseline jpeg的用户体验的(目前还没有找到在ImageView上渐进地显示progressive jpeg的方法),所以我要做的工作是使用NDK移植jpeg编解码库,然后暴露这两个选项出来,让业务来调用我的接口。
第一步:使用Android NDK移植jpeg-turbo库
jpeg-turbo库是对jpeg库的一个优化,此处移植jpeg-turbo库
jpeg-turbo库下载链接:http://download.csdn.net/detail/lihuapinghust/8220993
将下载的zip包解压到android工程的jni目录,在工程的Properties->Builders中新建一个Builder,设置如下:
并且将新建的builder放在第一个位置,然后build,就可以编译so库了
第二部,设计接口
因为我们只在编码的时候做优化,所以我们就要求业务使用Android原生的解码和缩放工具得到要编码的bitmap,然后我们再把bitmap的字节数据拷贝出来,传给我们的接口进行编码操作,所以jni接口部分的代码如下
void write_to_RGB(char * dst, const void* srcRow, int width) {const uint32_t* src = (const uint32_t*)srcRow; while (--width >= 0) { uint32_t c = *src++; dst[0] = SkGetPackedR32(c); dst[1] = SkGetPackedG32(c); dst[2] = SkGetPackedB32(c); dst += 3; }}JNIEXPORT jint JNICALL Java_com_skynet_compressor_image_NativeJpeg_doJpegCompressBitmap (JNIEnv * env, jclass cls, jbyteArray byteArray, jint width, jint height, jstring out_file_path, jint quality) {uint8_t *buf = (uint8_t *)(*env)->GetByteArrayElements(env, byteArray, 0);jlong capacity = (*env)->GetArrayLength(env, byteArray);char * c_out_file_path = (char *) (*env)->GetStringUTFChars(env, out_file_path, NULL);struct jpeg_compress_struct cinfo;struct jpeg_error_mgr jerr;FILE * output_file;cinfo.err = jpeg_std_error(&jerr);jpeg_create_compress(&cinfo);/* Add some application-specific error messages (from cderror.h) */jerr.addon_message_table = cdjpeg_message_table;jerr.first_addon_message = JMSG_FIRSTADDONCODE;jerr.last_addon_message = JMSG_LASTADDONCODE;cinfo.image_width = width;cinfo.image_height = height;cinfo.input_components = 3;cinfo.in_color_space = JCS_RGB;cinfo.optimize_coding = TRUE;cinfo.input_gamma = 1;cinfo.dct_method = JDCT_IFAST;jpeg_set_defaults(&cinfo);jpeg_set_quality(&cinfo, quality, TRUE);jpeg_simple_progression(&cinfo);if ((output_file = fopen(c_out_file_path, "wb")) == NULL) {__android_log_print(ANDROID_LOG_INFO, "native-method", "open outfile failed"); return -1;}jpeg_stdio_dest(&cinfo, output_file);jpeg_start_compress(&cinfo, TRUE);uint8_t* oneRowP = (uint8_t*)malloc(width * 3);const void* srcRow = (const void *)buf;while (cinfo.next_scanline < cinfo.image_height) {JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */write_to_RGB(oneRowP, srcRow, width); row_pointer[0] = oneRowP;(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);srcRow = (const void*)((const char*)srcRow + width * 4);}free(oneRowP);jpeg_finish_compress(&cinfo);jpeg_destroy_compress(&cinfo);fclose(output_file);return 0;}
代码是参考jpeg库本身代码和Android平台源码写的,
然后在Java层声明jni方法:
public static native int doJpegCompressBitmap(byte[] bytes, int width,int height, String outFilePath, int quality);
然后java层就可以使用我们的接口进行jpeg编码了
得到的文件大小会比使用Androdi原生的编码方法得到的文件小6%左右,虽然提升性能不是特别明显,但是在以用户体验为中心的互联网时代,即使是1K的流量也要为用户节省
- android平台移植jpeg-turbo库达到减小jpeg编码体积的目的
- ARM平台移植jpeg z png 库
- JPEG的编码步骤
- VS上jpeg编码程序移植到DSP的总结
- JPEG编码
- JPEG编码
- 关于JPEG编码的感想
- 简单的jpeg编码程序
- 简单的jpeg编码程序
- 简单的jpeg编码程序
- 如何移动表来达到减小数据文件大小的目的
- 如何移动表来达到减小数据文件大小的目的
- 如何移动表来达到减小数据文件大小的目的
- jpeg库移植,mjpg-streamer库移植
- android jpeg库的简单使用
- JPEG库的安装:
- JPEG库的安装
- JPEG库的使用方法
- JAVA WEB知识总结之一--response&&request
- 解读uCos中优先级判定表OSUnMapTbl原理
- 简单的css js控制table隔行变色
- SOLR 中 Schema.xml 的filedType 的一些属性的理解
- 练手小项目(5)安全卫士_利用内容提供者进行短信备份
- android平台移植jpeg-turbo库达到减小jpeg编码体积的目的
- 开源加快了软件产业前进的速度
- 安装Tengine
- 系统状态栏设置
- android客户端通过webServcie与服务器交互,如何保持Session
- 卡特兰数的应用 Catalan number
- solr的multivalued使用说明
- python 的 do ~ while 语法
- Chrome内核解析 -- 绘制引擎基础篇:绘图上下文(RenderingContext, GraphicsContext)