Pull to refresh

Сохранение изображения из java InputStream без потери качества, стандартными средствами

Если Вы имели опыт с загрузкой изображений через ImageIO, то знаете что сохранив изображение через стандартный метод ImageIO.write() можно получить шумную, мутную фотографию, качество которой будет достойно только маленькой превьюшки. Но что делать если другие средства недоступны? Как с помощью java сохранить изображение «как есть»?

Предполагается, что Вы уже разобрались с загрузкой изображений из формы или из иного источника. У нас есть InputStream и… всё.

Нам нужно получить из InputStream изображение для последующей работы. А использовать мы будем ImageIO. Да, тот самый который коверкает качество. Но делает он это при сохранении. Иначе говоря с помощью такой конструкции:

BufferedImage im = ImageIO.read(in);

Мы получим полноценное загруженное изображение в переменной im. К слову, рекомендую узнать больше о BufferedImage в документации

Так почему же ImageIO не может сохранить изображение как есть? Дело в том, что у него нет характеристики «качество». Он сохраняет изображение с одним качеством и очень плохим. Но выход есть!

В данном коде мы выбираем записыватель для нашего изображения:

Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
ImageWriter writer = (ImageWriter) iter.next();


В примере я ищу обработчик для jpg. А можно было бы и gif. Вот только если Вы попробуете найти обработчик для gif изображения, вылезет исключение NoSuchElementExeption. Оно сигнализирует нам о том, что в java не входит обработчик для gif. Странно, но ничего не поделаешь.

В коде ниже мы получаем возможность изменить параметры сохранения:

ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1);


Соответственно setCompressionMode позволяет нам изменить режим компрессии.
  • MODE_EXPLICIT — отменяет все настройки компрессии и делает главными настройки нашего «ImageWriteParam».
  • MODE_DISABLED — этот флаг отменяет компрессию вообще. Но в сочетании с jpg выдаст «UnsupportedOperationException», причем режим компрессии не будет изменён.
  • Есть так же менее значимые MODE_COPY_FROM_METADATA, MODE_DEFAULT. Причём первый используется по умолчанию. Этот флаг берёт параметры из METADATA прошедших через наш writer.


setCompressionQuality — качество сохраняемого изображения. Значение может быть от 0 до 1. Соответственно 0 — приоритет размера над качеством, а 1 — наоборот. Мы можем использовать float значения. Например 0.95F.

Теперь создадим исходящий поток и запишем в переменную image наше изображение:

FileImageOutputStream output = new FileImageOutputStream(new File("/exampleFolder/image.jpg"));
IIOImage image = new IIOImage(im, null, null);


Теперь наконец таки применяем наш writer. Думаю несложно догадаться что происходит дальше:

writer.setOutput(output);
writer.write(null, image, iwp);


И освобождаем writer:
writer.dispose();


Вот и всё! Надеюсь это будет полезно кому-то так, как это было бы полезно мне в своё время.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.