Java konvertiert Image in BufferedImage

83

Es gibt bereits Fragen wie diesen Link zu StackOverflow und die akzeptierte Antwort lautet "Casting":

Image image = ImageIO.read(new File(file));
BufferedImage buffered = (BufferedImage) image;

In meinem Programm versuche ich:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = (BufferedImage) image;

Leider erhalte ich einen Laufzeitfehler:

sun.awt.image.ToolkitImage kann nicht in java.awt.image.BufferedImage umgewandelt werden

Offensichtlich funktioniert das Casting nicht.
Die Frage ist: Was ist (oder gibt es) die richtige Art, ein Bild in BufferedImage zu konvertieren?

Arek Wilk
quelle
Wenn Sie ein gepuffertes Bild skalieren möchten, versuchen Sie Folgendes : [ stackoverflow.com/questions/4216123/… [1]: stackoverflow.com/questions/4216123/…
user902383
7
Für die Aufzeichnung ist es NICHT der Compiler, der das sagt. Sie sehen tatsächlich einen Laufzeitfehler ... keinen Kompilierungsfehler.
Stephen C
1
Du hast recht. Vielen Dank für den Hinweis. Ich werde die Frage entsprechend bearbeiten.
Arek Wilk
@ user902383 Auch wenn sie meine Frage nicht direkt beantworten - das sind auch großartige Lösungen.
Arek Wilk
Kleine Sache zu OP: Methode ImageIO.read(File)gibt a BufferedImagedurch seine Signatur zurück. ( Referenz ) Es ist nicht erforderlich, zuerst eine ImageVariable zuzuweisen und dann in Typ umzuwandeln BufferedImage. Das könnte die Leute verwirren, die Ihren Code lesen.
Kevinarpe

Antworten:

123

Von einer Java Game Engine :

/**
 * Converts a given Image into a BufferedImage
 *
 * @param img The Image to be converted
 * @return The converted BufferedImage
 */
public static BufferedImage toBufferedImage(Image img)
{
    if (img instanceof BufferedImage)
    {
        return (BufferedImage) img;
    }

    // Create a buffered image with transparency
    BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

    // Draw the image on to the buffered image
    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(img, 0, 0, null);
    bGr.dispose();

    // Return the buffered image
    return bimage;
}
Sri Harsha Chilakapati
quelle
7
@SriHarshaChilakapati You shouldn't be worrying about the memory when using Java.Nach dem durchschnittlichen Speicherverbrauch von Java-Anwendungen zu urteilen, machen sich andere Entwickler definitiv keine Sorgen um den Speicher.
Tomáš Zato - Wiedereinsetzung Monica
1
@ TomášZato Es schien mir, dass Sie aus der C ++ - Welt stammten und daran dachten, den Speicher der Pixel der Bilddaten wiederzuverwenden. Ich meine mit meinem vorherigen Kommentar, dass in diesem Fall kein Grund zur Sorge besteht, da der GC sich in Java darum kümmert.
Sri Harsha Chilakapati
2
@SriHarshaChilakapati Also verbrauchen Müllsammler keine Ressourcen? GC speichert Sie nur vor dem Code, der den Speicher umgibt. Es beseitigt kein Hardwarelimit.
Andrew Sannier
5
Dies funktioniert nicht , wenn Imagenoch nicht geladen ist , da getWidth(null)oder getHeight(null)wird wieder -1in dem Fall
Dimmt
1
Ich musste BufferedImage.TYPE_INT_RGBanstelle von ARGB verwenden, um die Farben meines Miniaturbilds richtig zu machen
Stephanie
20

Eine Möglichkeit, dies zu handhaben, besteht darin, ein neues BufferedImage zu erstellen und dessen Grafikobjekt anzuweisen, Ihr skaliertes Bild in das neue BufferedImage zu zeichnen:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(scaleX, scaleY, TYPE);
buffered.getGraphics().drawImage(image, 0, 0 , null);

Das sollte den Trick ohne Casting machen.

Salbeira
quelle
2
Vergessen Sie niemals, erstellte Grafikinstanzen zu entsorgen
Sri Harsha Chilakapati
Wie "erstellte Grafikschnittstellen entsorgen"?
Buffalo
Sollte der Typ im BufferedImage-Konstruktor mit dem in getScaledInstance übereinstimmen?
Drazen Bjelovuk
Nein, der TYP ist so etwas wie ARGB oder RGBA, die Art und Weise, wie die Bilddaten intern gespeichert werden - wählen Sie, was sich für Ihre Anwendung am natürlichsten anfühlt. Schauen Sie einfach in Ihre Autocomplete, wenn Sie BufferedImage eingeben. [Autocomplete], um alle Auswahlmöglichkeiten zu sehen
Salbeira
3

Wenn Sie ein zurückbekommen sun.awt.image.ToolkitImage, können Sie das Image in dieses umwandeln und dann getBufferedImage () verwenden , um das abzurufenBufferedImage .

Anstelle Ihrer letzten Codezeile, in der Sie das Casting durchführen, würden Sie einfach Folgendes tun:

BufferedImage buffered = ((ToolkitImage) image).getBufferedImage();
Hermann Hans
quelle
7
1) Es ist verpönt, Klassen aus dem sunPaket zu verwenden. Es ist nicht garantiert, dass sie in Nicht-Oracle-JDKs verfügbar sind. 2) Die Methode getBufferedImage()funktioniert nur, wenn das gepufferte Bild intern von generiert wurde TookitImage. Meistens (99%) ist dies nicht der Fall, daher ist der Rückgabewert null. Quellenangabe
Kevinarpe
3

Wenn Sie Kotlin verwenden, können Sie Image auf dieselbe Weise eine Erweiterungsmethode hinzufügen, wie es Sri Harsha Chilakapati vorschlägt.

fun Image.toBufferedImage(): BufferedImage {
    if (this is BufferedImage) {
        return this
    }
    val bufferedImage = BufferedImage(this.getWidth(null), this.getHeight(null), BufferedImage.TYPE_INT_ARGB)

    val graphics2D = bufferedImage.createGraphics()
    graphics2D.drawImage(this, 0, 0, null)
    graphics2D.dispose()

    return bufferedImage
}

Und benutze es so:

myImage.toBufferedImage()
Steven Spungin
quelle