Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix link shapes #477 #480

Merged
merged 4 commits into from
May 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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