All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jpedal.display.GUIDisplay Maven / Gradle / Ivy
/*
* ===========================================
* 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@
*
* ---------------
* GUIDisplay.java
* ---------------
*/
package org.jpedal.display;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import org.jpedal.external.Options;
import org.jpedal.external.RenderChangeListener;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.acroforms.AcroRenderer;
import org.jpedal.parser.DecoderOptions;
import org.jpedal.render.DynamicVectorRenderer;
import org.jpedal.text.TextLines;
import org.jpedal.utils.ScalingFactory;
/**
* hold code generic to Swing or FX
*/
public class GUIDisplay implements Display {
protected int lastFormPage = -1, lastStart = -1, lastEnd = -1;
protected int pageUsedForTransform;
/**
* tracks indent so changing to continuous does not disturb display
*/
protected int lastIndent = -1;
protected double indent;
/**
* Normally null - user object to listen to paint events
*/
public RenderChangeListener customRenderChangeListener;
//rectangle onscreen
public int rx, ry, rw, rh;
protected DisplayOffsets displayOffsets;
public DecoderOptions options;
/**
* Flag if we should allow cursor to change
*/
public static boolean allowChangeCursor = true;
public final MultiDisplayOptions multiDisplayOptions = new MultiDisplayOptions();
//Animation enabled (currently just turnover in facing)
public static boolean default_turnoverOn = true; //can be altered by user
//Display the first page separately in Facing mode
public static boolean default_separateCover = true; //can be altered by user
public DynamicVectorRenderer currentDisplay;
public boolean isInitialised;
/**
* flag to switch back to unaccelerate screen if no enough memory for scaling
*/
public boolean overRideAcceleration;
/**
* render screen using hardware acceleration
*/
public boolean useAcceleration = true;
public boolean ignoreScalingForAcceleration;
public boolean accelerationAlwaysRedraw;
public PageOffsets currentOffset;
/**
* Holds the x,y,w,h of the current highlighted image, null if none
*/
private int[] highlightedImage;
protected GUIThumbnailPanel thumbnails;
/**
* Keep a record of cumulative offsets for SINGLE_PAGE mode
*/
public int[] pageOffsetH, pageOffsetW;
public boolean[] isRotated;
public int topW, topH;
public double cropX, cropY, cropW, cropH;
/**
* used to draw demo cross
*/
public int crx, cry, crw, crh;
/**
* local copies
*/
public int displayRotation, displayView = SINGLE_PAGE;
public int lastDisplayRotation;
public int insetW, insetH;
public float scaling;
public float lastScaling;
public int pageNumber;
/**
* any scaling factor being used to convert co-ords into correct values
* and to alter image size
*/
public float oldScaling = -1, oldRotation = -1;
public PdfPageData pageData;
// Affine transformation as a double array
protected double[] displayScalingDbl;
/**
* used internally by multiple pages
* scaling -1 to ignore, -2 to force reset
*/
@Override
public int getYCordForPage(final int page, final float scaling) {
if (scaling == -2 || (scaling != -1f && scaling != oldScaling)) {
oldScaling = scaling;
setPageOffsets(page);
}
return getYCordForPage(page);
}
@Override
public boolean getBoolean(final BoolValue option) {
switch (option) {
case SEPARATE_COVER:
return multiDisplayOptions.isSeparateCover();
case TURNOVER_ON:
return multiDisplayOptions.isTurnoverOn();
default:
throw new RuntimeException("GetBoolean called with unknown value " + option);
}
}
@Override
public void setBoolean(final BoolValue option, final boolean value) {
switch (option) {
case SEPARATE_COVER:
multiDisplayOptions.setSeparateCover(value);
return;
case TURNOVER_ON:
multiDisplayOptions.setTurnoverOn(value);
return;
default:
throw new RuntimeException("setBoolean called with unkown value " + value);
}
}
/**
* general method to pass in Objects - only takes RenderChangeListener at present
*
* @param type
* @param newHandler
*/
@Override
public void setObjectValue(final int type, final Object newHandler) {
//set value
switch (type) {
case Options.RenderChangeListener:
customRenderChangeListener = (RenderChangeListener) newHandler;
break;
default:
throw new RuntimeException("setObjectValue does not take value " + type);
}
}
/**
* @param displayView is of type int
* @return returns an int[] with 2 values ([0]width and [1]height)
* which we then use to create a Dimension object in current Swing code
*/
@Override
public int[] getPageSize(final int displayView) {
final int[] pageSize = new int[2]; //element 0 = width, element 1 = height
//height for facing pages
int biggestFacingHeight = 0;
int facingWidth = 0;
if ((displayView == FACING) && (multiDisplayOptions.getPageW() != null)) {
//get 2 facing page numbers
int p1;
final int p2;
if (multiDisplayOptions.isSeparateCover()) {
p1 = pageNumber;
if ((p1 & 1) == 1) {
p1--;
}
p2 = p1 + 1;
} else {
p1 = pageNumber;
if ((p1 & 1) == 0) {
p1--;
}
p2 = p1 + 1;
}
if (p1 == 0) {
biggestFacingHeight = multiDisplayOptions.getPageH(p2);
facingWidth = multiDisplayOptions.getPageW(p2) * 2;
} else {
biggestFacingHeight = multiDisplayOptions.getPageH(p1);
if (p2 < multiDisplayOptions.getPageH().length) {
if (biggestFacingHeight < multiDisplayOptions.getPageH(p2)) {
biggestFacingHeight = multiDisplayOptions.getPageH(p2);
}
facingWidth = multiDisplayOptions.getPageW(p1) + multiDisplayOptions.getPageW(p2);
} else {
facingWidth = multiDisplayOptions.getPageW(p1) * 2;
}
}
}
final int gaps = currentOffset.getGaps();
final int doubleGaps = currentOffset.getDoubleGaps();
switch (displayView) {
case FACING:
pageSize[0] = facingWidth + insetW + insetW;
pageSize[1] = biggestFacingHeight + insetH + insetH;
break;
case CONTINUOUS:
if ((displayRotation == 90) | (displayRotation == 270)) {
pageSize[0] = ((int) (currentOffset.getBiggestHeight() * scaling) + insetW + insetW);
pageSize[1] = pageData.getScaledTotalSingleWidth() + gaps + insetH + insetH;
} else {
pageSize[0] = ((int) (currentOffset.getBiggestWidth() * scaling) + insetW + insetW);
pageSize[1] = pageData.getScaledTotalSingleHeight() + gaps + insetH + insetH;
}
break;
case CONTINUOUS_FACING:
final int pageCount = pageData.getPageCount();
if ((displayRotation == 90) | (displayRotation == 270)) {
if (pageCount == 2) {
pageSize[0] = ((int) (currentOffset.getDoublePageHeight() * scaling) + insetW + insetW);
pageSize[1] = ((int) (currentOffset.getBiggestWidth() * scaling) + gaps + insetH + insetH);
} else {
pageSize[0] = ((int) (currentOffset.getDoublePageHeight() * scaling) + insetW + insetW);
pageSize[1] = pageData.getScaledTotalDoubleWidth() + doubleGaps + insetH + insetH;
}
} else {
if (pageCount == 2) {
pageSize[0] = ((int) (currentOffset.getDoublePageWidth() * scaling) + insetW + insetW);
pageSize[1] = ((int) (currentOffset.getBiggestHeight() * scaling) + gaps + insetH + insetH);
} else {
pageSize[0] = ((int) (currentOffset.getDoublePageWidth() * scaling) + insetW + insetW);
pageSize[1] = pageData.getScaledTotalDoubleHeight() + doubleGaps + insetH + insetH;
}
}
break;
}
return pageSize;
}
@Override
public void setup(final boolean useAcceleration, final PageOffsets currentOffset) {
this.useAcceleration = useAcceleration;
this.currentOffset = currentOffset;
overRideAcceleration = false;
}
@Override
public void setAcceleration(final boolean enable) {
useAcceleration = enable;
}
@Override
public void setAccelerationAlwaysRedraw(final boolean enable) {
accelerationAlwaysRedraw = enable;
}
public void setPageSize(final int pageNumber, final float scaling) {
/*
*handle clip - crop box values
*/
pageData.setScalingValue(scaling); //ensure aligned
topW = pageData.getScaledCropBoxWidth(pageNumber);
topH = pageData.getScaledCropBoxHeight(pageNumber);
final double mediaH = pageData.getScaledMediaBoxHeight(pageNumber);
cropX = pageData.getScaledCropBoxX(pageNumber);
cropY = pageData.getScaledCropBoxY(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
final int offsetY = (int) (mediaH - cropH);
if ((displayRotation == 90 || displayRotation == 270)) {
crw = (int) (cropH);
crh = (int) (cropW);
final int tmp = crx;
crx = cry;
cry = tmp;
crx += offsetY;
} else {
crw = (int) (cropW);
crh = (int) (cropH);
cry += offsetY;
}
}
@Override
public void decodeOtherPages(final int pageNumber, final int pageCount) {
}
@Override
public void disableScreen() {
isInitialised = false;
oldScaling = -1;
}
@Override
public float getOldScaling() {
return oldScaling;
}
@Override
public void refreshDisplay() {
throw new UnsupportedOperationException("refreshDisplay Not supported yet.");
}
@Override
public void flushPageCaches() {
}
@Override
public void init(final float scaling, final int displayRotation, int pageNumber, final DynamicVectorRenderer currentDisplay, final boolean isInit) {
if (pageNumber < 1) {
pageNumber = 1;
}
if (currentDisplay != null) {
this.currentDisplay = currentDisplay;
}
this.scaling = scaling;
this.displayRotation = displayRotation;
this.pageNumber = pageNumber;
this.insetW = options.getInsetW();
this.insetH = options.getInsetH();
//reset over-ride which may have been enabled
pageData.setScalingValue(scaling); //ensure aligned
if (isInit) {
setPageOffsets(this.pageNumber);
isInitialised = true;
}
lastScaling = scaling;
}
@Override
public void setThumbnailPanel(final GUIThumbnailPanel thumbnails) {
this.thumbnails = thumbnails;
}
@Override
public void stopGeneratingPage() {
//request any processes die
multiDisplayOptions.setIsGeneratingOtherPages(false);
multiDisplayOptions.waitToDieThred();
}
@Override
public int getYCordForPage(final int page) {
final int[] yReached = multiDisplayOptions.getyReached();
//int[] pageH=multiDisplayOptions.getPageH();
if (yReached != null) {
//Prevent Continous Facing mode from shifting forward a page
//when scaling from large to small
// if(displayView==Display.CONTINUOUS_FACING){
// return yReached[page] + insetH; // - pageH[page];
// }else{
return yReached[page] + insetH;
// }
} else {
return insetH;
}
}
public int getStartPage() {
return multiDisplayOptions.getStartViewPage();
}
public int getEndPage() {
return multiDisplayOptions.getEndViewPage();
}
@Override
public void setScaling(final float scaling) {
this.scaling = scaling;
if (pageData != null) {
pageData.setScalingValue(scaling);
}
}
@Override
public void setHighlightedImage(final int[] highlightedImage) {
this.highlightedImage = highlightedImage;
}
@Override
public int[] getHighlightedImage() {
return highlightedImage;
}
@Override
public void drawBorder() {
throw new UnsupportedOperationException("drawBorder Not supported yet.");
}
@Override
public int getXCordForPage(final int page) {
final int[] xReached = multiDisplayOptions.getxReached();
if (xReached != null) {
return xReached[page] + insetW;
} else {
return insetW;
}
}
/**
* workout offsets so we can draw pages
*/
@Override
public void setPageOffsets(final int pageNumber) {
final int pageCount = pageData.getPageCount();
multiDisplayOptions.resetValues(pageCount);
pageOffsetW = new int[pageCount + 1];
pageOffsetH = new int[pageCount + 1];
int heightCorrection;
int displayRotation;
isRotated = new boolean[pageCount + 1];
int gap = PageOffsets.pageGap; //set.pageGap*scaling);
if (multiDisplayOptions.isTurnoverOn() &&
pageCount != 2 &&
!pageData.hasMultipleSizes() &&
displayView == Display.FACING) {
gap = 0;
}
//Used to help allign first page is page 2 is cropped / rotated
int LmaxWidth = 0;
int LmaxHeight = 0;
int RmaxWidth = 0;
int RmaxHeight = 0;
final int[] pageW = multiDisplayOptions.getPageW();
final int[] pageH = multiDisplayOptions.getPageH();
/*work out page sizes - need to do it first as we can look ahead*/
for (int i = 1; i < pageCount + 1; i++) {
pageW[i] = pageData.getScaledCropBoxWidth(i);
pageH[i] = pageData.getScaledCropBoxHeight(i);
displayRotation = pageData.getRotation(i) + this.displayRotation;
if (displayRotation >= 360) {
displayRotation -= 360;
}
//swap if this page rotated and flag
if ((displayRotation == 90 || displayRotation == 270)) {
final int tmp = pageW[i];
pageW[i] = pageH[i];
pageH[i] = tmp;
isRotated[i] = true; //flag page as rotated
}
if ((i & 1) == 1) {
if (pageW[i] > RmaxWidth) {
RmaxWidth = pageW[i];
}
if (pageH[i] > RmaxHeight) {
RmaxHeight = pageH[i];
}
} else {
if (multiDisplayOptions.getPageW(i) > LmaxWidth) {
LmaxWidth = multiDisplayOptions.getPageW(i);
}
if (pageH[i] > LmaxHeight) {
LmaxHeight = pageH[i];
}
}
}
final int[] xReached = multiDisplayOptions.getxReached();
final int[] yReached = multiDisplayOptions.getyReached();
//loop through all pages and work out positions
for (int i = 1; i < pageCount + 1; i++) {
heightCorrection = 0;
if (((pageCount == 2) && (displayView == FACING || displayView == CONTINUOUS_FACING)) || (displayView == FACING && !multiDisplayOptions.isSeparateCover())) { //special case
//if only 2 pages display side by side
if ((i & 1) == 1) {
xReached[i] = 0;
yReached[i] = 0;
} else {
xReached[i] = xReached[i - 1] + pageW[i - 1] + gap;
yReached[i] = 0;
if (!(i == 2 && pageData.getRotation(1) == 270)) {
pageOffsetW[2] = (pageW[2] - pageW[1]) + pageOffsetW[1];
pageOffsetH[2] = (pageH[2] - pageH[1]) + pageOffsetH[1];
}
}
} else if (i == 1) { //first page is special case
//First page should be on the left so indent
if (displayView == CONTINUOUS) {
xReached[1] = 0;
yReached[1] = 0;
pageOffsetW[1] = 0;
pageOffsetH[1] = 0;
pageOffsetW[0] = gap; //put the gap values in the empty entry in the offset array. A bit bodgy!
pageOffsetH[0] = gap;
} else if (displayView == CONTINUOUS_FACING) {
pageOffsetW[0] = gap; //put the gap values in the empty entry in the offset array. A bit bodgy!
pageOffsetH[0] = gap;
pageOffsetW[1] = 0;
pageOffsetH[1] = 0;
xReached[1] = LmaxWidth + gap;
yReached[1] = 0;
} else if (displayView == FACING) {
xReached[1] = pageW[1] + gap;
yReached[1] = 0;
}
} else {
//Calculate position for all other pages / cases
if ((displayView == CONTINUOUS_FACING)) {
if (!(i >= 2 &&
(((pageData.getRotation(i) == 270 || pageData.getRotation(i) == 90) &&
(pageData.getRotation(i - 1) != 270 || pageData.getRotation(i - 1) != 90))
|| ((pageData.getRotation(i - 1) == 270 || pageData.getRotation(i - 1) == 90) &&
(pageData.getRotation(i) != 270 || pageData.getRotation(i) != 90))))) {
pageOffsetW[i] = (pageW[i] - pageW[i - 1]) + pageOffsetW[i - 1];
pageOffsetH[i] = (pageH[i] - pageH[i - 1]) + pageOffsetH[i - 1];
}
//Left Pages
if ((i & 1) == 0) {
//Last Page rotated so correct height
if (i < pageCount) {
heightCorrection = (pageH[i + 1] - pageH[i]) / 2;
}
if (heightCorrection < 0) {
heightCorrection = 0; //-heightCorrection;
}
if (i > 3) {
final int temp = (pageH[i - 2] - pageH[i - 1]) / 2;
if (temp > 0) {
heightCorrection += temp;
}
}
yReached[i] = (yReached[i - 1] + pageH[i - 1] + gap) + heightCorrection;
} else { //Right Pages
//Last Page rotated so correct height
heightCorrection = (pageH[i - 1] - pageH[i]) / 2;
yReached[i] = (yReached[i - 1]) + heightCorrection;
}
if ((i & 1) == 0) { //Indent Left pages by diff between maxWidth and pageW (will only indent unrotated)
xReached[i] += (LmaxWidth - pageW[i]);
} else { //Place Right Pages with a gap (This keeps pages centered)
xReached[i] = xReached[i - 1] + pageW[i - 1] + gap;
}
} else if (displayView == CONTINUOUS) {
//Place page below last with gap
yReached[i] = (yReached[i - 1] + pageH[i - 1] + gap);
if (!(i >= 2 &&
(((pageData.getRotation(i) == 270 || pageData.getRotation(i) == 90) &&
(pageData.getRotation(i - 1) != 270 || pageData.getRotation(i - 1) != 90))
|| ((pageData.getRotation(i - 1) == 270 || pageData.getRotation(i - 1) == 90) &&
(pageData.getRotation(i) != 270 || pageData.getRotation(i) != 90))))) {
pageOffsetW[i] = (pageW[i] - pageW[i - 1]) + pageOffsetW[i - 1];
pageOffsetH[i] = (pageH[i] - pageH[i - 1]) + pageOffsetH[i - 1];
}
} else if ((displayView == FACING)) {
if ((i & 1) == 1) { //If right page, place on right with gap
xReached[i] = (xReached[i - 1] + pageW[i - 1] + gap);
if (pageH[i] < pageH[i - 1])//Drop page down to keep pages centred
{
yReached[i] += (((pageH[i - 1] - pageH[i]) / 2));
}
} else { //If left page, indent by diff of max and current page
xReached[i] = 0;
if (i < pageCount && (pageH[i] < pageH[i + 1])) {
//Drop page down to keep pages centered
yReached[i] += ((pageH[i + 1] - pageH[i]) / 2);
}
}
}
}
}
}
@Override
public void dispose() {
currentOffset = null;
multiDisplayOptions.setPageValuesToNull();
this.isRotated = null;
}
@Override
public int[] getCursorBoxOnScreenAsArray() {
throw new UnsupportedOperationException("getCursorBoxOnScreenAsArray Not supported yet.");
}
@Override
public double getIndent() {
return indent;
}
@Override
public void forceRedraw() {
lastFormPage = -1;
lastEnd = -1;
lastStart = -1;
}
/**
* initialise panel and set size to display during updates and update the AffineTransform to new values
*/
@Override
public void setPageRotation(int newRotation) {
//assume unrotated for multiple views and rotate on a page basis
if (displayView != Display.SINGLE_PAGE) {
newRotation = 0;
}
pageUsedForTransform = pageNumber;
if (displayView != Display.SINGLE_PAGE && displayView != Display.FACING) {
displayScalingDbl = ScalingFactory.getScalingForImage(1, 0, scaling, pageData); //(int)(pageData.getCropBoxWidth(pageNumber)*scaling),(int)(pageData.getCropBoxHeight(pageNumber)*scaling),
} else {
displayScalingDbl = ScalingFactory.getScalingForImage(pageNumber, newRotation, scaling, pageData); //(int)(pageData.getCropBoxWidth(pageNumber)*scaling),(int)(pageData.getCropBoxHeight(pageNumber)*scaling),
}
final int insetW = options.getInsetW();
final int insetH = options.getInsetH();
// Affine transformations
switch (newRotation) {
case 90:
displayScalingDbl[4] += ((insetW / scaling) * displayScalingDbl[1]);
displayScalingDbl[5] += ((insetH / scaling) * displayScalingDbl[2]);
break;
case 270:
displayScalingDbl[4] += ((-insetW / scaling) * displayScalingDbl[1]);
displayScalingDbl[5] += ((-insetH / scaling) * displayScalingDbl[2]);
break;
case 180:
displayScalingDbl[4] += ((-insetW / scaling) * displayScalingDbl[0]);
displayScalingDbl[5] += ((insetH / scaling) * displayScalingDbl[3]);
break;
default:
displayScalingDbl[4] += ((insetW / scaling) * displayScalingDbl[0]);
displayScalingDbl[5] += ((-insetH / scaling) * displayScalingDbl[3]);
break;
}
//force redraw if screen being cached
refreshDisplay();
}
@Override
public void resetViewableArea() {
throw new UnsupportedOperationException("resetViewableArea Not supported yet.");
}
@Override
public void paintPage(final Graphics2D g2, final AcroRenderer formRenderer, final TextLines textLines) {
throw new UnsupportedOperationException("paintPage not supported yet.");
}
@Override
public void updateCursorBoxOnScreen(final int[] newOutlineRectangle, final int outlineColor, final int pageNumber, final int x_size, final int y_size) {
throw new UnsupportedOperationException("updateCursorBoxOnScreen Not supported yet.");
}
@Override
public void drawCursor(final Graphics g, final float scaling) {
throw new UnsupportedOperationException("drawCursor Not supported yet.");
}
@Override
public void drawFacing(final Rectangle visibleRect) {
throw new UnsupportedOperationException("drawFacing Not supported yet.");
}
public void setCurrentDisplay(final DynamicVectorRenderer pageView) {
this.currentDisplay = pageView;
}
public int getDisplayRotation() {
return displayRotation;
}
public int getRx() {
return rx;
}
public int getRy() {
return ry;
}
public int getRw() {
return rw;
}
public int getRh() {
return rh;
}
public int getInsetW() {
return insetW;
}
public int getInsetH() {
return insetH;
}
@Override
public Rectangle getDisplayedRectangle() {
throw new UnsupportedOperationException("getDisplayedRectangle Not supported yet.");
}
public Rectangle getDisplayedRectangle(final boolean isShowing, final Rectangle userAnnot) {
//get raw rectangle
rx = userAnnot.x;
ry = userAnnot.y;
rw = userAnnot.width;
rh = userAnnot.height;
//Best way I found to catch if pdf decoder is being used but never displayed
if (!isShowing && (rw == 0 || rh == 0)) {
rx = 0;
ry = 0;
rw = pageData.getScaledCropBoxWidth(pageNumber);
rh = pageData.getScaledCropBoxHeight(pageNumber);
if (pageData.getRotation(pageNumber) % 180 != 0) {
rh = pageData.getScaledCropBoxWidth(pageNumber);
rw = pageData.getScaledCropBoxHeight(pageNumber);
}
}
return userAnnot;
}
}