Як я можу змінити розмір зображення за допомогою Java?


126

Мені потрібно змінити розмір файлів PNG, JPEG та GIF. Як я можу це зробити за допомогою Java?


14
так як ви просили бібліотеки, реальний відповідь тут: stackoverflow.com/questions/244164 / ... . Це набагато простіше у використанні, ніж код у прийнятій відповіді;)
Артур Гайові

Я не згоден у частині бібліотеки: Graphics2D є частиною бібліотеки awt, і вона є відкритим кодом. Для останньої частини (відкритий код) я не впевнений на 100%, але хто б все-таки подивився на код awt?
Беркхард

Відповіді:


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 (ширина, висота, підказки)?
кодова гра

1
чи невірно зберегти запасAlpha (для 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 пікселів заввишки, і за замовчуванням він автоматично вибере найкращий і найшвидший підхід для цього, оскільки він не був не вказано

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


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

4
Amir, шаблон будівельника прекрасно працює для цих типів бібліотек , як добре, я тільки що стався , щоб піти з статичним методом підходом , тому що я думав , що це волосся легше слідувати для нових користувачів і використання-шаблону я очікував від imgscalr (спочатку тільки один метод зміни розміру) не отримав користі від того, щоб мати екземпляр, що тримає стан (екземпляр Builder). Тож я заощадив на об'єкті інстанціювання і пішов зі статичними методами. Я зайняв рішучу позицію проти створення об'єктів всередині imgscalr у кожному місці, я можу цього уникнути. Обидва підходи, хоча працюють чудово.
Ріяд Калла

5
+1 для надання цього доступу до центрального сховища Maven!
Grilse

Що це клас BufferedImage, чому андроїд студія не знаходить @Riyad Калла?
Milad

3
@ xe4me BufferedImage - це клас в JDSE 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 х 100, залежно від пропорції вихідного зображення,
  3. збережіть їх усіх у JPEG з налаштуваннями якості 0.85,
  4. де назви файлів взяті з оригіналу із thumbnail.додаванням до початку

Перекладене на мініатюру, ми зможемо виконати вищезазначене з наступним:

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

Примітка про якість та швидкість зображення

Ця бібліотека також використовує прогресивний метод білінеарного масштабування, виділений у брудних клієнтів Chet Haase та Romain Guy, щоб генерувати якісні ескізи, забезпечуючи при цьому прийнятну ефективність виконання.


1
coobird, дуже приємна робота з API. Дуже прямий вперед і простий у використанні.
Ріяд Калла

@LordT: Я радий, що Ви знайшли Thumbnailator простим у використанні :)
coobird

Як я можу створити мініатюру 80x80 із зображенням оригіналу 500x400? я не бачив жодного варіанту для цього. Дякую!
махровий

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

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

12

Для цього вам не потрібна бібліотека. Ви можете це зробити з самою Java.

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

Чет Хааз та Ромен Гай також мають детальну та дуже інформативну написання масштабування зображень у своїй книзі " Клієни Брудні Річки" .


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-масштабування" у свій pom.xml.

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

У сховищі Maven ви отримаєте останню версію для цього.

Вих. У вашій програмі 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, ти (змінивши джерело та ціль принаймні 1.6, оскільки новіший Maven вже не підтримує 1,5).
Cromax

2

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

Є багато переваг GraphicsMagick, але одна для всіх:

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

1

Згаданий образ Magick. Є передній проект 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, воно дасть зображення кращої якості, але це більш дорога операція. Можна встановити й інші підказки щодо візуалізації, але я виявив, що інтерполяція дає найбільш помітний ефект. Майте на увазі, якщо ви хочете збільшити масштаб, ява-код, швидше за все, буде дуже повільним. Я вважаю, що більші зображення починають створювати відставання близько 300% масштабу навіть при встановленні всіх підказок на візуалізацію для оптимізації швидкості над якістю.



1

Виявляється, написання виконавського скалера - не тривіально. Я зробив це один раз для проекту з відкритим кодом: ImageScaler .

В принципі, "java.awt.Image # getScaledInstance (int, int, int)" також зробив би цю роботу, але з цим є неприємна помилка - для детальної інформації зверніться до мого посилання.


0

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


1
Будь ласка, зазначте у відповіді, якщо ви пов’язані з продуктом, який ви рекомендуєте.
Ганс Ольссон

waw ... це для зміни розміру анімаційного зображення GIF? і це безкоштовно ?? Wwaww ... я повинен спробувати це зараз ...
gumuruh

Так, це розроблено мною. Ось вихідний код для цього github.com/rt29/jgifcode - Це зараз тут. Я вже не підтримую цього.
Рохіт Тіварі


0

Якщо ви не хочете імпортувати imgScalr, як-от @Riyad Kalla, відповідь, над якою я тестував, теж добре працює, ви можете зробити це взято з відповіді Пітера Уолсера @ Петера Вальсера з іншого питання:

 /**
     * 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.