美文网首页
图片压缩—开发属于自己的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