2012-06-16 30 views
49

Tôi có tệp hình ảnh URI và tôi muốn giảm kích thước tệp của nó để tải lên. Kích thước tệp hình ảnh ban đầu phụ thuộc từ thiết bị di động đến thiết bị di động (có thể là 2MB có thể là 500KB), nhưng tôi muốn kích thước cuối cùng khoảng 200KB, để tôi có thể tải lên.
Từ những gì tôi đọc, tôi có (ít nhất) 2 lựa chọn:Android - Giảm kích thước tệp hình ảnh

  • Sử dụng BitmapFactory.Options.inSampleSize, để subsample ảnh gốc và có được một hình ảnh nhỏ hơn;
  • Sử dụng Bitmap.compress để nén hình ảnh chỉ định chất lượng nén.

Lựa chọn tốt nhất là gì?


Tôi đã suy nghĩ ban đầu thay đổi kích thước hình ảnh chiều rộng/chiều cao cho đến khi chiều rộng hoặc chiều cao là trên 1000px (cái gì đó như 1024x768 hoặc những người khác), sau đó nén hình ảnh với chất lượng giảm cho đến khi kích thước tập tin là trên 200KB. Dưới đây là ví dụ:

int MAX_IMAGE_SIZE = 200 * 1024; // max final file size 
Bitmap bmpPic = BitmapFactory.decodeFile(fileUri.getPath()); 
if ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) { 
    BitmapFactory.Options bmpOptions = new BitmapFactory.Options(); 
    bmpOptions.inSampleSize = 1; 
    while ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) { 
     bmpOptions.inSampleSize++; 
     bmpPic = BitmapFactory.decodeFile(fileUri.getPath(), bmpOptions); 
    } 
    Log.d(TAG, "Resize: " + bmpOptions.inSampleSize); 
} 
int compressQuality = 104; // quality decreasing by 5 every loop. (start from 99) 
int streamLength = MAX_IMAGE_SIZE; 
while (streamLength >= MAX_IMAGE_SIZE) { 
    ByteArrayOutputStream bmpStream = new ByteArrayOutputStream(); 
    compressQuality -= 5; 
    Log.d(TAG, "Quality: " + compressQuality); 
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream); 
    byte[] bmpPicByteArray = bmpStream.toByteArray(); 
    streamLength = bmpPicByteArray.length; 
    Log.d(TAG, "Size: " + streamLength); 
} 
try { 
    FileOutputStream bmpFile = new FileOutputStream(finalPath); 
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpFile); 
    bmpFile.flush(); 
    bmpFile.close(); 
} catch (Exception e) { 
    Log.e(TAG, "Error on saving file"); 
} 

Có cách nào tốt hơn để làm điều đó không? Tôi có nên cố gắng tiếp tục sử dụng tất cả 2 phương pháp hay chỉ một phương pháp? Cảm ơn

+0

liệu hình ảnh nguồn png hoặc jpg? –

+0

Hình ảnh nguồn là JPG – KitKat

Trả lời

27

Sử dụng Bitmap.compress() bạn chỉ cần chỉ định thuật toán nén và theo cách hoạt động nén mất lượng thời gian khá lớn. Nếu bạn cần phát các kích thước để giảm phân bổ bộ nhớ cho hình ảnh của mình, bạn cần sử dụng chính xác tỷ lệ hình ảnh của mình bằng cách sử dụng Bitmap.Options, tính toán giới hạn bitmap lúc đầu và sau đó giải mã nó theo kích thước đã chỉ định của bạn.

Mẫu tốt nhất mà tôi tìm thấy trên StackOverflow là this one.

+1

Ý tưởng đầu tiên của tôi là lặp lại việc chia tỷ lệ hình ảnh (sử dụng 'inSampleSize') cho đến khi tệp hình ảnh nhỏ hơn' MAX_IMAGE_SIZE' nhưng, vì tôi phải lưu bitmap vào một tệp, tôi phải sử dụng 'Bitmap. compress() '(hoặc có thể có những cách khác nhau để lưu nó trên một tập tin?), và gọi nó cho chất lượng 100%, hình ảnh lớn hơn' MAX_IMAGE_SIZE', vì vậy tôi nên lặp lại 'Bitmap.compress()' (giảm chất lượng) cho đến khi kích thước tệp <'MAX_IMAGE_SIZE'. Có lẽ có giải pháp tốt hơn? – KitKat

0

Hầu hết các câu trả lời tôi nhận thấy chỉ là phần mà tôi đã phải đặt lại với nhau để có được một mã làm việc, được đăng tải dưới đây

public void compressBitmap(File file, int sampleSize, int quality) { 
     try { 
      BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inSampleSize = sampleSize; 
      FileInputStream inputStream = new FileInputStream(file); 

      Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, options); 
      inputStream.close(); 

      FileOutputStream outputStream = new FileOutputStream("location to save"); 
      selectedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream); 
      outputStream.close(); 
      long lengthInKb = photo.length()/1024; //in kb 
      if (lengthInKb > SIZE_LIMIT) { 
       compressBitmap(file, (sampleSize*2), (quality/4)); 
      } 

      selectedBitmap.recycle(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

2 thông số sampleSize và chất lượng đóng một vai trò quan trọng

sampleSize được sử dụng để subsample hình ảnh gốc và trả lại hình ảnh nhỏ hơn, tức là
SampleSize == 4 trả về một hình ảnh có chiều rộng/chiều cao là 1/4.

chất lượng được sử dụng để gợi ý máy nén, phạm vi đầu vào nằm trong khoảng từ 0-100. 0 có nghĩa là nén cho kích thước nhỏ, 100 nghĩa là nén cho chất lượng tối đa

+0

Rõ ràng đây không phải là hoàn thành.Biến "ảnh" thậm chí không được khai báo cục bộ. Ngoài ra, nó sử dụng đệ quy, KHÔNG phải là một ý tưởng hay. – Shroud

+0

@Shroud xin vui lòng chỉnh sửa và thêm những điều còn thiếu, –

+0

@war_Hero: đệ quy không phải là một ý tưởng tốt .. – Pawan