美文网首页
图片压缩—开发属于自己的SDK(二)

图片压缩—开发属于自己的SDK(二)

作者: CaoMeng | 来源:发表于2019-06-14 12:06 被阅读0次

前言:

在上一篇文章中,已经编译好可行性文件了,那么接下来配置好Cmake,废话不多说了,直接撸码...

Step1:新建一个NDK工程

Window平台NDK版本:android-ndk-r19c
Android Studio:3.4

Step2:复制相关文件到AS工程
项目结构.png

备注:相关文件会上传到github上

CMakeLists.txt:


cmake_minimum_required(VERSION 3.4.1)

#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
add_library( # Sets the name of the library.
        compress-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             native-lib.cpp )

#STATIC
add_library(libjpeg STATIC IMPORTED)
set_target_properties(libjpeg PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libturbojpeg.a)

#引入头文件    import
include_directories(${CMAKE_SOURCE_DIR}/include)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -D__STDC_CONSTANT_MACROS -L${CMAKE_SOURCE_DIR}/libs/armeabi-v7a")



target_link_libraries( # Specifies the target library.
        compress-lib

        libjpeg
        #jnigraphics是安卓NDK目录中直接有的
        jnigraphics

                       # Links the target library to the log library
                       # included in the NDK.
                       log )

build.grade(app):

apply plugin: 'com.android.application'
android {
    compileSdkVersion 28
    buildToolsVersion "29.0.0"
    defaultConfig {
        applicationId "com.chen.libjpegcompress"
        minSdkVersion 18
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters 'armeabi-v7a'
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation project(path: ':compress')
    implementation 'com.github.bumptech.glide:glide:4.9.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
    api 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'
    api 'io.reactivex.rxjava2:rxandroid:2.0.1'
    api 'io.reactivex.rxjava2:rxjava:2.0.5'
}

Step3:压缩原理

参考:https://www.jianshu.com/p/097f4486f3e6
参考:https://www.jianshu.com/p/eebe2107da6d

Step4:C++代码实现压缩
extern "C"
JNIEXPORT void JNICALL
Java_com_chen_compress_CompressUtils_nativeCompress(JNIEnv *env, jobject instance,
                                                    jobject bitmap, jint q, jstring path_) {

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

    jclass jclazz = env->GetObjectClass(instance);

    jmethodID onCompleteListenerId = env->GetMethodID(jclazz, "onCompleteListener", "()V");
    jmethodID onStartListenerId = env->GetMethodID(jclazz, "onStartListener", "()V");

    env->CallVoidMethod(instance, onStartListenerId);


    //从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);

    env->CallVoidMethod(instance, onCompleteListenerId);

    //释放内存
    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);
}
Step5:效果图 压缩效果图.jpg

备注:原图2.8M 压缩后图片401kb
好了,效果达到了。
github:https://github.com/MrRightChen/LibJpegCompress。还有SDK制作,敬请期待!

相关文章

网友评论

      本文标题:图片压缩—开发属于自己的SDK(二)

      本文链接:https://www.haomeiwen.com/subject/kzeufctx.html