2013-12-15 49 views
6

我正在開發一款安卓應用,該應用具有相機捕獲和照片上傳功能。如果設備具有高分辨率照相機,拍攝的圖像尺寸將非常大(1〜3MB或更多)。
由於應用程序需要將此圖像上傳到服務器,因此我需要在上傳前壓縮圖像。例如,如果相機捕獲1920x1080全分辨率照片,理想的輸出是保持圖像的16:9比例,將其壓縮爲640x360圖像,以降低某些圖像質量並使其以較小的字節數進行縮小。Android - 縮放並壓縮位圖

這是我的代碼(來自谷歌引用):

/** 
* this class provide methods that can help compress the image size. 
* 
*/ 
public class ImageCompressHelper { 

/** 
* Calcuate how much to compress the image 
* @param options 
* @param reqWidth 
* @param reqHeight 
* @return 
*/ 
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
// Raw height and width of image 
final int height = options.outHeight; 
final int width = options.outWidth; 
int inSampleSize = 1; 

if (height > reqHeight || width > reqWidth) { 

    final int halfHeight = height/2; 
    final int halfWidth = width/2; 

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both 
    // height and width larger than the requested height and width. 
    while ((halfHeight/inSampleSize) > reqHeight 
      && (halfWidth/inSampleSize) > reqWidth) { 
     inSampleSize *= 2; 
    } 
} 

return inSampleSize; 
} 

/** 
* resize image to 480x800 
* @param filePath 
* @return 
*/ 
public static Bitmap getSmallBitmap(String filePath) { 

    File file = new File(filePath); 
    long originalSize = file.length(); 

    MyLogger.Verbose("Original image size is: " + originalSize + " bytes."); 

    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filePath, options); 

    // Calculate inSampleSize based on a preset ratio 
    options.inSampleSize = calculateInSampleSize(options, 480, 800); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 

    Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options); 

    MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes"); 

    return compressedImage; 
} 

與上述代碼的問題是:

  1. 它不能保持率,代碼迫使圖像大小調整爲爲480x800。如果用戶以另一個比例捕捉圖像,壓縮後圖像看起來不太好。
  2. 它運行不正常。無論原始文件大小如何,代碼將始終將圖像大小更改爲7990272byte。如果原始圖像尺寸是非常小的已經,它將使大(我的測試結果把我的牆,這是非常單色的圖片):

    Original image size is: 990092 bytes.
    Compressed image size is 7990272 bytes

我在問是否有更好的方式來壓縮照片,以便它可以順利上傳的建議?

+2

的大小代替使用硬編碼的480×800大小 - 你應該計算出維持所需的縱橫比i動態輸出位圖的大小。e改變風景和人像。對於圖像大小 - 請記住,您正在比較原始*壓縮*文件大小與縮放*未壓縮*位圖大小。 – harism

回答

12
  1. 您需要決定寬度或高度的限制(不是兩個,顯然)。然後替換那些固定的圖像尺寸的計算的,說:

    int targetWidth = 640; // your arbitrary fixed limit 
    int targetHeight = (int) (originalHeight * targetWidth/(double) originalWidth); // casts to avoid truncating 
    

    (添加檢查和橫向/縱向姿態計算的替代品,如需要)。

  2. 由於@harism也評論:大尺寸您提到的是原始大小,即480x800位圖,而不是文件大小,在你的情況下應該是JPEG。你如何保存該位圖,BTW?您的代碼似乎不包含保存部分。

    用於對幫助,請參見this question here,關鍵是這樣的:

    OutputStream imagefile = new FileOutputStream("/your/file/name.jpg"); 
    // Write 'bitmap' to file using JPEG and 80% quality hint for JPEG: 
    bitmap.compress(CompressFormat.JPEG, 80, imagefile); 
    
2

首先我檢查圖像的大小,然後我根據大小壓縮圖像,並得到壓縮的位圖,然後發送一個位圖服務器 對於低於funtion壓縮位電話我們必須通過以下funtion圖像路徑

public Bitmap get_Picture_bitmap(String imagePath) { 

    long size_file = getFileSize(new File(imagePath)); 

    size_file = (size_file)/1000;// in Kb now 
    int ample_size = 1; 

    if (size_file <= 250) { 

     System.out.println("SSSSS1111= " + size_file); 
     ample_size = 2; 

    } else if (size_file > 251 && size_file < 1500) { 

     System.out.println("SSSSS2222= " + size_file); 
     ample_size = 4; 

    } else if (size_file >= 1500 && size_file < 3000) { 

     System.out.println("SSSSS3333= " + size_file); 
     ample_size = 8; 

    } else if (size_file >= 3000 && size_file <= 4500) { 

     System.out.println("SSSSS4444= " + size_file); 
     ample_size = 12; 

    } else if (size_file >= 4500) { 

     System.out.println("SSSSS4444= " + size_file); 
     ample_size = 16; 
    } 

    Bitmap bitmap = null; 

    BitmapFactory.Options bitoption = new BitmapFactory.Options(); 
    bitoption.inSampleSize = ample_size; 

    Bitmap bitmapPhoto = BitmapFactory.decodeFile(imagePath, bitoption); 

    ExifInterface exif = null; 
    try { 
     exif = new ExifInterface(imagePath); 
    } catch (IOException e) { 
     // Auto-generated catch block 
     e.printStackTrace(); 
    } 
    int orientation = exif 
      .getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); 
    Matrix matrix = new Matrix(); 

    if ((orientation == 3)) { 
     matrix.postRotate(180); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else if (orientation == 6) { 
     matrix.postRotate(90); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else if (orientation == 8) { 
     matrix.postRotate(270); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } else { 
     matrix.postRotate(0); 
     bitmap = Bitmap.createBitmap(bitmapPhoto, 0, 0, 
       bitmapPhoto.getWidth(), bitmapPhoto.getHeight(), matrix, 
       true); 

    } 

    return bitmap; 

} 

getFileSize funtion用於獲取圖像

public long getFileSize(final File file) { 
    if (file == null || !file.exists()) 
     return 0; 
    if (!file.isDirectory()) 
     return file.length(); 
    final List<File> dirs = new LinkedList<File>(); 
    dirs.add(file); 
    long result = 0; 
    while (!dirs.isEmpty()) { 
     final File dir = dirs.remove(0); 
     if (!dir.exists()) 
      continue; 
     final File[] listFiles = dir.listFiles(); 
     if (listFiles == null || listFiles.length == 0) 
      continue; 
     for (final File child : listFiles) { 
      result += child.length(); 
      if (child.isDirectory()) 
       dirs.add(child); 
     } 
    } 

    return result; 
}