All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.examples.baseviewer.BaseViewerFX Maven / Gradle / Ivy

There is a newer version: 7.15.25
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * BaseViewerFX.java
 * ---------------
 */

package org.jpedal.examples.baseviewer;


import java.io.File;
import java.util.List;

import javafx.animation.Transition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.jpedal.PdfDecoderFX;
import org.jpedal.examples.viewer.gui.javafx.FXViewerTransitions;
import org.jpedal.examples.viewer.gui.javafx.FXViewerTransitions.TransitionDirection;
import org.jpedal.examples.viewer.gui.javafx.FXViewerTransitions.TransitionType;
import org.jpedal.examples.viewer.gui.javafx.dialog.FXInputDialog;
import org.jpedal.exception.PdfException;
import org.jpedal.external.PluginHandler;
import org.jpedal.objects.PdfPageData;
import org.jpedal.parser.DecoderOptions;

/**
 * 

BaseViewerFX

*
*

If you are compiling, you will need to download all the examples source files from : * How to View PDF File in Java.

*
*

Run directly from jar with java -cp jpedal.jar org/jpedal/examples/baseviewer/BaseViewerFX

*
*

There are plenty of tutorials on how to configure the Viewer on our website Support Section.

*
*

This class provides example code to create a bare-bones PDF Viewer in JavaFX.

*
*

Click here for a bare-bones PDF Viewer in Java Swing.

*
*

For more help and tutorials, visit our websites Support Section.

*/ public class BaseViewerFX extends Application { private final org.jpedal.PdfDecoderFX pdf = new org.jpedal.PdfDecoderFX(); PluginHandler customPluginHandle; public enum FitToPage { // control how we fit the content to the page AUTO, // AUTO will automatically fit the content to the stage depending on its orientation WIDTH, // WIDTH will fit the content to the stage width depending on its orientation HEIGHT, // HEIGHT will fit the content to the stage height depending on its orientation NONE } String PDFfile; // Variable to hold the current file/directory File file; // These two variables are to do with PDF encryption & passwords private String password; // Holds the password from the JVM or from User input private boolean closePasswordPrompt; // Controls whether or not we should close the prompt box // Layout panes private VBox top; private HBox bottom; private ScrollPane center; // Group is a container which holds the decoded PDF content private Group group; // For the location of the pdf file private Text fileLoc; private float scale = 1.0f; private final float[] scalings = {0.01f, 0.1f, 0.25f, 0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 2.0f, 4.0f, 7.5f, 10.0f}; private int currentScaling = 5; private static final float insetX = 25; private static final float insetY = 25; private int currentPage = 1; Stage stage; Scene scene; /* * Controls size of the stage, in theory setting this to a higher value will * increase image quality as there's more pixels due to higher image * resolutions */ static final int FXscaling = 1; FitToPage zoomMode = FitToPage.AUTO; private TransitionType transitionType = TransitionType.None; public static void main(final String[] args) { DecoderOptions.javaVersion = Float.parseFloat(System.getProperty("java.specification.version")); System.out.println("JAVA VERSION : " + DecoderOptions.javaVersion); if (DecoderOptions.javaVersion < 1.8f) { throw new RuntimeException("You need to Run Java 1.8+"); } launch(args); } /** * launches BaseViewerFX viewer using supplied stage for displaying PDF files * * @param stage is of type final Stage */ @Override public void start(final Stage stage) { stage.setTitle("Base Viewer FX - " + PdfDecoderFX.version); // Set transition if set in properites: String trans = System.getProperty("org.jpedal.fxtransition"); if (trans != null) { // Ensure correct lettering trans = trans.substring(0, 1).toUpperCase() + trans.substring(1).toLowerCase(); transitionType = TransitionType.valueOf(trans); } // Set page if set in JVM flag final String pageNum = System.getProperty("org.jpedal.page"); if (pageNum != null) { currentPage = Integer.parseInt(pageNum); } this.stage = stage; scene = setupViewer(800, 600); // Get command line arguments final List args = this.getParameters().getUnnamed(); /* * setup initial display * Setting this before loadPDF() gives access to the toolbar buttons * when called in loadPDF() via id. */ stage.setScene(scene); stage.show(); if (args.size() == 1) { final String input = args.get(0); file = new File(input); Platform.runLater(new Runnable() { @Override public void run() { loadPDF(file); // Unset the page if (System.getProperty("org.jpedal.page") != null) { System.setProperty("org.jpedal.page", ""); } } }); } addListeners(); } /** * creates all the components and adds change listeners for auto-centering * for JavaFX PDF viewer * * @param w The width to use for the viewer * @param h The height to use for the viewer * @return scene */ public Scene setupViewer(final int w, final int h) { // Setting up layout panes and assigning them to the appropiate locations final BorderPane root = new BorderPane(); top = new VBox(); root.setTop(top); top.getChildren().add(setupToolBar()); bottom = new HBox(); bottom.setPadding(new Insets(0, 10, 0, 10)); root.setBottom(bottom); center = new ScrollPane(); center.setPannable(true); center.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); center.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); // Needs to be added via group so resizes group = new Group(); group.getChildren().add(pdf); center.setContent(group); root.setCenter(center); center.viewportBoundsProperty().addListener(new ChangeListener() { @Override public void changed(final ObservableValue ov, final Bounds ob, final Bounds nb) { adjustPagePosition(nb); } }); // Sets the text to be displayed at the bottom of the FX Viewer fileLoc = new Text("No PDF Selected"); fileLoc.setId("file_location"); bottom.getChildren().add(fileLoc); scene = new Scene(root, w * FXscaling, h * FXscaling); return scene; } public void addListeners() { // Auto adjust so dynamically resized as viewer width alters scene.widthProperty().addListener(new ChangeListener() { @Override public void changed(final ObservableValue observableValue, final Number oldSceneWidth, final Number newSceneWidth) { fitToX(zoomMode); } }); scene.heightProperty().addListener(new ChangeListener() { @Override public void changed(final ObservableValue observableValue, final Number oldSceneHeight, final Number newSceneHeight) { fitToX(zoomMode); } }); /* * Controls for dragging a PDF into the scene * Using the dragboard, which extends the clipboard class, * detect a file being dragged onto the scene and if the user drops the file * we load it. */ scene.setOnDragOver(new EventHandler() { @Override public void handle(final DragEvent event) { final Dragboard db = event.getDragboard(); if (db.hasFiles()) { event.acceptTransferModes(TransferMode.COPY); } else { event.consume(); } } }); scene.setOnDragDropped(new EventHandler() { @Override public void handle(final DragEvent event) { final Dragboard db = event.getDragboard(); boolean success = false; if (db.hasFiles()) { success = true; // Only get the first file from the list file = db.getFiles().get(0); Platform.runLater(new Runnable() { @Override public void run() { loadPDF(file); } }); } event.setDropCompleted(success); event.consume(); } }); } /** * Sets up a MenuBar to be used at the top of the window. * It contains one Menu - navMenu - which allows the user to open and navigate pdf files * * @return ToolBar object used at the top of the user interface */ private ToolBar setupToolBar() { final ToolBar toolbar = new ToolBar(); final Button open = new Button("Open"); final Button back = new Button("Back"); final ComboBox pages = new ComboBox(); final Label pageCount = new Label(); final Button forward = new Button("Forward"); final Button zoomIn = new Button("Zoom in"); final Button zoomOut = new Button("Zoom out"); final Button fitWidth = new Button("Fit to Width"); final Button fitHeight = new Button("Fit to Height"); final Button fitPage = new Button("Fit to Page"); ComboBox transitionList = new ComboBox(); open.setId("open"); back.setId("back"); pageCount.setId("pgCount"); pages.setId("pages"); forward.setId("forward"); zoomIn.setId("zoomIn"); zoomOut.setId("zoomOut"); fitWidth.setId("fitWidth"); fitHeight.setId("fitHeight"); fitPage.setId("fitPage"); open.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { final FileChooser chooser = new FileChooser(); chooser.setTitle("Open PDF file"); //Open directory from existing directory if (file != null) { final File existDirectory = file.getParentFile(); if (existDirectory.exists()) { chooser.setInitialDirectory(existDirectory); } } //Set extension filter final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PDF files (*.pdf)", "*.pdf"); chooser.getExtensionFilters().add(extFilter); file = chooser.showOpenDialog(null); if (file != null) { Platform.runLater(new Runnable() { @Override public void run() { loadPDF(file); } }); } } }); pages.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener() { @Override public void changed(final ObservableValue ov, final Number oldVal, final Number newVal) { if (newVal.intValue() != -1 && newVal.intValue() + 1 != currentPage) { final int newPage = newVal.intValue() + 1; goToPage(newPage); } } }); back.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { if (currentPage > 1) { goToPage(currentPage - 1); } } }); forward.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { if (currentPage < pdf.getPageCount()) { goToPage(currentPage + 1); } } }); zoomIn.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.NONE; if (currentScaling < scalings.length - 1) { currentScaling = findClosestIndex(scale, scalings); if (scale >= scalings[findClosestIndex(scale, scalings)]) { currentScaling++; } scale = scalings[currentScaling]; } pdf.setPageParameters(scale, currentPage); adjustPagePosition(center.getViewportBounds()); } }); zoomOut.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.NONE; if (currentScaling > 0) { currentScaling = findClosestIndex(scale, scalings); if (scale <= scalings[findClosestIndex(scale, scalings)]) { currentScaling--; } scale = scalings[currentScaling]; } pdf.setPageParameters(scale, currentPage); adjustPagePosition(center.getViewportBounds()); } }); fitWidth.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.WIDTH; fitToX(FitToPage.WIDTH); } }); fitHeight.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.HEIGHT; fitToX(FitToPage.HEIGHT); } }); fitPage.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.AUTO; fitToX(FitToPage.AUTO); } }); final Region spacerLeft = new Region(); final Region spacerRight = new Region(); HBox.setHgrow(spacerLeft, Priority.ALWAYS); HBox.setHgrow(spacerRight, Priority.ALWAYS); // Set up the ComboBox for transitions final ObservableList options = FXCollections.observableArrayList(); for (final TransitionType transition : TransitionType.values()) { options.add(transition.name()); } if (!options.isEmpty()) { transitionList = new ComboBox(options); // Put before setValue so that setValue triggers the event transitionList.valueProperty().addListener(new ChangeListener() { @Override public void changed(final ObservableValue ov, final String oldVal, final String newVal) { transitionType = TransitionType.valueOf(newVal); } }); transitionList.setValue(options.get(transitionType.ordinal())); } toolbar.getItems().addAll(open, spacerLeft, back, pages, pageCount, forward, zoomIn, zoomOut, spacerRight, transitionList); return toolbar; } /** * Take a File handle to PDF file on local file system and displays in PDF viewer * * @param input The PDF file to load in the viewer */ public void loadPDF(final File input) { if (input == null) { return; } scale = 1; // Reset to default for new page PDFfile = input.getAbsolutePath(); fileLoc.setText(PDFfile); openFile(input, null, false); } /** * Take a File handle to PDF file on local file system and displays in PDF viewer * * @param input The PDF file to load in the viewer */ public void loadPDF(final String input) { if (input == null) { return; } scale = 1; // Reset to default for new page PDFfile = input; fileLoc.setText(PDFfile); if (input.startsWith("http")) { openFile(null, input, true); } else { openFile(new File(input), null, false); } } private void openFile(final File input, final String url, final boolean isURL) { try { // Open the pdf file so we can check for encryption if (isURL) { pdf.openPdfFileFromURL(url, false); } else { pdf.openPdfFile(input.getAbsolutePath()); } if (customPluginHandle != null) { if (isURL) { customPluginHandle.setFileName(url); } else { customPluginHandle.setFileName(input.getAbsolutePath()); } } if (System.getProperty("org.jpedal.page") != null && !System.getProperty("org.jpedal.page").isEmpty()) { currentPage = currentPage < 1 ? 1 : currentPage; currentPage = currentPage > pdf.getPageCount() ? pdf.getPageCount() : currentPage; } else { currentPage = 1; } // This code block deals with user input and JVM passwords in Encrypted PDF documents. if (pdf.isEncrypted()) { int passwordCount = 0; // Monitors how many attempts there have been to the password closePasswordPrompt = false; // Do not close the prompt box // While the PDF content is not viewable, repeat until the correct password is found while (!pdf.isFileViewable() && !closePasswordPrompt) { /* * See if there's a JVM flag for the password & Use it if there is * Otherwise prompt the user to enter a password */ if (System.getProperty("org.jpedal.password") != null) { password = System.getProperty("org.jpedal.password"); } else if (!closePasswordPrompt) { showPasswordPrompt(passwordCount); } // If we have a password, try and open the PdfFile again with the password if (password != null) { if (isURL) { pdf.openPdfFileFromURL(url, false, password); } else { pdf.openPdfFile(input.getAbsolutePath()); } } passwordCount += 1; // Increment he password attempt } } // Set up top bar values ((Labeled) top.lookup("#pgCount")).setText("/" + pdf.getPageCount()); final ComboBox pages = ((ComboBox) top.lookup("#pages")); pages.getItems().clear(); for (int i = 1; i <= pdf.getPageCount(); i++) { pages.getItems().add(String.valueOf(i)); } // Goes to the first page and starts the decoding process goToPage(currentPage); } catch (final PdfException ex) { ex.printStackTrace(); } } /** * This method will show a popup box and request for a password. * If the user does not enter the correct password it will ask them to try again. * If the user presses the Cross button, the password prompt will close. * * @param passwordCount is an int which represents the current input attempt */ private void showPasswordPrompt(final int passwordCount) { // Setup password prompt content final Text titleText = new Text("Password Request"); final TextField inputPasswordField = new TextField("Please Enter Password"); // If the user has attempted to enter the password more than once, change the text if (passwordCount >= 1) { titleText.setText("Incorrect Password"); inputPasswordField.setText("Please Try Again"); } final FXInputDialog passwordInput = new FXInputDialog(stage, titleText.getText()) { @Override protected void positiveClose() { super.positiveClose(); closePasswordPrompt = true; } }; password = passwordInput.showInputDialog(); } private void fitToX(final FitToPage fitToPage) { if (fitToPage == FitToPage.NONE) { return; } final float pageW = pdf.getPdfPageData().getCropBoxWidth2D(currentPage); final float pageH = pdf.getPdfPageData().getCropBoxHeight2D(currentPage); final int rotation = pdf.getPdfPageData().getRotation(currentPage); // Handle how we auto fit the content to the page if (fitToPage == FitToPage.AUTO && (pageW < pageH)) { if (pdf.getPDFWidth() < pdf.getPDFHeight()) { fitToX(FitToPage.HEIGHT); } else { fitToX(FitToPage.WIDTH); } } // Handle how we fit the content to the page width or height if (fitToPage == FitToPage.WIDTH) { final float width = (float) (scene.getWidth()); if (rotation == 90 || rotation == 270) { scale = (width - insetX - insetX) / pageH; } else { scale = (width - insetX - insetX) / pageW; } } else if (fitToPage == FitToPage.HEIGHT) { final float height = (float) (scene.getHeight() - top.getBoundsInLocal().getHeight() - bottom.getHeight()); if (rotation == 90 || rotation == 270) { scale = (height - insetY - insetY) / pageW; } else { scale = (height - insetY - insetY) / pageH; } } pdf.setPageParameters(scale, currentPage); } /** * Locate scaling value closest to current scaling setting * * @param scale float value of the scale value to check * @param scalings float array holding scaling values * @return int value of the index from scalings closest to the value of scale */ private static int findClosestIndex(final float scale, final float[] scalings) { float currentMinDiff = Float.MAX_VALUE; int closest = 0; for (int i = 0; i < scalings.length - 1; i++) { final float diff = Math.abs(scalings[i] - scale); if (diff < currentMinDiff) { currentMinDiff = diff; closest = i; } } return closest; } private void decodePage() { try { final PdfPageData pageData = pdf.getPdfPageData(); final int rotation = pageData.getRotation(currentPage); //rotation angle of current page /* * Only call this when the page is displayed vertically, otherwise * it will mess up the document cropping on side-ways documents. */ if (rotation == 0 || rotation == 180) { pdf.setPageParameters(scale, currentPage); } pdf.decodePage(currentPage); //wait to ensure decoded pdf.waitForDecodingToFinish(); } catch (final Exception e) { e.printStackTrace(); } fitToX(FitToPage.AUTO); updateNavButtons(); setBorder(); adjustPagePosition(center.getViewportBounds()); } private void updateNavButtons() { if (currentPage > 1) { top.lookup("#back").setDisable(false); } else { top.lookup("#back").setDisable(true); } if (currentPage < pdf.getPageCount()) { top.lookup("#forward").setDisable(false); } else { top.lookup("#forward").setDisable(true); } ((ComboBox) top.lookup("#pages")).getSelectionModel().select(currentPage - 1); } private void goToPage(final int newPage) { final TransitionDirection direction; // For sliding Transitions if (transitionType != TransitionType.Fade || transitionType != TransitionType.None) { direction = newPage > currentPage ? TransitionDirection.LEFT : TransitionDirection.RIGHT; } else { direction = TransitionDirection.NONE; } switch (transitionType) { case Fade: startTransition(newPage, direction); break; case Scale: startTransition(newPage, direction); break; case Rotate: startTransition(newPage, direction); break; case CardStack: startTransition(newPage, direction); break; default: //no transition currentPage = newPage; decodePage(); break; } } private void startTransition(final int newPage, final TransitionDirection direction) { final Transition exitTransition = FXViewerTransitions.exitTransition(pdf, transitionType, direction); if (exitTransition != null) { exitTransition.setOnFinished(new EventHandler() { @Override public void handle(final ActionEvent t) { currentPage = newPage; Platform.runLater(new Runnable() { @Override public void run() { decodePage(); } }); TransitionDirection entryDirection = direction; if (direction != TransitionDirection.NONE) { entryDirection = direction == TransitionDirection.LEFT ? TransitionDirection.RIGHT : TransitionDirection.LEFT; } final Transition entryTransition = FXViewerTransitions.entryTransition(pdf, transitionType, entryDirection); entryTransition.play(); } }); exitTransition.play(); } } /** * @return the case sensitive full path and name of the PDF file */ public String getPDFfilename() { return PDFfile; } private void adjustPagePosition(final Bounds nb) { double adjustment = ((nb.getWidth() / 2) - (group.getBoundsInLocal().getWidth() / 2)); // Keep the group within the viewport of the scrollpane if (adjustment < 0) { adjustment = 0; } group.setTranslateX(adjustment); } // Set a space between the top toolbar and the page private void setBorder() { // Why it's easier to use a dropshadow for this is beyond me, but here it is... final int rotation = pdf.getPdfPageData().getRotation(currentPage); final double x = (rotation == 90 || rotation == 270) ? 40 : 0; final double y = (rotation == 90 || rotation == 270) ? 0 : 40; final DropShadow pdfBorder = new DropShadow(0, x, y, Color.TRANSPARENT); pdf.setEffect(pdfBorder); } public void addExternalHandler(final PluginHandler customPluginHandle) { this.customPluginHandle = customPluginHandle; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy