Как изменить размер изображения с помощью Java?


126

Мне нужно изменить размер файлов PNG, JPEG и GIF. Как я могу это сделать с помощью Java?


14
поскольку вы просили библиотеку, настоящий ответ здесь: stackoverflow.com/questions/244164/… . Это намного проще в использовании, чем код в принятом ответе;)
Artur Gajowy 03

Я не согласен с библиотечной частью: Graphics2D является частью библиотеки awt и имеет открытый исходный код. Что касается последней части (с открытым исходным кодом), я не уверен на 100%, но кто вообще будет смотреть на код awt?
Burkhard

Ответы:


87

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

BufferedImage createResizedCopy(Image originalImage, 
            int scaledWidth, int scaledHeight, 
            boolean preserveAlpha)
    {
        System.out.println("resizing...");
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha) {
            g.setComposite(AlphaComposite.Src);
        }
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null); 
        g.dispose();
        return scaledBI;
    }

9
Я обнаружил, что этот метод создает изображение, качество которого недостаточно для моих нужд.
morgancodes

1
будет ли Image.getScaledInstance (ширина, высота, подсказки) также делать?
codeplay

1
проверяет preserveAlpha неправильно (для imageType)?
Тило

Я согласен с @morgancodes. Качество изображения намного хуже, чем то, что вы получаете, например, в OS X Preview при изменении размера до тех же размеров. Попробую некоторые библиотеки с открытым исходным кодом, чтобы увидеть, насколько они лучше.
Тило

1
«Попробую некоторые библиотеки с открытым исходным кодом, чтобы увидеть, будут ли они лучше». +1 за imgscalr из ответа @RiyadKalla.
Тило

182

FWIW Я только что выпустил (Apache 2, размещенный на GitHub) простую библиотеку масштабирования изображений для Java под названием imgscalr (доступная в Maven central ).

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

Использование предельно простое, просто набор статических методов. Самый простой вариант использования:

BufferedImage scaledImage = Scalr.resize(myImage, 200);

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

Я понимаю, что вначале это похоже на саморекламу (так оно и есть), но я потратил немало времени на поиски в Google точно такой же темы и продолжал придумывать разные результаты / подходы / мысли / предложения и решил сесть и написать простая реализация, которая решила бы те 80-85% случаев использования, когда у вас есть изображение и, вероятно, вам нужна его миниатюра - как можно быстрее или как можно красивее (для тех, кто пробовал, вы заметите при выполнении Graphics.drawImage даже с интерполяцией BICUBIC для достаточно маленького изображения это все равно выглядит мусором).


1
Рияд, мне понравилось использовать Scalr. Мне любопытно узнать, как вы в итоге выбрали API со всеми статическими методами? Я написал похожий API, который был ближе к строителю. Нравится new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Мне твой способ тоже нравится, и я думаю, что он проще.
Амир Раминфар

4
Amir, шаблон строителя прекрасно работает для этих типов библиотек , как хорошо, я только что произошел , чтобы пойти с статическим методом подходом , потому что я думал , что это волосы легче следовать для новых пользователей и использование-шаблона я ожидал от imgscalr (первоначально только одиночные методы изменения размера) не выиграли от наличия состояния хранения экземпляра (экземпляр построителя). Поэтому я сэкономил на создании экземпляра объекта и перешел на статические методы. Я категорически против создания объектов внутри imgscalr везде, где могу этого избежать. Однако оба подхода работают отлично.
Рияд Калла,

5
+1 за то, что сделал это доступным в центральном репозитории Maven!
Grilse

Что это класс BufferedImage, почему андроид студия не находит @Riyad Калла?
Milad

3
@ xe4me BufferedImage - это класс в J2SE JDK (часть платформы Java2D), используемый для представления необработанных несжатых данных пикселей. Он недоступен на Android, Android предоставляет собственные классы для работы с данными изображений.
Рияд Калла

54

Thumbnailator - это библиотека для изменения размера изображений с открытым исходным кодом для Java с плавным интерфейсом, распространяемая по лицензии MIT.

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

Простой пример

В качестве простого примера, взяв изображение и изменив его размер до 100 x 100 (с сохранением соотношения сторон исходного изображения), и сохранив его в файл, можно выполнить одно действие:

Thumbnails.of("path/to/image")
    .size(100, 100)
    .toFile("path/to/thumbnail");

Продвинутый пример

Быстрый интерфейс Thumbnailator упрощает выполнение сложных задач по изменению размера.

Предположим, мы хотим сделать следующее:

  1. взять изображения в каталог и,
  2. изменить их размер до 100 x 100 с соотношением сторон исходного изображения,
  3. сохранить их все в формате JPEG с настройками качества 0.85,
  4. где имена файлов взяты из оригинала с thumbnail.добавлением в начало

В переводе на Thumbnailator мы могли бы выполнить вышеуказанное с помощью следующего:

Thumbnails.of(new File("path/to/directory").listFiles())
    .size(100, 100)
    .outputFormat("JPEG")
    .outputQuality(0.85)
    .toFiles(Rename.PREFIX_DOT_THUMBNAIL);

Замечание о качестве и скорости изображения

Эта библиотека также использует метод прогрессивного билинейного масштабирования, выделенный в Filthy Rich Clients Чет Хаасе и Роменом Гаем, для создания высококачественных эскизов при обеспечении приемлемой производительности во время выполнения.


1
coobird, отличная работа с API. Очень простой и простой в использовании.
Рияд Калла

@LordT: Я рад, что вы нашли Thumbnailator простым в использовании :)
coobird

Как создать миниатюру 80x80 с оригинальным изображением 500x400? я не видел для этого никакого варианта. Спасибо!
Терри

".outputFormat (" JPEG ")" нигде в документации не написано.
Винсент Кантин

@Vincent Полный список методов, которые можно использовать, можно найти в документации API Thumbnailator - thumbnailator.googlecode.com/hg/javadoc/net/coobird/…
coobird

12

Для этого вам не нужна библиотека. Вы можете сделать это с помощью самой Java.

У Криса Кэмпбелла есть отличное и подробное описание масштабирования изображений - см. Эту статью .

Чет Хаасе и Ромен Гай также опубликовали подробную и очень информативную статью о масштабировании изображений в своей книге Filthy Rich Clients .


7
Статья Криса - это именно то, что изначально побудило меня написать imgscalr; и подобные вопросы (и ответы, подобные твоим). Многие люди снова и снова спрашивают, как получить красивые миниатюры из изображения. Есть несколько способов сделать это, Крис не всегда лучший способ, это зависит от того, что вы пытаетесь сделать и насколько велико сокращение. imgscalr обращается ко всему этому, и это 1 класс.
Рияд Калла

2
+1, я согласен, клиенты Filthy Rich - одна из лучших книг по java наравне с «Эффективной java», но ImgScalr - это то, что я использую, потому что я ленив.
Шон Вейдер


9

Если вы имеете дело с большими изображениями или хотите получить красивый результат, в java это нетривиальная задача. Простое выполнение этого с помощью операции масштабирования через Graphics2D не приведет к созданию высококачественного эскиза. Вы можете сделать это с помощью JAI, но это требует больше работы, чем вы можете себе представить, чтобы получить что-то, что хорошо выглядит, и у JAI есть неприятная привычка выдувать нашу JVM ошибками OutOfMemory.

Я предлагаю использовать ImageMagick в качестве внешнего исполняемого файла, если вам это удастся. Он прост в использовании и выполняет свою работу правильно, так что вам не придется это делать.


4

Если у вас есть возможность установить imagemagick на вашем компьютере, я рекомендую im4java . Это очень тонкий слой абстракции в интерфейсе командной строки, но он очень хорошо выполняет свою работу.


3

Java API не предоставляет стандартной функции масштабирования изображений и снижения качества изображения.

Из-за этого я попытался использовать cvResize из JavaCV, но, похоже, это вызывает проблемы.

Я нашел хорошую библиотеку для масштабирования изображений: просто добавьте зависимость для «java-image-scaling» в свой pom.xml.

<dependency>
    <groupId>com.mortennobel</groupId>
    <artifactId>java-image-scaling</artifactId>
    <version>0.8.6</version>
</dependency>

В репозитории maven вы получите последнюю версию для этого.

Ex. В вашей Java-программе

ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);

Он также доступен на GitHub ( github.com/mortennobel/java-image-scaling.git ) и на данный момент имеет версию 8.7. Требуется небольшое исправление в pom.xml, thou (изменение источника и цели как минимум на 1.6, поскольку новый Maven больше не поддерживает 1.5).
Cromax

2

Вы можете попробовать использовать систему обработки изображений GraphicsMagick с im4java в качестве интерфейса строки для Java.

У GraphicsMagick много преимуществ, но одно на всех:

  • GM используется для обработки миллиардов файлов на крупнейших мировых фото-сайтах (например, Flickr и Etsy).

1

Была упомянута магия изображений. Существует интерфейсный проект JNI под названием JMagick. Это не особо стабильный проект (известно, что сама Image Magick сильно меняет и даже нарушает совместимость). Тем не менее, у нас есть хороший опыт использования JMagick и совместимой версии Image Magick в производственной среде для выполнения масштабирования с высокой пропускной способностью и низкой задержкой. Скорость была значительно выше, чем у графической библиотеки Java, которую мы пробовали ранее.

http://www.jmagick.org/index.html


1

Просто используйте ответ Буркхарда, но добавьте эту строку после создания графики:

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

Вы также можете установить значение BICUBIC, это даст изображение лучшего качества, но это более дорогая операция. Вы можете установить и другие подсказки рендеринга, но я обнаружил, что наиболее заметный эффект дает интерполяция. Имейте в виду, что если вы хотите сильно увеличить масштаб, код Java, скорее всего, будет очень медленным. Я обнаружил, что большие изображения начинают давать задержку около 300% масштабирования, даже если все подсказки рендеринга настроены на оптимизацию скорости по качеству.



1

Оказывается, написать эффективный скейлер нетривиально. Я сделал это однажды для проекта с открытым исходным кодом: ImageScaler. .

В принципе, java.awt.Image # getScaledInstance (int, int, int) тоже подойдет, но с этим есть неприятная ошибка - подробности см. В моей ссылке.


0

Я разработал решение со свободно доступными классами (AnimatedGifEncoder, GifDecoder и LWZEncoder), доступными для обработки анимации GIF.
Вы можете загрузить jgifcode jar и запустить класс GifImageUtil. Ссылка: http://www.jgifcode.com


1
Пожалуйста, укажите в ответе, являетесь ли вы аффилированным лицом к рекомендованному вами продукту.
Ханс Олссон

уау ... это что для изменения размера анимированного изображения GIF? а это бесплатно ?? Wwaww ... я должен примерить это сейчас ...
gumuruh

Да, это разработано мной. Вот исходный код для него github.com/rt29/jgifcode - теперь он здесь. Я больше не поддерживаю это.
Рохит Тивари,


0

Если вы не хотите импортировать imgScalr, например, ответ @Riyad Kalla, который я тестировал, тоже работает нормально, вы можете сделать это, взятое из ответа Питера Уолсера @Peter Walser по другой проблеме:

 /**
     * utility method to get an icon from the resources of this class
     * @param name the name of the icon
     * @return the icon, or null if the icon wasn't found.
     */
    public Icon getIcon(String name) {
        Icon icon = null;
        URL url = null;
        ImageIcon imgicon = null;
        BufferedImage scaledImage = null;
        try {
            url = getClass().getResource(name);

            icon = new ImageIcon(url);
            if (icon == null) {
                System.out.println("Couldn't find " + url);
            }

            BufferedImage bi = new BufferedImage(
                    icon.getIconWidth(),
                    icon.getIconHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = bi.createGraphics();
            // paint the Icon to the BufferedImage.
            icon.paintIcon(null, g, 0,0);
            g.dispose();

            bi = resizeImage(bi,30,30);
            scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
            imgicon = new ImageIcon(scaledImage);

        } catch (Exception e) {
            System.out.println("Couldn't find " + getClass().getName() + "/" + name);
            e.printStackTrace();
        }
        return imgicon;
    }

 public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
        float scaleX = (float) areaWidth / image.getWidth();
        float scaleY = (float) areaHeight / image.getHeight();
        float scale = Math.min(scaleX, scaleY);
        int w = Math.round(image.getWidth() * scale);
        int h = Math.round(image.getHeight() * scale);

        int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        boolean scaleDown = scale < 1;

        if (scaleDown) {
            // multi-pass bilinear div 2
            int currentW = image.getWidth();
            int currentH = image.getHeight();
            BufferedImage resized = image;
            while (currentW > w || currentH > h) {
                currentW = Math.max(w, currentW / 2);
                currentH = Math.max(h, currentH / 2);

                BufferedImage temp = new BufferedImage(currentW, currentH, type);
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(resized, 0, 0, currentW, currentH, null);
                g2.dispose();
                resized = temp;
            }
            return resized;
        } else {
            Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = resized.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(image, 0, 0, w, h, null);
            g2.dispose();
            return resized;
        }
    }

0

Попробуйте следующий метод:

ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.