android圖片壓縮不失真實戰
相信大家在專案開發中,不管是大小企業,伺服器上傳速度都是有限的,更何況不少公司是通過存在第三方的雲端儲存如七牛中間站的,這就造成假設我們需要上傳多張圖片會很慢,給使用者很差的體驗了,這裡是個人在專案中需求需要上傳三十張照片,對圖片壓縮的心得,可能存在不足的地方,希望能指正。
廢話客套話就不多說了,我們搬磚裝修吧,核心實現程式碼如下:
// 根據路徑獲得圖片並壓縮,返回bitmap用於顯示
public static Bitmap getSmallBitmap(String filePath) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, 480, 800); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filePath, options); }
//把bitmap轉換成String public static String bitmapToString(String filePath) { Bitmap bm = getSmallBitmap(filePath); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 40, baos); byte[] b = baos.toByteArray(); return Base64.encodeToString(b, Base64.DEFAULT); }另外在我們儲存圖片還可以使用Base64轉化為位元組流儲存檔案,檔案傳輸入,為了傳輸方便最好的辦法是將檔案轉化成base64字串,再將base64字串轉成位元組流儲存在檔案了。不過這種做法雖然簡單,但還要根據實際需求進行選擇,弊端是不能轉太大的檔案,檔案太大會造成效率問題,現在暫且這麼處理。
具體程式碼如下:
public void saveBitmap(String filePath) {
try {
String path = Environment.getExternalStorageDirectory() + "/test" + System.currentTimeMillis() + ".png";
decoderBase64File(bitmapToString(filePath), path);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* decoderBase64File:(將base64字元解碼儲存檔案). <br/>
*
* @param base64Code 編碼後的字串
* @param savePath 檔案儲存路徑
* @throws Exception
* @author BinaryKnight
* @since JDK 1.6
*/
public void decoderBase64File(String base64Code, String savePath) throws Exception {
//byte[] buffer = new BASE64Decoder().decodeBuffer(base64Code);
byte[] buffer = Base64.decode(base64Code, Base64.DEFAULT);
File f = new File(savePath);
f.createNewFile();
FileOutputStream out = new FileOutputStream(f);
out.write(buffer);
out.close();
}
對圖片壓縮的講解:壓縮圖片我們需要知道圖片的尺寸,然後根據比例無失真壓縮:
主要分成以下三步:
1.獲取原始圖片的長和寬
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); int height = options.outHeight; int width = options.outWidth;以上程式碼是對圖片進行解碼,inJustDecodeBounds設定為true,可以不把圖片讀到記憶體中,但依然可以計算出圖片的大小,這正好可以滿足我們第一步的需要
2.計算壓縮比例
int height = options.outHeight; int width = options.outWidth; int inSampleSize = 1; int reqHeight=800; int reqWidth=480; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height/ (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; }這裡以手機解析度480*800為例,我們期望的寬高分別設定為480,800,這兩個值只是我們的期望值,實際壓縮後的寬度和高度都會比期望的要大。如果原始圖片的尺寸大於我們設定的期望值才會進行壓縮,否則不壓縮。heightRatio是圖片原始高度與壓縮後高度的倍數,widthRatio是圖片原始寬度與壓縮後寬度的倍數。inSampleSize為heightRatio與widthRatio中最小的那個,inSampleSize就是縮放值。 inSampleSize為1表示寬度和高度不縮放,為2表示壓縮後的寬度與高度為原來的1/2。
3.縮放並壓縮圖片
//在記憶體中建立bitmap物件,這個物件按照縮放大小建立的
byte[] b = baos.toByteArray();options.inSampleSize = calculateInSampleSize(options, 480, 800);
options.inJustDecodeBounds = false; Bitmap bitmap= BitmapFactory.decodeFile(filePath, options); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 60, baos); byte[] b = baos.toByteArray();
前三行的程式碼其實已經得到了一個縮放的bitmap物件,如果你在應用中顯示圖片,就可以使用這個bitmap物件了。由於考慮到網路流量的問題。我們好需要犧牲圖片的質量來換取一部分空間,這裡呼叫bm.compress()方法進行壓縮,這個方法的第二個引數,如果是100,表示不壓縮,我這裡設定的是60,你也可以更加你的需要進行設定,在實驗的過程中我設定為30,圖片都不會失真。
壓縮效果:可以把1.5M左右的圖片壓縮到100K左右,並且沒有失真。
另外附加乾貨:
/* 壓縮圖片,處理某些手機拍照角度旋轉的問題 */ public static String compressImage(Context context,String filePath,String fileName,int q) throws FileNotFoundException { Bitmap bm = getSmallBitmap(filePath); int degree = readPictureDegree(filePath); if(degree!=0){//旋轉照片角度 bm=rotateBitmap(bm,degree); } File imageDir = SDCardUtils.getImageDir(context); File outputFile=new File(imageDir,fileName); FileOutputStream out = new FileOutputStream(outputFile); bm.compress(Bitmap.CompressFormat.JPEG, q, out); return outputFile.getPath(); }判斷照片角度
public static int readPictureDegree(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace(); } return degree; }旋轉照片
public static Bitmap rotateBitmap(Bitmap bitmap,int degress) { if (bitmap != null) { Matrix m = new Matrix(); m.postRotate(degress); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); return bitmap; } return bitmap; }
相關文章
- Android 載入大圖片,不壓縮圖片Android
- android下圖片壓縮Android
- Android壓縮圖片後再上傳圖片Android
- 在rails中使用sprockets-image_compressor無失真壓縮圖片AI
- JNI實現圖片壓縮
- 簡單實用的android 圖片的壓縮Android
- Android 中圖片壓縮分析(上)Android
- 前端的圖片壓縮image-compressor(可在圖片上傳前實現圖片壓縮)前端
- 前端圖片壓縮 - H5&Uni-App圖片壓縮前端H5APP
- 利用 canvas 實現圖片壓縮Canvas
- Android圖片壓縮實現過程及程式碼Android
- ??圖片壓縮CanvasCanvas
- IOS圖片壓縮iOS
- canvas 壓縮圖片Canvas
- 圖片壓縮怎樣操作?分享幾種實用的批次圖片壓縮技巧
- Nginx網路壓縮 CSS壓縮 圖片壓縮 JSON壓縮NginxCSSJSON
- 圖片壓縮不求人,3個親測實用高效的圖片壓縮神器
- 很實用的android壓縮圖片的演算法Android演算法
- 圖片壓縮知識梳理(0) 圖片壓縮學習計劃
- Android-圖片壓縮(二)-純乾貨Android
- android 比較靠譜的圖片壓縮Android
- 仿寫一個android圖片壓縮工具Android
- Android 圖片壓縮方法分析與學習Android
- iOS 圖片壓縮方法iOS
- 前端圖片壓縮方案前端
- java,springboot + thymeleaf 上傳圖片、刪除圖片到伺服器、本地,壓縮圖片上傳(有些圖片會失真),原圖上傳JavaSpring Boot伺服器
- layui中實現上傳圖片壓縮UI
- 圖片純前端JS壓縮的實現前端JS
- web前端實現圖片壓縮處理Web前端
- 純前端實現 JPG 圖片壓縮 | canvas前端Canvas
- Lepton 無失真壓縮原理及效能分析
- 淺談移動端圖片壓縮(iOS & Android)iOSAndroid
- Android如何壓縮圖片上傳服務端Android服務端
- 用Kotlin擼一個圖片壓縮外掛-實戰篇(三)Kotlin
- Android-壓縮大圖到容量超小的圖片Android
- Android 高清載入巨圖方案 拒絕壓縮圖片Android
- SmallImage for Mac(圖片壓縮工具)Mac
- js上傳圖片壓縮JS