图片压缩之图片大小极限压缩


Android开发中,我们需要处理图片压缩,今天要介绍的是基于NDK层利用libjpeg-turbo(基于哈夫曼算法)类库做图片体积的极限压缩,跟libjpeg相比速度提升2-6倍。

1. 编译libjpeg-turbo准备工作

(1)NDK下载 ,去官方网站下载 (官网),笔者用的是android-ndk-r16c版本。NDK,Android Native Development Kit一套允许使用原生代码语言C/C++,实现部分应用的集。 C/C++与Java通过JNI交互。

(2)LibJpeg库。下载路径  wget https://github.com/libjpeg-turbo/libjpeg-turbo/archive/2.0.2.tar.gz,建议使用release版本,解压  tar xvf 2.0.2.tar.gz;编译可参考官方文档说明 (编辑官方文档说明)

(3)安装NASM。选择最新的发布版本,压缩包下载路径(下载路径),解压下载的文件,进入解压后的目录可以看到一个文件configure  用于生成Makefile文件,编译出该文件    ./configure

(4)安装cmake。官网地址(下载)

2.接下来可以进入libjepg目录进行编译了

(1)生成shell脚本。如下:

笔者mac环境下脚本如图:

图片压缩之图片大小极限压缩_第1张图片

执行该脚本后,去libjpeg-turbo目录下查看,找到如下图几个文件,并copy到项目的相应目录


图片压缩之图片大小极限压缩_第2张图片

以上几个文件就是我们编译libjpeg-turbo所得到的压缩图片的核心类库,接下来要实现native方法去对图片进行压缩

3.项目用使用。

(1)注意你的项目在创建的时候要勾选 Include C++ support。接下来配置CMakeLists,如下图:


图片压缩之图片大小极限压缩_第3张图片

注意:如果你的Gradle编译不过,检查下gradle版本(要更高版本),笔者用的是 classpath'com.android.tools.build:gradle:3.2.0'(供参考)

(2)开始压缩,大致分为下面几个步骤:

1、获得待压缩Bitmap

2、获得Bitmap中像素数据(ARGB->BGR)

3、Libjpeg压缩。

创建jpeg压缩对象;指定存储文件;设置压缩参数;开始压缩;循环写入每一行数据;压缩完成;释放jpeg对象。

压缩核心方法代码:

extern "C"

JNIEXPORTvoid JNICALL

Java_com_example_administrator_demo_MainActivity_nativeCompress(JNIEnv *env,

                                                                        jobject instance,

                                                                        jobject bitmap, jint q,

                                                                        jstring path_) {

const char *path = env->GetStringUTFChars(path_, 0);

    //从bitmap获取argb数据

    AndroidBitmapInfo info;//info=new 对象();

//获取里面的信息

    AndroidBitmap_getInfo(env, bitmap, &info);//  void method(list)

//得到图片中的像素信息

    uint8_t *pixels;//uint8_t char    java  byte    *pixels可以当byte[]

    AndroidBitmap_lockPixels(env, bitmap, (void **) &pixels);

    //jpeg argb中去掉他的a ===>rgb

    int w = info.width;

    int h = info.height;

    int color;

    //开一块内存用来存入rgb信息

    uint8_t *data = (uint8_t *) malloc(w * h *3);//data中可以存放图片的所有内容

    uint8_t *temp = data;

    uint8_t r, g, b;//byte

//循环取图片的每一个像素

    for (int i =0; i < h; i++) {

for (int j =0; j < w; j++) {

color = *(int *) pixels;//0-3字节  color4 个字节  一个点

//取出rgb

            r = (color >>16) &0xFF;//    #00rrggbb  16  0000rr  8  00rrgg

            g = (color >>8) &0xFF;

            b = color &0xFF;

            //存放,以前的主流格式jpeg    bgr

            *data = b;

            *(data +1) = g;

            *(data +2) = r;

            data +=3;

            //指针跳过4个字节

            pixels +=4;

        }

}

//把得到的新的图片的信息存入一个新文件 中

    write_JPEG_file(temp, w, h, q, path);

    //释放内存

    free(temp);

    AndroidBitmap_unlockPixels(env, bitmap);

    env->ReleaseStringUTFChars(path_, path);

}

void 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 binary

    FILE *f = fopen(path, "wb");

    jpeg_stdio_dest(&jcs, f);

//    3.3、设置压缩参数

    jcs.image_width = w;

    jcs.image_height = h;

    //bgr

    jcs.input_components =3;

    jcs.in_color_space = JCS_RGB;

    jpeg_set_defaults(&jcs);

    //开启哈夫曼功能

    jcs.optimize_coding =true;

    jpeg_set_quality(&jcs, q, 1);

//    3.4、开始压缩

    jpeg_start_compress(&jcs, 1);

//    3.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);

    }

//    3.6、压缩完成

    jpeg_finish_compress(&jcs);

//    3.7、释放jpeg对象

    fclose(f);

    jpeg_destroy_compress(&jcs);

}

在java层调用native方法,如下图:


图片压缩之图片大小极限压缩_第4张图片

以上是对图片大小进行压缩,实质上是体积的一种压缩,图片显示效果根据上图方法的q(质量参数)参数来写,一般情况下50左右就可以达到效果与原图没有区别,一般情况下比如2M的图片,经过这样的压缩 ,可以压缩到1M以下,大大减少了图片所占有存储空间。至于应用跑起来的时候,怎么去对图片加载需要的内存压缩,后续会补上图片内存压缩相关博客!

你可能感兴趣的:(图片压缩之图片大小极限压缩)