Frage

Im Anschluss an die javadocs habe ich versucht, einen BufferedImage ohne Erfolg maßstabs hier ist mein Code:

BufferedImage image = MatrixToImageWriter.getBufferedImage(encoded);
Graphics2D grph = image.createGraphics();
grph.scale(2.0, 2.0);
grph.dispose();

Ich kann nicht verstehen, warum es nicht funktioniert, jede mögliche Hilfe?

War es hilfreich?

Lösung

AffineTransformOp bietet den zusätzlichen Flexibilität der Interpolationsart wählen.

BufferedImage before = getBufferedImage(encoded);
int w = before.getWidth();
int h = before.getHeight();
BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(2.0, 2.0);
AffineTransformOp scaleOp = 
   new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
after = scaleOp.filter(before, after);

Das Fragment gezeigt zeigt Resampling , nicht Zuschneiden ; Zusammenhang mit dieser Antwort Adressen der Ausgabe ; einige relevante Beispiele hier untersucht werden.

Andere Tipps

Leider ist die Leistung von getScaledInstance () ist sehr schlecht, wenn nicht problematisch.

Der alternative Ansatz ist es, eine neue BufferedImage zu erstellen und und eine skalierte Version des Originals auf dem neuen ziehen.

BufferedImage resized = new BufferedImage(newWidth, newHeight, original.getType());
Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, newWidth, newHeight, 0, 0, original.getWidth(),
    original.getHeight(), null);
g.dispose();

newWidth, newHeight zeigt die neue BufferedImage Größe und hat richtig berechnet werden. Im Fall des Skalierungsfaktors:

int newWidth = new Double(original.getWidth() * widthFactor).intValue();
int newHeight = new Double(original.getHeight() * heightFactor).intValue();

Bearbeiten : Fand der Artikel das Leistungsproblem darstellt: The Perils von Image.getScaledInstance ()

Wie @Bozho sagt, werden Sie wahrscheinlich zu verwenden getScaledInstance wollen.

Um zu verstehen, wie grph.scale(2.0, 2.0) jedoch funktioniert, könnte man an diesem Code einen Blick:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;


class Main {
    public static void main(String[] args) throws IOException {

        final int SCALE = 2;

        Image img = new ImageIcon("duke.png").getImage();

        BufferedImage bi = new BufferedImage(SCALE * img.getWidth(null),
                                             SCALE * img.getHeight(null),
                                             BufferedImage.TYPE_INT_ARGB);

        Graphics2D grph = (Graphics2D) bi.getGraphics();
        grph.scale(SCALE, SCALE);

        // everything drawn with grph from now on will get scaled.

        grph.drawImage(img, 0, 0, null);
        grph.dispose();

        ImageIO.write(bi, "png", new File("duke_double_size.png"));
    }
}

Bei duke.png :
eingeben Bild Beschreibung hier

es produziert duke_double_size.png :
eingeben Bild Beschreibung hier

Mit imgscalr - Java Bildskalierung Bibliothek :

BufferedImage image =
     Scalr.resize(originalImage, Scalr.Method.BALANCED, newWidth, newHeight);

Das ist schnell genug für mich.

Wenn Sie nichts dagegen haben eine externe Bibliothek verwenden, Thumbnailator können Skalierung von BufferedImage s.

Thumbnailator kümmert sich um den Umgang mit den Java 2D Verarbeitung (wie die Verwendung von < a href = "https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html" rel = "noreferrer"> Graphics2D und Festlegung geeigneter Rendering-Hinweise ), so dass ein einfacher fließend API-Aufruf verwendet werden, kann Bilder auf der Größe:

BufferedImage image = Thumbnails.of(originalImage).scale(2.0).asBufferedImage();

Obwohl Thumbnailator, wie der Name schon sagt, in Richtung schrumpfen Bilder ausgerichtet ist, wird es einen anständigen Job tun Bilder auch vergrößern, bilineare Interpolation in dem Standard Resizer Implementierung verwendet wird.


Disclaimer:. Ich bin der Maintainer des Thumbnailator Bibliothek

scale(..) funktioniert ein bisschen anders. Sie können bufferedImage.getScaledInstance(..) verwenden

Um ein Bild zu skalieren, müssen Sie ein neues Bild erstellen und hinein zu ziehen. Eine Möglichkeit ist es, die filter() Methode eines AffineTransferOp zu verwenden, wie vorgeschlagen href="https://stackoverflow.com/a/4216635/230513">. Dadurch können Sie die Interpolationstechnik wählen.

private static BufferedImage scale1(BufferedImage before, double scale) {
    int w = before.getWidth();
    int h = before.getHeight();
    // Create a new image of the proper size
    int w2 = (int) (w * scale);
    int h2 = (int) (h * scale);
    BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB);
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale);
    AffineTransformOp scaleOp 
        = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR);

    scaleOp.filter(before, after);
    return after;
}

Eine andere Möglichkeit ist, einfach das Originalbild in das neue Bild zu zeichnen, eine Skalierung mit der Skalierung zu tun. Diese Methode ist sehr ähnlich, aber es zeigt auch, wie Sie alles, was Sie wollen im endgültigen Bild zeichnen. (Ich habe in einer leeren Zeile, wo die beiden Methoden zu unterscheiden beginnen.)

private static BufferedImage scale2(BufferedImage before, double scale) {
    int w = before.getWidth();
    int h = before.getHeight();
    // Create a new image of the proper size
    int w2 = (int) (w * scale);
    int h2 = (int) (h * scale);
    BufferedImage after = new BufferedImage(w2, h2, BufferedImage.TYPE_INT_ARGB);
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale);
    AffineTransformOp scaleOp 
        = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR);

    Graphics2D g2 = (Graphics2D) after.getGraphics();
    // Here, you may draw anything you want into the new image, but we're
    // drawing a scaled version of the original image.
    g2.drawImage(before, scaleOp, 0, 0);
    g2.dispose();
    return after;
}

Nachtrag: Ergebnisse

Um die Unterschiede zu erläutern, ich verglichen die Ergebnisse der fünf Methoden unten. Hier ist, was die Ergebnisse aussehen, sowohl nach oben skaliert und nach unten, zusammen mit Leistungsdaten. (Performance variiert von einem Lauf zum nächsten, nehmen Sie so diese Zahlen nur als grobe Richtlinien.) Das obere Bild ist das Original. Ich vergrößere es in doppelter Größe und halber Größe.

Wie Sie sehen können, AffineTransformOp.filter(), in scaleBilinear() verwendet wird, ist schneller als die Standard-Ziehverfahren von Graphics2D.drawImage() in scale2(). Auch BiCubic Interpolation ist die langsamste, aber die besten Ergebnisse, wenn das Bild zu erweitern. (Für Leistung, es sollte nur mit scaleBilinear() und scaleNearest(). verglichen werden) Bilinear besser zu sein scheint das Bild für das Schrumpfen, obwohl es eine schwierige ist. Und NearestNeighbor ist die schnellste, mit den schlechtesten Ergebnissen. Bilinear scheint der beste Kompromiss zwischen Geschwindigkeit und Qualität zu sein. Die Image.getScaledInstance(), in der questionable() Methode aufgerufen, entwickelte sich sehr schlecht, und kehrte die gleiche niedrige Qualität wie NearestNeighbor. (Performance-Nummern werden für die Erweiterung des Bildes nur gegeben.)

public static BufferedImage scaleBilinear(BufferedImage before, double scale) {
    final int interpolation = AffineTransformOp.TYPE_BILINEAR;
    return scale(before, scale, interpolation);
}

public static BufferedImage scaleBicubic(BufferedImage before, double scale) {
    final int interpolation = AffineTransformOp.TYPE_BICUBIC;
    return scale(before, scale, interpolation);
}

public static BufferedImage scaleNearest(BufferedImage before, double scale) {
    final int interpolation = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
    return scale(before, scale, interpolation);
}

@NotNull
private static 
BufferedImage scale(final BufferedImage before, final double scale, final int type) {
    int w = before.getWidth();
    int h = before.getHeight();
    int w2 = (int) (w * scale);
    int h2 = (int) (h * scale);
    BufferedImage after = new BufferedImage(w2, h2, before.getType());
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale);
    AffineTransformOp scaleOp = new AffineTransformOp(scaleInstance, type);
    scaleOp.filter(before, after);
    return after;
}

/**
 * This is a more generic solution. It produces the same result, but it shows how you 
 * can draw anything you want into the newly created image. It's slower 
 * than scaleBilinear().
 * @param before The original image
 * @param scale The scale factor
 * @return A scaled version of the original image
 */
private static BufferedImage scale2(BufferedImage before, double scale) {
    int w = before.getWidth();
    int h = before.getHeight();
    // Create a new image of the proper size
    int w2 = (int) (w * scale);
    int h2 = (int) (h * scale);
    BufferedImage after = new BufferedImage(w2, h2, before.getType());
    AffineTransform scaleInstance = AffineTransform.getScaleInstance(scale, scale);
    AffineTransformOp scaleOp
            = new AffineTransformOp(scaleInstance, AffineTransformOp.TYPE_BILINEAR);

    Graphics2D g2 = (Graphics2D) after.getGraphics();
    // Here, you may draw anything you want into the new image, but we're just drawing
    // a scaled version of the original image. This is slower than 
    // calling scaleOp.filter().
    g2.drawImage(before, scaleOp, 0, 0);
    g2.dispose();
    return after;
}

/**
 * I call this one "questionable" because it uses the questionable getScaledImage() 
 * method. This method is no longer favored because it's slow, as my tests confirm.
 * @param before The original image
 * @param scale The scale factor
 * @return The scaled image.
 */
private static Image questionable(final BufferedImage before, double scale) {
    int w2 = (int) (before.getWidth() * scale);
    int h2 = (int) (before.getHeight() * scale);
    return before.getScaledInstance(w2, h2, Image.SCALE_FAST);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top