Lesen einer Bilddatei die sich in der JAR befindet


#1

Hallo Leute,

Ich habe eben ein Programm mit Netbeans geschrieben, als ich fertig war startete ich es nicht über Netbeans sondern die eigentliche Jar File.

Ich musste feststellen das die Bilder nicht angezeigt werden.

Ich habe jetzt 4 Stunden damit verbraucht mit getResource irgendwas zu laden ohne Erfolg.

Package Verzeichnis

myApp.ui. Hier ist die JavaFX Klasse
myApp.ui.bilder.bilder hier sind die Bilder

Wie erstelle ich jetzt eine JavaFX Image? Bin mit den Nerven am Ende.


#2

Wäre sicher gut hier auch Code von dir zu sehen. Aber prinzipiell: mit getResource kannst du auf Dateien innerhalb der Jar lesend zugreifen. Dabei kannst du einen relativen Pfad (ui/images) oder einen absoluten Pfad (/ich/bin/absolut/weil/slash/am/Anfang). Bei deinem absoluten Pfad ist das root-verzeichnis deiner Jar auch zugeleich dein root.


#3
                URL resource = MyJavaFX.class.getResource("/myApp/ui/bilder/bilder/" + figur.getName() + ".png");
               

                Image img = new Image(resource.toString());

Das ist der Code, er funktioniert wenn ich es aus Netbeans starte, nicht aber wenn ich die JAr starte.

Das hier startet auch in Netbeans aber nicht wenn ich die JAR ausführe:

           BufferedImage bufferedImage = ImageIO.read(resource);
               
                Image img = SwingFXUtils.toFXImage(bufferedImage, null);

#4

Schonmal nachgeschaut, ob sich die Bilder auch tatsächlich in der Jar befinden?


#5

Natuerlich


#6

Was sagt die Konsole, welche Exception wird geschmissen. Möglicherweise passt der Pfad doch nicht mehr.

Hast du die Möglichkeit die Jar hier zu posten?


#7

Warum so umständlich?

InputStream inputStream = MyJavaFX.class.getResourceAsStream("/myApp/ui/bilder/bilder/" + figur.getName() + ".png");

Image img = new Image(inputStream);

Dazu dann noch einen Check ob inputStream nicht vielleicht null ist und eventuell eine Meldung auf der Konsole ausgeben.

Wenn man beim obigen bleiben möchte, dann kann man sich auch noch anschauen was bei resource.toString() rauskommt.

Ansonsten ist der Pfad falsch, Groß/Kleinschreibung beachten oder die Dateien sind nicht im JAR vorhanden.


#8

Damit hab ich mich auch mal herumgeschlagen und mir folgende Hilfsklasse geschrieben:

import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.swing.Icon;
import javax.swing.ImageIcon;

/**
 * Diese Klasse bietet Möglichkeiten, benannte Grafikdateien zu laden.
 */

public class IconLoader {

    /**
     * Dieses Verzeichnis bietet sprechende Kürzel für die Namen von Bilddateien
     * (ohne Pfad). Es ist empfehlenswert, im anwendenden Programm diese
     * sprechenden Namen wiederum als Konstanten zu definieren in etwa so:         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String INSPECT = "INSPECT";                                <br><br>
     *
     * später kann dann im Programm per                                            <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br>&nbsp;&nbsp;&nbsp;&nbsp;
     *     iconloader.addPictureIdentifier(INSPECT, "ecke_inspizieren.gif");       <br><br>
     *
     * der Verweis eingetragen werden. Mit                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Icon icon = iconloader.load(INSPECT);                                   <br><br>
     *
     * kann dann das Bild geladen werden.
     */
    private final Map<String, String> pictureByIdentifier;

    /** Eine Klasse, bei der die Bilddateien liegen. */
    private final Class<?> clazz;

    /**
     * Kürzel für das Bild für das Programm. Dieses muss vorher per                <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String PROGRAMM_IMAGE = "PROGRAM_IMAGE";                   <br><br>
     *
     * definiert und dem IconLoader per                                            <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br>&nbsp;&nbsp;&nbsp;&nbsp;
     *     iconloader.addPictureIdentifier(PROGRAMM_IMAGE, "ged24.jpg");           <br><br>
     *
     * bekannt gemacht werden. Mit                                                 <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Image image = iconloader.loadProgramIconImage();                        <br><br>
     *
     * kann dann das Bild geladen werden.
     *
     */
    private final String programmImageIdentifier;

    /**
     * Konstruktor
     *
     * @param clazz
     *            Klasse, bei der die Resourcen liegen. Hierbei bietet es sich
     *            an, die Bilder in einem extra Verzeichnis unterzubringen,
     *            etwa src/ui/resources und dann dort eine Klasse anzulegen,
     *            die die Bilderkürzel der Form                                    <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *                static final String INSPECT = "INSPECT";                     <br><br>
     *
     *            enthält.
     * @param programmImageIdentifier
     *            Kürzel für das Bild zum Programm. Dieses sollte vorher per       <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *                static final String PROGRAMM_IMAGE = "PROGRAM_IMAGE";        <br><br>
     *
     *            definiert werden.
     */
    public IconLoader(Class<?> clazz, String programmImageIdentifier) {
        this.clazz = clazz;
        this.programmImageIdentifier = programmImageIdentifier;
        pictureByIdentifier = new HashMap<>();
    }

    /**
     * Fügt ein Kürzel für eine Bilddatei hinzu. Das Kürzel selbst sollte so
     * definitiert werden:                                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String INSPECT = "INSPECT";                                <br><br>
     *
     * Dann kann im Programm per                                                   <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br>&nbsp;&nbsp;&nbsp;&nbsp;
     *     iconloader.addPictureIdentifier(INSPECT, "ecke_inspizieren.gif");       <br><br>
     *
     * der Verweis eingetragen werden. Mit                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Icon icon = iconloader.loadIcon(INSPECT);                               <br><br>
     *
     * oder                                                                        <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Image programImage = iconloader.loadImage(INSPECT);                     <br><br>
     *
     * kann schließlich das Bild geladen werden.
     *
     * @param pictureIdentifier
     *            Kürzel für das Bild.
     * @param pictureFileNameWithoutPath
     *            Name der Bilddatei ohne Pfad, also etwa
     *            "ecke_inspizieren.gif".
     */
    public void addPictureIdentifier(String pictureIdentifier, String pictureFileNameWithoutPath) {
        pictureByIdentifier.put(pictureIdentifier, pictureFileNameWithoutPath);
    }

    /**
     * Diese Methode lädt ein Bild zu einem Kürzel für dieses Bild. Das
     * Kürzel Dieses muss vorher per                                               <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String INSPECT = "INSPECT";                                <br><br>
     *
     * definiert werden und kann dann per                                          <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br>&nbsp;&nbsp;&nbsp;&nbsp;
     *     iconloader.addPictureIdentifier(INSPECT, "ecke_inspizieren.gif");       <br><br>
     *
     * der Verweis eingetragen werden. Mit                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Icon icon = iconloader.loadIcon(INSPECT);                               <br><br>
     *
     * kann später das hinterlegte Bild geladen werden.
     *
     * @param pictureIdentifier
     *            Kürzel für das Bild.
     * @return Icon mit dem gewünschten Bild.
     */
    public Icon loadIcon(String pictureIdentifier) {
        URL url = getResource(pictureIdentifier);
        Icon icon = new ImageIcon(url);
        return icon;
    }

    /**
     * Gibt das Icon des Programms als Image zurück. Dafür sollte vorher
     * ein Kürzel auf die folgende Weise hinterlegt werden:                        <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String PROGRAMM_IMAGE = "PROGRAM_IMAGE";                   <br><br>
     *
     * Bei der Erzeugung des IconLoaders wird dieses dann angegeben:               <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br><br>
     *
     * Mit                                                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Image image = iconloader.loadProgramIconImage();                        <br><br>
     *
     * kann dann das Bild geladen werden.
     */
    public Image loadProgramIconImage() {
        return loadImage(programmImageIdentifier);
    }

    /**
     * Diese Methode lädt ein Bild zu einem Kürzel für dieses Bild. Das
     * Kürzel Dieses muss vorher per                                               <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     static final String INSPECT = "INSPECT";                                <br><br>
     *
     * definiert werden und kann dann per                                          <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     IconLoader iconloader = new IconLoader(..., PROGRAMM_IMAGE);            <br>&nbsp;&nbsp;&nbsp;&nbsp;
     *     iconloader.addPictureIdentifier(INSPECT, "ecke_inspizieren.gif");       <br><br>
     *
     * der Verweis eingetragen werden. Mit                                         <br><br>&nbsp;&nbsp;&nbsp;&nbsp;
     *
     *     Image programImage = iconloader.loadImage(INSPECT);                     <br><br>
     *
     * kann schließlich das Bild geladen werden.
     *
     * @param pictureIdentifier
     *            Kürzel für das Bild.
     * @return Image mit dem gewünschten Bild.
     */
    public Image loadImage(String pictureIdentifier) {
        URL url = getResource(pictureIdentifier);
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Image imgage = toolkit.createImage(url);

        return imgage;
    }

    /**
     * Lädt eine Resource (etwa ein Bild) über einen Dateinamen ohne Pfad bei der hinterlegten
     * Klasse.
     *
     * @param pictureIdentifier
     *            Kürzel für das Bild.
     * @return URL zu dem gewünschten Bild.
     * @throws RuntimeException
     *             Falls das Kürzel für das Bild unbekannt ist oder für den zum Kürzel hinterlegten
     *             Resourcenamen keine solche Resource bekannt ist.
     */
    private URL getResource(String pictureIdentifier) {
        if (!pictureByIdentifier.containsKey(pictureIdentifier)) {
            throw new RuntimeException("Das Kürzel '" + pictureIdentifier
                    + "' ist nicht bekannt!");
        }
        String pictureFileNameWithoutPath = pictureByIdentifier.get(pictureIdentifier);
        URL url = clazz.getResource(pictureFileNameWithoutPath);
        if (null == url) {
            throw new RuntimeException("Zum Kürzel '" + pictureIdentifier
                    + "' ist der Dateiname '" + pictureFileNameWithoutPath
                    + "' hinterlegt. Zu diesem wurde aber keine Resource gefunden!");
        }
        return url;
    }

}

Vielleicht nutzt sie dir was. Ich habe dann dort, wo ich die Klasse verwende, ein Verzeichnis “resources” erstellt, in dem die Bilddateien liegen sowie eine Datei der Art

public class IconDefinitions {

    /** Kürzel für das Bild des Programms. */
    public static final String PROGRAMM_IMAGE = "PROGRAM_IMAGE";

    public static final String GED_PROGRAMM_ICON = "GED_PROGRAMM_ICON";
    public static final String INSPECT = "INSPECT";
    public static final String ADD_VERTEX = "ADD_VERTEX";
    public static final String ADD_UNDIRECTED_EDGE = "ADD_UNDIRECTED_EDGE";
    public static final String ADD_EDGE_TO_VERTEX = "ADD_EDGE_TO_VERTEX";
    public static final String ADD_EDGE_FROM_VERTEX = "ADD_EDGE_FROM_VERTEX";
    public static final String ADD_BOTH_DIRECTED_EDGE = "ADD_BOTH_DIRECTED_EDGE";
    public static final String MOVE_VERTEX = "MOVE_VERTEX";
    public static final String DELETE_VERTEX = "DELETE_VERTEX";
    public static final String MERGE_VERTEX = "MERGE_VERTEX";
    public static final String DELETE_EDGE = "DELETE_EDGE";
    public static final String DELETE_MULTIPLE_EDGES = "DELETE_MULTIPLE_EDGES";
    public static final String FILE_NEW = "FILE_NEW";
    public static final String FILE_LOAD = "FILE_LOAD";
    public static final String FILE_SAVE = "FILE_SAVE";
    public static final String FILE_SAVE_AS = "FILE_SAVE_AS";
    public static final String HISTORY_PREVIOUS = "HISTORY_PREVIOUS";
    public static final String HISTORY_NEXT = "HISTORY_NEXT";
    public static final String MOVE_GRAPH_LEFT = "MOVE_GRAPH_LEFT";
    public static final String MOVE_GRAPH_UP = "MOVE_GRAPH_UP";
    public static final String MOVE_GRAPH_DOWN = "MOVE_GRAPH_DOWN";
    public static final String MOVE_GRAPH_RIGHT = "MOVE_GRAPH_RIGHT";
    public static final String CENTER_GRAPH = "CENTER_GRAPH";
    public static final String MAXIMIZE_GRAPH = "MAXIMIZE_GRAPH";
    public static final String SMALLER_GRAPH = "SMALLER_GRAPH";
    public static final String BIGGER_GRAPH = "BIGGER_GRAPH";

    /**
     * Erzeugt einen IconLoader mit allen Bilddefinitionen.
     *
     * @return IconLoader
     */
    public IconLoader createIconLoader() {
        IconLoader iconLoader = new IconLoader(this.getClass(),
                PROGRAMM_IMAGE);
        iconLoader.addPictureIdentifier(PROGRAMM_IMAGE, "ged24.jpg");
        iconLoader.addPictureIdentifier(INSPECT, "ecke_inspizieren.gif");
        iconLoader.addPictureIdentifier(ADD_VERTEX, "ecke_neu.gif");
        iconLoader.addPictureIdentifier(ADD_UNDIRECTED_EDGE, "kante.gif");
        iconLoader.addPictureIdentifier(ADD_EDGE_TO_VERTEX, "kante_hin.gif");
        iconLoader.addPictureIdentifier(ADD_EDGE_FROM_VERTEX, "kante_zurueck.gif");
        iconLoader.addPictureIdentifier(ADD_BOTH_DIRECTED_EDGE, "kante_beide.gif");
        iconLoader.addPictureIdentifier(MOVE_VERTEX, "ecke_verschieben2.gif");

        iconLoader.addPictureIdentifier(DELETE_VERTEX, "ecke_weg.gif");
        iconLoader.addPictureIdentifier(MERGE_VERTEX, "ecke_mergen.gif");
        iconLoader.addPictureIdentifier(DELETE_EDGE, "kante_loeschen.gif");
        iconLoader.addPictureIdentifier(DELETE_MULTIPLE_EDGES, "kanten_loeschen.gif");

        /* Dateioperationen: */
        iconLoader.addPictureIdentifier(FILE_NEW, "datei_neu.gif");
        iconLoader.addPictureIdentifier(FILE_LOAD, "datei_oeffnen.gif");
        iconLoader.addPictureIdentifier(FILE_SAVE, "datei_speichern.gif");
        iconLoader.addPictureIdentifier(FILE_SAVE_AS, "datei_speichern_unter.gif");

        /* Historie: */
        iconLoader.addPictureIdentifier(HISTORY_PREVIOUS, "rueckgaengig.gif");
        iconLoader.addPictureIdentifier(HISTORY_NEXT, "wiederholung.gif");

        /* Knöpfe zur Beeinflusssung des ganzen Graphen: */
        iconLoader.addPictureIdentifier(MOVE_GRAPH_LEFT, "nach_links.gif");
        iconLoader.addPictureIdentifier(MOVE_GRAPH_UP, "nach_oben.gif");
        iconLoader.addPictureIdentifier(MOVE_GRAPH_DOWN, "nach_unten.gif");
        iconLoader.addPictureIdentifier(MOVE_GRAPH_RIGHT, "nach_rechts.gif");
        iconLoader.addPictureIdentifier(CENTER_GRAPH, "zentrieren.gif");
        iconLoader.addPictureIdentifier(MAXIMIZE_GRAPH, "zentrieren_plus.gif");
        iconLoader.addPictureIdentifier(SMALLER_GRAPH, "kleiner.gif");
        iconLoader.addPictureIdentifier(BIGGER_GRAPH, "groesser.gif");

        iconLoader.addPictureIdentifier(GED_PROGRAMM_ICON, "ged24.jpg");

        return iconLoader;
    }

}

Die Anwendung im Programm erfolgt dann so:

        IconDefinitions iconDefinitions = new IconDefinitions();
        IconLoader iconLoader = iconDefinitions.createIconLoader();
        frame.setIconImage(iconLoader.loadProgramIconImage());

Oder so:

        IconDefinitions iconDefinitions = new IconDefinitions();
        IconLoader iconLoader = iconDefinitions.createIconLoader();
        Icon icon = iconLoader.loadIcon(IconDefinitions.FILE_NEW);
        JButton emptyButton = new JButton(icon);

#9

Sieh dir auch mal den Wiki-Beitrag an: http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen_(Java)


#10

Darauf wollte ich auch verlinken, aber http://wiki.byte-welt.net/wiki/Grafikdateien_laden_und_anzeigen_(Java)#Bibliotheken_im_Classpath ist noch TODO…


#11

Lass dir spaßeshalber mal das ausgeben:

System.out.println( MyJavaFX.class.getResource("/").getFile().getAbsolutePath());

Meine Vermutung ist, dass es in dem Jar den Ordner myApp nicht gibt.

Probleme wegen Groß/Kleinschreibung hast Du sicher schon ausgeschlossen, oder?

bye
TT


#12

hmm, ich weiß nicht mehr, was ich da vor hatte, aber es darf sich jeder beteiligen. Wenn du eine Idee hast, was man da schreiben könnte, darfst du auch gerne loslegen, oder die anderen Teile auch gern berichtigen.