Каков наилучший способ масштабирования изображений в Java? - PullRequest
12 голосов
/ 03 мая 2009

У меня есть веб-приложение, написанное на Java (Spring, Hibernate / JPA, Struts2), где пользователи могут загружать изображения и сохранять их в файловой системе. Я хотел бы масштабировать эти изображения так, чтобы они имели одинаковый размер для отображения на сайте. Какие библиотеки или встроенные функции будут предлагать наилучшие результаты? При принятии решения я буду учитывать следующие критерии:

  • Бесплатно / с открытым исходным кодом (обязательно)
  • Простота реализации
  • Качество результатов
  • Performance
  • Размер исполняемого файла

Ответы [ 7 ]

9 голосов
/ 05 июля 2011

Я бы действительно рекомендовал посмотреть imgscalr .

Он выпущен по лицензии Apache 2, размещен на GitHub , уже развернут в нескольких веб-приложениях, имеет очень простой, но документированный API , имеет код которая работает с 2 основными ошибками изображения в JDK для вас прозрачно, что вы когда-либо заметите, только если вдруг начнете получать «черные» изображения после операции масштабирования или ужасно выглядящих результатов, дадут вам наилучшие возможные результаты, доступные в Java, доступен через Maven, а также через ZIP и представляет собой один класс.

Основное использование выглядит так:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 320);

Это самый простой вызов, при котором библиотека делает точные предположения о качестве, учитывает пропорции вашего изображения и помещает результат в ограничивающий прямоугольник 320x320. ПРИМЕЧАНИЕ: ограничивающий прямоугольник - это только максимальное используемое значение W / H, поскольку пропорции вашего изображения соблюдаются, результирующее изображение все равно будет учитывать это, например, 320x200.

Если вы хотите переопределить автоматический режим и заставить его получить лучший результат и даже применить к нему очень мягкий фильтр сглаживания, чтобы он выглядел еще лучше (особенно хорошо для миниатюр), этот вызов будет выглядеть:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

Это всего лишь примеры, API является широким и охватывает все: от очень простых вариантов использования до очень специализированных. Вы даже можете передать свои собственные BufferedImageOps, которые будут применены к изображению (и библиотека автоматически исправит 6-летнюю ошибку BufferedImageOp JDK для вас!)

Существует гораздо больше возможностей для успешного масштабирования изображений в Java, чем делает библиотека, например, всегда сохраняя изображение в одном из наилучших поддерживаемых типов изображений RGB или ARGB при работе с ним. Под прикрытием конвейер обработки изображений Java2D возвращается к подчиненному программному конвейеру, если тип изображения, используемый для любых операций с изображениями, плохо поддерживается.

Если все это звучало как сильная головная боль, это вроде бы ... вот почему я написал библиотеку и открыл ее из открытых источников, чтобы люди могли просто изменять размеры своих изображений и продолжать жить, не беспокоясь об этом .

Надеюсь, это поможет.

4 голосов
/ 08 мая 2010

Смотрите также в библиотеку java-image-scaling . Он создал изображения лучшего качества, чем ImageIO.

4 голосов
/ 03 мая 2009

Посмотрите на API ввода / вывода Java Image для чтения / записи изображения. Затем используйте AffineTransform для изменения размера.

Также, вот полный пример использования java.awt.Image.

1 голос
/ 29 июля 2017

Я знаю, что это очень старый вопрос, но у меня есть собственное решение для этого с использованием стандартного Java API

import java.awt.*;
import java.awt.event.*;
import javax.imageio.*
import java.awt.image.*;

BufferedImage im, bi, bi2;
Graphics2D gfx;
int imWidth, imHeight, dstWidth, dstHeight;
int DESIRED_WIDTH = 500, DESIRED_HEIGHT = 500;

im = ImageIO.read(new File(filePath));
imWidth = im.getWidth(null);
imHeight = im.getHeight(null);

dstWidth = DESIRED_WIDTH;
dstHeight = (dstWidth * imHeight) / imWidth;

bi = new BufferedImage(dstWidth, dstHeight, im.getType());

gfx = bi.createGraphics();
gfx.drawImage(im, 0, 0, dstWidth, dstHeight, 0, 0, imWidth, imHeight, null);

bi2 = new BufferedImage(DESIRED_WIDTH, DESIRED_HEIGHT, im.getType());
gfx = bi2.createGraphics();

gfx.drawImage(bi, 0, 0, DESIRED_WIDTH, DESIRED_HEIGHT, null);

ImageIO.write(bi2, "jpg", new File(filePath));

Я уверен, что его можно улучшить и адаптировать.

0 голосов
/ 17 июля 2015

Обнаружено, что это быстрее:

public static BufferedImage getScaledInstance(final BufferedImage img, final int targetWidth, final int targetHeight,
                                              final Object hint) {
    final int type = BufferedImage.TYPE_INT_RGB;
    int drawHeight = targetHeight;
    int drawWidth = targetWidth;
    final int imageWidth = img.getWidth();
    final int imageHeight = img.getHeight();
    if ((imageWidth <= targetWidth) && (imageHeight <= targetHeight)) {
        logger.info("Image " + imageWidth + "/" + imageHeight + " within desired scale");
        return img;
    }
    final double sar = ((double) imageWidth) / ((double) imageHeight);
    if (sar != 0) {
        final double tar = ((double) targetWidth) / ((double) targetHeight);
        if ((Math.abs(tar - sar) > .001) && (tar != 0)) {
            final boolean isSoureWider = sar > (targetWidth / targetHeight);
            if (isSoureWider) {
                drawHeight = (int) (targetWidth / sar);
            }
            else {
                drawWidth = (int) (targetHeight * sar);
            }
        }
    }
    logger.info("Scaling image from " + imageWidth + "/" + imageHeight + " to " + drawWidth + "/" + drawHeight);
    final BufferedImage result = new BufferedImage(drawWidth, drawHeight, type);
    try {
        final Graphics2D g2 = result.createGraphics();
        try {
            if (hint != null) {
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            }
            g2.drawImage(img, 0, 0, drawWidth, drawHeight, null);
        }
        finally {
            g2.dispose();
        }
        return result;
    }
    finally {
        result.flush();
    }
}
0 голосов
/ 02 апреля 2013

Я попробовал imgscalr по сравнению со стандартной Java 1.6, и я не могу сказать, что она лучше.

Я попробовал

BufferedImage bufferedScaled = Scalr.resize(sourceImage, Method.QUALITY, 8000, height);

и

  Image scaled = sourceImage.getScaledInstance(-1, height, Image.SCALE_SMOOTH);
  BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null),  scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
  bufferedScaled.getGraphics().drawImage(scaled, 0, 0, null);

На 5-минутное тестирование мне показалось, что вторая вещь (чистая Java 1.6) дает лучшие результаты.

0 голосов
/ 11 апреля 2011

Лучший инструмент для редактирования изображений - ImageMagick , и это с открытым исходным кодом.

Существует два интерфейса для языка Java:

JMagick , который использует интерфейс JNI для ImageMagick

и

im4java что такое интерфейс командной строки для ImageMagick

...