Skip to content

Commit

Permalink
GH-173 popup annotation printing tweaks (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcorless authored Jul 14, 2023
1 parent 634bffa commit e1f0cab
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -581,9 +581,11 @@ public void paint(Graphics g, int renderHintType, final int boundary,
if (oldClip == null) {
g2.setClip(rect);
} else {
Area area = new Area(oldClip);
area.intersect(new Area(rect));
g2.setClip(area);
// pages/paper are generally rectangular, so we'll drop the shape
// the union insures we respect the parent clip, mainly for printing popup outside of the page clip
Rectangle currentClip = oldClip.getBounds();
Rectangle.union(currentClip, rect, rect);
g2.setClip(rect);
}

paintPageContent(g2, renderHintType, userRotation, userZoom, paintAnnotations, paintSearchHighlight);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ public void init() throws InterruptedException {
public abstract void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace, boolean isNew);

@Override
protected void renderAppearanceStream(Graphics2D g) {
protected void renderAppearanceStream(Graphics2D g, float rotation, float zoom) {

Appearance appearance = appearances.get(currentAppearance);
if (appearance != null) {
AppearanceState appearanceState = appearance.getSelectedAppearanceState();
if (appearanceState != null &&
appearanceState.getShapes() != null) {
// render the main annotation content
super.renderAppearanceStream(g);
super.renderAppearanceStream(g, rotation, zoom);
}
}
// check the highlight widgetAnnotation field and if true we draw a light background colour to mark
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ public void render(Graphics2D origG, int renderHintType,
origG.clip(deriveDrawingRectangle());
}

renderAppearanceStream(origG);
renderAppearanceStream(origG, totalRotation, userZoom);

origG.setTransform(at);
origG.setClip(preAppearanceStreamClip);
Expand All @@ -1338,7 +1338,7 @@ public void render(Graphics2D origG, int renderHintType,
//origG.fill( topLeft );
}

protected void renderAppearanceStream(Graphics2D g) {
protected void renderAppearanceStream(Graphics2D g, float rotation, float zoom) {
Appearance appearance = appearances.get(currentAppearance);
if (appearance == null) return;
AppearanceState appearanceState = appearance.getSelectedAppearanceState();
Expand Down Expand Up @@ -1980,6 +1980,34 @@ else if (value instanceof StringObject)
return sb.toString();
}

public Rectangle calculatePageSpaceRectangle(Page page, final int boundary, final float rotation, final float zoom) {
AffineTransform at = page.getPageTransform(
boundary,
rotation,
zoom);
Rectangle annotationPageSpaceBounds = commonBoundsNormalization(new GeneralPath(getUserSpaceRectangle()), at);
return annotationPageSpaceBounds;
}

/**
* Normalizes and the given path with the specified transform. The method
* also rounds the Rectangle2D bounds values when creating a new rectangle
* instead of truncating the values.
*
* @param shapePath path to apply transform to
* @param at transform to apply to shapePath
* @return bound value of the shape path.
*/
public static Rectangle commonBoundsNormalization(GeneralPath shapePath, AffineTransform at) {
shapePath.transform(at);
Rectangle2D pageSpaceBound = shapePath.getBounds2D();
return new Rectangle(
(int) Math.round(pageSpaceBound.getX()),
(int) Math.round(pageSpaceBound.getY()),
(int) Math.round(pageSpaceBound.getWidth()),
(int) Math.round(pageSpaceBound.getHeight()));
}

public void syncBBoxToUserSpaceRectangle(Rectangle2D bbox) {
Appearance appearance = appearances.get(currentAppearance);
AppearanceState appearanceState = appearance.getSelectedAppearanceState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ public PopupAnnotation getPopupAnnotation() {
return popupAnnotation;
}

public void setContents(String content) {
super.setContents(content);
if (popupAnnotation != null) {
popupAnnotation.updatePaintables();
}
}

protected static void generateExternalGraphicsState(Form form, float opacity) {
// add the transparency graphic context settings.
if (form != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public MarkupGlueAnnotation(Library l, MarkupAnnotation markupAnnotation, PopupA
this.popupAnnotation = popupAnnotation;
}

protected void renderAppearanceStream(Graphics2D g2d) {
protected void renderAppearanceStream(Graphics2D g2d, float rotation, float zoom) {
if (this.popupAnnotation == null || this.markupAnnotation == null) return;

GraphicsConfiguration graphicsConfiguration = g2d.getDeviceConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,15 @@ public class PopupAnnotation extends Annotation {

protected MarkupAnnotation parent;

protected final float fontSize = new JLabel().getFont().getSize();
protected float textAreaFontsize = fontSize;
protected float headerLabelsFontSize = fontSize;


protected JPanel popupPaintablesPanel;
protected JLabel creationLabel;
protected JLabel titleLabel;
protected JTextArea textArea;
private boolean resetPopupPaintables = true;

public PopupAnnotation(Library library, DictionaryEntries dictionaryEntries) {
Expand Down Expand Up @@ -124,7 +132,7 @@ public static PopupAnnotation getInstance(Library library,
}

@Override
protected void renderAppearanceStream(Graphics2D g2d) {
protected void renderAppearanceStream(Graphics2D g2d, float rotation, float zoom) {
GraphicsConfiguration graphicsConfiguration = g2d.getDeviceConfiguration();
boolean isPrintingAllowed = getParent().getFlagPrint();
if (graphicsConfiguration.getDevice().getType() == GraphicsDevice.TYPE_PRINTER &&
Expand All @@ -133,6 +141,7 @@ protected void renderAppearanceStream(Graphics2D g2d) {
if (resetPopupPaintables) {
buildPopupPaintables();
}
applyFontScaling(zoom);
paintPopupPaintables(g2d);
}
}
Expand All @@ -158,6 +167,12 @@ private void paintPopupPaintables(Graphics2D g2d) {
g2d.setTransform(oldTransform);
}

private void applyFontScaling(float zoom) {
PopupAnnotation.updateTextAreaFontSize(titleLabel, headerLabelsFontSize, zoom);
PopupAnnotation.updateTextAreaFontSize(creationLabel, headerLabelsFontSize, zoom);
PopupAnnotation.updateTextAreaFontSize(textArea, textAreaFontsize, zoom);
}

/**
* Builds a JPanel representing the popup annotation that can be printed.
*/
Expand All @@ -180,20 +195,22 @@ private void buildPopupPaintables() {
MarkupAnnotation markupAnnotation = getParent();
// user
String title = markupAnnotation.getFormattedTitleText();
JLabel titleLabel = new JLabel(title);
titleLabel = new JLabel(title);
titleLabel.setForeground(contrastColor);
popupPaintablesPanel.add(titleLabel);

// creation date
JLabel creationLabel = new JLabel();
creationLabel = new JLabel();
creationLabel.setText(markupAnnotation.getFormattedCreationDate(FormatStyle.MEDIUM));
creationLabel.setForeground(contrastColor);
popupPaintablesPanel.add(creationLabel);

// text area
String contents = getParent() != null ? getParent().getContents() : "";
JTextArea textArea = new JTextArea(contents);
textArea.setFont(new JLabel().getFont());
textArea = new JTextArea(contents);
Font font = new JLabel().getFont();
font = font.deriveFont(fontSize);
textArea.setFont(font);
textArea.setWrapStyleWord(true);
textArea.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(color),
BorderFactory.createEmptyBorder(2, 2, 2, 2)));
Expand Down Expand Up @@ -227,11 +244,38 @@ public Color calculateContrastHighLowColor(int rgb) {

}

public void setContents(String content) {
super.setString(CONTENTS_KEY, content);
public void updatePaintables() {
resetPopupPaintables = true;
}

public void setUserSpaceRectangle(Rectangle2D.Float rect) {
super.setUserSpaceRectangle(rect);
resetPopupPaintables = true;
}

public float getTextAreaFontsize() {
return textAreaFontsize;
}

public void setTextAreaFontsize(float textAreaFontsize) {
this.textAreaFontsize = textAreaFontsize;
}

public float getHeaderLabelsFontSize() {
return headerLabelsFontSize;
}

public void setHeaderLabelsFontSize(float headerLabelsFontSize) {
this.headerLabelsFontSize = headerLabelsFontSize;
}

public static void updateTextAreaFontSize(Component component, float fontSize, float zoom) {
final float scaledFontSize = fontSize * zoom;
final Font font = component.getFont();
component.setFont(font.deriveFont(scaledFontSize));
component.revalidate();
}

@Override
public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform, boolean isNew) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,14 +329,14 @@ public void resetAppearanceStream(double dx, double dy, AffineTransform pageTran
}

@Override
protected void renderAppearanceStream(Graphics2D g) {
protected void renderAppearanceStream(Graphics2D g, float rotation, float zoom) {
Appearance appearance = appearances.get(currentAppearance);
AppearanceState appearanceState = appearance.getSelectedAppearanceState();
Shapes shapes = appearanceState.getShapes();

// Appearance stream takes precedence over the quad points.
if (shapes != null) {
super.renderAppearanceStream(g);
super.renderAppearanceStream(g, rotation, zoom);
}
// draw the quad points.
else if (quadrilaterals != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,15 @@ protected static DocAttributeSet createDocAttributeSet(final MediaSizeName paper
final MediaSize mediaSize =
MediaSize.getMediaSizeForName(paperSizeName);
final float[] size = mediaSize.getSize(MediaSize.INCH);
docAttributeSet.add(new MediaPrintableArea(0, 0, size[0], size[1],
MediaPrintableArea.INCH));
docAttributeSet.add(new MediaPrintableArea(0, 0, size[0], size[1], MediaPrintableArea.INCH));
return docAttributeSet;
}

protected static PrintRequestAttributeSet createPrintRequestAttributeSet(final PrintQuality printQuality,
final MediaSizeName paperSizeName) {
// default printing properties.
final PrintRequestAttributeSet printRequestAttributeSet =
new HashPrintRequestAttributeSet();
final PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();

// assign print quality.
printRequestAttributeSet.add(printQuality);

Expand All @@ -92,9 +91,7 @@ protected static PrintRequestAttributeSet createPrintRequestAttributeSet(final P
final MediaSize mediaSize =
MediaSize.getMediaSizeForName(paperSizeName);
final float[] size = mediaSize.getSize(MediaSize.INCH);
printRequestAttributeSet
.add(new MediaPrintableArea(0, 0, size[0], size[1],
MediaPrintableArea.INCH));
printRequestAttributeSet.add(new MediaPrintableArea(0, 0, size[0], size[1], MediaPrintableArea.INCH));
return printRequestAttributeSet;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.icepdf.core.pobjects.PDimension;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.pobjects.PageTree;
import org.icepdf.core.pobjects.annotations.Annotation;
import org.icepdf.core.util.GraphicsRenderingHints;

import javax.print.*;
Expand All @@ -28,10 +29,13 @@
import javax.print.attribute.standard.PrintQuality;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -71,7 +75,6 @@ public PrintHelperImpl(Container container, PageTree pageTree,
}



/**
* Creates a new <code>PrintHelper</code> instance using the specified
* doc and print attribute sets. This constructor offers the most flexibility
Expand Down Expand Up @@ -160,12 +163,12 @@ public int print(Graphics printGraphics, PageFormat pageFormat, int pageIndex) {
Point imageablePrintLocation = new Point();

// detect if page is being drawn in landscape, if so then we should
// should be rotating the page so that it prints correctly
// be rotating the page so that it prints correctly
float rotation = userRotation;
boolean isDefaultRotation = true;
if ((pageWidth > pageHeight &&
pageFormat.getOrientation() == PageFormat.PORTRAIT)
// auto rotation for landscape.
// autorotation for landscape.
// (pageHeight > pageFormat.getImageableWidth() &&
// pageFormat.getOrientation() == PageFormat.LANDSCAPE )
) {
Expand All @@ -174,13 +177,22 @@ public int print(Graphics printGraphics, PageFormat pageFormat, int pageIndex) {
rotation -= 90;
}

// if true, we want to shrink out page to the new area.
Rectangle pageBoundaryClip = null;
if (isPrintFitToMargin()) {
// find page size including any popup annotations.
Dimension dim = pageDim.toDimension();
Rectangle2D.Float rect = new Rectangle2D.Float(0, 0, dim.width, dim.height);
List<Annotation> annotations = currentPage.getAnnotations();
for (Annotation annot : annotations) {
Rectangle2D.union(
rect,
annot.calculatePageSpaceRectangle(currentPage, Page.BOUNDARY_MEDIABOX, rotation, zoomFactor),
rect);
}

// Get location of imageable area from PageFormat object
Dimension imageablePrintSize;
// correct scale to fit calculation for a possible automatic
// rotation.
// correct scale to fit calculation for a possible automatic rotation.
if (isDefaultRotation) {
imageablePrintSize = new Dimension(
(int) pageFormat.getImageableWidth(),
Expand All @@ -189,17 +201,24 @@ public int print(Graphics printGraphics, PageFormat pageFormat, int pageIndex) {
imageablePrintSize = new Dimension(
(int) pageFormat.getImageableHeight(),
(int) pageFormat.getImageableWidth());

}
float zw = imageablePrintSize.width / pageWidth;
float zh = imageablePrintSize.height / pageHeight;
float zw = imageablePrintSize.width / rect.width;
float zh = imageablePrintSize.height / rect.height;
zoomFactor = Math.min(zw, zh);
imageablePrintLocation.x = (int) pageFormat.getImageableX();
imageablePrintLocation.y = (int) pageFormat.getImageableY();

AffineTransform zoomAf = new AffineTransform();
zoomAf.setToScale(zoomFactor, zoomFactor);
pageBoundaryClip = zoomAf.createTransformedShape(rect).getBounds();

// adjust for new size but also the imageable area of the printer
imageablePrintLocation.x = (int) pageFormat.getImageableX() - pageBoundaryClip.x;
imageablePrintLocation.y = (int) pageFormat.getImageableY() - pageBoundaryClip.y;

}
// apply imageablePrintLocation, normally (0,0)
printGraphics.translate(imageablePrintLocation.x,
imageablePrintLocation.y);
printGraphics.translate(imageablePrintLocation.x, imageablePrintLocation.y);
// apply the new clip is popup printing is active
printGraphics.setClip(pageBoundaryClip);

// Paint the page content
currentPage.paint(printGraphics,
Expand Down
Loading

0 comments on commit e1f0cab

Please sign in to comment.