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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

android图片压缩上传系列-基础篇

發(fā)布時(shí)間:2023/11/29 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android图片压缩上传系列-基础篇 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

開(kāi)發(fā)中遇到需要上傳圖片的場(chǎng)景還是很常見(jiàn)的,這就涉及到圖片的壓縮處理。如果不進(jìn)行壓縮,勢(shì)必造成消耗大量的流量,下載圖片的速度慢等。

關(guān)于android如何壓縮,網(wǎng)上的資料也是很多,但大多數(shù)都是代碼片段,講解壓縮步驟,而沒(méi)有一個(gè)實(shí)用的工具類庫(kù)。那么如何將壓縮算法封裝成一個(gè)實(shí)用工具庫(kù)呢?其中會(huì)遇到些什么問(wèn)題,比如:

  • 需要壓縮的圖片有多少
  • 壓縮后的圖片是覆蓋還是保存到另外的目錄
  • 如果是另存目錄需要將原始圖片刪除嗎
  • 如果改變壓縮后的圖片的尺寸大小是按照原圖的比例縮小還是直接指定大小
  • 如果原圖有旋轉(zhuǎn)問(wèn)題,需不需要進(jìn)行修正
  • 對(duì)于多圖壓縮是并發(fā)還是線性的處理
  • 能不能使用service來(lái)進(jìn)行壓縮處理,是local(本地)還是remote(遠(yuǎn)程)的方式來(lái)啟動(dòng)service
  • 如果需要壓縮的圖片非常多,如何使用線程池來(lái)處理
  • 基于以上幾點(diǎn)的思考,本人打算寫(xiě)個(gè)系列文章來(lái)一步一步解決這些問(wèn)題(忘大家持續(xù)關(guān)注),將Service,多線程的使用及壓縮算法集合到一個(gè)項(xiàng)目中。這樣不僅在實(shí)際應(yīng)用中還是作為學(xué)習(xí)資料來(lái)講都是比較好的。最終我會(huì)將這個(gè)系列中涉及的代碼及迭代的過(guò)程開(kāi)源到github,歡迎大家star,歡迎遞交bug。

    當(dāng)然有些朋友可能會(huì)說(shuō)實(shí)際應(yīng)用中一次上傳的圖片數(shù)量不會(huì)太多吧,考慮這些問(wèn)題是不是有點(diǎn)多慮了,好吧,如果您真是這么認(rèn)為的那么可以忽略本系列文章。

    實(shí)際需求中基本都會(huì)是按照原圖的寬高比進(jìn)行壓縮,直接指定尺寸大小的比較少見(jiàn),所以本系列文章也是針對(duì)這種等比率壓縮來(lái)進(jìn)行的。

    總之,對(duì)圖片進(jìn)行壓縮,大家主要關(guān)注兩點(diǎn):

  • 對(duì)圖片的尺寸大小進(jìn)行縮放來(lái)達(dá)到壓縮的目的
  • 對(duì)圖片進(jìn)行質(zhì)量壓縮
  • 對(duì)圖片的尺寸大小進(jìn)行縮放來(lái)達(dá)到壓縮的目的

    針對(duì)這種情況及圖片旋轉(zhuǎn)問(wèn)題,大家可以參考我的 android處理拍照旋轉(zhuǎn)問(wèn)題及帶來(lái)的對(duì)內(nèi)存占用的思考 這篇文章。

    只是大家需要注意的是,這里需要按照原始圖片的寬高比(srcRatio)來(lái)計(jì)算最終輸出圖片的寬高(actualOutWidth,actualOutHeight),最后通過(guò)actualOutWidth,actualOutHeight來(lái)計(jì)算采樣值sampleSize。
    核心代碼如下:
    LGImageCompressor.java

    BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(srcImagePath, options); //根據(jù)原始圖片的寬高比和期望的輸出圖片的寬高比計(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;} } //計(jì)算sampleSize options.inSampleSize = computSampleSize(options, actualOutWidth, actualOutHeight);

    為了方便大家理解以上代碼,舉個(gè)極端例子:
    假如原始圖片寬為srcWidth=40,高為srcHeight=20。期望輸出的寬為maxWidth=300,高為maxHeight=10。 那么srcRatio=40:20=2,outRatio=300:10=30. 顯然srcRatio<outRatio,那么我們的實(shí)際最終輸出圖片的尺寸應(yīng)該以maxHeight(10)為準(zhǔn)即actualOutHeight = maxHeight,最后根據(jù)原圖的比率來(lái)計(jì)算actualOutWidth=actualOutHeight*srcRatio = 10*40/20=20,最后得到的actualOutWidth=20. 最終輸出圖片的寬高比為20:10=2,和原始圖片寬高比相同。其它情況類似,這里不做詳解了。

    對(duì)圖片進(jìn)行質(zhì)量壓縮

    針對(duì)這種情況,android的Bitmap類中API接口有compress方法
    public boolean compress(CompressFormat format, int quality, OutputStream stream)
    三個(gè)參數(shù)的理解應(yīng)該不難,大家可以查看官方doc文檔。compress方法主要通過(guò)quality來(lái)控制輸入到stream中的像素質(zhì)量。
    這針對(duì)希望輸出的圖片占用的空間不大于一定的值這種場(chǎng)景會(huì)比較合適,因?yàn)槲覀兛梢酝ㄟ^(guò)循環(huán)判斷壓縮后的大小是否大于定值,如果滿足則減少quality繼續(xù)執(zhí)行compress操作。核心代碼如下:

    //進(jìn)行有損壓縮 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即讓下一次的寫(xiě)入覆蓋之前的內(nèi)容options_ = Math.max(0, options_ - 10);//圖片質(zhì)量每次減少10actualOutBitmap.compress(Bitmap.CompressFormat.JPEG, options_, baos);//將壓縮后的圖片保存到baos中baosLength = baos.toByteArray().length;if (options_ == 0)//如果圖片的質(zhì)量已降到最低則,不再進(jìn)行壓縮break; }

    壓縮一個(gè)超大圖是要費(fèi)時(shí)間的,所以大家應(yīng)該考慮將壓縮放到后臺(tái)線程中執(zhí)行,如果沒(méi)有高并發(fā)的需求使用AsyncTask就能解決問(wèn)題。
    核心代碼:

    private class CompressTask extends AsyncTask<String, Void, String> {@Overrideprotected String doInBackground(String... params) {return compressImage();//執(zhí)行壓縮操作}@Overrideprotected void onPreExecute() {if (compressListener != null) {compressListener.onCompressStart();//監(jiān)聽(tīng)回調(diào)(開(kāi)始?jí)嚎s)}}@Overrideprotected void onPostExecute(String imageOutPath) {if (compressListener != null) {compressListener.onCompressEnd(imageOutPath);//監(jiān)聽(tīng)回調(diào)(壓縮結(jié)束)}} }

    經(jīng)過(guò)適當(dāng)?shù)姆庋b代碼可以通過(guò)在Activity中的執(zhí)行
    LGImgCompressor.getInstance(this).withListener(this).starCompress(Uri.fromFile(imageFile).toString(),outWidth,outHeight,maxFileSize);

    來(lái)啟動(dòng)壓縮任務(wù)

    寫(xiě)在最后

    為了達(dá)到最佳的壓縮結(jié)果,可以將上面兩種方案同時(shí)進(jìn)行。如果壓縮消耗的時(shí)間很長(zhǎng),需要將壓縮過(guò)程放入后臺(tái)線程中執(zhí)行。本人寫(xiě)了個(gè)簡(jiǎn)單的demo程序,實(shí)現(xiàn)的功能有:

  • 開(kāi)啟攝像頭拍攝照片
  • 指定照片的存儲(chǔ)位置
  • 壓縮照片到指定目錄下
  • 使用AsyncTask執(zhí)行壓縮操作
  • 顯示壓縮后的照片及其相關(guān)信息到前臺(tái)activity
  • 由于這個(gè)版本是使用AsyncTask異步任務(wù)來(lái)執(zhí)行compress的,而AsyncTask由于android版本分裂問(wèn)題有些版本是多線程的,有些版本是單線程的,也是醉了,總之此版本適用于一次壓縮任務(wù)不是很多的情況,如果需要處理數(shù)據(jù)很大的壓縮任務(wù),需要考慮用線程池來(lái)處理。
    另外,如何結(jié)合使用service和多線程會(huì)在下篇文章具體說(shuō)明。

    demo開(kāi)源github地址如下:
    LGImageCompressor
    歡迎大家訪問(wèn)并star,如果有任何問(wèn)題可以在評(píng)論中加以提問(wèn),謝謝~~

    轉(zhuǎn)載于:https://www.cnblogs.com/laoguigame/p/5531770.html

    總結(jié)

    以上是生活随笔為你收集整理的android图片压缩上传系列-基础篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。