org.jpedal.display.javafx.SingleDisplayFX Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
Open Source (LGPL) JavaFX PDF Viewer for NetBeans plugin
/*
* ===========================================
* 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@
*
* ---------------
* SingleDisplayFX.java
* ---------------
*/
package org.jpedal.display.javafx;
import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.transform.Transform;
import org.jpedal.PdfDecoderFX;
import org.jpedal.display.Display;
import org.jpedal.display.GUIDisplay;
import org.jpedal.objects.acroforms.AcroRenderer;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.render.DynamicVectorRenderer;
import org.jpedal.render.FXDisplay;
public class SingleDisplayFX extends GUIDisplay {
final PdfDecoderFX pdf;
// Rectangle drawn on screen by user
private int[] cursorBoxOnScreen;
final Pane cursorBoxPane = new Pane();
public SingleDisplayFX(int pageNumber, final DynamicVectorRenderer currentDisplay, final PdfDecoderFX pdf, final DecoderOptions options) {
if (pageNumber < 1) {
pageNumber = 1;
}
this.pageNumber = pageNumber;
this.currentDisplay = currentDisplay;
this.pdf = pdf;
this.options = options;
displayOffsets = pdf.getDisplayOffsets();
pageData = pdf.getPdfPageData();
}
public SingleDisplayFX(final PdfDecoderFX pdf, final DecoderOptions options) {
this.pdf = pdf;
this.options = options;
displayOffsets = pdf.getDisplayOffsets();
pageData = pdf.getPdfPageData();
}
@Override
public void refreshDisplay() {
if (Platform.isFxApplicationThread()) {
if (displayScalingDbl != null) {
pdf.getTransforms().setAll(Transform.affine(displayScalingDbl[0], displayScalingDbl[1], displayScalingDbl[2], displayScalingDbl[3], displayScalingDbl[4], displayScalingDbl[5]));
}
if (currentDisplay != null) {
paintPage(pdf.highlightsPane, pdf.getFormRenderer());
}
} else {
// Ensure dialog is handled on FX thread
Platform.runLater(new Runnable() {
@Override
public void run() {
if (displayScalingDbl != null) {
pdf.getTransforms().setAll(Transform.affine(displayScalingDbl[0], displayScalingDbl[1], displayScalingDbl[2], displayScalingDbl[3], displayScalingDbl[4], displayScalingDbl[5]));
}
if (currentDisplay != null) {
paintPage(pdf.highlightsPane, pdf.getFormRenderer());
}
}
});
}
}
/**
* initialise panel and set size to display during updates and update the AffineTransform to new values
*
* @param newRotation int value to specify the rotation for the page
*/
@Override
public void setPageRotation(final int newRotation) {
super.setPageRotation(newRotation);
// force redraw if screen being cached
refreshDisplay();
}
static Path getBorder(final int crw, final int crh) {
final Path border = new Path();
border.getElements().add(new MoveTo(-1, -1));
border.getElements().add(new LineTo(crw + 2, -1));
border.getElements().add(new LineTo(crw + 2, crh + 2));
border.getElements().add(new LineTo(-1, crh + 2));
border.getElements().add(new ClosePath());
border.setStroke(Color.rgb(0, 0, 0));
return border;
}
/**
* Resets the FXPane when we open a new PDF
*/
@Override
public void disableScreen() {
if (currentDisplay != null) {
final Group FXpane = ((FXDisplay) currentDisplay).getFXPane();
if (pdf.getChildren().contains(FXpane)) {
final int count = pdf.getChildren().size();
for (int i = 0; i < count; i++) {
pdf.getChildren().remove(0);
}
}
}
}
private void paintPage(final Object rawBox, final AcroRenderer formRenderer) {
final boolean debugPane = false;
final Pane box = (Pane) rawBox;
final Group fxPane = ((FXDisplay) currentDisplay).getFXPane();
final String pageNumberStr = String.valueOf(pageNumber);
final Rectangle clip = new Rectangle(crx, cry, crw, crh);
clip.setFill(Color.WHITE);
// Remove box from the current node it belongs to - avoids duplication errors
if (box != null && box.getParent() != null) {
((Group) box.getParent()).getChildren().remove(box);
}
fxPane.getChildren().addAll(box);
pdf.setPrefSize(crw, crh);
if (displayView == SINGLE_PAGE) {
pdf.getChildren().clear();
if (formRenderer.isXFA()) {
// Draw wihte background border on xfa contents
final Path border = getBorder(crw, crh);
border.setFill(Color.WHITE);
pdf.getChildren().addAll(border);
border.setLayoutX(crx);
border.setLayoutY(cry);
}
if (!pdf.getChildren().contains(fxPane)) {
pdf.getChildren().addAll(fxPane);
}
fxPane.setLayoutX(-crx);
fxPane.setLayoutY(-cry);
} else {
Node pagePath = null;
for (final Node child : pdf.getChildren()) {
if (child.getId() != null && child.getId().equals(pageNumberStr)) {
if (child instanceof Path) {
pagePath = child;
}
}
}
if (pagePath != null) {
pdf.getChildren().remove(pagePath);
}
fxPane.setId(pageNumberStr);
if (!pdf.getChildren().contains(fxPane)) {
pdf.getChildren().addAll(fxPane);
}
final int[] xReached = multiDisplayOptions.getxReached();
final int[] yReached = multiDisplayOptions.getyReached();
int cx;
final int cy;
final int j = pageNumber;
cx = (int) (xReached[j] / scaling);
cy = (int) (yReached[j] / scaling);
// Code works differently in Swing and FX so needs reversing
if (displayView == CONTINUOUS_FACING) {
cx = currentOffset.getWidestPageR() - cx;
}
fxPane.setLayoutX(-cx);
fxPane.setLayoutY(pdf.getHeight() - cy);
}
if (!debugPane) {
clip.setFill(Color.WHITE);
fxPane.setClip(clip);
} else {
// Debug Different GUI Display Panes
clip.setFill(Color.BLUE);
clip.setOpacity(0.5);
fxPane.getChildren().add(clip);
pdf.setStyle("-fx-background-color: red;");
pdf.getParent().setStyle("-fx-background-color: yellow;");
fxPane.setStyle("-fx-background-color: green;");
}
addForms(formRenderer);
}
private void addForms(final AcroRenderer formRenderer) {
int start = pageNumber, end = pageNumber;
// Control if we display forms on multiple pages
if (displayView != Display.SINGLE_PAGE) {
start = getStartPage();
end = getEndPage();
if (start == 0 || end == 0 || lastEnd != end || lastStart != start) {
lastFormPage = -1;
}
lastEnd = end;
lastStart = start;
}
if ((lastFormPage != pageNumber) && (formRenderer != null)) {
formRenderer.displayComponentsOnscreen(start, end);
// Switch off if forms for this page found
if (formRenderer.getCompData().hasformsOnPageDecoded(pageNumber)) {
lastFormPage = pageNumber; //ensure not called too early
}
}
// Add the forms to the Pane
if (formRenderer != null && currentOffset != null) { // If all forms flattened, we can get a null value for currentOffset so avoid this case
formRenderer.getCompData().setPageValues(scaling, displayRotation, (int) indent, displayOffsets.getUserOffsetX(), displayOffsets.getUserOffsetY(), displayView, currentOffset.getWidestPageNR(), currentOffset.getWidestPageR());
formRenderer.getCompData().resetScaledLocation(scaling, displayRotation, (int) indent); // Indent here does nothing.
}
}
@Override
public void init(final float scaling, final int displayRotation, final int pageNumber, final DynamicVectorRenderer currentDisplay, final boolean isInit) {
this.pageData = pdf.getPdfPageData();
super.init(scaling, displayRotation, pageNumber, currentDisplay, isInit);
setPageSize(pageNumber, scaling);
lastFormPage = -1;
}
/**
* Set the page size for the given page and scaling.
* The scaling is not actually applied here. It is instead passed along to
* used by FX transformations.
*
* @param pageNumber int value representing the page number
* @param scaling float value representing the scaling for the page
*/
@Override
public void setPageSize(final int pageNumber, final float scaling) {
// Handle clip - crop box values
pageData.setScalingValue(scaling); //ensure aligned
topW = pageData.getCropBoxWidth(pageNumber);
topH = pageData.getCropBoxHeight(pageNumber);
final double mediaH = pageData.getMediaBoxHeight(pageNumber);
cropX = pageData.getCropBoxX(pageNumber);
cropY = pageData.getCropBoxY(pageNumber);
cropW = topW;
cropH = topH;
// Actual clip values - for flipped page
if (displayView == Display.SINGLE_PAGE) {
crx = (int) (insetW + cropX);
cry = (int) (insetH - cropY);
} else {
crx = insetW;
cry = insetH;
}
// Amount needed to move cropped page into correct position
int offsetY = (int) (mediaH - cropH);
// Adjust the offset more in cases like costena
if (!pageData.getMediaValue(pageNumber).isEmpty()) {
offsetY -= pageData.getMediaBoxHeight(pageNumber) - (int) (cropY + cropH) - pageData.getCropBoxY(pageNumber);
}
crw = (int) (cropW);
crh = (int) (cropH);
cry += offsetY;
}
@Override
public int[] getCursorBoxOnScreenAsArray() {
return cursorBoxOnScreen;
}
@Override
public void updateCursorBoxOnScreen(final int[] newOutlineRectangle, final int outlineColor, final int pageNumber, final int x_size, final int y_size) {
if (displayView != Display.SINGLE_PAGE && getPageSize(displayView)[0] == 0 && getPageSize(displayView)[1] == 0) {
return;
}
if (newOutlineRectangle != null) {
final int x = newOutlineRectangle[0] - pageData.getCropBoxX(pageNumber);
final int y = newOutlineRectangle[1] - pageData.getCropBoxY(pageNumber);
final int w = newOutlineRectangle[2];
final int h = newOutlineRectangle[3];
cursorBoxOnScreen = new int[]{x, y, w, h};
if (DecoderOptions.showMouseBox) {
//Setup Cursor box.
final Rectangle cursorRect = new Rectangle(x, y, w, h);
cursorRect.setStroke(shiftColorSpaceToFX(outlineColor));
cursorRect.setFill(Color.TRANSPARENT);
//Draw Cursor box.
if (pdf.getChildren().contains(cursorBoxPane)) {
cursorBoxPane.getChildren().clear();
cursorBoxPane.getChildren().add(cursorRect);
pdf.getChildren().remove(cursorBoxPane);
}
pdf.getChildren().add(cursorBoxPane);
}
} else {
cursorBoxOnScreen = null;
if (pdf.getChildren().contains(cursorBoxPane)) {
cursorBoxPane.getChildren().clear();
pdf.getChildren().remove(cursorBoxPane);
}
}
}
@Override
public java.awt.Rectangle getDisplayedRectangle() {
return new java.awt.Rectangle(0, 0, 0, 0);
}
/**
* Performs a Bitshift so we can use Swing get sRGB with JavaFX Color.
*
* @param raw of type int
* @return Color
*/
final private static Color shiftColorSpaceToFX(final int raw) {
final int r = ((raw >> 16) & 255);
final int g = ((raw >> 8) & 255);
final int b = ((raw) & 255);
return Color.rgb(r, g, b);
}
}