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