libjpeg哈夫曼算法压缩图片

之前的博客提到过关于图片压缩的方法: Android 图片压缩,Bitmap优化


Android原生的压缩方法,不在乎两种:通过设置simpleSize根据图片尺寸压缩图片;通过Bitmap.compress方法通过压缩图片质量,去压缩。但是我们当我们对图片质量和图片文件大小同时存在要求时,我们发现无论怎么去设置参数,我们所做的效果总是不能尽如人意,而且同样大小的图片,效果却总是比iOS的效果差很多。

其实归根到底的是iOS和Android的压缩算法存在一些差异。

Android所用的是skia的压缩算法,它在google的很多地方,比如chrome、Android等都有使用,而Bitmap的压缩算法就是通过这个实现。而Skia是libjpeg进行了封装,google在实现skia时对其中一个地方进行了修改:通过哈夫曼算法来进行图片压缩,但是采用这个算法的时候,机器可能会出现性能问题,于是并没有调动这个方法。

[plain]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. boolean optimize_coding   
  2. TRUE causes the compressor to compute optimal Huffman coding tables   
  3. for the image. This requires an extra pass over the data and   
  4. therefore costs a good deal of space and time. The default is   
  5. FALSE, which tells the compressor to use the supplied or default   
  6. Huffman tables. In most cases optimal tables save only a few percent   
  7. of file size compared to the default tables. Note that when this is   
  8. TRUE, you need not supply Huffman tables at all, and any you do   
  9. supply will be overwritten.  
但是,这个问题在十年前或许存在,但是现在的机器已经完全可以解决性能问题,而google却忘记了更正当年的代码。


接下来,我们就自己去编译生成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  
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要裁剪一张图片,可以使用libjpeg库提供的函数进行操作。以下是一个简单的例子: ```c #include <stdio.h> #include <stdlib.h> #include <jpeglib.h> int main(int argc, char **argv) { if (argc != 6) { fprintf(stderr, "Usage: %s <input file> <output file> <x> <y> <width> <height>\n", argv[0]); exit(1); } const char *input_file = argv[1]; const char *output_file = argv[2]; int x = atoi(argv[3]); int y = atoi(argv[4]); int width = atoi(argv[5]); int height = atoi(argv[6]); FILE *infile = fopen(input_file, "rb"); if (!infile) { fprintf(stderr, "Failed to open input file %s\n", input_file); exit(1); } struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); int row_stride = cinfo.output_width * cinfo.output_components; JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); FILE *outfile = fopen(output_file, "wb"); if (!outfile) { fprintf(stderr, "Failed to open output file %s\n", output_file); exit(1); } struct jpeg_compress_struct cinfo_out; struct jpeg_error_mgr jerr_out; cinfo_out.err = jpeg_std_error(&jerr_out); jpeg_create_compress(&cinfo_out); jpeg_stdio_dest(&cinfo_out, outfile); cinfo_out.image_width = width; cinfo_out.image_height = height; cinfo_out.input_components = cinfo.output_components; cinfo_out.in_color_space = cinfo.out_color_space; jpeg_set_defaults(&cinfo_out); jpeg_start_compress(&cinfo_out, TRUE); while (cinfo.output_scanline < cinfo.output_height) { int row = cinfo.output_scanline; if (row >= y && row < y + height) { jpeg_read_scanlines(&cinfo, buffer, 1); int offset = (row - y) * row_stride + x * cinfo.output_components; jpeg_write_scanlines(&cinfo_out, buffer + offset, 1); } else { jpeg_skip_scanlines(&cinfo, 1); } } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); jpeg_finish_compress(&cinfo_out); jpeg_destroy_compress(&cinfo_out); fclose(outfile); return 0; } ``` 这个程序从命令行接收输入文件名、输出文件名、裁剪的x、y坐标和宽度、高度参数。它使用libjpeg库从输入文件中读取图像,裁剪它,并将结果写入输出文件中。 要编译这个程序,需要安装libjpeg库,并使用以下命令: ``` gcc -o jpeg_crop jpeg_crop.c -ljpeg ``` 然后可以使用以下命令来裁剪一张图片: ``` ./jpeg_crop input.jpg output.jpg 100 100 200 200 ``` 这将从输入文件中裁剪一个200x200像素的矩形,从左上角的坐标(100, 100)开始,并将结果写入输出文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值