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: 20151002
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-2016 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * 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; /** * Enum to control how we fit the content to the page. * * AUTO will automatically fit the content to the stage depending on its orientation * WIDTH will fit the content to the stage width depending on its orientation * HEIGHT will fit the content to the stage height depending on its orientation */ public enum FitToPage{ AUTO, WIDTH, HEIGHT, NONE } String PDFfile; //Variable to hold the current file/directory File file; //These two variables are todo with PDF encryption & passwords private String password; //Holds the password from the JVM or from User input private boolean closePasswordPrompt; //boolean 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(); // this.getParameters().getUnamed() will never be null according to FX Javadoc, so no null check needed // http://docs.oracle.com/javafx/2/api/javafx/application/Application.Parameters.html#getUnnamed%28%29 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 (see http://pixelduke.wordpress.com/2012/09/16/zooming-inside-a-scrollpane/) 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 */ 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 the PDF File */ 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); } }}); // Navigate backward back.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { if (currentPage > 1) { goToPage(currentPage - 1); } } }); // Navigate forward forward.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { if (currentPage < pdf.getPageCount()) { goToPage(currentPage + 1); } } }); // Zoom in 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()); } }); // Zoom out 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()); } }); // Fit to width fitWidth.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.WIDTH; fitToX(FitToPage.WIDTH); } }); // Fit to height fitHeight.setOnAction(new EventHandler() { @Override public void handle(final ActionEvent t) { zoomMode = FitToPage.HEIGHT; fitToX(FitToPage.HEIGHT); } }); // Fit to Page 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 filesystem 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 filesystem 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,String url, 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()); } //pdf.setEncryptionPassword(password); } 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() 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){ // (new scrollbar width / 2) - (page width / 2) 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(PluginHandler customPluginHandle){ this.customPluginHandle=customPluginHandle; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy