<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在Android中我們經常會遇到圖片壓縮的場景,比如給伺服器端上傳圖片,包括個人資訊的使用者頭像,有時候臉部辨識也需要捕獲圖片等等。這種情況下,我們都需要對圖片做一定的處理,比如大小,尺寸等的壓縮。
首先我們要介紹一個api--Bitmap.compress()
@WorkerThread public boolean compress(CompressFormat format, int quality, OutputStream stream) { checkRecycled("Can't compress a recycled bitmap"); // do explicit check before calling the native method if (stream == null) { throw new NullPointerException(); } if (quality < 0 || quality > 100) { throw new IllegalArgumentException("quality must be 0..100"); } StrictMode.noteSlowCall("Compression of a bitmap is slow"); Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress"); boolean result = nativeCompress(mNativePtr, format.nativeInt, quality, stream, new byte[WORKING_COMPRESS_STORAGE]); Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); return result; }
compress()是系統的API,也是質量和尺寸壓縮常用的方法。
public boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream);這個方法有三個引數:
返回值:如果成功地把壓縮資料寫入輸出流,則返回true。
虛擬碼
val baos= ByteArrayoutputstream () try { var quality = 50 do { quality -= 10 baos.reset() bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos) } while (baos.toByteArray().size / 1024 > 100) fos.write(baos.toByteArray(o)) }catch (ex : Throwable) { ex.printStackTrace ()} finally { fos.apply i this: FileOutputStream flush () close () }
先來看看一個屬性Options
兩次decode,傳入不同的options設定:
部分虛擬碼
val reqWidth = 500 val reqHeight = 300 val bitmap = decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight) val fos = Fileoutputstream( File(applicationContext.filesDir, child: "$ {system.currentTimeMillis() }_scale.jpg") ) try { val quality = 50 bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fos) catch(ex: Throwable) { ex.printstackTrace() finally { fos.apply { flush() close() } } } } } private fun decodeSampledBitmapFromFile(imageFile: File,reqWidth: Int,reqHeight: Int): Bitmap { return BitmapFactory.Options().run { inJustDecodeBounds = true //先獲取原始圖片的寬高,不會將Bitmap載入到記憶體中,返回null BitmapFactory.decodeFile(imageFile.absolutePath, opts: this) inSamplesize = calculateInSampleSize(options: this, reqWidth,reqHeight) inJustDecodeBounds - false BitmapFactory.decodeFile(imageFile.absolutePath, opts : this) } } private fun calculateInSampleSize(context: BitmapFactory, reqWidth: Int, reqHeight: Int): Int { //解構語法,獲取原始圖片的寬高 val (height: Int, width: Int) = options.run { outHeight to outwidth } //計算最大的inSampleSize值,該值為2的冪次方,並同時保持這兩個值高度和寬度大於請求的高度和寬度。 //原始圖片的寬高要大於要求的寬高 var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight: Int = height / 2 val halfwidth: Int = width / 2 while (halfHeight / inSampleSize >= reqHeight && halfwidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
inSampleSize都是2的倍數 .
BitmapFactory 給我們提供了一個解析圖片大小的引數類 BitmapFactory.Options ,把這個類的物件的 inJustDecodeBounds 引數設定為 true,這樣解析出來的 Bitmap 雖然是個 null,但是 options 中可以得到圖片的寬和高以及圖片的型別。得到了圖片實際的寬和高之後我們就可以進行壓縮設定了,主要是計算圖片的取樣率。
其實最重要的是把ARGB轉換為RBG,也就是把每個畫素4個位元組,轉換為每個畫素3個位元組。
匯入對應的so庫檔案即可編寫C的程式碼 jpeg.so 和 jpeg-turbo.so
編寫這部分的程式碼需要NDK的環境和C語言的基礎
虛擬碼
int generateCompressJPEG(BYTE *data, int w, int h, int quality, const char *outfileName, jboolean optimize) { //結構體相當於java的類 struct jpeg_compress_struct jcs; //當讀完整個檔案的時候回回撥 struct my_error_mgr jem; jcs.err = jpeg_std_error(&jem.pub); jem.pub.error_exit = my_error_exit; //setjmp是一個系統級函數,是一個回撥 if (setjmp(jem.setjmp_buffer)) { return 0; } //初始化jsc結構體 jpeg_create_compress(&jcs); //開啟輸出檔案 wb可寫 rb可讀 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 jcs.arith_code = false; int nComponent = 3; // 顏色的組成rgb,三個 of color components in input image jcs.input_components = nComponent; // 設定顏色空間為rgb jcs.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; }
for (int i = 0; i < bitmapInfo.height; ++i) { for (int j= 0; j < bitmapInfo.width; ++j){ if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888){ //0x2312faff ->588446463 color = *(int *) (pixelsColor); // 從color值中讀取RGBA的值/ /ABGR b = (color >> 16)& 0xFE; g = (color >> 8)& OxFF; r = (color >> 0) & OxFF; *data = r; * (data + 1) =g; *(data + 2) = b; data += 3; //移動步長4個位元組 pixelsColor +- 4 ; }else { return -2; } // 是否採用哈夫曼 jcs.optimize_coding = optimize;
至此,三種圖片壓縮的方法已經介紹完畢了。
經過圖片壓縮實踐,質量壓縮和libjpeg最後的圖片的大小一樣,效果也和原圖差不多。
其實,經過我翻查原碼發現,新版本的Bitmap.compress() 會呼叫
boolean result = nativeCompress(mNativePtr, format.nativeInt, quality, stream, new byte[WORKING_COMPRESS_STORAGE]); private static native boolean nativeCompress(long nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage);
其實最後也會呼叫到nativeCompress的壓縮,也會採用哈夫曼演演算法,提高壓縮效率。
既然這樣,那麼這裡為什麼還要介紹libjpeg的方法呢?
到此這篇關於Android效能優化之圖片大小,尺寸壓縮綜合解決方案的文章就介紹到這了,更多相關Android圖片壓縮解決內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45