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

de.rpgframework.jfx.attach.impl.DesktopPDFViewerService Maven / Gradle / Ivy

There is a newer version: 5.2.1
Show newest version
package de.rpgframework.jfx.attach.impl;

import java.awt.image.BufferedImage;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.time.Duration;
import java.time.Instant;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.prelle.javafx.FlexibleApplication;
import org.prelle.javafx.SymbolIcon;

import com.mortennobel.imagescaling.ResampleOp;

import de.rpgframework.core.RoleplayingSystem;
import de.rpgframework.jfx.attach.PDFViewerConfig;
import de.rpgframework.jfx.attach.PDFViewerConfig.PathAndOffset;
import de.rpgframework.jfx.attach.PDFViewerService;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * @author prelle
 *
 */
public class DesktopPDFViewerService implements PDFViewerService, Runnable {

	private final static Logger logger = System.getLogger("rpgframework.pdf");

	private static String path = "/";

	private static ImageView iView;
	private static Scene scene;
	private static Stage stage;
	private static VBox parent;
	private static ButtonBar bar;
	private static Button btnPrev, btnNext;
	private static int currentPage;

	private static Thread displayThread;
	private static int nextPage;
	private static String nextPath;
	private static PDDocument pdDocument;
	private static PDFRenderer renderer;

	//-------------------------------------------------------------------
	public DesktopPDFViewerService() {
		System.out.println("DesktopPDFViewerService");
		logger.log(Level.INFO, "Initializing DesktopPDFViewerService via PDFBox");

		displayThread = new Thread(this, "PDFViewer");
		displayThread.start();
	}

	//-------------------------------------------------------------------
	public void run() {
		do {
			synchronized (logger) {
				try {
					logger.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
				logger.log(Level.INFO, "Render page {0} of {1}", nextPage, nextPath);
				try {
					if (!nextPath.equals(path)) {
						Instant start = Instant.now();
						logger.log(Level.INFO, "Load PDF");
						FlexibleApplication.getInstance().getAppLayout().getScene().setCursor(Cursor.WAIT);
						logger.log(Level.INFO, "Opening input stream");
						logger.log(Level.INFO, "Calling  PDDocument.load");
						pdDocument = Loader.loadPDF(
								 new RandomAccessReadBufferedFile(nextPath),
								 null,
								 null,
								 null, null);
						logger.log(Level.INFO, "Calling new PDFRenderer");
						renderer = new PDFRenderer(pdDocument);
						path = nextPath;
						logger.log(Level.INFO, "PDF newly loaded within {0} ms",Duration.between(start, Instant.now()).toMillis());
						FlexibleApplication.getInstance().getAppLayout().getScene().setCursor(Cursor.DEFAULT);
					}
					if (nextPage!=currentPage) {
						Instant start = Instant.now();
						logger.log(Level.INFO, "Start Rendering page {0}", nextPage);
						logger.log(Level.INFO, "Hints {0}", renderer.getRenderingHints());

						// Evil line
						BufferedImage image = renderer.renderImageWithDPI(nextPage, 300,ImageType.RGB);
						ResampleOp  resampleOp = new ResampleOp (image.getWidth()/3,image.getHeight()/3);
						image= resampleOp.filter(image, null);

//						BufferedImage image = renderer.renderImage(nextPage, 1.5f);
						image.createGraphics();
						Image fxImg = SwingFXUtils.toFXImage(image, null);
//						Image fxImg = new Image(ClassLoader.getSystemResourceAsStream("Rendering.jpg"));
						iView.setImage(fxImg);
//						iView.setFitHeight(fxImg.getHeight()/1.5);
//						iView.setFitWidth(fxImg.getWidth()/1.5);
						stage.setHeight(fxImg.getHeight()+56+bar.getHeight());
						stage.setWidth(fxImg.getWidth()+11);
						parent.requestLayout();
						currentPage = nextPage;
						logger.log(Level.INFO, "Rendering done in {0} ms",Duration.between(start, Instant.now()).toMillis());
					}
					if (!stage.isShowing()) {
						if (Platform.isFxApplicationThread())
							stage.show();
						else
							Platform.runLater( ()->stage.show() );
					}
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					Image fxImg = new Image(ClassLoader.getSystemResourceAsStream("Rendering.jpg"));
					iView.setImage(fxImg);
					stage.setHeight(fxImg.getHeight()+56+bar.getHeight());
					stage.setWidth(fxImg.getWidth()+11);
					parent.requestLayout();
					if (!stage.isShowing()) {
						if (Platform.isFxApplicationThread()) {
							stage.show();
						} else {
							Platform.runLater( () -> stage.show());
						}
					}
				}
		} while (true);
	}

	//-------------------------------------------------------------------
	private static void ensureStage() {
		if (stage==null) {
			iView = new ImageView();
			Image fxImg = new Image(ClassLoader.getSystemResourceAsStream("Rendering.jpg"));
			iView.setImage(fxImg);
			btnPrev = new Button(null,new SymbolIcon("back"));
			btnNext = new Button(null,new SymbolIcon("forward"));
			btnPrev.setOnAction(ev -> {
				if (currentPage>0) showPage(currentPage-1);
			});
			btnNext.setOnAction(ev -> showPage(currentPage+1));

			ScrollPane scroll = new ScrollPane(iView);
			scroll.setFitToWidth(true);
			bar = new ButtonBar();
			bar.getButtons().addAll(btnPrev, btnNext);
			parent = new VBox(10,scroll, bar);
			parent.setAlignment(Pos.CENTER);
			scene = new Scene(parent);
			scene.getStylesheets().addAll( FlexibleApplication.getInstance().getAppLayout().getScene().getStylesheets() );
			stage = new Stage();
			stage.setScene(scene);
			stage.show();
		}
	}

	//-------------------------------------------------------------------
	private static void showPage(int showPage) {
		if (nextPath==null || nextPath.isEmpty()) return;
		nextPage = showPage;
		synchronized (logger) {
			logger.notify();
		}
	}

	@Override
	public void show(RoleplayingSystem rules, String productID, String lang, int page) {
		logger.log(Level.DEBUG, "Show {1} for RPG {0} in language ''{2}'' on page {3}", rules, productID, lang, page );
		if (!PDFViewerConfig.isEnabled()) return;
		if (PDFViewerConfig.getPDFPathResolver()==null || page==0)
			return;

		ensureStage();
		PathAndOffset pair = PDFViewerConfig.getPDFPathResolver().apply(productID, lang);
		nextPath = pair.path;
		page += pair.offset;
		logger.log(Level.INFO, "..resolved to path: {0}", nextPath);
		if (nextPath==null) return;
//		path = "/home/data/Rollenspiel/Shadowrun/SR6_Englisch/Shadowrun_Sixth_World_Core_Rulebook_City_Edition_Seattle.pdf";
		showPage(page);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy