Android圖片壓縮加密上傳 - NDK終極壓縮和加密上傳

1. 概述


上一期已講到Android圖片壓縮加密上傳 - JPEG壓縮算法解析填物,我們不打算采用BitmapFactory去壓縮晨另,而是采用JPEG的壓縮算法霹粥,當(dāng)然大家最好是將兩者結(jié)合一下渺氧,今天我們直接去網(wǎng)上找一個已經(jīng)寫好的開源庫嫂沉,然后我們在他的基礎(chǔ)上再寫一些Native代碼就好,當(dāng)然也可以自己一步一步去寫算法處理缚态。

效果演示

所有分享大綱:2017Android進(jìn)階之路與你同行

視頻講解地址:http://pan.baidu.com/s/1eR8ZnxS

2. 編譯libjpeg.so庫文件


關(guān)于C和C++以及NDK的基礎(chǔ)我這里就不強調(diào)磁椒,如果大家覺得我寫的C++代碼看不懂那么也沒關(guān)系,你只需要關(guān)注我這里所實現(xiàn)的思路玫芦,我最終把它編譯成.so庫你能用就行浆熔。
  打開https://github.com/libjpeg-turbo/libjpeg-turbo 下載已經(jīng)提供好的開源庫,打開后你會看到有很多的.c文件和.h頭文件桥帆,把他編譯成.so庫文件即可医增,當(dāng)然道路曲折會出現(xiàn)很多問題慎皱,這里我就不寫過程了,等到增量更新的時候我會一步一步去帶大家編譯的叶骨。
  我們將已經(jīng)編譯好的libjpeg.so以及.h頭文件拷貝到j(luò)ni目錄下面茫多,就可以開始寫壓縮代碼了:

目前jni目錄

3. 編寫imgcompcrypt.cpp


我使用的是AS,網(wǎng)上關(guān)于AS的NDK方面的資料比較少忽刽,需要多花一些功夫天揖,最好把AS升級到2.2版本以上,然后下載NDK跪帝、CMake宝剖、LLDB,一個支持歉甚、一個插件万细、一個調(diào)試:

{4U3J{YTF`%)}1T4)W6LUH1.png

升級到2.2之后我們寫C和C++的代碼才會有提示,之前的版本我還沒找到解決的方案纸泄,網(wǎng)上搜索了很多也沒有相關(guān)答案赖钞,而且它也支持Cmake和ndk-build兩種方式,相比與以前的gradle去配置ndk編譯目錄什么的簡直是方便多了聘裁。對于老的通過Android.mk文件編譯的NDK項目雪营,直接一條配置整個項目就可以被AS支持了。如果覺得Cmake的方式不習(xí)慣還是可以采用ndk-build的方式這點倒是無所謂衡便,至于代碼提示肯定是要的這個很致命献起,要不然寫代碼會比較慢。怎么生成頭文件我就不講了镣陕,這里直接上代碼:

#include "imgcompcrypt.h"
#include <string.h>
#include <android/bitmap.h>
#include <android/log.h>
#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <stdint.h>
#include <time.h>



//統(tǒng)一編譯方式
extern "C" {
#include "jpeg/jpeglib.h"
#include "jpeg/cdjpeg.h"        /* Common decls for cjpeg/djpeg applications */
#include "jpeg/jversion.h"      /* for version message */
#include "jpeg/jconfig.h"
#include "filecrypt.c"
}

// log打印
#define LOG_TAG "jni"
#define LOGW(...)  __android_log_write(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

#define true 1
#define false 0

typedef uint8_t BYTE;

// error 結(jié)構(gòu)體
char *error;
struct my_error_mgr {
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};

typedef struct my_error_mgr *my_error_ptr;

METHODDEF(void)
my_error_exit(j_common_ptr cinfo) {
    my_error_ptr myerr = (my_error_ptr) cinfo->err;
    (*cinfo->err->output_message)(cinfo);
    error = (char *) myerr->pub.jpeg_message_table[myerr->pub.msg_code];
    LOGE("jpeg_message_table[%d]:%s", myerr->pub.msg_code,
         myerr->pub.jpeg_message_table[myerr->pub.msg_code]);
    longjmp(myerr->setjmp_buffer, 1);
}

int generateJPEG(BYTE *data, int w, int h, int quality,
                 const char *outfilename, jboolean optimize) {

    // 結(jié)構(gòu)體相當(dāng)于Java類
    struct jpeg_compress_struct jcs;

    //當(dāng)讀完整個文件的時候就會回調(diào)my_error_exit這個退出方法谴餐。
    struct my_error_mgr jem;
    jcs.err = jpeg_std_error(&jem.pub);
    jem.pub.error_exit = my_error_exit;
    // setjmp是一個系統(tǒng)級函數(shù),是一個回調(diào)呆抑。
    if (setjmp(jem.setjmp_buffer)) {
        return 0;
    }

    //初始化jsc結(jié)構(gòu)體
    jpeg_create_compress(&jcs);
    //打開輸出文件 wb 可寫  rb 可讀
    FILE *f = fopen(outfilename, "wb");
    if (f == NULL) {
        return 0;
    }
    //設(shè)置結(jié)構(gòu)體的文件路徑岂嗓,以及寬高
    jpeg_stdio_dest(&jcs, f);
    jcs.image_width = w;
    jcs.image_height = h;

    // /* TRUE=arithmetic coding, FALSE=Huffman */
    jcs.arith_code = false;
    int nComponent = 3;
    /* 顏色的組成 rgb,三個 # of color components in input image */
    jcs.input_components = nComponent;
    //設(shè)置顏色空間為rgb
    jcs.in_color_space = JCS_RGB;
    ///* Default parameter setup for compression */
    jpeg_set_defaults(&jcs);
    //是否采用哈弗曼
    jcs.optimize_coding = optimize;
    //設(shè)置質(zhì)量
    jpeg_set_quality(&jcs, quality, true);
    //開始壓縮
    jpeg_start_compress(&jcs, TRUE);

    JSAMPROW row_pointer[1];
    int row_stride;
    row_stride = jcs.image_width * nComponent;
    while (jcs.next_scanline < jcs.image_height) {
        //得到一行的首地址
        row_pointer[0] = &data[jcs.next_scanline * row_stride];
        jpeg_write_scanlines(&jcs, row_pointer, 1);
    }
    // 壓縮結(jié)束
    jpeg_finish_compress(&jcs);
    // 銷毀回收內(nèi)存
    jpeg_destroy_compress(&jcs);
    //關(guān)閉文件
    fclose(f);
    return 1;
}

jint Java_net_bither_util_NativeUtil_compressBitmap(JNIEnv *env,
                                                    jclass thiz, jobject bitmap, int quality,
                                                    jstring fileNameStr, jboolean optimize) {
    // 1.獲取Bitmap信息
    AndroidBitmapInfo android_bitmap_info;
    AndroidBitmap_getInfo(env, bitmap, &android_bitmap_info);
    // 獲取bitmap的 寬鹊碍,高厌殉,format
    int bitmap_width = android_bitmap_info.width;
    int bitmap_height = android_bitmap_info.height;
    int format = android_bitmap_info.format;

    if (format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        return -1;
    }
    // 2.解析Bitmap的像素信息,并轉(zhuǎn)換成RGB數(shù)據(jù),保存到二維byte數(shù)組里面
    BYTE *pixelscolor;
    // 2.1 鎖定畫布
    AndroidBitmap_lockPixels(env, bitmap, (void **) &pixelscolor);
    // 2.2 解析初始化參數(shù)值
    BYTE *data;
    BYTE r, g, b;
    data = (BYTE *) malloc(bitmap_width * bitmap_height * 3);//每一個像素都有三個信息RGB
    BYTE *tmpData;
    tmpData = data;//臨時保存data的首地址
    int i = 0, j = 0;
    int color;
    //2.3 解析每一個像素點里面的rgb值(去掉alpha值)侈咕,保存到一維數(shù)組data里面
    for (i = 0; i < bitmap_height; ++i) {
        for (j = 0; j < bitmap_width; ++j) {
            //獲取二維數(shù)組的每一個像素信息首地址
            color = *((int *) pixelscolor);
            r = ((color & 0x00FF0000) >> 16);
            g = ((color & 0x0000FF00) >> 8);
            b = ((color & 0x000000FF));
            //保存到data數(shù)據(jù)里面
            *data = b;
            *(data + 1) = g;
            *(data + 2) = r;
            data = data + 3;
            // 一個像素包括argb四個值公罕,每+4就是取下一個像素點
            pixelscolor += 4;
        }
    }
    // 2.4. 解鎖Bitmap
    AndroidBitmap_unlockPixels(env, bitmap);
    // jstring --> c char
    char *fileName = (char*)(env)->GetStringUTFChars(fileNameStr, 0);

    //3. 調(diào)用libjpeg核心方法實現(xiàn)壓縮
    int resultCode = generateJPEG(tmpData, bitmap_width, bitmap_height, quality, fileName, optimize);

    //4.釋放資源
    env->ReleaseStringUTFChars(fileNameStr, fileName);
    free((void *) tmpData);
    // 4.2 釋放Bitmap
    // 4.2.1 通過對象獲取類
    jclass bitmap_clz = env->GetObjectClass(bitmap);
    // 4.2.2 通過類和方法簽名獲取方法id
    jmethodID recycle_mid = env->GetMethodID(bitmap_clz, "recycle", "()V");
    // 4.2.3 執(zhí)行回收釋放方法
    env->CallVoidMethod(bitmap, recycle_mid);

    // 5.返回結(jié)果
    if (resultCode == 0) {
        return -1;
    }
    return 1;
}

3. 圖片文件加密


文件的加密相對來說就比較簡單了,因為可能可很多地方涉及到文件加密耀销,這里我就把文件加密單獨分開了楼眷,當(dāng)然也可以寫到圖片壓縮一起,可以用C寫也可以用C++因為上面是用的C++,那么加密我們就采用C:

#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "net_bither_util_FileCrypt.h"

// 加密的秘鑰
char password[] = "Big god take me fly!";

// 加密文件
void crypt_file(char *normal_path, char *crypt_path) {
    //打開文件
    FILE *normal_fp = fopen(normal_path, "rb");
    FILE *crypt_fp = fopen(crypt_path, "wb");
    //一次讀取一個字符
    int ch;
    int i = 0; //循環(huán)使用密碼中的字母進(jìn)行異或運算
    int pwd_len = strlen(password); //密碼的長度
    while ((ch = fgetc(normal_fp)) != EOF) { //End of File
        //寫入(異或運算)
        fputc(ch ^ password[i % pwd_len], crypt_fp);
        i++;
    }
    // 關(guān)閉
    fclose(crypt_fp);
    fclose(normal_fp);
}

// 加密文件摩桶,jfile_path 源文件路徑  jcrypt_path 加密后文件路徑
JNIEXPORT void JNICALL Java_com_hc_filecrypt_FileCrypt_cryptFile
        (JNIEnv *env, jclass jclazz, jstring jfile_path, jstring jcrypt_path) {
    char *normal_path = (char*)(*env)->GetStringUTFChars(env, jfile_path, JNI_FALSE);
    char *crypt_path = (char*)(*env)->GetStringUTFChars(env, jcrypt_path, JNI_FALSE);
    crypt_file(normal_path, crypt_path);
}

4. 最后的測試


接近3M的原圖壓縮到30K,可以找找哪一張是被壓縮過的桥状,會比我們使用BitmapFarctory或者Bitmap.compress()壓縮出來的一些效果要好很多:

效果對比

所有分享大綱:2017Android進(jìn)階之路與你同行

視頻講解鏈接:https://pan.baidu.com/s/1VQhMemYubQfldEcu9gVMEg 密碼:8abx

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帽揪,一起剝皮案震驚了整個濱河市硝清,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌转晰,老刑警劉巖芦拿,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異查邢,居然都是意外死亡蔗崎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門齐鲤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘲碧,“玉大人几睛,你說我怎么就攤上這事∥辞牛” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵芥备,是天一觀的道長冬耿。 經(jīng)常有香客問我,道長萌壳,這世上最難降的妖魔是什么亦镶? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮袱瓮,結(jié)果婚禮上缤骨,老公的妹妹穿的比我還像新娘。我一直安慰自己尺借,他們只是感情好荷憋,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著褐望,像睡著了一般勒庄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瘫里,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天实蔽,我揣著相機與錄音,去河邊找鬼谨读。 笑死局装,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铐尚,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拨脉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宣增?” 一聲冷哼從身側(cè)響起玫膀,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爹脾,沒想到半個月后帖旨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡灵妨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年解阅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泌霍。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡货抄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朱转,到底是詐尸還是另有隱情蟹地,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布肋拔,位于F島的核電站锈津,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凉蜂。R本人自食惡果不足惜琼梆,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窿吩。 院中可真熱鬧茎杂,春花似錦、人聲如沸纫雁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轧邪。三九已至刽脖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忌愚,已是汗流浹背曲管。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硕糊,地道東北人院水。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓腊徙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親檬某。 傳聞我的和親對象是個殘疾皇子撬腾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 注:首發(fā)地址 0. 前言 如果只學(xué)理論,不做實踐恢恼,不踩踩坑民傻,一般很難發(fā)現(xiàn)真正實踐項目中的問題的,也比較難以加深對技...
    cfanr閱讀 9,490評論 4 50
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,099評論 25 707
  • 注:首發(fā)地址 1. 前言 當(dāng)在做 Android NDK 開發(fā)時厅瞎,如果不熟悉用 CMake 來構(gòu)建饰潜,讀不懂 CMa...
    cfanr閱讀 24,374評論 1 53
  • 先發(fā)一張昨天去看我雷哥演唱會的皂片然后再說正文哈哈初坠。 簡介 由于工作原因和簸,boss下達(dá)的任務(wù)就大概說了對圖片進(jìn)行壓...
    我叫王菜鳥閱讀 5,224評論 2 16
  • 一、“閱人無數(shù)”不如名師指路 1碟刺、人到中年锁保,抬頭就是天花板。 三個月前半沽,華為清理35歲以上員工的消息引發(fā)網(wǎng)友對“3...
    瑨瑗閱讀 626評論 10 17