de.rpgframework.jfx.attach.impl.DesktopPDFViewerService Maven / Gradle / Ivy
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