Android-уменьшить размер файла изображения


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

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

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


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

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 метода или только один? Спасибо

2 52

2 ответа:

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

лучший образец, который я нашел на StackOverflow является этот.

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

 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 означает сжатие для максимального качества