2012-06-16 2 views
49

У меня есть файл изображения URI, и я хочу уменьшить его размер, чтобы его загрузить. Размер исходного файла изображения зависит от мобильного телефона (может быть 2 МБ, а может быть 500 КБ), но я хочу, чтобы конечный размер составлял около 200 КБ, поэтому я могу его загрузить.
Из того, что я читал, у меня есть (по крайней мере) 2 выбора:Android - Уменьшить размер файла изображения

  • Использование BitmapFactory.Options.inSampleSize, чтобы субсемплировать исходное изображение и получить изображение меньшего размера;
  • Использование Bitmap.compress для сжатия изображения, определяющего качество сжатия.

Какой лучший выбор?


Я думал сначала изменить размер изображения ширина/высота до ширина или высота не превышает 1000px (что-то вроде 1024x768 или других), а затем сжать изображение с уменьшением качества, пока размер файла не превышает 200 КБ. Вот пример:

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"); 
} 

Есть ли лучший способ сделать это? Должен ли я попытаться использовать все 2 метода или только один? Спасибо

+0

ли исходное изображение png или jpg? –

+0

Исходное изображение JPG – KitKat

ответ

27

С помощью Bitmap.compress() вы просто определяете алгоритм сжатия и, кстати, операция сжатия занимает довольно большое количество времени. Если вам нужно играть с размерами для уменьшения выделения памяти для своего изображения, вам нужно использовать масштабирование вашего изображения, используя Bitmap.Options, сначала вычисляя границы растровых изображений, а затем декодируя его до указанного размера.

Лучший образец, который я нашел на StackOverflow, - this one.

+1

Моя первая идея состояла в том, чтобы итератировать масштабирование изображения (используя 'inSampleSize'), пока файл изображения не станет меньше, чем' MAX_IMAGE_SIZE', но поскольку мне нужно сохранить растровое изображение в файл, я должен использовать «Bitmap». compress() '(или, может быть, есть разные способы сохранить его в файле?), и, называя его 100% -ным качеством, изображение становится больше, чем' MAX_IMAGE_SIZE', поэтому я все равно должен итерации 'Bitmap.compress()' (уменьшение качество) до размера файла <'MAX_IMAGE_SIZE'. Может быть, есть ли лучшие решения? – KitKat

0

Большинство ответов я нашел были только куски, которые я должен был положить вместе, чтобы получить рабочий код, который размещен ниже

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 параметров SampleSize и качество играет важную роль

SampleSize используется для подвыборки оригинал изображения и возвращает меньшее изображение, т.е.
SampleSize == 4 возвращает изображение, которое составляет 1/4 ширины/высоты оригинала.

Качество используется для обозначения компрессора, диапазон ввода составляет от 0 до 100. 0 означает компресс для маленький размер, 100 означает компресс для максимального качества

+0

Очевидно, что это НЕ выполнено.Переменная «фото» даже не объявлена ​​локально. Кроме того, он использует рекурсию, а не хорошую идею. – Shroud

+0

@Shroud, пожалуйста, не стесняйтесь редактировать и добавлять недостающие вещи, –

+0

@war_Hero: Рекурсия не хорошая идея .. – Pawan

Смежные вопросы