1. 程式人生 > >Android中使用libjpeg-turbo進行圖片質量壓縮過程記錄

Android中使用libjpeg-turbo進行圖片質量壓縮過程記錄

開發十年,就只剩下這套架構體系了! >>>   

專案開發過程中發現Android的質量壓縮演算法在圖片過大,色彩豐富的前提下,壓縮的效能不是特別好,經過調查發現Android底層實現使用Skia引擎,封裝了了libjpeg影象庫。為了適配低版本的Android手機,其內部的壓縮演算法並沒有採用普遍的哈夫曼演算法,因為哈夫曼演算法比較佔CPU,從而選擇了其他的演算法B,而演算法B的效果並沒有達到專案預期,所以這裡的方案就是通過自編譯libjpeg來使用哈夫曼演算法進行圖片壓縮的操作。

libjpeg-turbo是針對libjpeg庫的一個優化版本,具體的介紹可以移步官方網站。接下來記錄如何編譯出對應的so包檔案,這裡採用Cmake的方式進行。

首先下載libjpeg-turbo原始碼,將原始碼中的所有檔案拷貝到cpp資料夾目錄下:

這裡需要注意的是需要把專案的CmakeList檔案改變成libjpeg-turbo資料夾下面的CmakeList檔案,然後進行編譯,就可以在如下目錄中產生so檔案了:

第二步是要複製對應的標頭檔案到新專案當中,主要的標頭檔案包括如下幾個,當然如果呼叫時候需要用到其他的標頭檔案,那麼在複製進去即可:

然後在CmakeList中增加so庫連結,連線到我們專案中的so包中去:



cmake_minimum_required(VERSION 3.4.1)
set(distribution_DIR ../../../../libs)
#新增lib,SHARED型別,是IMPORTED 引入的庫
add_library(libjpeg
        SHARED
        IMPORTED)

#設定 庫的屬性   裡面是名稱 ,屬性:引入地址把我們的真實地址填寫進去
set_target_properties(libjpeg
        PROPERTIES IMPORTED_LOCATION
        ${distribution_DIR}/arm64-v8a/libjpeg.so)

#新增lib,SHARED型別,是IMPORTED 引入的庫
add_library(libturbojpeg
        SHARED
        IMPORTED)

#設定 庫的屬性   裡面是名稱 ,屬性:引入地址把我們的真實地址填寫進去
set_target_properties(libturbojpeg
        PROPERTIES IMPORTED_LOCATION
        ${distribution_DIR}/arm64-v8a/libturbojpeg.so)

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

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


find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)


target_link_libraries( # Specifies the target library.
        native-lib
        libjpeg
        -ljnigraphics
        libturbojpeg
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

進行來編譯即可,編譯通過說明匯入成功。然後進行JNI編碼:

//java
public native int nativeCompressBitmap(Bitmap bitmap, int quality, String destFile);

//jni

#include <jni.h>
#include <string>
#include "turbojpeg.h"
#include "jpeglib.h"
#include <android/bitmap.h>
#include <android/log.h>
#include <csetjmp>

#define LOG_TAG  "C_TAG"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
typedef u_int8_t BYTE;
struct my_error_mgr {
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};

typedef struct my_error_mgr *my_error_ptr;


extern "C" JNIEXPORT jstring JNICALL
Java_com_lin_libjpeg_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */, jstring name) {
    std::string hello = "Hello from C++";
    const char *destFile = env->GetStringUTFChars(name, 0);
    env->ReleaseStringUTFChars(name, destFile);
    return env->NewStringUTF(hello.c_str());
}

int generateJPEG(BYTE *data, int w, int h, jint quality, const char *location, jint quality1) {
    int nComponent = 3;
    struct jpeg_compress_struct jcs;
    //自定義的error
    struct my_error_mgr jem;

    jcs.err = jpeg_std_error(&jem.pub);

    if (setjmp(jem.setjmp_buffer)) {
        return 0;
    }
    //為JPEG物件分配空間並初始化
    jpeg_create_compress(&jcs);
    //獲取檔案資訊
    FILE *f = fopen(location, "wb");
    if (f == NULL) {
        return 0;
    }

    //指定壓縮資料來源
    jpeg_stdio_dest(&jcs, f);
    jcs.image_width = w;
    jcs.image_height = h;

    jcs.arith_code = false;
    jcs.input_components = nComponent;
    jcs.in_color_space = JCS_RGB;

    jpeg_set_defaults(&jcs);
    jcs.optimize_coding = quality;

    //為壓縮設定引數,包括影象大小,顏色空間
    jpeg_set_quality(&jcs, quality, true);
    //開始壓縮
    jpeg_start_compress(&jcs, true);
    JSAMPROW row_point[1];
    int row_stride;
    row_stride = jcs.image_width * nComponent;
    while (jcs.next_scanline < jcs.image_height) {
        row_point[0] = &data[jcs.next_scanline * row_stride];
        jpeg_write_scanlines(&jcs, row_point, 1);
    }

    if (jcs.optimize_coding) {
        LOGD("使用了哈夫曼演算法完成壓縮");
    } else {
        LOGD("未使用哈夫曼演算法");
    }
    //壓縮完畢
    jpeg_finish_compress(&jcs);
    //釋放資源
    jpeg_destroy_compress(&jcs);
    fclose(f);
    return 1;
}

const char *jstringToString(JNIEnv *env, jstring jstr) {
    char *ret;
    const char *tempStr = env->GetStringUTFChars(jstr, NULL);
    jsize len = env->GetStringUTFLength(jstr);
    if (len > 0) {
        ret = (char *) malloc(len + 1);
        memcpy(ret, tempStr, len);
        ret[len] = 0;
    }
    env->ReleaseStringUTFChars(jstr, tempStr);
    return ret;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_lin_libjpeg_MainActivity_nativeCompressBitmap(JNIEnv *env, jobject,
                                                       jobject bitmap, jint optimize,
                                                       jstring destFile_) {
    AndroidBitmapInfo androidBitmapInfo;
    BYTE *pixelsColor;
    int ret;
    BYTE *data;
    BYTE *tmpData;
    const char *dstFileName = jstringToString(env, destFile_);
    //解碼Android Bitmap資訊
    if ((ret = AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo)) < 0) {
        LOGD("AndroidBitmap_getInfo() failed error=%d", ret);
        return ret;
    }
    if ((ret = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void **>(&pixelsColor))) < 0) {
        LOGD("AndroidBitmap_lockPixels() failed error=%d", ret);
        return ret;
    }

    LOGD("bitmap: width=%d,height=%d,size=%d , format=%d ",
         androidBitmapInfo.width, androidBitmapInfo.height,
         androidBitmapInfo.height * androidBitmapInfo.width,
         androidBitmapInfo.format);

    BYTE r, g, b;
    int color;

    int w, h, format;
    w = androidBitmapInfo.width;
    h = androidBitmapInfo.height;
    format = androidBitmapInfo.format;

    data = (BYTE *) malloc(androidBitmapInfo.width * androidBitmapInfo.height * 3);
    tmpData = data;
    // 將bitmap轉換為rgb資料
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            //只處理 RGBA_8888
            if (format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
                color = (*(int *) (pixelsColor));
                // 這裡取到的顏色對應的 A B G R  各佔8位
                b = (color >> 16) & 0xFF;
                g = (color >> 8) & 0xFF;
                r = (color >> 0) & 0xFF;
                *data = r;
                *(data + 1) = g;
                *(data + 2) = b;

                data += 3;
                pixelsColor += 4;

            } else {
                return -2;
            }
        }
    }
    AndroidBitmap_unlockPixels(env, bitmap);
    //進行壓縮
    ret = generateJPEG(tmpData, w, h, optimize, dstFileName, optimize);
    free((void *) dstFileName);
    free((void *) tmpData);
    return ret;
}


大功告成,Demo程式碼地址:

相關推薦

Android使用libjpeg-turbo進行圖片質量壓縮過程記錄

開發十年,就只剩下這套架構體系了! >>>   

android基於libjpeg-turbo圖片壓縮框架

Light a lightweight image compress framework for Android based on libJpeg. 一個基於libJpeg的壓縮圖片框架, 支援配合rxjava使用。 可以一行程式碼解決圖片下載->壓縮->顯

Android使用Sonar進行程式碼質量分析

以Android Studio為例,在專案根目錄下的build.gradle檔案中 1.新增倉庫地址 allprojects { repositories { maven { url "https://plugins.gradle.org/

Android利用Picasso實現圖片壓縮指定任意尺寸

之前做專案時,有個需求是指定照片壓縮到任意寬高尺寸上傳給伺服器。當時我自己寫了個圖片壓縮方法,但是不夠完美,小問題不斷(比如OOM之類的)。後來看到了神器Picasso不光能載入網路圖片,還能以任意尺寸載入本地圖片。於是我想,既然Picasso能任意尺寸載入本地圖片,那它肯

Android圖片質量壓縮以及縮圖生成

1、圖片的質量壓縮 圖片的質量壓縮是指,僅僅壓縮圖片檔案的大小,但當圖片載入到記憶體中時,佔用的記憶體大小並沒有太大變化。可以通過質量壓縮,加快圖片上傳的速度。 程式碼如下: /** *將檔案壓縮後覆蓋原始檔 */ public static

java使用FTP進行圖片的上傳

let pack ddn true download ati eno exce list 使用ftp需要引入兩個jar包(commons-net、commons-fileupload) 1、添加ftp服務器配置文件 #FTP FTP_ADDRESS=192.168.25.

python使用PIL模組的ImageEnhance進行圖片資料增強

使用此方法將圖片進行資料增強,具體增強圖片的形式是如下幾種: """ 1、對比度:白色畫面(最亮時)下的亮度除以黑色畫面(最暗時)下的亮度; 2、色彩飽和度::彩度除以明度,指色彩的鮮豔程度,也稱色彩的純度; 3、色調:向負方向調節會顯現紅色,正方向調節則增加黃色。適合對膚色物件進行微調; 4、

在迅捷OCR文字識別軟件怎麽進行圖片局部識別

小夥伴 http alt 分享 接下來 eba 添加文件 位置 方框 怎麽進行圖片局部識別呢?我們在觀看一些圖片的時候,有些圖片上的文字我們會需要將局部文字識別提取出來,但是如何去識別呢,借助圖片文字識別軟件就可以幫助實現了,下面為大家講解下具體的操作方法。   使用工具:

Android利用Shareinstall進行多渠道一鍵自動打包!

目前國內的安卓渠道有幾百家,我們要根據不同的渠道打不同渠道的apk來統計每個渠道帶來的使用者數,統計每個渠道使用者的存活率和活躍度等等資訊,但是手動對每個渠道的APK進行簽名打包實在是讓人感到厭煩且低效,這時我們需要一個全自動化的打包工具----Shareins

Androidlibjpeg-turbo編譯筆記

#####學習libjpeg-turbo的原因,最近專案中需要解碼1080p的圖片轉為yuv進行視訊預覽,原本的ffmpeg實現解碼及縮放圖片,但是在大部分主流Android機型上效率不高,android手機發熱會有明顯降頻現象,導致速率降低,偶爾在網上看到libjpeg-t

[譯] 最佳安全實踐:在 Java 和 Android 使用 AES 進行對稱加密

原文地址:Security Best Practices: Symmetric Encryption with AES in Java and Android 原文作者:Patrick Favre-Bulle 最佳安全實踐:在 Java 和 Android 中使用 AES 進行

androidPicasso顯示網路圖片

使用之前匯入jar包(picasso.jar網上搜搜都有)或者在android studio中新增依賴compile 'com.squareup.picasso:picasso:2.5.2' 使用方式

androidOkhttp框架進行網路請求的工具類()

package com.example.utils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Iterat

android利用opencv進行影象識別

之前開發的時候老大讓研究下影象識別的功能,同事推薦看看opencv,發現對於移動端來說opencv的資料和demo都比較少,現在整理下之前的工作成果。 首先是進行配置工作,先匯入opencv的一個程式碼模組 之後是匯入opencv的具體的演算法,當然是c

Android繪製圓角矩形圖片

轉自:http://blog.chinaunix.net/uid-20771867-id-3260250.html 圓角矩形圖片在蘋果的產品中很流行,相比於普通的矩形,很多人都喜歡圓角矩形的圖片,下面在Android中實現將普通的矩形圖片繪製成圓角矩形。      

Android繪製圓角矩形圖片及任意形狀圖片

package com.example.phototest; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactor

android使用Nine-Patch圖片

android中可以把圖片進行處理,如果圖片被拉伸的話,允許讓圖片部分割槽域不拉伸,部分割槽域拉伸。這個功能非常好,比如聊天的氣泡,如果整個氣泡被拉伸的話,會非常的醜。 老版的sdk中提供的有draw9patch.bat檔案,允許對圖片進行該項處理,不過新版的已經沒有這個檔案了,而是被整合到了Android

[譯]最佳安全實踐:在 Java 和 Android 使用 AES 進行對稱加密:第2部分:AES-CBC + HMAC

原文地址:Security Best Practices: Symmetric Encryption with AES in Java and Android: Part 2: AES-CBC + HMAC 本文是我上一篇文章:“最佳安全實踐:在 Java 和 Android 中使用 AES 進行

自動提取HTML的JS進行合併與壓縮

前段時間公司做網站的優化,其中就有將HTML檔案中用到的多個JS壓縮成一個min.js。現在做一個總結: css js 壓縮用的是 gulp,只要寫一個gulpfile.js指令碼即可,非常方便 css 目前只是將每個源CSS檔案壓縮了一下,沒有進行合併。 JS 做了兩

Android與JS進行互動

背景 我們在開發Android應用的時候,很多的時候需要跟網頁打交道,網頁與原生Android之間的互動就涉及到Java與JS之間的相互方法 WebView的使用 我們在Android中如果希望展示一個網頁,基本上都會使用WebView這個元件,它的基本使用也很簡單,假如我們