Android圖片壓縮上傳之基礎(chǔ)篇
在android程序開發(fā)中我們經(jīng)常見到需要上傳圖片的場景,在這里有個技術(shù)點,需要把圖片壓縮處理,然后再進行上傳。這樣可以減少流量的消耗,提高圖片的上傳速度等問題。
關(guān)于android如何壓縮,網(wǎng)上的資料也是很多,但大多數(shù)都是代碼片段,講解壓縮步驟,而沒有一個實用的工具類庫。那么如何將壓縮算法封裝成一個實用工具庫呢?其中會遇到些什么問題,比如:
1.需要壓縮的圖片有多少
2.壓縮后的圖片是覆蓋還是保存到另外的目錄
3.如果是另存目錄需要將原始圖片刪除嗎
4.如果改變壓縮后的圖片的尺寸大小是按照原圖的比例縮小還是直接指定大小
5.如果原圖有旋轉(zhuǎn)問題,需不需要進行修正
6.對于多圖壓縮是并發(fā)還是線性的處理
7.能不能使用service來進行壓縮處理,是local(本地)還是remote(遠程)的方式來啟動service
8.如果需要壓縮的圖片非常多,如何使用線程池來處理
基于以上幾點的思考,本人打算寫個系列文章來一步一步解決這些問題(忘大家持續(xù)關(guān)注),將Service,多線程的使用及壓縮算法集合到一個項目中。這樣不僅在實際應(yīng)用中還是作為學(xué)習(xí)資料來講都是比較好的。最終我會將這個系列中涉及的代碼及迭代的過程開源到github,歡迎大家star,歡迎遞交bug。
當然有些朋友可能會說實際應(yīng)用中一次上傳的圖片數(shù)量不會太多吧,考慮這些問題是不是有點多慮了,好吧,如果您真是這么認為的那么可以忽略本系列文章。
實際需求中基本都會是按照原圖的寬高比進行壓縮,直接指定尺寸大小的比較少見,所以本系列文章也是針對這種等比率壓縮來進行的。
總之,對圖片進行壓縮,大家主要關(guān)注兩點:
1.對圖片的尺寸大小進行縮放來達到壓縮的目的
2.對圖片進行質(zhì)量壓縮
對圖片的尺寸大小進行縮放來達到壓縮的目的
針對這種情況及圖片旋轉(zhuǎn)問題,大家可以參考我的 android處理拍照旋轉(zhuǎn)問題及帶來的對內(nèi)存占用的思考 這篇文章。
只是大家需要注意的是,這里需要按照原始圖片的寬高比(srcRatio)來計算最終輸出圖片的寬高(actualOutWidth,actualOutHeight),最后通過actualOutWidth,actualOutHeight來計算采樣值sampleSize。
核心代碼如下:
LGImageCompressor.java BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(srcImagePath, options); //根據(jù)原始圖片的寬高比和期望的輸出圖片的寬高比計算最終輸出的圖片的寬和高 float srcWidth = options.outWidth; float srcHeight = options.outHeight; float maxWidth = outWidth;//期望輸出的圖片寬度 float maxHeight = outHeight;//期望輸出的圖片高度 float srcRatio = srcWidth / srcHeight; float outRatio = maxWidth / maxHeight; float actualOutWidth = srcWidth;//最終輸出的圖片寬度 float actualOutHeight = srcHeight;//最終輸出的圖片高度 if (srcWidth > maxWidth || srcHeight > maxHeight) { if (srcRatio < outRatio) { actualOutHeight = maxHeight; actualOutWidth = actualOutHeight * srcRatio; } else if (srcRatio > outRatio) { actualOutWidth = maxWidth; actualOutHeight = actualOutWidth / srcRatio; } else { actualOutWidth = maxWidth; actualOutHeight = maxHeight; } } //計算sampleSize options.inSampleSize = computSampleSize(options, actualOutWidth, actualOutHeight);
為了方便大家理解以上代碼,舉個極端例子:
假如原始圖片寬為srcWidth=40,高為srcHeight=20。期望輸出的寬為maxWidth=300,高為maxHeight=10。 那么srcRatio=40:20=2,outRatio=300:10=30. 顯然srcRatio<outRatio,那么我們的實際最終輸出圖片的尺寸應(yīng)該以maxHeight(10)為準即actualOutHeight = maxHeight,最后根據(jù)原圖的比率來計算actualOutWidth=actualOutHeight*srcRatio = 10*40/20=20,最后得到的actualOutWidth=20. 最終輸出圖片的寬高比為20:10=2,和原始圖片寬高比相同。其它情況類似,這里不做詳解了。
對圖片進行質(zhì)量壓縮
針對這種情況,android的Bitmap類中API接口有compress方法
public boolean compress(CompressFormat format, int quality, OutputStream stream)
三個參數(shù)的理解應(yīng)該不難,大家可以查看官方doc文檔。compress方法主要通過quality來控制輸入到stream中的像素質(zhì)量。
這針對希望輸出的圖片占用的空間不大于一定的值這種場景會比較合適,因為我們可以通過循環(huán)判斷壓縮后的大小是否大于定值,如果滿足則減少quality繼續(xù)執(zhí)行compress操作。核心代碼如下:
//進行有損壓縮 ByteArrayOutputStream baos = new ByteArrayOutputStream(); int options_ = 100; actualOutBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//質(zhì)量壓縮方法,把壓縮后的數(shù)據(jù)存放到baos中 (100表示不壓縮,0表示壓縮到最小) int baosLength = baos.toByteArray().length; while (baosLength / 1024 > maxFileSize) {//循環(huán)判斷如果壓縮后圖片是否大于maxMemmorrySize,大于繼續(xù)壓縮 baos.reset();//重置baos即讓下一次的寫入覆蓋之前的內(nèi)容 options_ = Math.max(0, options_ - 10);//圖片質(zhì)量每次減少10 actualOutBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//將壓縮后的圖片保存到baos中 baosLength = baos.toByteArray().length; if (options_ == 0)//如果圖片的質(zhì)量已降到最低則,不再進行壓縮 break; }
壓縮一個超大圖是要費時間的,所以大家應(yīng)該考慮將壓縮放到后臺線程中執(zhí)行,如果沒有高并發(fā)的需求使用AsyncTask就能解決問題。
核心代碼:
private class CompressTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { return compressImage();//執(zhí)行壓縮操作 } @Override protected void onPreExecute() { if (compressListener != null) { compressListener.onCompressStart();//監(jiān)聽回調(diào)(開始壓縮) } } @Override protected void onPostExecute(String imageOutPath) { if (compressListener != null) { compressListener.onCompressEnd(imageOutPath);//監(jiān)聽回調(diào)(壓縮結(jié)束) } } }
經(jīng)過適當?shù)姆庋b代碼可以通過在Activity中的執(zhí)行
LGImgCompressor.getInstance(this).withListener(this).starCompress(Uri.fromFile(imageFile).toString(),outWidth,outHeight,maxFileSize);
來啟動壓縮任務(wù)
寫在最后
為了達到最佳的壓縮結(jié)果,可以將上面兩種方案同時進行。如果壓縮消耗的時間很長,需要將壓縮過程放入后臺線程中執(zhí)行。
本人寫了個簡單的demo程序,實現(xiàn)的功能有:
1.開啟攝像頭拍攝照片
2.指定照片的存儲位置
3.壓縮照片到指定目錄下
4.使用AsyncTask執(zhí)行壓縮操作
5.顯示壓縮后的照片及其相關(guān)信息到前臺activity
由于這個版本是使用AsyncTask異步任務(wù)來執(zhí)行compress的,而AsyncTask由于android版本分裂問題有些版本是多線程的,有些版本是單線程的,也是醉了,總之此版本適用于一次壓縮任務(wù)不是很多的情況,如果需要處理數(shù)據(jù)很大的壓縮任務(wù),需要考慮用線程池來處理。
另外,如何結(jié)合使用service和多線程會在下篇文章具體說明。
demo開源github地址如下:
以上所述是小編給大家介紹的Android圖片壓縮上傳之基礎(chǔ)篇的相關(guān)知識,希望對大家有所幫助,如果大家想了解更多資訊敬請關(guān)注腳本之家網(wǎng)站!
相關(guān)文章
Android實現(xiàn)在子線程中更新Activity中UI的方法
這篇文章主要介紹了Android實現(xiàn)在子線程中更新Activity中UI的方法,涉及Android線程與activity操作的相關(guān)技巧,需要的朋友可以參考下2016-04-04Android判斷應(yīng)用程序退到后臺的方法(示例代碼)
判斷手機是否退到后臺,這是我們在Android開發(fā)中實現(xiàn)一些功能時,經(jīng)常會考慮的問題,這篇文章主要介紹了android判斷應(yīng)用程序退到后臺的方法,需要的朋友可以參考下2023-03-03移動端android上line-height不居中的問題的解決
現(xiàn)在越來越多的移動界面使用rem適配,最近發(fā)現(xiàn)了移動端android上line-height不居中的問題,今日就來介紹一下解決的方法,非常具有實用價值,需要的朋友可以參考下2018-03-03Android 仿小米鎖屏實現(xiàn)九宮格解鎖功能(無需圖片資源)
最近公司要求做個九宮格解鎖,本人用的是小米手機,看著他那個設(shè)置鎖屏九宮格很好看,就做了該組件,不使用圖片資源,純代碼實現(xiàn),感興趣的朋友參考下吧2016-12-12Android自定義ViewFlipper實現(xiàn)滾動效果
這篇文章主要為大家詳細介紹了Android自定義ViewFlipper實現(xiàn)滾動效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-08-08Android自定義布局實現(xiàn)仿qq側(cè)滑部分代碼
這篇文章主要為大家詳細介紹了自定義布局實現(xiàn)仿qq側(cè)滑Android部分代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03Android 中RecyclerView多種item布局的寫法(頭布局+腳布局)
這篇文章主要介紹了Android 中RecyclerView多種item布局的寫法(頭布局+腳布局)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-01-01