Рубрики
Java

Уменьшение изображения на Java

Довольно рутинная операция. Есть несколько способов.
Возьмём исходное изображение:

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();

Результат:

Недостатки:
Реализация метода может различаться на конкретных платформах.

Рубрики
4. Полезняшки

Простые хаки и Greasemonkey


Недавно обратил внимание на то, что шрифты на сайте java.net какие-то неприятные – мутные и плохо читаются. Может они всегда были такими, а я стал чуть-более придирчивым, а может быть стали такими после мега_перезагрузки_сайта.
На самом деле не столь важно почему, важно понять как подправить...

Могу предложить два способа из разряда "быстрых хаков".

Способ 1. Простой и скучный (и только для только для пользователей Firefox-а).
Нужно в файле: C:\Documents and Settings\\Application Data\Mozilla\Firefox\Profiles\\chrome\userContent.css
добавить настройку для конкретного домена:

@-moz-document domain(java.net) {
  body {
    font-family: Arial,Helvetica,sans-serif !important; 
  }
}

Способ 2. Простые хитрости Greasemonkey.

Greasemonkey (замасленная обезьяна, "механик") - удобная тулза для различного рода кастомизации, переделавание и допиливания страничек. Один из моих любимых инструментов для подобного рода экспериментов.
Если кратко, используя Greasemonkey вы сможете запускать свои скрипты на JavaScript-е у себя в браузере для определенных сайтов.

Приведу несколько очень полезных ссылок:

Кстати Greasemonkey сейчас работает в Google Chrome "из коробки". Для установки вы просто драг-анд-дропаете в окно браузера ваш файлик (что-то типа sitefix.user.js) и он будет воспринят как обычное расширение.
Для Firefox, как и раньше нужно поставить плагин https://addons.mozilla.org/ru/firefox/addon/greasemonkey/.

Примерный скрипт для подмены шрифтов выглядит следующим образом:

// ==UserScript==
// @name           FontFix
// @namespace      programmisty
// @include        http://*.java.net/*
// ==/UserScript==
var head = document.getElementsByTagName("head")[0];
var style = document.createElement("style");
style.setAttribute("type", 'text/css');
style.innerHTML = " body { font-family: arial,helvetica,sans-serif} ";
head.appendChild(style);

Рубрики
4. Полезняшки Java

Удобный небезопасный кастинг

Удобный автоматический кастинг

Вещь не новая, но для тех, кто начинал программировать на Java в 90-ые и не очень привык к Generics-ам, это может быть интересно.

Пример использования. Вам нужен метод, который возвращает объекты разных классов. Это могут быть обычные объекты – String, Integer, List, а могут быть и какие-то "свои" сложные бизнес-объекты вроде – ABController, XYZComponent, QWERTYHelper, FooManager (название зависит от возраста и предпочтений программиста).

Так писали некоторые до Java 5.

    Helper helper = ....; // Какой-то вспомогательный класс, который хранит всякую ерунду
 
    String  path = (String) helper.get("storage.path");  // да, я знаю, хардкодить константы плохо. 
    Integer maxSize  = (Integer) helper.get("max.size"); 
    MyAwesomeDocumentManager manager = (MyAwesomeDocumentManager) helper.get("manager");

Сейчас можно писать попроще. Конечно это сахар, но код выглядит полегче: