摘要:但是為了能夠適配低端的手機這里的低端是指以前的硬件配置不高的手機,和內存在手機上都非常吃緊,性能差,由于哈夫曼算法比較吃并且編解碼慢,被迫用了其他的算法。
使用方式
在 project/build.gradle 上添加以下代碼
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
在 app/build.gradle 添加依賴
dependencies {
implementation "com.github.yangkun19921001:LIBJPEG_SAMPLE:v1.0.1"
}
壓縮使用
//bitmap : 需要壓縮的 bitmap
//q : 壓縮質量 建議 30 - 50
//outputFilePath: 壓縮之后存儲的圖片地址
JpegUtils.native_Compress(Bitmap bitmap,int q,String outputFilePath);
相信有一部分使用 iPhone 手機用微信發送圖片的時候,明明圖片大小只有 1M ,但清晰度比 Android 手機 5 M 圖片大小的還要清晰,那么這是為什么呢 ?。
當時谷歌開發 Android 的時候,考慮了大部分手機的配置并沒有那么高,所以對圖片處理使用的是 Skia。當然這個庫的底層還是用的 jpeg 圖片壓縮處理。但是為了能夠適配低端的手機(這里的低端是指以前的硬件配置不高的手機,CPU 和內存在手機上都非常吃緊,性能差),由于哈夫曼算法比較吃 CPU 并且編解碼慢,被迫用了其他的算法。所以 Skia 在進行圖片處理在低版本中并沒有開啟哈弗曼算法。
那么,JEPG 到底是什么?JEPG (全稱是 Joint Photographic Experts Group) 是一種常見的一種圖像格式,為什么我在這里會提到 JEPG 呢?是因為開源了一個 C/C++ 庫底層是基于哈夫曼算法對圖片的壓縮 (libjpeg),下面我們就來著重了解下 libjpeg 這個庫
libjpeg 簡介libjpeg-turbo 是一個 JPEG 圖像編解碼器,它使用 SIMD 指令(MMX,SSE2,AVX2,NEON,AltiVec)來加速 x86,x86-64,ARM 和 PowerPC 系統上的基線 JPEG 壓縮和解壓縮,以及漸進式JPEG 壓縮 x86 和 x86-64 系統。在這樣的系統上,libjpeg-turbo 的速度通常是 libjpeg 的 2 - 6 倍,其他條件相同。在其他類型的系統上,憑借其高度優化的霍夫曼編碼例程,libjpeg-turbo 仍然可以大大超過 libjpeg。在許多情況下,libjpeg-turbo 的性能可與專有的高速 JPEG 編解碼器相媲美。 libjpeg-turbo 實現了傳統的 libjpeg API 以及功能較弱但更直接的 TurboJPEG API 。 libjpeg-turbo 還具有色彩空間擴展,允許它從/解壓縮到32位和大端像素緩沖區(RGBX,XBGR等),以及功能齊全的 Java 接口。 libjpeg-turbo 最初基于 libjpeg / SIMD,這是由 Miyasaka Masaru 開發的 libjpeg v6b 的 MMX 加速衍生物。 TigerVNC 和 VirtualGL 項目在 2009 年對編解碼器進行了大量增強,并且在2010年初,libjpeg-turbo 分拆成一個獨立項目,目標是為更廣泛的用戶提供高速 JPEG壓縮/解壓縮技術。開發人員。
現在我們大概了解到了 libjpeg 是一個對圖像編解碼庫,現在我們需要準備環境去編譯 libjpeg。
編譯準備工作系統: Ubuntu 18.04 也可以使用我下載好的 提取碼:biyt
libjpeg: libjepg 2.0.2
cmake: cmake-3.14.4-Linux-x86_64.tar.gz
ndk: android-ndk-r17c
開始發車準備編譯
ubuntu 中下載 libjpeg
wget github.com/libjpeg-tur…
解壓 tar xvf 2.0.2.tar.gz
編譯參考
ubuntu 中安裝 cmake
刪除原來的 apt-get autoremove cmake
wget github.com/Kitware/CMa…
解壓 tar zxvf cmake-3.14.3.tar.gz
創建軟連接
mv cmake-3.14.3-Linux-x86_64 /opt/cmake-3.14.3
ln -sf /opt/cmake-3.14.3/bin/* /usr/bin/
輸入 cmake -- version 如果有這樣的顯示代表安裝成功
進入到 libjpeg 目錄,生成 shell 腳本
vim build.sh 新建一個文件
# lib-name MY_LIBS_NAME=libjpeg-turbo_2.0.2 # 源碼目錄 MY_SOURCE_DIR=/home/yangkun/libjpeg-turbo-2.0.2 MY_BUILD_DIR=yangkun # android-cmake CMAKE_PATH=/opt/cmake-3.14.4/bin export PATH=${CMAKE_PATH}/bin:$PATH NDK_PATH=/home/yangkun//android-ndk-r17c BUILD_PLATFORM=linux-x86_64 TOOLCHAIN_VERSION=4.9 ANDROID_VERSION=24 ANDROID_ARMV5_CFLAGS="-march=armv5te" ANDROID_ARMV7_CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=neon" # -mfpu=vfpv3-d16 -fexceptions -frtti ANDROID_ARMV8_CFLAGS="-march=armv8-a" # -mfloat-abi=softfp -mfpu=neon -fexceptions -frtti ANDROID_X86_CFLAGS="-march=i386 -mtune=intel -mssse3 -mfpmath=sse -m32" ANDROID_X86_64_CFLAGS="-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel" # params($1:arch,$2:arch_abi,$3:host,$4:compiler,$5:cflags,$6:processor) build_bin() { echo "-------------------star build $2-------------------------" ARCH=$1 # arm arm64 x86 x86_64 ANDROID_ARCH_ABI=$2 # armeabi armeabi-v7a x86 mips # 最終編譯的安裝目錄 PREFIX=$(pwd)/dist/${MY_LIBS_NAME}/${ANDROID_ARCH_ABI}/ HOST=$3 COMPILER=$4 PROCESSOR=$6 SYSROOT=${NDK_PATH}/platforms/android-${ANDROID_VERSION}/arch-${ARCH} CFALGS="$5" TOOLCHAIN=${NDK_PATH}/toolchains/${HOST}-${TOOLCHAIN_VERSION}/prebuilt/${BUILD_PLATFORM} # build 中間件 BUILD_DIR=./${MY_BUILD_DIR}/${ANDROID_ARCH_ABI} export CFLAGS="$5 -Os -D__ANDROID_API__=${ANDROID_VERSION} --sysroot=${SYSROOT} -isystem ${NDK_PATH}/sysroot/usr/include -isystem ${NDK_PATH}/sysroot/usr/include/${HOST} " export LDFLAGS=-pie echo "path==>$PATH" echo "build_dir==>$BUILD_DIR" echo "ARCH==>$ARCH" echo "ANDROID_ARCH_ABI==>$ANDROID_ARCH_ABI" echo "HOST==>$HOST" echo "CFALGS==>$CFALGS" echo "COMPILER==>$COMPILER-gcc" echo "PROCESSOR==>$PROCESSOR" mkdir -p ${BUILD_DIR} #創建當前arch_abi的編譯目錄,比如:binary/armeabi-v7a cd ${BUILD_DIR} #此處 進了當前arch_abi的2級編譯目錄 #運行時創建臨時編譯鏈文件toolchain.cmake cat >toolchain.cmake << EOF set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR $6) set(CMAKE_C_COMPILER ${TOOLCHAIN}/bin/${COMPILER}-gcc) set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN}/${COMPILER}) EOF cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DCMAKE_POSITION_INDEPENDENT_CODE=1 -DCMAKE_INSTALL_PREFIX=${PREFIX} -DWITH_JPEG8=1 ${MY_SOURCE_DIR} make clean make make install #從當前arch_abi編譯目錄跳出,對應上面的cd ${BUILD_DIR},以便function多次執行 cd ../../ echo "-------------------$2 build end-------------------------" } # build armeabi build_bin arm armeabi arm-linux-androideabi arm-linux-androideabi "$ANDROID_ARMV5_CFLAGS" arm #build armeabi-v7a build_bin arm armeabi-v7a arm-linux-androideabi arm-linux-androideabi "$ANDROID_ARMV7_CFLAGS" arm #build arm64-v8a build_bin arm64 arm64-v8a aarch64-linux-android aarch64-linux-android "$ANDROID_ARMV8_CFLAGS" aarch64 #build x86 build_bin x86 x86 x86 i686-linux-android "$ANDROID_X86_CFLAGS" i386 #build x86_64 build_bin x86_64 x86_64 x86_64 x86_64-linux-android "$ANDROID_X86_64_CFLAGS" x86_64
如果編譯遇見 權限問題
給它一個 可執行文件的權限 chmod +x build.sh
繼續執行
編譯完成
這里我們發現 已經有我們需要的 靜態庫 .a 和 動態庫 .so
在 AndroidStudio 中創建一個簡單的項目 用于測試是否壓縮成功
結構目錄
標紅的都是重要的文件,include 頭文件和 libs/armeabi-v7a 是我們剛剛編譯出來的文件
下面我們就來運行一下看看壓縮效果
壓縮主要代碼
jni 代碼
#include
#include
#include "../include/jpeglib.h"
#include
#include
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);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_yk_libjpeg_1sample_libjpeg_JpegUtils_native_1Compress__Landroid_graphics_Bitmap_2ILjava_lang_String_2(
JNIEnv *env, jclass type, 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);
}
調用代碼
public class JpegUtils {
static {
System.loadLibrary("jpeg-yk");
}
/**
* A native method that is implemented by the "native-lib" native library,
* which is packaged with this application.
*/
public native static void native_Compress(Bitmap bitmap, int q, String path);
}
開始壓縮
public void click(View view) {
File input = new File(Environment.getExternalStorageDirectory(), "/girl.jpg");
ImageView preImg = findViewById(R.id.pre);
mNextImg = findViewById(R.id.next);
inputBitmap = BitmapFactory.decodeFile(input.getAbsolutePath());
preImg.setImageBitmap(inputBitmap);
JpegUtils .native_Compress(inputBitmap, 10, Environment.getExternalStorageDirectory() + "/girl4.jpg");
Toast.makeText(this, "執行完成", Toast.LENGTH_SHORT).show();
String filePath = Environment.getExternalStorageDirectory() + "/girl4.jpg";
mNextImg.setImageBitmap(BitmapFactory.decodeFile(filePath));
}
動畫效果
壓縮效果: 壓縮質量在 10 的時候用壓縮出來的質量也還是挺好了,只有周圍有點點模糊,但是建議壓縮質量在 30 -50 之間。
壓縮率: 大約壓縮后的圖片大小是原圖的縮小 6 倍的樣子。
圖片優化計劃出三篇文章
libjpeg 編譯及使用
長圖巨圖優化
bitmap 內存管理 三級緩存
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/6819.html
摘要:發布應用市場的平臺搶紅包工具紅包精靈開源啦掘金紅包精靈,如果喜歡,點個開源不易。作者將原素材文章進行了新內容的添加和重新排列,但是因為文章高效的代碼編寫技巧總結前端掘金本文總結了代碼編寫技巧,來提升你的和代碼。 收藏安卓開發中非常實用優秀的庫! 有圖有真相! - Android - 掘金本來是打算收藏工具類的,但轉念一想,已經有這么多優秀的庫了,就沒必要再去重復造輪子了,便歸納工作中比...
摘要:寫在前面開發中的圖像壓縮是一個很重要的部分。而這篇文章會讓我們從另外一個角度來認識平臺下的圖像壓縮和優化。所以,它是你圖像壓縮和優化的首選,盡可能的去使用吧。 寫在前面 Android開發中的圖像壓縮是一個很重要的部分。而這篇文章會讓我們從另外一個角度來認識Android平臺下的圖像壓縮和優化。 這篇文章更適合和設計師一起來看,所以,如果你和你的設計師是好基友的話,不妨叫上他,倒兩杯咖...
閱讀 881·2023-04-25 19:17
閱讀 2179·2021-09-10 11:26
閱讀 1898·2019-08-30 15:54
閱讀 3411·2019-08-30 15:53
閱讀 2681·2019-08-30 11:20
閱讀 3392·2019-08-29 15:12
閱讀 1230·2019-08-29 13:16
閱讀 2384·2019-08-26 12:19