Skip to content

Commit

Permalink
Merge pull request #480 from rototor/fix-link-shapes-#477
Browse files Browse the repository at this point in the history
Fix link shapes #477
  • Loading branch information
danfickle authored May 16, 2020
2 parents 7771b60 + 498e52f commit 9034e37
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDObjectReference;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
Expand Down Expand Up @@ -270,25 +268,33 @@ private boolean placeAnnotation(AffineTransform transform, Shape linkShape, Rect
annot.setPrinted(true);

if (linkShape != null) {
float[] quadPoints = mapShapeToQuadPoints(transform, linkShape, targetArea);
QuadPointShape quadPointsResult = mapShapeToQuadPoints(transform, linkShape, targetArea);
/*
* Is this not an area shape? Then we can not setup quads - ignore this shape.
*/
if (quadPoints.length == 0)
if (quadPointsResult.quadPoints.length == 0)
return false;
annot.setQuadPoints(quadPoints);
annot.setQuadPoints(quadPointsResult.quadPoints);
Rectangle2D reducedTarget = quadPointsResult.boundingBox;
annot.setRectangle(new PDRectangle((float) reducedTarget.getMinX(), (float) reducedTarget.getMinY(),
(float) reducedTarget.getWidth(), (float) reducedTarget.getHeight()));
}
return true;
}

private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
List<Point2D.Float> points = new ArrayList<Point2D.Float>();
static class QuadPointShape {
float[] quadPoints;
Rectangle2D boundingBox;
}

static QuadPointShape mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
List<Point2D.Float> points = new ArrayList<>();
AffineTransform transformForQuads = new AffineTransform();
transformForQuads.translate(targetArea.getMinX(), targetArea.getMinY());
// We must flip the whole thing upside down
transformForQuads.translate(0, targetArea.getHeight());
transformForQuads.scale(1, -1);
transformForQuads.concatenate(transform);
transformForQuads.concatenate(AffineTransform.getScaleInstance(transform.getScaleX(), transform.getScaleX()));
Area area = new Area(linkShape);
PathIterator pathIterator = area.getPathIterator(transformForQuads, 1.0);
double[] vals = new double[6];
Expand Down Expand Up @@ -318,7 +324,12 @@ private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape,
KongAlgo algo = new KongAlgo(points);
algo.runKong();

float ret[] = new float[algo.getTriangles().size() * 8];
float minX = (float) targetArea.getMaxX();
float maxX = (float) targetArea.getMinX();
float minY = (float) targetArea.getMaxY();
float maxY = (float) targetArea.getMinY();

float[] ret = new float[algo.getTriangles().size() * 8];
int i = 0;
for (Triangle triangle : algo.getTriangles()) {
ret[i++] = triangle.a.x;
Expand All @@ -333,17 +344,36 @@ private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape,

ret[i++] = triangle.c.x;
ret[i++] = triangle.c.y;

for (Point2D.Float p : new Point2D.Float[] { triangle.a, triangle.b, triangle.c }) {
float x = p.x;
float y = p.y;

minX = Math.min(x, minX);
minY = Math.min(y, minY);

maxX = Math.max(x, maxX);
maxY = Math.max(y, maxY);
}
}

//noinspection ConstantConditions
if (ret.length % 8 != 0)
throw new IllegalStateException("Not exact 8xn QuadPoints!");
for (; i < ret.length; i += 2) {
if (ret[i] < targetArea.getMinX() || ret[i] > targetArea.getMaxX())
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
if (ret[i + 1] < targetArea.getMinY() || ret[i + 1] > targetArea.getMaxY())
if (ret[i + 1] < targetArea.getMinY() || ret[
i + 1] > targetArea.getMaxY())
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
}
return ret;

QuadPointShape result = new QuadPointShape();
result.quadPoints = ret;
Rectangle2D.Float boundingRectangle = new Rectangle2D.Float(minX, minY, maxX - minX, maxY - minY);
Rectangle.intersect(targetArea, boundingRectangle, boundingRectangle);
result.boundingBox = boundingRectangle;
return result;
}

private void addLinkToPage(PDPage page, PDAnnotationLink annot, Box anchor, Box target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import com.openhtmltopdf.extend.NamespaceHandler;
import com.openhtmltopdf.extend.ReplacedElement;
import com.openhtmltopdf.layout.SharedContext;
import com.openhtmltopdf.pdfboxout.quads.KongAlgo;
import com.openhtmltopdf.pdfboxout.quads.Triangle;
import com.openhtmltopdf.render.BlockBox;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.PageBox;
Expand All @@ -29,6 +27,8 @@
import java.util.List;
import java.util.Map.Entry;

import static com.openhtmltopdf.pdfboxout.PdfBoxFastLinkManager.mapShapeToQuadPoints;

/**
* @deprecated Use fast link manager instead.
*/
Expand Down Expand Up @@ -253,82 +253,20 @@ private boolean placeAnnotation(AffineTransform transform, Shape linkShape, Rect
annot.setRectangle(new PDRectangle((float) targetArea.getMinX(), (float) targetArea.getMinY(),
(float) targetArea.getWidth(), (float) targetArea.getHeight()));
if (linkShape != null) {
float[] quadPoints = mapShapeToQuadPoints(transform, linkShape, targetArea);
PdfBoxFastLinkManager.QuadPointShape quadPointsResult = mapShapeToQuadPoints(transform, linkShape, targetArea);
/*
* Is this not an area shape? Then we can not setup quads - ignore this shape.
*/
if (quadPoints.length == 0)
if (quadPointsResult.quadPoints.length == 0)
return false;
annot.setQuadPoints(quadPoints);
annot.setQuadPoints(quadPointsResult.quadPoints);
Rectangle2D reducedTarget = quadPointsResult.boundingBox;
annot.setRectangle(new PDRectangle((float) reducedTarget.getMinX(), (float) reducedTarget.getMinY(),
(float) reducedTarget.getWidth(), (float) reducedTarget.getHeight()));
}
return true;
}

private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
List<Point2D.Float> points = new ArrayList<Point2D.Float>();
AffineTransform transformForQuads = new AffineTransform();
transformForQuads.translate(targetArea.getMinX(), targetArea.getMinY());
// We must flip the whole thing upside down
transformForQuads.translate(0, targetArea.getHeight());
transformForQuads.scale(1, -1);
transformForQuads.concatenate(transform);
Area area = new Area(linkShape);
PathIterator pathIterator = area.getPathIterator(transformForQuads, 1.0);
double[] vals = new double[6];
while (!pathIterator.isDone()) {
int type = pathIterator.currentSegment(vals);
switch (type) {
case PathIterator.SEG_CUBICTO:
throw new RuntimeException("Invalid State, Area should never give us a curve here!");
case PathIterator.SEG_LINETO:
points.add(new Point2D.Float((float) vals[0], (float) vals[1]));
break;
case PathIterator.SEG_MOVETO:
points.add(new Point2D.Float((float) vals[0], (float) vals[1]));
break;
case PathIterator.SEG_QUADTO:
throw new RuntimeException("Invalid State, Area should never give us a curve here!");
case PathIterator.SEG_CLOSE:
break;
default:
break;
}
pathIterator.next();
}

removeDoublicatePoints(points);

KongAlgo algo = new KongAlgo(points);
algo.runKong();

float ret[] = new float[algo.getTriangles().size() * 8];
int i = 0;
for (Triangle triangle : algo.getTriangles()) {
ret[i++] = triangle.a.x;
ret[i++] = triangle.a.y;
ret[i++] = triangle.b.x;
ret[i++] = triangle.b.y;
/*
* To get a quad we add the point between b and c
*/
ret[i++] = triangle.b.x + (triangle.c.x - triangle.b.x) / 2;
ret[i++] = triangle.b.y + (triangle.c.y - triangle.b.y) / 2;

ret[i++] = triangle.c.x;
ret[i++] = triangle.c.y;
}

if (ret.length % 8 != 0)
throw new IllegalStateException("Not exact 8xn QuadPoints!");
for (; i < ret.length; i += 2) {
if (ret[i] < targetArea.getMinX() || ret[i] > targetArea.getMaxX())
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
if (ret[i + 1] < targetArea.getMinY() || ret[i + 1] > targetArea.getMaxY())
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
}
return ret;
}

private void addLinkToPage(PDPage page, PDAnnotationLink annot) {
PDBorderStyleDictionary styleDict = new PDBorderStyleDictionary();
styleDict.setWidth(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
* https://www.sunshine2k.de/coding/java/Polygon/Kong/Kong.html
*/
public class KongAlgo {
private static boolean isDebug = false;
private static final boolean isDebug = false;

private List<Point2D.Float> points;
private List<Point2D.Float> nonconvexPoints;
private List<Triangle> triangles;
private final List<Point2D.Float> points;
private final List<Point2D.Float> nonconvexPoints;
private final List<Triangle> triangles;

// orientation of polygon - true = clockwise, false = counterclockwise
private boolean isCw;
Expand Down

0 comments on commit 9034e37

Please # to comment.