Wie kann ich die Größe eines Bildes mit Java ändern?

126

Ich muss die Größe von PNG-, JPEG- und GIF-Dateien ändern. Wie kann ich das mit Java machen?

pbreault
quelle
14
Da Sie nach einer Bibliothek gefragt haben, lautet die eigentliche Antwort hier: stackoverflow.com/questions/244164/… . Es ist viel einfacher zu verwenden als der Code in der akzeptierten Antwort;)
Artur Gajowy
Ich bin mit dem Bibliotheksteil nicht einverstanden: Graphics2D ist Teil der awt-Bibliothek und Open Source. Für den letzten Teil (Open Source) bin ich mir nicht 100% sicher, aber wer würde sich den awt-Code überhaupt ansehen?
Burkhard

Antworten:

87

Nach dem Laden des Bildes können Sie versuchen:

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;
    }
Burkhard
quelle
9
Ich fand, dass diese Technik ein Bild erzeugt, das für meine Bedürfnisse nicht hoch genug ist.
Morgancodes
1
funktioniert Image.getScaledInstance (Breite, Höhe, Hinweise) auch?
Codeplay
1
Prüfen Sie mit der MethodeerveAlpha die falsche Richtung (für den Bildtyp)?
Thilo
Ich stimme @morgancodes zu. Die Bildqualität ist viel schlechter als bei OS X Preview, wenn Sie die Größe auf die gleichen Abmessungen ändern. Ich werde einige Open-Source-Bibliotheken ausprobieren, um festzustellen, ob sie besser abschneiden.
Thilo
1
"Ich werde einige Open-Source-Bibliotheken ausprobieren, um zu sehen, ob sie besser abschneiden." +1 für imgscalr aus der Antwort von @ RiyadKalla.
Thilo
182

FWIW Ich habe gerade (Apache 2, gehostet auf GitHub) eine einfache Bildskalierungsbibliothek für Java namens imgscalr veröffentlicht (verfügbar in Maven Central ).

Die Bibliothek implementiert einige verschiedene Ansätze zur Bildskalierung (einschließlich des inkrementellen Ansatzes von Chris Campbell mit einigen geringfügigen Verbesserungen) und wählt entweder den für Sie optimalen Ansatz aus, wenn Sie dazu aufgefordert werden, oder bietet Ihnen den schnellsten oder am besten aussehenden Ansatz (wenn Sie dies wünschen) danach fragen).

Die Verwendung ist kinderleicht, nur eine Reihe statischer Methoden. Der einfachste Anwendungsfall ist:

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

Bei allen Vorgängen werden die ursprünglichen Proportionen des Bildes beibehalten. In diesem Fall fordern Sie imgscalr auf, die Größe Ihres Bilds innerhalb von 200 Pixel Breite und 200 Pixel Höhe zu ändern. Standardmäßig wird automatisch der am besten aussehende und schnellste Ansatz ausgewählt, da dies nicht der Fall war nicht angegeben.

Am Anfang war mir klar, dass dies wie Eigenwerbung aussieht (es ist), aber ich verbrachte meinen Teil der Zeit damit, genau dasselbe Thema zu googeln und kam immer wieder auf unterschiedliche Ergebnisse / Ansätze / Gedanken / Vorschläge und beschloss, mich hinzusetzen und eine zu schreiben einfache Implementierung, die 80-85% der Anwendungsfälle anspricht, in denen Sie ein Bild haben und wahrscheinlich ein Miniaturbild dafür möchten - entweder so schnell wie möglich oder so gut wie möglich (für diejenigen, die es versucht haben, werden Sie feststellen Wenn Sie ein Graphics.drawImage auch mit BICUBIC-Interpolation auf ein ausreichend kleines Bild ausführen, sieht es immer noch wie Müll aus.

Riad Kalla
quelle
1
Riad, ich habe Scalr gern benutzt. Ich bin gespannt, wie Sie zu einer API mit allen statischen Methoden gekommen sind. Ich hatte eine ähnliche API geschrieben, die einem Baumeister näher kam. Wie new ImageScaler(img).resizeTo(...).rotate(...).cropTo(...).toOutputBuffer(). Ich mag deinen Weg auch und ich denke, es ist einfacher.
Amir Raminfar
4
Amir, das Builder-Muster funktioniert auch wunderbar für diese Arten von Bibliotheken. Ich habe mich zufällig für den Ansatz der statischen Methode entschieden, weil ich dachte, es sei für neue Benutzer einfacher, dem Haar zu folgen, und für das Verwendungsmuster, das ich von imgscalr (ursprünglich) erwartet hatte Nur einzelne Größenänderungsmethoden) profitierten nicht von einem Instanzhaltestatus (der Builder-Instanz). Also habe ich die Objektinstanziierung gespeichert und mich für die statischen Methoden entschieden. Ich habe mich an jeder Stelle, an der ich dies vermeiden kann, entschieden gegen die Schaffung von Objekten innerhalb von imgscalr ausgesprochen. Beide Ansätze funktionieren jedoch hervorragend.
Riyad Kalla
5
+1 für die Bereitstellung im zentralen Maven-Repository!
Grilse
Was ist diese BufferedImage-Klasse? Warum findet Android Studio sie nicht? @Riyad Kalla
Milad
3
@ xe4me BufferedImage ist eine Klasse im J2SE JDK (Teil des Java2D-Frameworks), die zur Darstellung unkomprimierter Pixeldaten verwendet wird. Es ist nicht für Android verfügbar. Android bietet eigene Klassen für die Arbeit mit Bilddaten.
Riyad Kalla
54

Thumbnailator ist eine Open-Source-Bibliothek zur Größenänderung von Bildern für Java mit einer fließenden Oberfläche, die unter der MIT-Lizenz vertrieben wird.

Ich habe diese Bibliothek geschrieben, weil es überraschend schwierig sein kann, hochwertige Miniaturansichten in Java zu erstellen, und der resultierende Code ziemlich chaotisch sein kann. Mit Thumbnailator ist es möglich, ziemlich komplizierte Aufgaben mit einer einfachen fließenden API auszudrücken.

Ein einfaches Beispiel

Ein einfaches Beispiel: Nehmen Sie ein Bild und ändern Sie die Größe auf 100 x 100 (wobei das Seitenverhältnis des Originalbilds beibehalten wird) und speichern Sie es in einer Datei in einer einzigen Anweisung:

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

Ein fortgeschrittenes Beispiel

Das Ausführen komplexer Größenänderungsaufgaben wird durch die fließende Benutzeroberfläche von Thumbnailator vereinfacht.

Nehmen wir an, wir möchten Folgendes tun:

  1. Nehmen Sie die Bilder in ein Verzeichnis und,
  2. Ändern Sie die Größe auf 100 x 100 mit dem Seitenverhältnis des Originalbilds.
  3. Speichern Sie sie alle in JPEGs mit Qualitätseinstellungen von 0.85,
  4. Dabei werden die Dateinamen aus dem Original übernommen und thumbnail.an den Anfang angehängt

In Thumbnailator übersetzt, könnten wir die oben genannten Schritte wie folgt ausführen:

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

Ein Hinweis zur Bildqualität und -geschwindigkeit

Diese Bibliothek verwendet auch die progressive bilineare Skalierungsmethode , die in Filthy Rich Clients von Chet Haase und Romain Guy hervorgehoben wurde, um hochwertige Miniaturansichten zu generieren und gleichzeitig eine akzeptable Laufzeitleistung sicherzustellen.

Coobird
quelle
1
Coobird, wirklich gute Arbeit mit der API. Sehr einfach und einfach zu bedienen.
Riyad Kalla
@ LordT: Ich bin froh, dass Sie Thumbnailator einfach zu bedienen fanden :)
Coobird
Wie kann ich ein 80x80-Miniaturbild mit einem 500x400-Originalbild erstellen? Ich habe keine Option dafür gesehen. Vielen Dank!
Terry
".outputFormat (" JPEG ")" ist nirgends in der Dokumentation geschrieben.
Vincent Cantin
@ Vincent Die vollständige Liste der Methoden, die verwendet werden können, befindet sich in der Thumbnailator-API-Dokumentation - thumbnailator.googlecode.com/hg/javadoc/net/coobird/…
coobird
12

Sie benötigen dazu keine Bibliothek. Sie können es mit Java selbst tun.

Chris Campbell hat eine ausgezeichnete und detaillierte Beschreibung der Skalierung von Bildern - siehe diesen Artikel .

Chet Haase und Romain Guy haben in ihrem Buch Filthy Rich Clients auch eine detaillierte und sehr informative Beschreibung der Bildskalierung .

David Koelle
quelle
7
Chris 'Artikel hat mich genau dazu motiviert, imgscalr zu schreiben. und Fragen wie diese (und Antworten wie Ihre). Viele Leute fragen immer und immer wieder, wie man gut aussehende Thumbnails von einem Bild bekommt. Es gibt eine Reihe von Möglichkeiten, Chris's ist nicht immer der beste Weg, es hängt davon ab, was Sie versuchen und wie groß die Reduzierung ist. imgscalr spricht all das an und es ist 1 Klasse.
Riyad Kalla
2
+1, ich stimme zu, Filthy Rich-Kunden sind eines der besten Java-Bücher auf dem Markt von "Effective Java", aber ImgScalr verwende ich, weil ich faul bin.
Shawn Vader
9

Wenn Sie mit großen Bildern arbeiten oder ein gut aussehendes Ergebnis erzielen möchten, ist dies in Java keine triviale Aufgabe. Wenn Sie dies einfach über eine Rescale-Operation über Graphics2D tun, wird keine hochwertige Miniaturansicht erstellt. Sie können dies mit JAI tun, aber es erfordert mehr Arbeit, als Sie sich vorstellen können, um etwas zu erhalten, das gut aussieht, und JAI hat die böse Angewohnheit, Ihre JVM mit OutOfMemory-Fehlern zu belasten.

Ich schlage vor, ImageMagick als externe ausführbare Datei zu verwenden, wenn Sie damit durchkommen können. Es ist einfach zu bedienen und macht den Job richtig, so dass Sie nicht müssen.

Joel Carranza
quelle
4

Wenn es möglich ist, imagemagick auf Ihrer Maschine zu installieren, empfehle ich im4java . Es ist eine sehr dünne Abstraktionsschicht auf der Befehlszeilenschnittstelle, macht aber ihre Arbeit sehr gut.

Naltatis
quelle
3

Die Java-API bietet keine Standard-Skalierungsfunktion für Bilder und eine Herabstufung der Bildqualität.

Aus diesem Grund habe ich versucht, cvResize von JavaCV aus zu verwenden, aber es scheint Probleme zu verursachen.

Ich habe eine gute Bibliothek für die Bildskalierung gefunden: Fügen Sie einfach die Abhängigkeit für "Java-Bildskalierung" in Ihre pom.xml ein.

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

Im Maven-Repository erhalten Sie dazu die aktuelle Version.

Ex. In Ihrem Java-Programm

ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
Ruju
quelle
Es ist auch auf GitHub ( github.com/mortennobel/java-image-scaling.git ) verfügbar und hat derzeit Version 8.7. Es musste in pom.xml behoben werden (Änderung von Quelle und Ziel auf mindestens 1.6, da neuere Maven 1.5 nicht mehr unterstützen).
Cromax
2

Sie können versuchen, das GraphicsMagick-Bildverarbeitungssystem mit im4java als Befehlszeilenschnittstelle für Java zu verwenden.

GraphicsMagick bietet viele Vorteile, aber einen für alle:

  • GM wird verwendet, um Milliarden von Dateien auf den weltweit größten Fotoseiten (z. B. Flickr und Etsy) zu verarbeiten.
Kajo
quelle
1

Image Magick wurde erwähnt. Es gibt ein JNI-Frontend-Projekt namens JMagick. Es ist kein besonders stabiles Projekt (und Image Magick selbst hat sich bekanntermaßen stark verändert und sogar die Kompatibilität beeinträchtigt). Wir haben jedoch gute Erfahrungen mit JMagick und einer kompatiblen Version von Image Magick in einer Produktionsumgebung gemacht, um die Skalierung mit hohem Durchsatz und geringer Latenz durchzuführen. Die Geschwindigkeit war wesentlich besser als bei einer Java-Grafikbibliothek, die wir zuvor ausprobiert haben.

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

Jice
quelle
1

Verwenden Sie einfach die Antwort von Burkhard, aber fügen Sie diese Zeile nach dem Erstellen der Grafiken hinzu:

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

Sie können den Wert auch auf BICUBIC setzen. Dies führt zu einer besseren Bildqualität, ist jedoch teurer. Es gibt andere Rendering-Hinweise, die Sie festlegen können, aber ich habe festgestellt, dass die Interpolation den bemerkenswertesten Effekt erzeugt. Denken Sie daran, wenn Sie viel zoomen möchten, wird Java-Code höchstwahrscheinlich sehr langsam sein. Ich finde, dass größere Bilder eine Verzögerung von etwa 300% Zoom erzeugen, selbst wenn alle Rendering-Hinweise so eingestellt sind, dass die Geschwindigkeit über die Qualität optimiert wird.

Der einzig wahre Colter
quelle
1

Es stellt sich heraus, dass das Schreiben eines performanten Skalierers nicht trivial ist. Ich habe es einmal für ein Open Source-Projekt gemacht: ImageScaler .

Im Prinzip würde 'java.awt.Image # getScaledInstance (int, int, int)' auch die Arbeit erledigen, aber es gibt einen bösen Fehler dabei - siehe meinen Link für Details.

aanno
quelle
0

Ich habe eine Lösung mit den frei verfügbaren Klassen (AnimatedGifEncoder, GifDecoder und LWZEncoder) entwickelt, die für die Verarbeitung von GIF-Animationen verfügbar sind.
Sie können das jgifcode jar herunterladen und die GifImageUtil-Klasse ausführen. Link: http://www.jgifcode.com

Rohit Tiwari
quelle
1
Bitte geben Sie in der Antwort an, ob Sie mit dem von Ihnen empfohlenen Produkt verbunden sind.
Hans Olsson
waw ... ist das für die Größenänderung von GIF-animierten Bildern? und es ist kostenlos? Wwaww ... ich sollte es jetzt
anprobieren
Ja das wird von mir entwickelt. Hier ist der Quellcode dafür github.com/rt29/jgifcode - Dies ist jetzt hier. Ich unterstütze es nicht mehr.
Rohit Tiwari
0

Wenn Sie imgScalr nicht importieren möchten, wie die Antwort von @Riyad Kalla, über der ich auch getestet habe, funktioniert dies einwandfrei. Sie können dies jedoch aus der Antwort von Peter Walser @Peter Walser zu einem anderen Problem machen:

 /**
     * 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;
        }
    }
shareef
quelle
0

Versuchen Sie diese folgende Methode:

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);
Fridjato Teil Fridjat
quelle