文檔處理控制欄:
* [x] 選題收集:
* [ ] 初稿整理:
* [ ] 補充校對:
* [ ] 入庫存檔:
---
原文鏈接:[Android圖片壓縮的幾種方案](https://juejin.im/entry/5a41c473f265da430f3258a7)
---
原文:http://blog.csdn.net/qq_30379689/article/details/78884167
## 效果演示
直接先給大家對比幾種圖片壓縮的效果

## 質量壓縮
質量壓縮:根據傳遞進去的質量大小,采用系統自帶的壓縮算法,將圖片壓縮成JPEG格式
~~~
/**
* 質量壓縮
*
* @param bitmap
* @param quality
* @param file
*/
public static void compressQuality(Bitmap bitmap, int quality, File file) {
? ?ByteArrayOutputStream baos = new ByteArrayOutputStream();
? ?bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
? ?try {
? ? ? ?FileOutputStream fos = new FileOutputStream(file);
? ? ? ?fos.write(baos.toByteArray());
? ? ? ?fos.flush();
? ? ? ?fos.close();
? ?} catch (Exception e) {
? ? ? ?e.printStackTrace();
? ?}
}
~~~
## 尺寸壓縮
尺寸壓縮:根據圖片的縮放比例進行等比大小的縮小尺寸,從而達到壓縮的效果
~~~
/**
* 尺寸壓縮
*
* @param bitmap
* @param file
*/
public static void compressSize(Bitmap bitmap, File file) {
? ?int ratio = 8;//尺寸壓縮比例
? ?Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / ratio, bitmap.getHeight() / ratio, Bitmap.Config.ARGB_8888);
? ?Canvas canvas = new Canvas(result);
? ?Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio);
? ?canvas.drawBitmap(bitmap, null, rect, null);
? ?compressQuality(result, 100, file);
}
~~~
## 采樣率壓縮
采樣率壓縮:根據圖片的采樣率大小進行壓縮
~~~
/**
* 采樣率壓縮
*
* @param filePath
* @param file
*/
public static void compressSample(String filePath, File file) {
? ?int inSampleSize = 8;//采樣率設置
? ?BitmapFactory.Options options = new BitmapFactory.Options();
? ?options.inJustDecodeBounds = false;
? ?options.inSampleSize = inSampleSize;
? ?Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
? ?compressQuality(bitmap, 100, file);
}
~~~
## LibJpeg壓縮
LibJpeg壓縮:通過Ndk調用LibJpeg庫進行壓縮,保留原有的像素,清晰度高
### 編譯LibJpeg
1、從Github上可以下載已經寫好編譯腳本的項目:https://github.com/Zelex/libjpeg-turbo-android ,并將其上傳到Linux服務器的某個目錄

2、授予整個目錄權限
~~~
chmod 777 -R libjpeg-turbo-android-master
~~~
3、進入libjpeg目錄,使用下面指令進行編譯,前提是你的服務器已經搭建了ndk-build和配置了環境變量
~~~
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi-v7a obj/local/armeabi-v7a/libjpeg.a LOCAL_ARM_MODE=arm LOCAL_ARM_NEON=true ARCH_ARM_HAVE_NEON=true
~~~
4、接著編譯成功后,會在 obj/local 目錄下生成我們需要的 libjpeg.a

### 創建工程
1、創建一個新的項目,勾選包含C++,勾選C++11和C++的依賴庫

2、將生成的 libjpeg.a和頭文件導入到我們的項目中

3、配置gradle
~~~
android {
? ?compileSdkVersion 25
? ?buildToolsVersion "25.0.3"
? ?defaultConfig {
? ? ? ?applicationId "com.handsome.bitmapcompress"
? ? ? ?minSdkVersion 16
? ? ? ?targetSdkVersion 25
? ? ? ?versionCode 1
? ? ? ?versionName "1.0"
? ? ? ?testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
? ? ? ?externalNativeBuild {
? ? ? ? ? ?cmake {
? ? ? ? ? ? ? ?cppFlags "-std=c++11 -frtti -fexceptions"
? ? ? ? ? ? ? ?//支持的CPU類型
? ? ? ? ? ? ? ?abiFilters "armeabi", "armeabi-v7a"
? ? ? ? ? ?}
? ? ? ?}
? ?}
? ?buildTypes {
? ? ? ?release {
? ? ? ? ? ?minifyEnabled false
? ? ? ? ? ?proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
? ? ? ?}
? ?} ? ?//修改Libs庫的路徑
? ?sourceSets.main {
? ? ? ?jniLibs.srcDirs = ['libs']
? ? ? ?jni.srcDirs = []
? ?}
? ?externalNativeBuild {
? ? ? ?cmake {
? ? ? ? ? ?path "CMakeLists.txt"
? ? ? ?}
? ?}
}
~~~
4、配置CMake
~~~
cmake_minimum_required(VERSION 3.4.1)
include_directories(./libs/jpeg)
link_directories(./libs/${ANDROID_ABI})
find_library(log-lib ? ? ? ? ? ? log)
find_library(android-lib
? ? ? ? ? ? android)
find_library(bitmap-lib
? ? ? ? ? ? jnigraphics)
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).
? ? ? ? ? ? src/main/cpp/native-lib.cpp )
target_link_libraries( native-lib
? ? ? ? ? ? ? ? ? ? ? ${log-lib}
? ? ? ? ? ? ? ? ? ? ? ${android-lib}
? ? ? ? ? ? ? ? ? ? ? ${bitmap-lib}
? ? ? ? ? ? ? ? ? ? ? jpeg )
~~~
5、聲明權限
~~~
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
~~~
### 使用LibJpeg
1、啟動選擇文件的Intent
~~~
/**
* 選擇文件
*/public void selectFile() { ? ? ? ?if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
? ? ? ?startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), REQUEST_PICK_IMAGE);
? ?} else {
? ? ? ?Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
? ? ? ?intent.addCategory(Intent.CATEGORY_OPENABLE);
? ? ? ?intent.setType("image/*");
? ? ? ?startActivityForResult(intent, REQUEST_KITKAT_PICK_IMAGE);
? ?}
}
~~~
2、對返回的結果進行壓縮
~~~
/**
* 返回結果
*
* @param requestCode
* @param resultCode
* @param data
*/@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) { ? ? ? ?super.onActivityResult(requestCode, resultCode, data); ? ? ? ?if (resultCode == RESULT_OK) { ? ? ? ? ? ? ? ?switch (requestCode) { ? ? ? ? ? ? ? ? ? ? ? ?case REQUEST_PICK_IMAGE: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (data != null) {
? ? ? ? ? ? ? ? ? ?Uri uri = data.getData();
? ? ? ? ? ? ? ? ? ?compressImage(uri);
? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?break; ? ? ? ? ? ? ? ? ? ? ? ?case REQUEST_KITKAT_PICK_IMAGE: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (data != null) {
? ? ? ? ? ? ? ? ? ?Uri uri = ensureUriPermission(this, data);
? ? ? ? ? ? ? ? ? ?compressImage(uri);
? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ?}
? ?}
}/**
* 壓縮圖片
* 注意:記得手動開啟權限
*
* @param uri
*/public void compressImage(Uri uri) { ? ? ? ?try {
? ? ? ?File saveFile = new File(getExternalCacheDir(), "NDK壓縮.jpg");
? ? ? ?Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri); ? ? ? ? ? ? ? ?int code = CompressUtils.compressBitmap(bitmap, 20, saveFile.getAbsolutePath().getBytes(), true);
? ? ? ?File saveFile1 = new File(getExternalCacheDir(), "質量壓縮.jpg");
? ? ? ?CompressUtils.compressQuality(bitmap, 20, saveFile1);
? ? ? ?File saveFile2 = new File(getExternalCacheDir(), "尺寸壓縮.jpg");
? ? ? ?CompressUtils.compressSize(bitmap, saveFile2); ? ? ? ?//采樣率比較特殊,需要傳遞文件的目錄,這里采用直接指定目錄的文件
? ? ? ?File saveFile3 = new File(getExternalCacheDir(), "采樣率壓縮.jpg");
? ? ? ?File LocalFile = new File("/storage/emulated/0/DCIM/Camera/IMG_20171216_171956.jpg"); ? ? ? ? ? ? ? ?if (LocalFile.exists()) {
? ? ? ? ? ?CompressUtils.compressSample(LocalFile.getAbsolutePath(), saveFile3);
? ? ? ?}
? ?} catch (IOException e) {
? ? ? ?e.printStackTrace();
? ?}
}
~~~
3、加載本地庫和聲明LibJpeg壓縮方法
~~~
public class CompressUtils { ? ? ? ?static {
? ? ? ?System.loadLibrary("native-lib");
? ?} ? ?public static native int compressBitmap(Bitmap bitmap, int quality, byte[] fileNameBytes, boolean optimize);
}
~~~
4、編寫LibJpeg的本地文件
* 提取圖片的ARGB通量的RGB通量
* 采用LibJpeg的API進行壓縮
* 將數據寫入到文件中
~~~
#include <jni.h>#include <string>#include <android/bitmap.h>#include <android/log.h>#include <setjmp.h>extern "C" { ? ?#include "jpeglib.h" ? ?#include "cdjpeg.h"}#define LOG_TAG "jni"#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)typedef uint8_t BYTE;typedef struct my_error_mgr *my_error_ptr;struct my_error_mgr { ? ? ? ?struct jpeg_error_mgr pub;
? ?jmp_buf setjmp_buffer;
};
METHODDEF(void)
my_error_exit(j_common_ptr cinfo) {
? ?my_error_ptr myerr = (my_error_ptr) cinfo->err;
? ?(*cinfo->err->output_message)(cinfo);
? ?LOGE("jpeg_message_table[%d]:%s", myerr->pub.msg_code,
? ? ? ? myerr->pub.jpeg_message_table[myerr->pub.msg_code]);
? ?longjmp(myerr->setjmp_buffer, 1);
} ? ?/**
* 采用Libjpeg壓縮
* @param data
* @param w
* @param h
* @param quality
* @param outfilename
* @param optimize
* @return
*/int generateJPEG(BYTE *data, int w, int h, int quality, const char *outfilename, jboolean optimize) { ? ?//jpeg的結構體,保存的比如寬、高、位深、圖片格式等信息
? ?struct jpeg_compress_struct jcs; ? ?//當讀完整個文件的時候就會回調my_error_exit
? ?struct my_error_mgr jem;
? ?jcs.err = jpeg_std_error(&jem.pub);
? ?jem.pub.error_exit = my_error_exit; ? ? ? ?if (setjmp(jem.setjmp_buffer)) { ? ? ? ? ? ? ? ?return 0;
? ?} ? ?//初始化jsc結構體
? ?jpeg_create_compress(&jcs); ? ?//打開輸出文件
? ?FILE* f = fopen(outfilename, "wb"); ? ? ? ?if (f == NULL) { ? ? ? ? ? ? ? ?return 0;
? ?} ? ?//設置結構體的文件路徑
? ?jpeg_stdio_dest(&jcs, f);
? ?jcs.image_width = w;//設置寬高
? ?jcs.image_height = h; ? ?//設置哈夫曼編碼,TRUE=arithmetic coding, FALSE=Huffman
? ?if (optimize) {
? ? ? ?jcs.arith_code = false;
? ?} else {
? ? ? ?jcs.arith_code = true;
? ?} ? ?//顏色通道數量
? ?int nComponent = 3;
? ?jcs.input_components = nComponent; ? ?//設置結構體的顏色空間為RGB
? ?jcs.in_color_space = JCS_RGB; ? ?//全部設置默認參數
? ?jpeg_set_defaults(&jcs); ? ?//是否采用哈弗曼表數據計算 品質相差5-10倍
? ?jcs.optimize_coding = optimize; ? ?//設置質量
? ?jpeg_set_quality(&jcs, quality, true); ? ?//開始壓縮,(是否寫入全部像素)
? ?jpeg_start_compress(&jcs, TRUE);
? ?JSAMPROW row_pointer[1]; ? ? ?int row_stride; ? ?//一行的RGB數量
? ?row_stride = jcs.image_width * nComponent; ? ?//一行一行遍歷
? ?while (jcs.next_scanline < jcs.image_height) { ? ? ? ?//得到一行的首地址
? ? ? ?row_pointer[0] = &data[jcs.next_scanline * row_stride]; ? ? ? ?//此方法會將jcs.next_scanline加1
? ? ? ?jpeg_write_scanlines(&jcs, row_pointer, 1);//row_pointer就是一行的首地址,1:寫入的行數
? ?}
? ?jpeg_finish_compress(&jcs);
? ?jpeg_destroy_compress(&jcs);
? ?fclose(f); ? ?return 1;
}/**
* byte數組轉C的字符串
*/char *jstrinTostring(JNIEnv *env, jbyteArray barr) { ? ? ? ?char *rtn = NULL;
? ?jsize alen = env->GetArrayLength(barr);
? ?jbyte *ba = env->GetByteArrayElements(barr, 0); ? ? ? ?if (alen > 0) {
? ? ? ?rtn = (char *) malloc(alen + 1); ? ? ? ? ? ? ? ?memcpy(rtn, ba, alen);
? ? ? ?rtn[alen] = 0;
? ?}
? ?env->ReleaseByteArrayElements(barr, ba, 0); ? ? ? ?return rtn;
} ? ?extern "C"JNIEXPORT jint JNICALL
Java_com_handsome_bitmapcompress_CompressUtils_compressBitmap(JNIEnv *env, jclass type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jobject bitmap,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jint quality,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jbyteArray fileNameBytes_,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jboolean optimize) { ? ?//獲取Bitmap信息
? ?AndroidBitmapInfo android_bitmap_info;
? ?AndroidBitmap_getInfo(env, bitmap, &android_bitmap_info); ? ?//獲取bitmap的 寬,高,format
? ?int w = android_bitmap_info.width; ? ? ? ?int h = android_bitmap_info.height; ? ? ? ?int format = android_bitmap_info.format; ? ? ? ?if (format != ANDROID_BITMAP_FORMAT_RGBA_8888) { ? ? ? ? ? ? ? ?return -1;
? ?} ? ?//存儲ARGB所有像素點
? ?BYTE *pixelsColor; ? ?//1、讀取Bitmap所有像素信息
? ?AndroidBitmap_lockPixels(env, bitmap, (void **) &pixelsColor); ? ?//2、解析每個像素,去除A通量,取出RGB通量
? ?int i = 0, j = 0;
? ?BYTE a, r, g, b; ? ?//存儲RGB所有像素點
? ?BYTE *data;
? ?data = (BYTE *) malloc(w * h * 3); ? ?//存儲RGB首地址
? ?BYTE *tempData = data; ? ? ? ?int color; ? ? ? ?for (i = 0; i < h; ++i) { ? ? ? ? ? ? ? ?for (j = 0; j < w; ++j) { ? ? ? ? ? ?//將8位通道轉成32位通道
? ? ? ? ? ?color = *((int *) pixelsColor); ? ? ? ? ? ?//取值
? ? ? ? ? ?a = ((color & 0xFF000000) >> 24);
? ? ? ? ? ?r = ((color & 0x00FF0000) >> 16);
? ? ? ? ? ?g = ((color & 0x0000FF00) >> 8);
? ? ? ? ? ?b = ((color & 0x000000FF)); ? ? ? ? ? ?//賦值
? ? ? ? ? ?*data = b;
? ? ? ? ? ?*(data + 1) = g;
? ? ? ? ? ?*(data + 2) = r; ? ? ? ? ? ?//指針往后移
? ? ? ? ? ?data += 3;
? ? ? ? ? ?pixelsColor += 4;
? ? ? ?}
? ?} ? ?//3、讀取像素點完畢
? ?AndroidBitmap_unlockPixels(env, bitmap); ? ? ? ?char *fileName = jstrinTostring(env, fileNameBytes_); ? ?//4、采用Libjpeg進行壓縮
? ?int resultCode = generateJPEG(tempData, w, h, quality, fileName, optimize); ? ? ? ?if (resultCode == 0) { ? ? ? ? ? ? ? ?return 0;
? ?} ? ? ? ?return 1;
}
~~~
需要跑一下以上幾種方案源碼的同學,可以訪問:https://github.com/AndroidHensen/BitmapCompress?獲取。
---
參考文章
* [Android圖片壓縮的幾種方案](https://juejin.im/entry/5a41c473f265da430f3258a7)
- 0-發現
- AndroidInterview-Q-A
- Android能讓你少走彎路的干貨整理
- LearningNotes
- temp
- temp11
- 部分地址
- 0-待辦任務
- 待補充列表
- 0-未分類
- AndroidView事件分發與滑動沖突處理
- Spannable
- 事件分發機制詳解
- 1-Java
- 1-Java-01基礎
- 未歸檔
- 你應該知道的JDK知識
- 集合框架
- 1-Java-04合集
- Java之旅0
- Java之旅
- JAVA之旅01
- JAVA之旅02
- JAVA之旅03
- JAVA之旅04
- JAVA之旅05
- JAVA之旅06
- JAVA之旅07
- JAVA之旅08
- JAVA之旅09
- java之旅1
- JAVA之旅10
- JAVA之旅11
- JAVA之旅12
- JAVA之旅13
- JAVA之旅14
- JAVA之旅15
- JAVA之旅16
- JAVA之旅17
- JAVA之旅18
- JAVA之旅19
- java之旅2
- JAVA之旅20
- JAVA之旅21
- JAVA之旅22
- JAVA之旅23
- JAVA之旅24
- JAVA之旅25
- JAVA之旅26
- JAVA之旅27
- JAVA之旅28
- JAVA之旅29
- java之旅3
- JAVA之旅30
- JAVA之旅31
- JAVA之旅32
- JAVA之旅33
- JAVA之旅34
- JAVA之旅35
- 1-Java-05辨析
- HashMapArrayMap
- Java8新特性
- Java8接口默認方法
- 圖解HashMap(1)
- 圖解HashMap(2)
- 2-Android
- 2-Android-1-基礎
- View繪制流程
- 事件分發
- AndroidView的事件分發機制和滑動沖突解決
- 自定義View基礎
- 1-安卓自定義View基礎-坐標系
- 2-安卓自定義View基礎-角度弧度
- 3-安卓自定義View基礎-顏色
- 自定義View進階
- 1-安卓自定義View進階-分類和流程
- 10-安卓自定義View進階-Matrix詳解
- 11-安卓自定義View進階-MatrixCamera
- 12-安卓自定義View進階-事件分發機制原理
- 13-安卓自定義View進階-事件分發機制詳解
- 14-安卓自定義View進階-MotionEvent詳解
- 15-安卓自定義View進階-特殊形狀控件事件處理方案
- 16-安卓自定義View進階-多點觸控詳解
- 17-安卓自定義View進階-手勢檢測GestureDetector
- 2-安卓自定義View進階-繪制基本圖形
- 3-安卓自定義View進階-畫布操作
- 4-安卓自定義View進階-圖片文字
- 5-安卓自定義View進階-Path基本操作
- 6-安卓自定義View進階-貝塞爾曲線
- 7-安卓自定義View進階-Path完結篇偽
- 8-安卓自定義View進階-Path玩出花樣PathMeasure
- 9-安卓自定義View進階-Matrix原理
- 通用類介紹
- Application
- 2-Android-2-使用
- 2-Android-02控件
- ViewGroup
- ConstraintLayout
- CoordinatorLayout
- 2-Android-03三方使用
- Dagger2
- Dagger2圖文完全教程
- Dagger2最清晰的使用教程
- Dagger2讓你愛不釋手-終結篇
- Dagger2讓你愛不釋手-重點概念講解、融合篇
- dagger2讓你愛不釋手:基礎依賴注入框架篇
- 閱讀筆記
- Glide
- Google推薦的圖片加載庫Glide:最新版使用指南(含新特性)
- rxjava
- 這可能是最好的RxJava2.x入門教程完結版
- 這可能是最好的RxJava2.x入門教程(一)
- 這可能是最好的RxJava2.x入門教程(三)
- 這可能是最好的RxJava2.x入門教程(二)
- 這可能是最好的RxJava2.x入門教程(五)
- 這可能是最好的RxJava2.x入門教程(四)
- 2-Android-3-優化
- 優化概況
- 各種優化
- Android端秒開優化
- apk大小優化
- 內存分析
- 混淆
- 2-Android-4-工具
- adb命令
- 一鍵分析Android的BugReport
- 版本控制
- git
- git章節簡述
- 2-Android-5-源碼
- HandlerThread 源碼分析
- IntentService的使用和源碼分析
- 2-Android-9-辨析
- LRU算法
- 什么是Bitmap
- 常見圖片壓縮方式
- 3-Kotlin
- Kotlin使用筆記1-草稿
- Kotlin使用筆記2
- kotlin特性草稿
- Kotlin草稿-Delegation
- Kotlin草稿-Field
- Kotlin草稿-object
- 4-JavaScript
- 5-Python
- 6-Other
- Git
- Gradle
- Android中ProGuard配置和總結
- gradle使用筆記
- Nexus私服搭建
- 編譯提速最佳實踐
- 7-設計模式與架構
- 組件化
- 組件化探索(OKR)
- 1-參考列表
- 2-1-組件化概述
- 2-2-gradle配置
- 2-3-代碼編寫
- 2-4-常見問題
- 2-9-值得一讀
- 8-數據結構與算法
- 0臨時文件
- 漢諾塔
- 8-數據-1數據結構
- HashMap
- HashMap、Hashtable、HashSet 和 ConcurrentHashMap 的比較
- 遲到一年HashMap解讀
- 8-數據-2算法
- 1個就夠了
- Java常用排序算法(必須掌握的8大排序算法)
- 常用排序算法總結(性能+代碼)
- 必須知道的八大種排序算法(java實現)
- 9-職業
- 閱讀
- 書單
- 面試
- 面試-01-java
- Java面試題全集駱昊(上)
- Java面試題全集駱昊(下)
- Java面試題全集駱昊(中)
- 面試-02-android
- 40道Android面試題
- 面試-03-開源源碼
- Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執行流程
- 面試-07-設計模式
- 面試-08-算法
- 面試-09-其他
- SUMMARY
- 版權說明
- temp111