Довольно рутинная операция. Есть несколько способов.
Возьмём исходное изображение:
1. Самый простой.
Первый на stackoverflow.
Суть метода очень проста — создаем BufferedImage меньшего размера, затем прорисовываем в него исходное изображение.
Далее сохраняем обычным ImageIO.write()
BufferedImage scaled = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = scaled.createGraphics(); g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); g.dispose(); ImageIO.write(scaled, "JPEG", new File("1.jpg")); |
Результат:
Недостатки:
— Алгоритм сжатия хоть и быстрый, но результат неприятный.
— Реализация сохранения JPEG ImageIO по-умолчанию не радует.
2. Улучшаем качество JPEG-картинки.
Для этого делаем так:
/* код приведён только в учебных целях! не использовать в продакшн */ public static void saveAsJPEG(BufferedImage scaledImage, OutputStream out) throws IOException { ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(scaledImage); Iterator iter = ImageIO.getImageWriters(type, "JPEG"); // берем первый попавшийся для JPEG ImageWriter writer = (ImageWriter) iter.next(); ImageOutputStream ios = ImageIO.createImageOutputStream(out); writer.setOutput(ios); JPEGImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault()); iwparam.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT); // Вот здесь выкручиваем качество на максимум! iwparam.setCompressionQuality(1.0F); IIOImage iioimage = new IIOImage(scaledImage, null, null); writer.write(null, iioimage, iwparam); ios.flush(); writer.dispose(); ios.close(); } |
Результат:
Недостатки:
— Сильно вырастает размер файла. Это известный баг. Подробности здесь: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5028259.
— Алгоритм уменьшения картинки всё равно оставляет желать лучшего.
3. Используем хинты.
У Graphics2D есть так называемые RenderingHints, которые позволяют улучшить качество относительно настроек по умолчанию:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); |
Результат:
Недостатки:
Качество стало лучше, но не сильно.
4. Уменьшаем постепенно.
Суть алгоритма — сжимать не сразу, а в несколько итераций.
Код можно посмотреть здесь: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html (очень позновательная и интересная статья, подробно расписано про уменьшение размера картинок).
Результат:
5. Метод из JDK 1.1.
Впринципе также можно воспользоваться методом из JDK 1.1:
Image.getScaledInstance(width,height, Image.SCALE_SMOOTH)
Image scaled = originalImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH); g.drawImage(scaled, 0, 0, null); g.dispose(); |
Результат:
Недостатки:
Реализация метода может различаться на конкретных платформах.