You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2018/06/08 17:07:30 UTC
svn commit: r1833197 - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers:
PDAbstractAppearanceHandler.java PDTextAppearanceHandler.java
Author: tilman
Date: Fri Jun 8 17:07:30 2018
New Revision: 1833197
URL: http://svn.apache.org/viewvc?rev=1833197&view=rev
Log:
PDFBOX-3353: support /Circle and /Insert; use the Adobe width for /Note; draw circle counterclockwise
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDAbstractAppearanceHandler.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDTextAppearanceHandler.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDAbstractAppearanceHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDAbstractAppearanceHandler.java?rev=1833197&r1=1833196&r2=1833197&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDAbstractAppearanceHandler.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDAbstractAppearanceHandler.java Fri Jun 8 17:07:30 2018
@@ -365,14 +365,14 @@ public abstract class PDAbstractAppearan
}
/**
- * Add a circle shape to the path.
+ * Add a circle shape to the path in clockwise direction.
*
* @param cs Content stream
* @param x
* @param y
* @param r Radius
*
- * @throws IOException If the content stream could not be written
+ * @throws IOException If the content stream could not be written.
*/
void addCircle(PDAppearanceContentStream cs, float x, float y, float r) throws IOException
{
@@ -386,6 +386,29 @@ public abstract class PDAbstractAppearan
cs.closePath();
}
+ /**
+ * Add a circle shape to the path in counterclockwise direction. You'll need this e.g. when
+ * drawing a doughnut shape. See "Nonzero Winding Number Rule" for more information.
+ *
+ * @param cs Content stream
+ * @param x
+ * @param y
+ * @param r Radius
+ *
+ * @throws IOException If the content stream could not be written.
+ */
+ void addCircle2(PDAppearanceContentStream cs, float x, float y, float r) throws IOException
+ {
+ // http://stackoverflow.com/a/2007782/535646
+ float magic = r * 0.551784f;
+ cs.moveTo(x, y + r);
+ cs.curveTo(x - magic, y + r, x - r, y + magic, x - r, y);
+ cs.curveTo(x - r, y - magic, x - magic, y - r, x, y - r);
+ cs.curveTo(x + magic, y - r, x + r, y - magic, x + r, y);
+ cs.curveTo(x + r, y + magic, x + magic, y + r, x, y + r);
+ cs.closePath();
+ }
+
private static Set<String> createShortStyles()
{
Set<String> shortStyles = new HashSet<>();
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDTextAppearanceHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDTextAppearanceHandler.java?rev=1833197&r1=1833196&r2=1833197&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDTextAppearanceHandler.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/PDTextAppearanceHandler.java Fri Jun 8 17:07:30 2018
@@ -20,9 +20,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.pdmodel.PDAppearanceContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
+import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationText;
-import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
/**
*
@@ -49,47 +51,62 @@ public class PDTextAppearanceHandler ext
public void generateNormalAppearance()
{
PDAnnotationText annotation = (PDAnnotationText) getAnnotation();
- if (!PDAnnotationText.NAME_NOTE.equals(annotation.getName()))
+ if (!PDAnnotationText.NAME_NOTE.equals(annotation.getName()) &&
+ !PDAnnotationText.NAME_INSERT.equals(annotation.getName()) &&
+ !"Circle".equals(annotation.getName()))
{
- //TODO Comment, Key, Help, NewParagraph, Paragraph, Insert
+ //TODO Comment, Key, Help, NewParagraph, Paragraph
return;
}
try (PDAppearanceContentStream contentStream = getNormalAppearanceAsContentStream())
{
- boolean hasBackground = contentStream.setNonStrokingColorOnDemand(getColor());
+ PDColor bgColor = getColor();
+ if (bgColor == null)
+ {
+ // White is used by Adobe when /C entry is missing
+ contentStream.setNonStrokingColor(1f);
+ }
+ else
+ {
+ contentStream.setNonStrokingColor(bgColor);
+ }
+ // stroking color is always black which is the PDF default
+
setOpacity(contentStream, annotation.getConstantOpacity());
- //TODO find out what Adobe chooses if color is missing
-
PDRectangle rect = getRectangle();
- PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
PDRectangle bbox = rect.createRetranslatedRectangle();
- appearanceStream.setBBox(bbox);
+ annotation.getNormalAppearanceStream().setBBox(bbox);
switch (annotation.getName())
{
case PDAnnotationText.NAME_NOTE:
- drawNote(contentStream, bbox, hasBackground);
+ drawNote(contentStream, bbox);
+ break;
+ case "Circle": //TODO constant
+ drawCircles(contentStream, bbox);
+ break;
+ case PDAnnotationText.NAME_INSERT:
+ drawInsert(contentStream, bbox);
break;
default:
break;
}
-
}
catch (IOException e)
{
LOG.error(e);
}
-
}
- private void drawNote(final PDAppearanceContentStream contentStream, PDRectangle bbox, boolean hasBackground)
+ private void drawNote(final PDAppearanceContentStream contentStream, PDRectangle bbox)
throws IOException
{
- contentStream.setLineJoinStyle(1); // round edge
- contentStream.addRect(1, 1, bbox.getWidth() - 2, bbox.getHeight() - 2);
+ contentStream.setLineJoinStyle(1); // get round edge the easy way
+ contentStream.setLineWidth(0.61f); // value from Adobe
+ contentStream.addRect(1, 1, bbox.getWidth() - 2, bbox.getHeight() - 2);
contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 2);
contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 2);
contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 3);
@@ -98,7 +115,58 @@ public class PDTextAppearanceHandler ext
contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 4);
contentStream.moveTo(bbox.getWidth() / 4, bbox.getHeight() / 7 * 5);
contentStream.lineTo(bbox.getWidth() * 3 / 4 - 1, bbox.getHeight() / 7 * 5);
- contentStream.drawShape(1, true, hasBackground);
+ contentStream.fillAndStroke();
+ }
+
+ private void drawCircles(final PDAppearanceContentStream contentStream, PDRectangle bbox)
+ throws IOException
+ {
+ // strategy used by Adobe:
+ // 1) add small circle in white using /ca /CA 0.6 and width 1
+ // 2) fill
+ // 3) add small circle in one direction
+ // 4) add large circle in other direction
+ // 5) stroke + fill
+ // with square width 20 small r = 6.36, large r = 9.756
+
+ // should be a square, but who knows...
+ float min = Math.min(bbox.getWidth(), bbox.getHeight());
+ float smallR = min / 20 * 6.36f;
+ float largeR = min / 20 * 9.756f;
+
+ contentStream.setMiterLimit(4);
+ contentStream.setLineJoinStyle(1);
+ contentStream.setLineCapStyle(0);
+ contentStream.saveGraphicsState();
+ contentStream.setLineWidth(1);
+ PDExtendedGraphicsState gs = new PDExtendedGraphicsState();
+ gs.setAlphaSourceFlag(false);
+ gs.setStrokingAlphaConstant(0.6f);
+ gs.setNonStrokingAlphaConstant(0.6f);
+ gs.setBlendMode(BlendMode.NORMAL);
+ contentStream.setGraphicsStateParameters(gs);
+ contentStream.setNonStrokingColor(1f);
+ addCircle(contentStream, bbox.getWidth() / 2, bbox.getHeight() / 2, smallR);
+ contentStream.fill();
+ contentStream.restoreGraphicsState();
+
+ contentStream.setLineWidth(0.59f); // value from Adobe
+ addCircle(contentStream, bbox.getWidth() / 2, bbox.getHeight() / 2, smallR);
+ addCircle2(contentStream, bbox.getWidth() / 2, bbox.getHeight() / 2, largeR);
+ contentStream.fillAndStroke();
+ }
+
+ private void drawInsert(final PDAppearanceContentStream contentStream, PDRectangle bbox)
+ throws IOException
+ {
+ contentStream.setMiterLimit(4);
+ contentStream.setLineJoinStyle(0);
+ contentStream.setLineCapStyle(0);
+ contentStream.setLineWidth(0.59f); // value from Adobe
+ contentStream.moveTo(bbox.getWidth() / 2 - 1, bbox.getHeight() - 2);
+ contentStream.lineTo(1, 1);
+ contentStream.lineTo(bbox.getWidth() - 2, 1);
+ contentStream.closeAndFillAndStroke();
}
@Override