Skip to content

Commit 9034e37

Browse files
authored
Merge pull request #480 from rototor/fix-link-shapes-#477
Fix link shapes #477
2 parents 7771b60 + 498e52f commit 9034e37

File tree

3 files changed

+53
-85
lines changed

3 files changed

+53
-85
lines changed

openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastLinkManager.java

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
import org.apache.pdfbox.pdmodel.PDPage;
1616
import org.apache.pdfbox.pdmodel.common.PDRectangle;
17-
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDObjectReference;
18-
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
1917
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
2018
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
2119
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
@@ -270,25 +268,33 @@ private boolean placeAnnotation(AffineTransform transform, Shape linkShape, Rect
270268
annot.setPrinted(true);
271269

272270
if (linkShape != null) {
273-
float[] quadPoints = mapShapeToQuadPoints(transform, linkShape, targetArea);
271+
QuadPointShape quadPointsResult = mapShapeToQuadPoints(transform, linkShape, targetArea);
274272
/*
275273
* Is this not an area shape? Then we can not setup quads - ignore this shape.
276274
*/
277-
if (quadPoints.length == 0)
275+
if (quadPointsResult.quadPoints.length == 0)
278276
return false;
279-
annot.setQuadPoints(quadPoints);
277+
annot.setQuadPoints(quadPointsResult.quadPoints);
278+
Rectangle2D reducedTarget = quadPointsResult.boundingBox;
279+
annot.setRectangle(new PDRectangle((float) reducedTarget.getMinX(), (float) reducedTarget.getMinY(),
280+
(float) reducedTarget.getWidth(), (float) reducedTarget.getHeight()));
280281
}
281282
return true;
282283
}
283284

284-
private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
285-
List<Point2D.Float> points = new ArrayList<Point2D.Float>();
285+
static class QuadPointShape {
286+
float[] quadPoints;
287+
Rectangle2D boundingBox;
288+
}
289+
290+
static QuadPointShape mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
291+
List<Point2D.Float> points = new ArrayList<>();
286292
AffineTransform transformForQuads = new AffineTransform();
287293
transformForQuads.translate(targetArea.getMinX(), targetArea.getMinY());
288294
// We must flip the whole thing upside down
289295
transformForQuads.translate(0, targetArea.getHeight());
290296
transformForQuads.scale(1, -1);
291-
transformForQuads.concatenate(transform);
297+
transformForQuads.concatenate(AffineTransform.getScaleInstance(transform.getScaleX(), transform.getScaleX()));
292298
Area area = new Area(linkShape);
293299
PathIterator pathIterator = area.getPathIterator(transformForQuads, 1.0);
294300
double[] vals = new double[6];
@@ -318,7 +324,12 @@ private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape,
318324
KongAlgo algo = new KongAlgo(points);
319325
algo.runKong();
320326

321-
float ret[] = new float[algo.getTriangles().size() * 8];
327+
float minX = (float) targetArea.getMaxX();
328+
float maxX = (float) targetArea.getMinX();
329+
float minY = (float) targetArea.getMaxY();
330+
float maxY = (float) targetArea.getMinY();
331+
332+
float[] ret = new float[algo.getTriangles().size() * 8];
322333
int i = 0;
323334
for (Triangle triangle : algo.getTriangles()) {
324335
ret[i++] = triangle.a.x;
@@ -333,17 +344,36 @@ private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape,
333344

334345
ret[i++] = triangle.c.x;
335346
ret[i++] = triangle.c.y;
347+
348+
for (Point2D.Float p : new Point2D.Float[] { triangle.a, triangle.b, triangle.c }) {
349+
float x = p.x;
350+
float y = p.y;
351+
352+
minX = Math.min(x, minX);
353+
minY = Math.min(y, minY);
354+
355+
maxX = Math.max(x, maxX);
356+
maxY = Math.max(y, maxY);
357+
}
336358
}
337359

360+
//noinspection ConstantConditions
338361
if (ret.length % 8 != 0)
339362
throw new IllegalStateException("Not exact 8xn QuadPoints!");
340363
for (; i < ret.length; i += 2) {
341364
if (ret[i] < targetArea.getMinX() || ret[i] > targetArea.getMaxX())
342365
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
343-
if (ret[i + 1] < targetArea.getMinY() || ret[i + 1] > targetArea.getMaxY())
366+
if (ret[i + 1] < targetArea.getMinY() || ret[
367+
i + 1] > targetArea.getMaxY())
344368
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
345369
}
346-
return ret;
370+
371+
QuadPointShape result = new QuadPointShape();
372+
result.quadPoints = ret;
373+
Rectangle2D.Float boundingRectangle = new Rectangle2D.Float(minX, minY, maxX - minX, maxY - minY);
374+
Rectangle.intersect(targetArea, boundingRectangle, boundingRectangle);
375+
result.boundingBox = boundingRectangle;
376+
return result;
347377
}
348378

349379
private void addLinkToPage(PDPage page, PDAnnotationLink annot, Box anchor, Box target) {

openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxLinkManager.java

Lines changed: 8 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import com.openhtmltopdf.extend.NamespaceHandler;
55
import com.openhtmltopdf.extend.ReplacedElement;
66
import com.openhtmltopdf.layout.SharedContext;
7-
import com.openhtmltopdf.pdfboxout.quads.KongAlgo;
8-
import com.openhtmltopdf.pdfboxout.quads.Triangle;
97
import com.openhtmltopdf.render.BlockBox;
108
import com.openhtmltopdf.render.Box;
119
import com.openhtmltopdf.render.PageBox;
@@ -29,6 +27,8 @@
2927
import java.util.List;
3028
import java.util.Map.Entry;
3129

30+
import static com.openhtmltopdf.pdfboxout.PdfBoxFastLinkManager.mapShapeToQuadPoints;
31+
3232
/**
3333
* @deprecated Use fast link manager instead.
3434
*/
@@ -253,82 +253,20 @@ private boolean placeAnnotation(AffineTransform transform, Shape linkShape, Rect
253253
annot.setRectangle(new PDRectangle((float) targetArea.getMinX(), (float) targetArea.getMinY(),
254254
(float) targetArea.getWidth(), (float) targetArea.getHeight()));
255255
if (linkShape != null) {
256-
float[] quadPoints = mapShapeToQuadPoints(transform, linkShape, targetArea);
256+
PdfBoxFastLinkManager.QuadPointShape quadPointsResult = mapShapeToQuadPoints(transform, linkShape, targetArea);
257257
/*
258258
* Is this not an area shape? Then we can not setup quads - ignore this shape.
259259
*/
260-
if (quadPoints.length == 0)
260+
if (quadPointsResult.quadPoints.length == 0)
261261
return false;
262-
annot.setQuadPoints(quadPoints);
262+
annot.setQuadPoints(quadPointsResult.quadPoints);
263+
Rectangle2D reducedTarget = quadPointsResult.boundingBox;
264+
annot.setRectangle(new PDRectangle((float) reducedTarget.getMinX(), (float) reducedTarget.getMinY(),
265+
(float) reducedTarget.getWidth(), (float) reducedTarget.getHeight()));
263266
}
264267
return true;
265268
}
266269

267-
private float[] mapShapeToQuadPoints(AffineTransform transform, Shape linkShape, Rectangle2D targetArea) {
268-
List<Point2D.Float> points = new ArrayList<Point2D.Float>();
269-
AffineTransform transformForQuads = new AffineTransform();
270-
transformForQuads.translate(targetArea.getMinX(), targetArea.getMinY());
271-
// We must flip the whole thing upside down
272-
transformForQuads.translate(0, targetArea.getHeight());
273-
transformForQuads.scale(1, -1);
274-
transformForQuads.concatenate(transform);
275-
Area area = new Area(linkShape);
276-
PathIterator pathIterator = area.getPathIterator(transformForQuads, 1.0);
277-
double[] vals = new double[6];
278-
while (!pathIterator.isDone()) {
279-
int type = pathIterator.currentSegment(vals);
280-
switch (type) {
281-
case PathIterator.SEG_CUBICTO:
282-
throw new RuntimeException("Invalid State, Area should never give us a curve here!");
283-
case PathIterator.SEG_LINETO:
284-
points.add(new Point2D.Float((float) vals[0], (float) vals[1]));
285-
break;
286-
case PathIterator.SEG_MOVETO:
287-
points.add(new Point2D.Float((float) vals[0], (float) vals[1]));
288-
break;
289-
case PathIterator.SEG_QUADTO:
290-
throw new RuntimeException("Invalid State, Area should never give us a curve here!");
291-
case PathIterator.SEG_CLOSE:
292-
break;
293-
default:
294-
break;
295-
}
296-
pathIterator.next();
297-
}
298-
299-
removeDoublicatePoints(points);
300-
301-
KongAlgo algo = new KongAlgo(points);
302-
algo.runKong();
303-
304-
float ret[] = new float[algo.getTriangles().size() * 8];
305-
int i = 0;
306-
for (Triangle triangle : algo.getTriangles()) {
307-
ret[i++] = triangle.a.x;
308-
ret[i++] = triangle.a.y;
309-
ret[i++] = triangle.b.x;
310-
ret[i++] = triangle.b.y;
311-
/*
312-
* To get a quad we add the point between b and c
313-
*/
314-
ret[i++] = triangle.b.x + (triangle.c.x - triangle.b.x) / 2;
315-
ret[i++] = triangle.b.y + (triangle.c.y - triangle.b.y) / 2;
316-
317-
ret[i++] = triangle.c.x;
318-
ret[i++] = triangle.c.y;
319-
}
320-
321-
if (ret.length % 8 != 0)
322-
throw new IllegalStateException("Not exact 8xn QuadPoints!");
323-
for (; i < ret.length; i += 2) {
324-
if (ret[i] < targetArea.getMinX() || ret[i] > targetArea.getMaxX())
325-
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
326-
if (ret[i + 1] < targetArea.getMinY() || ret[i + 1] > targetArea.getMaxY())
327-
throw new IllegalStateException("Invalid rectangle calculation. Map shape is out of bound.");
328-
}
329-
return ret;
330-
}
331-
332270
private void addLinkToPage(PDPage page, PDAnnotationLink annot) {
333271
PDBorderStyleDictionary styleDict = new PDBorderStyleDictionary();
334272
styleDict.setWidth(0);

openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/quads/KongAlgo.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
* https://www.sunshine2k.de/coding/java/Polygon/Kong/Kong.html
1111
*/
1212
public class KongAlgo {
13-
private static boolean isDebug = false;
13+
private static final boolean isDebug = false;
1414

15-
private List<Point2D.Float> points;
16-
private List<Point2D.Float> nonconvexPoints;
17-
private List<Triangle> triangles;
15+
private final List<Point2D.Float> points;
16+
private final List<Point2D.Float> nonconvexPoints;
17+
private final List<Triangle> triangles;
1818

1919
// orientation of polygon - true = clockwise, false = counterclockwise
2020
private boolean isCw;

0 commit comments

Comments
 (0)