Wie kann eine PDF-Datei angezeigt werden?

PDF-Dateien können mit Hilfe der Klasse Desktop in einem externen PDF-Reader angezeigt werden. Soll die PDF-Datei in einem Java-Programm geladen werden, so muss eine externe Bibliothek eingebunden werden. Im Beispiel wird dies anhand von ICEpdf gezeigt.

PDF in einem externen PDF-Reader anzeigen

Das Öffnen eines externen Standard-PDF-Readers erfolgt mittels der Klasse Desktop. Das Beispiel öffnet die Datei test.pdf, die im Home-Verzeichnis des Nutzers liegt, in dessen als Standard-Anzeigeprogramm eingerichteten PDF-Reader.
Hierzu wird zunächst ein Objekt vom Typ java.awt.Desktop erzeugt und dessen Methode open() die gewünschte Datei übergeben. Dies geschieht dadurch, dass mit dem String des absoluten Pfades zur Datei ein File-Objekt erzeugt wird, das dann als Parameter an open() übergeben wird. Der Rest geschieht automatisch. Zumindest in dem Fall, in dem eine Standard-Anwendung zum Öffnen von PDF-Dateien beim verwendeten System registriert ist.
Ist dies nicht der Fall, so wird eine Exception geworfen. Um diese, sowie Ein-Ausgabe-Fehler abzufangen, muss die Erzeugung des Desktop-Objektes und das Öffnen der Datei in einem try-catch-Block erfolgen.

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;

public class PDFExternAnzeigen {

    public static void main(String[] args) {
        try {
            Desktop desktop = Desktop.getDesktop();
            if (desktop != null && desktop.isSupported(Desktop.Action.OPEN)) {
                desktop.open(new File(System.getProperty("user.home")
                        + "/test.pdf"));
            } else {
                System.err.println("PDF-Datei kann nicht angezeigt werden!");
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

PDF im Java-Programm selbst anzeigen

Java bietet mit seinen Core-Dateien leider z.Zt. (Java 8) keine Möglichkeit, eine PDF-Datei anzuzeigen. Hierzu muss auf externe Bibliotheken zurückgegriffen werden. Allerdings sind einige im Internet zu finden, die teilweise auch kostenlos und/oder als OpenSource angeboten werden.
Für das folgende Beispiel wird IcePdf verwendet. Die Bibliothek ist selbst vollständig in Java geschrieben. Um das Beispiel nachvollziehen zu können, sollte die ZIP-Datei mit den bin-Dateien heruntergeladen, entpackt und die Dateien icepdf-core.jar und icepdf-viewer.jar nach der Anleitung unter Grundlagen/Bibliothek einbinden in das Projekt eingebunden werden.

Das Beispiel demonstriert, wie eine PDF-Datei aus dem Internet geladen, im temporären Verzeichnis des Systems zwischengespeichert und dann innerhalb eines JFrame geladen werden kann.

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ResourceBundle;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.icepdf.ri.common.SwingController;
import org.icepdf.ri.common.SwingViewBuilder;
import org.icepdf.ri.util.PropertiesManager;

public class PDFAnzeigen {

    public PDFAnzeigen() {
        String pdfPath = loadPDF("http://www.javabeginners.de/Test.pdf");
        if (pdfPath == null) {
                    System.err
                            .println("Datei kann nicht geladen werden oder ist keine PDF-Datei.");
                    System.exit(1);
                }
        SwingController controller = new SwingController();
        createGUI(controller);
        controller.openDocument(pdfPath);
    }

    public static void main(String[] args) {
        new PDFAnzeigen();
    }

    public String loadPDF(String adresse) {
        if (!adresse.toLowerCase().endsWith("pdf"))
                    return null;
                String fileName = adresse.substring(adresse.lastIndexOf("/") + 1,
                        adresse.lastIndexOf("."));
                String suffix = adresse.substring(adresse.lastIndexOf("."),
                        adresse.length());
        File temp = null;
        try (InputStream in = new URL(adresse).openStream()) {
            temp = File.createTempFile(fileName, suffix);
            temp.deleteOnExit();
            Files.copy(in, Paths.get(temp.toURI()),
                    StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temp.getAbsolutePath();
    }

   public static void createGUI(SwingController controller) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setLocationRelativeTo(null);
        frame.setTitle("PDF anzeigen");
        frame.setVisible(true);

        PropertiesManager properties = new PropertiesManager(
                System.getProperties(),
                ResourceBundle
                        .getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE));
        properties.set(PropertiesManager.PROPERTY_DEFAULT_ZOOM_LEVEL, "1.5");
        properties.set(PropertiesManager.PROPERTY_VIEWPREF_HIDETOOLBAR, "true");

        // nur für Event-Handling notwendig
        // controller.setIsEmbeddedComponent(true);
        SwingViewBuilder builder = new SwingViewBuilder(controller, properties);
        JPanel viewerPanel = builder.buildViewerPanel();
        frame.getContentPane().add(viewerPanel);
    }
}

Neben main() und dem Konstruktor enthält die Klasse zwei Methoden, die für die Erzeugung der Programmoberfläche und das Laden der PDF-Datei verantwortlich sind. Beide Methoden werden im Konstruktor aufgerufen.

In createGUI() wird zunächst das Programmfenster auf Basis eine JFrame erzeugt, hinsichtlich Größe, Titel, Verhalten beim Schließen, etc. konfiguriert und schließlich sichtbar gemacht.
In der Folge wird ein PropertyManager-Objekt erzeugt. Es ist für die Regelung der Eigenschaften des PDF-Viewers zuständig. Die Klasse enthält eine ganze Reihe statischer Felder, mit denen Voreinstellungen und Eigenschaften des PDF-Viewers beeinflusst werden können. Im vorliegenden Beispiel werden die Größe der Darstellung auf 150% gesetzt und die Toolbar verborgen.
Ein SwingViewBuilder-Objekt erzeugt den eigentlichen PDF-Viewer, der dann in ein JPanel eingebettet wird. Das Panel wird schließlich auf den Content-Pane des JFrame geladen.

Die Methode loadPDF() nimmt die Internet-Adresse zu einer PDF-Datei in Form eines Strings als Parameter entgegen und gibt den absoluten Pfad zu der heruntergeladenen, dann temporär gespeicherten Datei ebenfalls als String zurück.
Zunächst werden der Dateiname, sowie deren Endung ausgelesen und in zwei Variablen abgelegt. Beide werden später verwendet, um eine gleichnamige temporäre Datei zu erzeugen. Vorher wird jedoch erst geprüft, ob es sich um eine PDF-Datei handelt. Ist dies nicht der Fall, wird die Methode abgebrochen. Innerhalb eines try-catch-Blockes, um Ein-Ausgabe-Fehler abzufangen, wird die Datei dann durch einen InputStream geladen. Im systemeigenen temporären Verzeichnis wird das File-Objekt einer Datei mit Hilfe des ermittelten Dateibezeichners gebildet und so konfiguriert, dass diese beim Beenden der Anwendung wieder gelöscht wird.
Die durch den ImputStream geladene Datei wird in die neu erzeugte Datei kopiert und deren absoluter Pfad dann von der Methode zurückgegeben.

Im Konstruktor wird zunächst diese Methode ausgeführt und der ermittelte Pfad zwischengespeichert sowie überprüft. Dann wird ein Objekt vom Typ SwingController erzeugt. Es stellt die Verbindung zwischen dem User-Interface und dem eigentlichen PDF-Dokument dar und wird der Methode createGUI() als Parameter übergeben. Auf diesem Controller-Objekt wird dessen Methode openDocument() aufgerufen, die mit Hilfe des zwischengespeicherten Pfades schließlich die Datei öffnet und anzeigt.