標籤:
前言:目前一般手機的相機都能達到800萬像素,像我的Galaxy Nexus才500萬像素,拍攝的照片也有1.5M左右。這麼大的照片上傳到伺服器,不僅浪費流量,同時還浪費時間。
在開發Android公司專屬應用程式時,會經常上傳圖片到伺服器,而我們公司目前維護的一個項目便是如此。該項目是通過私人apn與伺服器進行互動的,聯通的還好,但移動的速度實在太慢,客戶在使用軟體的過程中,由於上傳的資訊中可能包含多張圖片,會經常出現上傳圖片失敗的問題,為瞭解決這個問題,我們決定把照片壓縮到100k以下,並且保證圖片不失真(目前圖片經過壓縮後,大約300k左右)。於是我就重新研究了一下Android的圖片壓縮技術。
Android端目錄結構如所示:
其中ksoap2-android-xxx.jar是Android用來調用webservice的,gson-xx.jar是把JavaBean轉成Json資料格式的。 本篇部落客要講解圖片壓縮的,核心代碼如下:
[java] view plaincopyprint?
- //計算圖片的縮放值
- public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {
- final int height = options.outHeight;
- final int width = options.outWidth;
- int inSampleSize = 1;
-
- 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;
- }
- return inSampleSize;
- }
//計算圖片的縮放值public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;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;} return inSampleSize;}
[java] view plaincopyprint?
- // 根據路徑獲得圖片並壓縮,返回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用於顯示public static Bitmap getSmallBitmap(String filePath) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(filePath, options);// Calculate inSampleSizeoptions.inSampleSize = calculateInSampleSize(options, 480, 800);// Decode bitmap with inSampleSize setoptions.inJustDecodeBounds = false;return BitmapFactory.decodeFile(filePath, options);}
[java] view plaincopyprint?
- //把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);
- }
//把bitmap轉換成Stringpublic 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);}
查看全部源碼,請訪問: https://github.com/feicien/StudyDemo/tree/master/FileUploadDemo
壓縮原理講解:壓縮一張圖片。我們需要知道這張圖片的原始大小,然後根據我們設定的壓縮比例進行壓縮。 這樣我們就需要做3件事: 1.擷取原始圖片的長和寬
[java] view plaincopyprint?
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(filePath, options);
- int height = options.outHeight;
- int width = options.outWidth;
BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(filePath, options); int height = options.outHeight; int width = options.outWidth;
以上代碼是對圖片進行解碼,inJustDecodeBounds設定為true,可以不把圖片讀到記憶體中,但依然可以計算出圖片的大小,這正好可以滿足我們第一步的需要。 2.計算壓縮比例
[java] view plaincopyprint?
- 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;
- }
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,這2個值只是期望的寬度與高度,實際上壓縮後的實際寬度也高度會比期望的要大。如果圖片的原始高度或者寬頻大約我們期望的寬頻和高度,我們需要計算出縮放比例的數值。否則就不縮放。heightRatio是圖片原始高度與壓縮後高度的倍數,widthRatio是圖片原始寬度與壓縮後寬度的倍數。inSampleSize為heightRatio與widthRatio中最小的那個,inSampleSize就是縮放值。 inSampleSize為1表示寬度和高度不縮放,為2表示壓縮後的寬度與高度為原來的1/2 3.縮放並壓縮圖片
[java] view plaincopyprint?
- //在記憶體中建立bitmap對象,這個對象按照縮放大小建立的
- 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對象,這個對象按照縮放大小建立的 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();
前3行的代碼其實已經得到了一個縮放的bitmap對象,如果你在應用中顯示圖片,就可以使用這個bitmap對象了。由於考慮到網路流量的問題。我們好需要犧牲圖片的品質來換取一部分空間,這裡調用bm.compress()方法進行壓縮,這個方法的第二個參數,如果是100,表示不壓縮,我這裡設定的是60,你也可以更加你的需要進行設定,在實驗的過程中我設定為30,圖片都不會失真。 壓縮效果:本demo可以把1.5M左右的圖片壓縮到100K左右,並且沒有失真。 如下:
轉自:http://my.eoe.cn/575776/archive/564.html
Android壓縮圖片到100K以下並保持不失真的高效方法