亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

JNI方法實現圖片壓縮(壓縮率極高)

2019-10-21 21:36:00
字體:
來源:轉載
供稿:網友

前言

直接使用項目或直接復制libs中的so庫到項目中即可(當前只構建了armeabi),需要其他ABI可檢下項目另外使用CMake構建即可。

結果預覽:

JNI,圖片壓縮
效果圖.png

JNI,圖片壓縮

jni_278KB.png

JNI,圖片壓縮

quality_484KB.png

JNI,圖片壓縮

sample_199KB.png

JNI,圖片壓縮

size_238KB.png

原圖大小5.99M~~ 我們把所有經過壓縮的圖片放到同等大小的情況后,很明顯,采樣壓縮跟尺寸壓縮都不是我們想要的結果,而質量壓縮跟JNI壓縮我設置的質量壓縮值都是30,JNI壓縮出來只有278KB,直接質量壓縮出來的有484KB,綜合之后,JNI才是綜合最優的方式,當然,如果只是頭像,我們設置可以把配置值設置得更小,圖片就更小。

為什么iPhone手機圖片的質量比Android的好?

首先了解兩個圖像處理庫:libjpeg、Skia。

Skia:圖像處理引擎,Google在Android系統上就是采用Skia,它是基于libjpeg的二次封裝,Google在很多其它產品也使用了這個庫,比如Chorme,Firefox等等。

libjpeg:早期的圖像處理引擎,用于PC端。

官方文檔可以看到libjpeg.doc這樣一段話:

boolean optimize_coding
TRUE causes the compressor to compute optimal Huffman coding tables
for the image. This requires an extra pass over the data and
therefore costs a good deal of space and time. The default is
FALSE, which tells the compressor to use the supplied or default
Huffman tables. In most cases optimal tables save only a few percent
of file size compared to the default tables. Note that when this is
TRUE, you need not supply Huffman tables at all, and any you do
supply will be overwritten.

boolean optimize_coding:

  • 參數為TRUE時,圖片壓縮算法使用最優的哈夫曼編碼表,它需要額外傳遞數據,因此會耗費CPU運算時間,以及開辟很多臨時內存空間。
  • 參數為FALSE時,使用默認的哈夫曼編碼表。在大多數情況,使用最優哈夫曼編碼表相比默認哈夫曼編碼表,能節省圖像文件很大比例的大小。

為什么使用最優哈夫曼編碼表可以節省圖像文件很大的比例大小呢?

哈夫曼樹和哈夫曼編碼

當樹中的節點被賦予一個表示某種意義的數值,我們稱之為該節點的權。從樹的根節點到任意節點的路徑長度(經過的邊數)與該節點上權值的乘積稱為該節點的帶權路徑長度。樹中所有葉節點的帶權路徑長度之和稱為該樹的帶權路徑長度(WPL)。當帶權路徑長度最小的二叉樹被稱為哈夫曼樹,也成為最優二叉樹。

如下圖所示,有三課二叉樹,每個樹都有四個葉子節點a,b,c,d,分別取帶權7,5,2,4。他們的帶權路徑長度分別為

(a) WPL = 7x2+5x2+2x2+4x2=36

(b) WPL = 2X1+4X2+7X3+5X3 = 46

(c) WPL = 7x1+5x2+2x3+4x3 = 35

JNI,圖片壓縮

節點如果像c中的方式分布的話,WPL能取最小值(可證明),我們稱為哈夫曼樹。

哈夫曼樹構造

哈夫曼樹在構造時每次從備選節點中挑出兩個權值最小的節點進行構造,每次構造完成后會生成新的節點,將構造的節點從備選節點中刪除并將新產生的節點加入到備選節點中。新產生的節點權值為參與構造的兩個節點權值之和。舉例如下:

JNI,圖片壓縮

  • 備選節點為a,b,c,d,權值分別為7,5,2,4
  • 選出c和d進行構造(權值最小),生成新節點為e(權值為6),備選節點變為7,5,6
  • 選出b和e進行構造,生成新節點f(權值為11),備選節點為7,11
  • 將最后的7和11節點進行構造,最后生成如圖所示的哈夫曼樹

哈夫曼樹應用

在處理字符串序列時,如果對每個字符串采用相同的二進制位來表示,則稱這種編碼方式為定長編碼。若允許對不同的字符采用不等長的二進制位進行表示,那么這種方式稱為可變長編碼??勺冮L編碼其特點是對使用頻率高的字符采用短編碼,而對使用頻率低的字符則采用長編碼的方式。這樣我們就可以減少數據的存儲空間,從而起到壓縮數據的效果。而通過哈夫曼樹形成的哈夫曼編碼是一種的有效的數據壓縮編碼。

如果沒有一個編碼是另一個編碼的前綴,則稱這樣的編碼為前綴編碼。如0,101和100是前綴編碼。由前綴碼形成的序列可以被唯一的組成一個字符串序列。如00101100可以被唯一的分析為0,0,101和100。

示例:

我們對一個字符串進行統計發現a-f出現的頻率分別為a:45,b:13,c:12,d:16,e:9,f:5,我們對該字符串進行采用哈夫曼編碼進行存儲。

JNI,圖片壓縮

WPL = 1x45+3x(13+12+16)+4x(5+9)=224

這樣算下來使用224二進制位就可以將該字符串存儲起來,因為哈夫曼碼是前綴碼,所以可以唯一的還原出原來的字符序列。如果我們每個字符使用3位進行存儲(至少3位),那么需要300bit才能將該字符串存儲下。

其次了解下libjpeg使用哈夫曼編碼是對圖片上的每個像素(ARGB)進行編碼,比如

ARGB(每個顏色通道取值范圍0-255)的編碼分別是:

A:001
R:010
G:011
B:100

如果采用定長,那一個圖片下來一個人像素就是001010011100...

如果我們使用可變長編碼方式,遍歷、再嵌套遍歷,再嵌套遍歷每一個像素來獲取前綴編碼(沒錯,這個運算過程很大,而且臨時變量內存也需要很大,但相對于今天的手機CPU來說,so easy),我們大致可以得到這樣的編碼:

A:01
R:10
G:11
B:100

那一個圖片下來一個人像素就是011011100...

編碼長度的優化后,接下來干的事就是計算權重以及每個顏色通道對應的編碼的出現頻次構建哈夫曼樹了,這里就參考上面的圖片了。

通過上面的介紹,可以知道最優哈夫曼編碼其實是使用了可變長編碼方式,而默認的哈夫曼編碼使用了定長編碼方式,因此需要更多的存儲空間,呈現出來的手機圖片自然會大很大。

libjpeg把optimize_coding參數默認設置為FALSE是因為10多年前的Android手機CPU跟內存都非常吃緊,所以當年沒有設置為TRUE。如今的手機CPU跟內存都“起飛了”,Goolge的Skia圖像處理引擎卻還是使用optimize_coding的默認值FALSE。我們無法修改系統Skia的這個參數值,所以只能默默忍受size很大的圖像文件。

經過大量圖像壓縮測試結果,得到兩個結論:

1.圖片壓縮到相同的質量,FALSE所產出的圖像文件大小是TRUE的5-10倍。

2.圖片壓縮到相同的質量,Android所產出的圖像文件大小比iOS也是大5-10倍。

所以,通過使用libjpeg編譯自己的native library修改optimize_coding參數的值,達圖像質量相同,所產出的圖像卻能節省5-10倍空間大小的效果。

實現的步驟:

1.構建libjpeg的so庫

到官方下載對應自己電腦系統類型的壓縮包,創建Android項目導入壓縮包里頭的xx.h、xx.c文件構建so庫。bither/bither-android-lib已經做了這個工作,因此我們只需直接拿他的libjpegbither.so即可。

2.導入libjpeg的聲明頭文件,因為步驟1的libjpegbither.so是對這些頭文件的實現,因此需要導入這些頭文件。

3.創建CMake腳本

cmake_minimum_required(VERSION 3.4.1)add_library( effective-bitmapSHAREDsrc/main/cpp/effective-bitmap.c )include_directories( src/main/cpp/jpeg/)add_library(jpegbither SHARED IMPORTED)set_target_properties(jpegbitherPROPERTIES IMPORTED_LOCATION${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libjpegbither.so)find_library( log-liblog )find_library( jnigraphics-lib jnigraphics )target_link_libraries( effective-bitmapjpegbither${log-lib}${jnigraphics-lib})

4.配置gradle關聯CMakeLists.txt構建腳本,以及指定產出的ABI的類型

android {// ...defaultConfig {// ...externalNativeBuild {cmake {cppFlags ""}}ndk {abiFilters 'armeabi'}}externalNativeBuild {cmake {path "CMakeLists.txt"}}}

5.編寫C/C++代碼

int generateJPEG(BYTE* data, int w, int h, int quality,const char* outfilename, jboolean optimize) {int nComponent = 3;// jpeg的結構體,保存的比如寬、高、位深、圖片格式等信息struct jpeg_compress_struct jcs;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;}jpeg_create_compress(&jcs);// 打開輸出文件 wb:可寫byteFILE* f = fopen(outfilename, "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;if (nComponent == 1)jcs.in_color_space = JCS_GRAYSCALE;elsejcs.in_color_space = JCS_RGB;jpeg_set_defaults(&jcs);jcs.optimize_coding = optimize;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);}jpeg_finish_compress(&jcs);jpeg_destroy_compress(&jcs);fclose(f);return 1;}

6.構建so庫

源碼:https://github.com/zengfw/EffectiveBitmap 

參考鏈接:

Why the image quality of iPhone is much better than Android?

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲最大的免费| 5566成人精品视频免费| 狠狠干狠狠久久| 欧美成人午夜剧场免费观看| 91精品国产91久久久久久吃药| 97视频免费观看| 热99在线视频| 精品国偷自产在线| 亚洲欧美精品在线| 91国内精品久久| 姬川优奈aav一区二区| 国内精品久久久久影院 日本资源| 亚洲第一免费播放区| 国产一区二区三区直播精品电影| 亚洲区免费影片| 国产视频精品va久久久久久| 久久精品一区中文字幕| 秋霞成人午夜鲁丝一区二区三区| 国产精品偷伦视频免费观看国产| 亚洲精品福利免费在线观看| 国产精品久久精品| 神马久久桃色视频| 91国内揄拍国内精品对白| 精品国产欧美成人夜夜嗨| 亚洲奶大毛多的老太婆| 欧美在线视频免费播放| 久久69精品久久久久久国产越南| 81精品国产乱码久久久久久| 欧美日韩999| 日韩欧美高清视频| 久久中文字幕在线视频| 青草成人免费视频| 国产精品羞羞答答| 亚洲国产精品久久久久| 成人欧美一区二区三区黑人孕妇| 国产一区二区黑人欧美xxxx| 国产精品草莓在线免费观看| 欧美日韩午夜视频在线观看| 亚洲欧美三级伦理| 亚洲伊人第一页| 久久av在线看| 国产大片精品免费永久看nba| 亚洲人成电影在线| 久久久亚洲精品视频| 国产精品女视频| 日韩欧美在线视频| 最近中文字幕mv在线一区二区三区四区| 国内精品久久久久久中文字幕| 午夜精品一区二区三区在线播放| 中文日韩在线视频| 久久久久久久国产精品视频| 夜夜躁日日躁狠狠久久88av| 午夜精品美女自拍福到在线| 国产亚洲xxx| 欧美另类极品videosbestfree| 91香蕉嫩草影院入口| 97在线精品视频| 国产一区二区三区在线观看网站| 蜜臀久久99精品久久久久久宅男| 高清亚洲成在人网站天堂| 久久99精品久久久久久琪琪| 91av在线看| 国产视频精品在线| 久热在线中文字幕色999舞| 国产成人精品久久久| 成人美女免费网站视频| 91深夜福利视频| 久久精品成人欧美大片古装| 色偷偷888欧美精品久久久| 国产精品极品尤物在线观看| 日韩国产欧美精品在线| 欧美激情中文字幕乱码免费| 成人免费视频网| 992tv成人免费视频| 亚洲第一色在线| 欧美国产精品人人做人人爱| 日韩av免费在线播放| 亚洲jizzjizz日本少妇| 国产剧情日韩欧美| 欧美亚洲视频在线看网址| 青青草成人在线| 国产91精品黑色丝袜高跟鞋| 久久久噜久噜久久综合| 久久免费视频在线| 国产在线观看精品一区二区三区| 欧美大成色www永久网站婷| 成人久久一区二区| 高清视频欧美一级| 国产日韩欧美在线看| 亚洲综合社区网| 欧美性猛交视频| 97人洗澡人人免费公开视频碰碰碰| 九九九久久国产免费| 亚洲精品v欧美精品v日韩精品| 中文字幕亚洲欧美| 在线看欧美日韩| 久久99视频免费| 欧美大尺度电影在线观看| 国产成人av在线播放| 国内外成人免费激情在线视频网站| 国产精品电影网| 欧美理论电影在线播放| 国产精品高潮呻吟久久av野狼| 国产成人精品日本亚洲专区61| 欧美激情一二区| 国外成人在线播放| 日韩精品欧美国产精品忘忧草| 亚洲国产精品悠悠久久琪琪| 成人免费xxxxx在线观看| 自拍偷拍亚洲一区| 日本久久中文字幕| 亚洲成人网av| 欧美日韩国产成人在线| 日本一区二区在线免费播放| 色樱桃影院亚洲精品影院| 欧洲成人在线观看| 国产91精品青草社区| 国产精品免费久久久久久| 亚洲国产精品久久久久秋霞蜜臀| 国产欧美精品va在线观看| 91久久精品国产91久久| 亚洲欧洲国产精品| 庆余年2免费日韩剧观看大牛| 91午夜理伦私人影院| 97久久久免费福利网址| 国产999精品| 欧美日韩中国免费专区在线看| 日韩精品在线观看视频| 97香蕉超级碰碰久久免费软件| 色偷偷91综合久久噜噜| 亚洲综合在线做性| 日韩在线观看免费全| 久久精品视频在线观看| 亚洲九九九在线观看| 久久久精品2019中文字幕神马| 欧日韩在线观看| 欧美小视频在线| 黑人巨大精品欧美一区二区| 日韩一区二区三区在线播放| 欧美性生交xxxxx久久久| 国产精品电影久久久久电影网| 亚洲国产美女精品久久久久∴| 伦理中文字幕亚洲| 欧美日韩国产综合新一区| 亚洲第一免费网站| 欧美激情中文字幕在线| 久久99久国产精品黄毛片入口| 成人黄色av播放免费| 中文字幕在线观看亚洲| 久久国产精品偷| 亚洲在线www| 国产日韩欧美在线看| 亚洲理论片在线观看| 日韩av网站导航| 亚洲第一福利在线观看| 欧美午夜xxx| 欧美视频一区二区三区…| 国产精品久久久久久久久久久久久| 欧美成年人在线观看| 亚洲乱码一区av黑人高潮| 欧美激情在线观看视频| zzijzzij亚洲日本成熟少妇| 欧美精品在线免费播放| 欧洲亚洲女同hd|