兩種方法都實裝在了我的項目中,結果卻發現在質量壓縮的模塊中,本來1.9M的圖片壓縮後反而變成3M多了,很是奇怪,再做了進一步調查終於知道原因了。下面這個博客說的比較清晰:
android圖片壓縮總結
總結來看,圖片有三種存在形式:硬盤上時是file,網絡傳輸時是stream,內存中是stream或bitmap,所謂的質量壓縮,它其實只能實現對file的影響,你可以把一個file轉成bitmap再轉成file,或者直接將一個bitmap轉成file時,這個最終的file是被壓縮過的,但是中間的bitmap並沒有被壓縮(或者說幾乎沒有被壓縮,我不確定),因爲bigmap在內存中的大小是按像素計算的,也就是width * height,對於質量壓縮,並不會改變圖片的像素,所以就算質量被壓縮了,但是bitmap在內存的佔有率還是沒變小,但你做成file時,它確實變小了;
而尺寸壓縮由於是減小了圖片的像素,所以它直接對bitmap產生了影響,當然最終的file也是相對的變小了;
最後把自己總結的工具類貼出來:
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.Config;
- import android.graphics.BitmapFactory;
- /**
- * Image compress factory class
- *
- * @author
- *
- */
- public class ImageFactory {
- /**
- * Get bitmap from specified image path
- *
- * @param imgPath
- * @return
- */
- public Bitmap getBitmap(String imgPath) {
- // Get bitmap through image path
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
- newOpts.inJustDecodeBounds = false;
- newOpts.inPurgeable = true;
- newOpts.inInputShareable = true;
- // Do not compress
- newOpts.inSampleSize = 1;
- newOpts.inPreferredConfig = Config.RGB_565;
- return BitmapFactory.decodeFile(imgPath, newOpts);
- }
- /**
- * Store bitmap into specified image path
- *
- * @param bitmap
- * @param outPath
- * @throws FileNotFoundException
- */
- public void storeImage(Bitmap bitmap, String outPath) throws FileNotFoundException {
- FileOutputStream os = new FileOutputStream(outPath);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
- }
- /**
- * Compress image by pixel, this will modify image width/height.
- * Used to get thumbnail
- *
- * @param imgPath image path
- * @param pixelW target pixel of width
- * @param pixelH target pixel of height
- * @return
- */
- public Bitmap ratio(String imgPath, float pixelW, float pixelH) {
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
- // 開始讀入圖片,此時把options.inJustDecodeBounds 設回true,即只讀邊不讀內容
- newOpts.inJustDecodeBounds = true;
- newOpts.inPreferredConfig = Config.RGB_565;
- // Get bitmap info, but notice that bitmap is null now
- Bitmap bitmap = BitmapFactory.decodeFile(imgPath,newOpts);
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
- // 想要縮放的目標尺寸
- float hh = pixelH;// 設置高度爲240f時,可以明顯看到圖片縮小了
- float ww = pixelW;// 設置寬度爲120f,可以明顯看到圖片縮小了
- // 縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
- int be = 1;//be=1表示不縮放
- if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0) be = 1;
- newOpts.inSampleSize = be;//設置縮放比例
- // 開始壓縮圖片,注意此時已經把options.inJustDecodeBounds 設回false了
- bitmap = BitmapFactory.decodeFile(imgPath, newOpts);
- // 壓縮好比例大小後再進行質量壓縮
- // return compress(bitmap, maxSize); // 這裏再進行質量壓縮的意義不大,反而耗資源,刪除
- return bitmap;
- }
- /**
- * Compress image by size, this will modify image width/height.
- * Used to get thumbnail
- *
- * @param image
- * @param pixelW target pixel of width
- * @param pixelH target pixel of height
- * @return
- */
- public Bitmap ratio(Bitmap image, float pixelW, float pixelH) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- image.compress(Bitmap.CompressFormat.JPEG, 100, os);
- if( os.toByteArray().length / 1024>1024) {//判斷如果圖片大於1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出
- os.reset();//重置baos即清空baos
- image.compress(Bitmap.CompressFormat.JPEG, 50, os);//這裏壓縮50%,把壓縮後的數據存放到baos中
- }
- ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
- //開始讀入圖片,此時把options.inJustDecodeBounds 設回true了
- newOpts.inJustDecodeBounds = true;
- newOpts.inPreferredConfig = Config.RGB_565;
- Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts);
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
- float hh = pixelH;// 設置高度爲240f時,可以明顯看到圖片縮小了
- float ww = pixelW;// 設置寬度爲120f,可以明顯看到圖片縮小了
- //縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
- int be = 1;//be=1表示不縮放
- if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0) be = 1;
- newOpts.inSampleSize = be;//設置縮放比例
- //重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了
- is = new ByteArrayInputStream(os.toByteArray());
- bitmap = BitmapFactory.decodeStream(is, null, newOpts);
- //壓縮好比例大小後再進行質量壓縮
- // return compress(bitmap, maxSize); // 這裏再進行質量壓縮的意義不大,反而耗資源,刪除
- return bitmap;
- }
- /**
- * Compress by quality, and generate image to the path specified
- *
- * @param image
- * @param outPath
- * @param maxSize target will be compressed to be smaller than this size.(kb)
- * @throws IOException
- */
- public void compressAndGenImage(Bitmap image, String outPath, int maxSize) throws IOException {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- // scale
- int options = 100;
- // Store the bitmap into output stream(no compress)
- image.compress(Bitmap.CompressFormat.JPEG, options, os);
- // Compress by loop
- while ( os.toByteArray().length / 1024 > maxSize) {
- // Clean up os
- os.reset();
- // interval 10
- options -= 10;
- image.compress(Bitmap.CompressFormat.JPEG, options, os);
- }
- // Generate compressed image file
- FileOutputStream fos = new FileOutputStream(outPath);
- fos.write(os.toByteArray());
- fos.flush();
- fos.close();
- }
- /**
- * Compress by quality, and generate image to the path specified
- *
- * @param imgPath
- * @param outPath
- * @param maxSize target will be compressed to be smaller than this size.(kb)
- * @param needsDelete Whether delete original file after compress
- * @throws IOException
- */
- public void compressAndGenImage(String imgPath, String outPath, int maxSize, boolean needsDelete) throws IOException {
- compressAndGenImage(getBitmap(imgPath), outPath, maxSize);
- // Delete original file
- if (needsDelete) {
- File file = new File (imgPath);
- if (file.exists()) {
- file.delete();
- }
- }
- }
- /**
- * Ratio and generate thumb to the path specified
- *
- * @param image
- * @param outPath
- * @param pixelW target pixel of width
- * @param pixelH target pixel of height
- * @throws FileNotFoundException
- */
- public void ratioAndGenThumb(Bitmap image, String outPath, float pixelW, float pixelH) throws FileNotFoundException {
- Bitmap bitmap = ratio(image, pixelW, pixelH);
- storeImage( bitmap, outPath);
- }
- /**
- * Ratio and generate thumb to the path specified
- *
- * @param image
- * @param outPath
- * @param pixelW target pixel of width
- * @param pixelH target pixel of height
- * @param needsDelete Whether delete original file after compress
- * @throws FileNotFoundException
- */
- public void ratioAndGenThumb(String imgPath, String outPath, float pixelW, float pixelH, boolean needsDelete) throws FileNotFoundException {
- Bitmap bitmap = ratio(imgPath, pixelW, pixelH);
- storeImage( bitmap, outPath);
- // Delete original file
- if (needsDelete) {
- File file = new File (imgPath);
- if (file.exists()) {
- file.delete();
- }
- }
- }
- }
一.圖片的存在形式
2.流的形式(即以二進制形式存在於內存中)
3.Bitmap形式
二.常見的壓縮方式
- public static void compressBmpToFile(Bitmap bmp,File file){
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int options = 80;//個人喜歡從80開始,
- bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
- while (baos.toByteArray().length / 1024 > 100) {
- baos.reset();
- options -= 10;
- bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
- }
- try {
- FileOutputStream fos = new FileOutputStream(file);
- fos.write(baos.toByteArray());
- fos.flush();
- fos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private Bitmap compressBmpFromBmp(Bitmap image) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int options = 100;
- image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
- while (baos.toByteArray().length / 1024 > 100) {
- baos.reset();
- options -= 10;
- image.compress(Bitmap.CompressFormat.JPEG, options, baos);
- }
- ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
- Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
- return bitmap;
- }
- private Bitmap compressImageFromFile(String srcPath) {
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
- newOpts.inJustDecodeBounds = true;//只讀邊,不讀內容
- Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
- float hh = 800f;//
- float ww = 480f;//
- int be = 1;
- if (w > h && w > ww) {
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0)
- be = 1;
- newOpts.inSampleSize = be;//設置採樣率
- newOpts.inPreferredConfig = Config.ARGB_8888;//該模式是默認的,可不設
- newOpts.inPurgeable = true;// 同時設置纔會有效
- newOpts.inInputShareable = true;//。當系統內存不夠時候圖片自動被回收
- bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
- // return compressBmpFromBmp(bitmap);//原來的方法調用了這個方法企圖進行二次壓縮
- //其實是無效的,大家儘管嘗試
- return bitmap;
- }