日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( 初始化压缩对象 | 打开文件 | 设置压缩参数 | 写入压缩图像数据 | 完成压缩 | 释放资源 )

發(fā)布時間:2025/6/17 Android 32 豆豆

文章目錄

  • 一、使用 libjpeg-turbo 壓縮圖片流程
  • 二、初始化 JPEG 壓縮對象
  • 三、打開文件
  • 四、設置壓縮參數
  • 五、開始壓縮
  • 六、循環(huán)寫入壓縮數據
  • 七、完成圖片壓縮及收尾
  • 八、libjpeg-turbo 圖片壓縮案例 ( 官方示例 )
  • 九、libjpeg-turbo 壓縮圖片代碼示例



上一篇博客 【Android 內存優(yōu)化】Android 工程中使用 libjpeg-turbo 壓縮圖片 ( JNI 傳遞 Bitmap | 獲取位圖信息 | 獲取圖像數據 | 圖像數據過濾 | 釋放資源 ) 介紹了從 Java 層傳入 Bitmap 對象到 JNI 層 , JNI 層獲取到了圖像對應的 RGB 像素數據 , 本篇博客中將獲取的圖像數據進行壓縮 , 存儲到 JPEG 格式圖片中 ;





一、使用 libjpeg-turbo 壓縮圖片流程



使用 libjpeg-turbo 壓縮圖片流程 :


① 初始化壓縮對象 : 初始化 JPEG 圖片壓縮對象 ;

② 打開文件 : 使用 Linux C API 打開壓縮圖片寫出文件 ;

③ 設置壓縮參數 : 設置圖片壓縮參數 , 如圖片寬高 , 像素格式 , 數據格式 , 質量等 ;

④ 開始壓縮 : 啟動壓縮 ;

⑤ 寫入壓縮數據 : 圖像數據逐行輸入 , 并壓縮 ;

⑥ 壓縮完畢 : 壓縮完畢后調用對應方法 ;

⑦ 釋放資源 : 文件資源 , 及壓縮相關的內存資源 , 需要釋放掉 ;





二、初始化 JPEG 壓縮對象



1. 初始化 JPEG 壓縮對象 :


① JPEG 壓縮對象概念 : jpeg_compress_struct 結構體和與其關聯的工作數據 , 該對象中存儲了 JPEG 壓縮參數 , 還包含了指向工作空間的指針 , JPEG 庫會在需要時分配該指針;

② 壓縮對象個數 : 該結構體可能會存在多個 , 每個結構體對象都表示了一個壓縮或解壓縮的工作;



2. 錯誤處理機制 :


① 錯誤處理程序 : jpeg_error_mgr 結構體表示錯誤處理程序 , 將其單獨定義成一個結構體 , 是因為應用經常需要提供一個專門的錯誤處理程序;

② 處理處理機制 : 在這里我們采用最簡單的方法 , 使用標準的錯誤處理程序 , 如果 壓縮失敗 , 在 stderr 上打印失敗信息, 并調用 exit() 退出程序 ;

③ 結構體生命周期 : 該結構體的生命周期必須與 jpeg_compress_struct 結構體的生命周期保持一致 , 以免產生野指針問題 ;

④ 錯誤處理設置時間 : 在所有操作之前 , 設置錯誤處理程序 , 為了防止 JPEG 壓縮對象初始化時出錯, 越早設置錯誤處理程序越好 , 在內存不足時, 創(chuàng)建 jpeg_compress_struct 可能會失敗 ;


2. 代碼示例 :

/* 該對象中存儲了 JPEG 壓縮參數, 還包含了指向工作空間的指針, JPEG 庫會在需要時分配該指針;* 該結構體可能會存在多個, 每個結構體對象都表示了一個壓縮或解壓縮的工作;* JPEG 對象 : jpeg_compress_struct 結構體和與其關聯的工作數據*/struct jpeg_compress_struct cinfo;/* 錯誤處理程序 : jpeg_error_mgr 結構體表示錯誤處理程序,* 將其單獨定義成一個結構體, 是因為應用經常需要提供一個專門的錯誤處理程序;* 處理處理機制 : 在這里我們采用最簡單的方法, 使用標準的錯誤處理程序,* 如果壓縮失敗, 在 stderr 上打印失敗信息, 并調用 exit() 退出程序 ;* 結構體聲明周期 : 該結構體的生命周期必須與 jpeg_compress_struct 結構體的生命周期保持一致,* 以免產生野指針問題 ;*/struct jpeg_error_mgr jerr;/* 為了防止 JPEG 壓縮對象初始化時出錯, 這里首先設置錯誤處理* 在內存不足時, 創(chuàng)建 jpeg_compress_struct 可能會失敗*/cinfo.err = jpeg_std_error(&jerr);// 初始化 JPEG 壓縮對象jpeg_create_compress(&cinfo);



三、打開文件



1. 打開文件 : 使用 Linux C 中的文件操作 , 調用 fopen 函數打開文件 , 傳入兩個參數 , 文件路徑名稱 , 和 打開模式 , 打開模式中 “wb” , w 代表寫出數據 , b 代表二進制數據 , 該模式的函數以是寫出二進制數據 ;


2. 為 JPEG 壓縮對象設置文件輸出 : 調用 jpeg_stdio_dest 函數 , 為 JPEG 對象設置輸出文件 ; 調用該函數的調用者需要負責文件打開 , 和文件關閉操作 ;

EXTERN(void) jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile);

3. 代碼示例 :

FILE *outfile;if ((outfile = fopen(filename, "wb")) == NULL) {fprintf(stderr, "can't open %s\n", filename);exit(1);}// 設置文件輸出jpeg_stdio_dest(&cinfo, outfile);



四、設置壓縮參數



1 . 設置默認參數 :

  • 圖片寬度 : cinfo.image_width ; 像素寬度 ;
  • 圖片高度 : cinfo.image_height ; 像素高度 ;
  • 像素組件 : cinfo.input_components ; 單個像素 BGR 3個組件 ;
  • 顏色空間 : cinfo.in_color_space ; 輸入圖像的顏色空間 ;

上述四個參數設置完畢后 , 調用 jpeg_set_defaults 方法 , 設置默認參數 ;



2 . 設置非默認參數 :

  • 哈夫曼編碼 : cinfo.optimize_coding = TRUE;
  • 編碼質量 : 調用 jpeg_set_quality 方法設置壓縮質量 ;
// 下面的四個參數是必須設置的參數// 設置圖片的寬度cinfo.image_width = imageWidth;// 設置圖片的高度cinfo.image_height = imageHeight;// 設置每個像素的顏色組件, BGR 3個cinfo.input_components = 3;// 輸入圖像數據的顏色空間cinfo.in_color_space = JCS_RGB;// 設置默認的壓縮參數, 該操作是函數庫的常規(guī)步驟// 設置該參數前需要設置 cinfo.in_color_space 輸入數據的顏色空間jpeg_set_defaults(&cinfo);// 打開哈夫曼編碼cinfo.optimize_coding = TRUE;// 設置非默認參數, 該方法設置質量jpeg_set_quality(&cinfo, compressQuality, 1);



五、開始壓縮



1 . 開始壓縮 : 調用 jpeg_start_compress 方法 , 開始進行圖片壓縮工作 ;


2 . 函數原型 :

  • j_compress_ptr cinfo 參數 : jpeg_compress_struct 結構指針 ;
  • boolean write_all_tables 參數 : 設置 TRUE 參數, 表示將完整的圖片進行壓縮 ; 一般情況下都是設置 TRUE, 如果進行定制壓縮, 可以設置 FALSE ;
typedef struct jpeg_compress_struct *j_compress_ptr;EXTERN(void) jpeg_start_compress(j_compress_ptr cinfo,boolean write_all_tables);

3 . 代碼示例 :

// 4. 開始壓縮 JPEG 格式圖片, 設置 TRUE 參數, 表示將完整的圖片進行壓縮// 一般情況下都是設置 TRUE, 如果進行定制壓縮, 可以設置 FALSEjpeg_start_compress(&cinfo, TRUE);



六、循環(huán)寫入壓縮數據



1 . 寫入壓縮數據原理 : 使用函數庫的狀態(tài)變量, cinfo.next_scanline 作為循環(huán)控制變量 , 這樣就可以不同自己實現循環(huán)控制 , 為了保持代碼簡單, 每次傳遞一行圖像數據 ;


2 . 計算每行數據字節(jié)數 : 像素寬度乘以 333 , 333 表示每個像素點有 BGR 三個顏色值 , 每個顏色 111 字節(jié) ;

int row_stride = imageWidth * 3;

3 . 計算每次循環(huán)拷貝的行數據首地址 : uint8_t *pixels = data + cinfo.next_scanline * row_stride 是計算過程 ;

  • data 是圖像的起始位置
  • row_stride 是每一行的字節(jié)數
  • cinfo.next_scanline 是當前的行數
  • 計算出來的 pixels 指針, 指向要寫出行的首地址

4 . 循環(huán)控制變量自增 : jpeg_write_scanlines(&cinfo, row, 1) , 調用 jpeg_write_scanlines 方法后, cinfo.next_scanline 自動加 1 ;


5 . 代碼示例 :

// 每一個行的數據個數int row_stride = imageWidth * 3;// 指向圖像數據中的某一行數據JSAMPROW row[1];while (cinfo.next_scanline < cinfo.image_height) {/* 獲取一行圖像數據* data 是圖像的起始位置* row_stride 是每一行的字節(jié)數* cinfo.next_scanline 是當前的行數* 計算出來的 pixels 指針, 指向要寫出行的首地址*/uint8_t *pixels = data + cinfo.next_scanline * row_stride;row[0] = pixels;// 調用 jpeg_write_scanlines 方法后, cinfo.next_scanline 自動加 1jpeg_write_scanlines(&cinfo, row, 1);}



七、完成圖片壓縮及收尾



1 . 完成圖片壓縮及收尾 :

  • 調用 jpeg_finish_compress 結束圖片壓縮過程 ;

  • 調用 fclose 關閉之前 fopen 打開的文件 ;

  • 調用 jpeg_destroy_compress 方法銷毀之前使用的 JPEG 壓縮對象 ;


2 . 代碼示例 :

// 6. 完成圖片壓縮jpeg_finish_compress(&cinfo);// 7. 釋放相關資源fclose(outfile);jpeg_destroy_compress(&cinfo);



八、libjpeg-turbo 圖片壓縮案例 ( 官方示例 )



在源碼 libjpeg-turbo-2.0.5/example.txt 文件中 , 有詳細的 JPEG 圖片壓縮流程 , 可以直接拷貝上述代碼進行使用 ;

點擊此處連接打開官方示例代碼





九、libjpeg-turbo 壓縮圖片代碼示例



/*** 壓縮 Jpeg 圖片** 完整的帶詳細注釋的代碼示例參考源碼 libjpeg-turbo-2.0.5/example.txt 示例文件* 里面有詳細的定義圖片壓縮的過程** @param data 要壓縮的圖片數據, 像素格式是 BGR* @param imageWidth 輸出的 JPEG 圖片寬度* @param imageHeight 輸出的 JPEG 圖片高度* @param compressQuality 輸出的 JPEG 圖片質量* @param filename 輸出文件路徑*/ void compressJpegFile(uint8_t *data, int imageWidth, int imageHeight,jint compressQuality, const char *filename) {// 1. 為 JPEG 圖片壓縮對象, 分配內存空間/* 該對象中存儲了 JPEG 壓縮參數, 還包含了指向工作空間的指針, JPEG 庫會在需要時分配該指針;* 該結構體可能會存在多個, 每個結構體對象都表示了一個壓縮或解壓縮的工作;* JPEG 對象 : jpeg_compress_struct 結構體和與其關聯的工作數據*/struct jpeg_compress_struct cinfo;/* 錯誤處理程序 : jpeg_error_mgr 結構體表示錯誤處理程序,* 將其單獨定義成一個結構體, 是因為應用經常需要提供一個專門的錯誤處理程序;* 處理處理機制 : 在這里我們采用最簡單的方法, 使用標準的錯誤處理程序,* 如果壓縮失敗, 在 stderr 上打印失敗信息, 并調用 exit() 退出程序 ;* 結構體聲明周期 : 該結構體的生命周期必須與 jpeg_compress_struct 結構體的生命周期保持一致,* 以免產生野指針問題 ;*/struct jpeg_error_mgr jerr;/* 為了防止 JPEG 壓縮對象初始化時出錯, 這里首先設置錯誤處理* 在內存不足時, 創(chuàng)建 jpeg_compress_struct 可能會失敗*/cinfo.err = jpeg_std_error(&jerr);// 初始化 JPEG 壓縮對象jpeg_create_compress(&cinfo);// 2. 打開文件, 準備向文件寫出二進制數據// w 代表寫出數據, b 代表二進制數據FILE *outfile;if ((outfile = fopen(filename, "wb")) == NULL) {fprintf(stderr, "can't open %s\n", filename);exit(1);}// 設置文件輸出jpeg_stdio_dest(&cinfo, outfile);// 3. 設置壓縮參數// 下面的四個參數是必須設置的參數// 設置圖片的寬度cinfo.image_width = imageWidth;// 設置圖片的高度cinfo.image_height = imageHeight;// 設置每個像素的顏色組件, BGR 3個cinfo.input_components = 3;// 輸入圖像數據的顏色空間cinfo.in_color_space = JCS_RGB;// 設置默認的壓縮參數, 該操作是函數庫的常規(guī)步驟// 設置該參數前需要設置 cinfo.in_color_space 輸入數據的顏色空間jpeg_set_defaults(&cinfo);// 打開哈夫曼編碼cinfo.optimize_coding = TRUE;// 設置非默認參數, 該方法設置質量jpeg_set_quality(&cinfo, compressQuality, 1);// 4. 開始壓縮 JPEG 格式圖片, 設置 TRUE 參數, 表示將完整的圖片進行壓縮// 一般情況下都是設置 TRUE, 如果進行定制壓縮, 可以設置 FALSEjpeg_start_compress(&cinfo, TRUE);// 5. 循環(huán)寫入數據/* 循環(huán)原理 : 使用函數庫的狀態(tài)變量, cinfo.next_scanline 作為循環(huán)控制變量* 這樣就可以不同自己實現循環(huán)控制* 為了保持簡單, 每次傳遞一行圖像數據*/// 每一個行的數據個數int row_stride = imageWidth * 3;// 指向圖像數據中的某一行數據JSAMPROW row[1];while (cinfo.next_scanline < cinfo.image_height) {/* 獲取一行圖像數據* data 是圖像的起始位置* row_stride 是每一行的字節(jié)數* cinfo.next_scanline 是當前的行數* 計算出來的 pixels 指針, 指向要寫出行的首地址*/uint8_t *pixels = data + cinfo.next_scanline * row_stride;row[0] = pixels;// 調用 jpeg_write_scanlines 方法后, cinfo.next_scanline 自動加 1jpeg_write_scanlines(&cinfo, row, 1);}// 6. 完成圖片壓縮jpeg_finish_compress(&cinfo);// 7. 釋放相關資源fclose(outfile);jpeg_destroy_compress(&cinfo); }

總結

以上是生活随笔為你收集整理的【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( 初始化压缩对象 | 打开文件 | 设置压缩参数 | 写入压缩图像数据 | 完成压缩 | 释放资源 )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。