Android開發(fā)實(shí)現(xiàn)圖片大小與質(zhì)量壓縮及保存
Android中圖片有四種屬性
ALPHA_8:每個(gè)像素占用1byte內(nèi)存
ARGB_4444:每個(gè)像素占用2byte內(nèi)存
ARGB_8888:每個(gè)像素占用4byte內(nèi)存 (默認(rèn))
RGB_565:每個(gè)像素占用2byte內(nèi)存
Android默認(rèn)的顏色模式為ARGB_8888,這個(gè)顏色模式色彩最細(xì)膩,顯示質(zhì)量最高。但同樣的,占用的內(nèi)存也最大。所以在對圖片效果不是特別高的情況下使用RGB_565(565沒有透明度屬性)
Android目前常用圖片格式
有png,jpeg和webp
png:無損壓縮圖片格式,支持Alpha通道,Android切圖素材多采用該格式
jpeg:有損壓縮圖片格式,不支持背景透明,適用于照片等色彩豐富的(大圖壓縮,不適合logo)
webp:是一種同時(shí)提供了有損壓縮和無損壓縮的圖片格式,派生自視頻編碼格式VP8,從谷歌官網(wǎng)來看,無損webp平均比png小26%,有損的webp平均比jpeg小25%~34%,無損webp支持Alpha通道,有損webp在一定的條件下同樣支持,有損webp在Android4.0(API 14)之后支持,無損和透明在Android4.3(API18)之后支持
使用
大小壓縮
private Bitmap getimage(String srcPath) { BitmapFactory.Options newOpts = new BitmapFactory.Options(); //開始讀入圖片,此時(shí)把options.inJustDecodeBounds 設(shè)回true了 newOpts.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此時(shí)返回bm為空 newOpts.inJustDecodeBounds = false; int w = newOpts.outWidth; int h = newOpts.outHeight; //現(xiàn)在主流手機(jī)比較多是800*480分辨率,所以高和寬我們設(shè)置為 float hh = 800f;//這里設(shè)置高度為800f float ww = 480f;//這里設(shè)置寬度為480f //縮放比。由于是固定比例縮放,只用高或者寬其中一個(gè)數(shù)據(jù)進(jìn)行計(jì)算即可 int be = 1;//be=1表示不縮放 if (w > h && w > ww) {//如果寬度大的話根據(jù)寬度固定大小縮放 be = (int) (newOpts.outWidth / ww); } else if (w < h && h > hh) {//如果高度高的話根據(jù)寬度固定大小縮放 be = (int) (newOpts.outHeight / hh); } if (be <= 0) be = 1; newOpts.inSampleSize = be;//設(shè)置縮放比例 //重新讀入圖片,注意此時(shí)已經(jīng)把options.inJustDecodeBounds 設(shè)回false了 bitmap = BitmapFactory.decodeFile(srcPath, newOpts); return compressImage(bitmap);//壓縮好比例大小后再進(jìn)行質(zhì)量壓縮 }
質(zhì)量壓縮
注意:
第二次壓縮之前都要先清空 baos.reset(); 再進(jìn)行壓縮
image.compress(Bitmap.CompressFormat.JPEG, quality, baos);
有時(shí)候我們采用質(zhì)量壓縮沒有效果,有可能是每次壓縮的質(zhì)量過小,所以我們可以嘗試修改壓縮質(zhì)量(quality)是10;
quality壓縮機(jī)提示,0-100。0表示壓縮小尺寸,100意味著最大質(zhì)量的壓縮。一些格式,如無損的PNG,將忽略質(zhì)量設(shè)定;
private Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 90; int length = baos.toByteArray().length / 1024; if (length>5000){ //重置baos即清空baos baos.reset(); //質(zhì)量壓縮方法,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, 10, baos); }else if (length>4000){ baos.reset(); image.compress(Bitmap.CompressFormat.JPEG, 20, baos); }else if (length>3000){ baos.reset(); image.compress(Bitmap.CompressFormat.JPEG, 50, baos); }else if (length>2000){ baos.reset(); image.compress(Bitmap.CompressFormat.JPEG, 70, baos); } //循環(huán)判斷如果壓縮后圖片是否大于1M,大于繼續(xù)壓縮 while (baos.toByteArray().length / 1024>1024) { //重置baos即清空baos baos.reset(); //這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, options, baos); //每次都減少10 options -= 10; } //把壓縮后的數(shù)據(jù)baos存放到ByteArrayInputStream中 ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); //把ByteArrayInputStream數(shù)據(jù)生成圖片 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null); return bitmap; }
混合方式壓縮
private Bitmap comp(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos); if( baos.toByteArray().length / 1024>1024) {//判斷如果圖片大于1M,進(jìn)行壓縮避免在生成圖片(BitmapFactory.decodeStream)時(shí)溢出 baos.reset();//重置baos即清空baos image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//這里壓縮50%,把壓縮后的數(shù)據(jù)存放到baos中 } ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); BitmapFactory.Options newOpts = new BitmapFactory.Options(); //開始讀入圖片,此時(shí)把options.inJustDecodeBounds 設(shè)回true了 newOpts.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); newOpts.inJustDecodeBounds = false; int w = newOpts.outWidth; int h = newOpts.outHeight; //現(xiàn)在主流手機(jī)比較多是800*480分辨率,所以高和寬我們設(shè)置為 float hh = 800f;//這里設(shè)置高度為800f float ww = 480f;//這里設(shè)置寬度為480f //縮放比。由于是固定比例縮放,只用高或者寬其中一個(gè)數(shù)據(jù)進(jìn)行計(jì)算即可 int be = 1;//be=1表示不縮放 if (w > h && w > ww) {//如果寬度大的話根據(jù)寬度固定大小縮放 be = (int) (newOpts.outWidth / ww); } else if (w < h && h > hh) {//如果高度高的話根據(jù)寬度固定大小縮放 be = (int) (newOpts.outHeight / hh); } if (be <= 0) be = 1; newOpts.inSampleSize = be;//設(shè)置縮放比例 //重新讀入圖片,注意此時(shí)已經(jīng)把options.inJustDecodeBounds 設(shè)回false了 isBm = new ByteArrayInputStream(baos.toByteArray()); bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); return compressImage(bitmap);//壓縮好比例大小后再進(jìn)行質(zhì)量壓縮 }
采樣率壓縮
采樣率壓縮是通過設(shè)置BitmapFactory.Options.inSampleSize,來減小圖片的分辨率,進(jìn)而減小圖片所占用的磁盤空間和內(nèi)存大小。
設(shè)置的inSampleSize會(huì)導(dǎo)致壓縮的圖片的寬高都為1/inSampleSize,整體大小變?yōu)樵紙D片的inSampleSize平方分之一,當(dāng)然,這些有些注意點(diǎn):
- 1、inSampleSize小于等于1會(huì)按照1處理
- 2、inSampleSize只能設(shè)置為2的平方,不是2的平方則最終會(huì)減小到最近的2的平方數(shù),如設(shè)置7會(huì)按4進(jìn)行壓縮,設(shè)置15會(huì)按8進(jìn)行壓縮。
/** * * @param inSampleSize 可以根據(jù)需求計(jì)算出合理的inSampleSize */ public static void compress(int inSampleSize) { File sdFile = Environment.getExternalStorageDirectory(); File originFile = new File(sdFile, "originImg.jpg"); BitmapFactory.Options options = new BitmapFactory.Options(); //設(shè)置此參數(shù)是僅僅讀取圖片的寬高到options中,不會(huì)將整張圖片讀到內(nèi)存中,防止oom options.inJustDecodeBounds = true; Bitmap emptyBitmap = BitmapFactory.decodeFile(originFile.getAbsolutePath(), options); options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; Bitmap resultBitmap = BitmapFactory.decodeFile(originFile.getAbsolutePath(), options); ByteArrayOutputStream bos = new ByteArrayOutputStream(); resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); try { FileOutputStream fos = new FileOutputStream(new File(sdFile, "resultImg.jpg")); fos.write(bos.toByteArray()); fos.flush(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
圖片保存到本地
/** * 保存bitmap到本地 * @param context the context * @param mBitmap the m bitmap * @return string */ public static String saveBitmap(Context context, Bitmap mBitmap) { String savePath; File filePic; try { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { savePath = SD_PATH; } else { savePath = context.getApplicationContext().getFilesDir().getAbsolutePath() + IN_PATH; } filePic = new File(savePath + DateTimeHelper.format(new Date(), "yyyyMMddHHmmss") + ".jpg"); Log.d("LUO", "圖片地址====" + filePic); if (!filePic.exists()) { filePic.getParentFile().mkdirs(); filePic.createNewFile(); } FileOutputStream fos = new FileOutputStream(filePic); //不壓縮,保存本地 mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); return null; } return filePic.getAbsolutePath(); }
以上就是Android開發(fā)實(shí)現(xiàn)圖片大小與質(zhì)量壓縮及保存的詳細(xì)內(nèi)容,更多關(guān)于Android開發(fā)圖片大小質(zhì)量壓縮保存的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android自定義dialog簡單實(shí)現(xiàn)方法
這篇文章主要介紹了Android自定義dialog簡單實(shí)現(xiàn)方法,實(shí)例分析了Android自定義對話框的相關(guān)設(shè)置技巧,代碼備有詳細(xì)的注釋便于理解,需要的朋友可以參考下2016-01-01Android使用KeyStore對數(shù)據(jù)進(jìn)行加密的示例代碼
這篇文章主要介紹了Android使用KeyStore對數(shù)據(jù)進(jìn)行加密的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01Android開發(fā)基礎(chǔ)之創(chuàng)建啟動(dòng)界面Splash Screen的方法
這篇文章主要介紹了Android開發(fā)基礎(chǔ)之創(chuàng)建啟動(dòng)界面Splash Screen的方法,以實(shí)例形式較為詳細(xì)的分析了Android定制啟動(dòng)界面的布局及功能實(shí)現(xiàn)相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android列表組件ListView使用詳解之動(dòng)態(tài)加載或修改列表數(shù)據(jù)
今天小編就為大家分享一篇關(guān)于Android列表組件ListView使用詳解之動(dòng)態(tài)加載或修改列表數(shù)據(jù),小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03Android 判斷日期是否在一年以內(nèi)的算法實(shí)例
下面小編就為大家?guī)硪黄狝ndroid 判斷日期是否在一年以內(nèi)的算法實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04android自定義toast(widget開發(fā))示例
這篇文章主要介紹了android自定義toast(widget開發(fā))示例,需要的朋友可以參考下2014-03-03使用android studio開發(fā)工具編譯GBK轉(zhuǎn)換三方庫iconv的方法
這篇文章主要介紹了使用android studio開發(fā)工具編譯GBK轉(zhuǎn)換三方庫iconv的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06android ViewPager實(shí)現(xiàn)自動(dòng)無限輪播和下方向?qū)A點(diǎn)
本篇文章主要介紹了android ViewPager實(shí)現(xiàn)自動(dòng)輪播和下方向?qū)A點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02利用Jetpack?Compose實(shí)現(xiàn)繪制五角星效果
這篇文章主要為大家介紹了Jetpack?Compose如何使用自定義操作符實(shí)現(xiàn)繪制五角星效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-04-04