From 214a21a6d550cfd5434e9e0f24b8d12c41add945 Mon Sep 17 00:00:00 2001 From: danfickle Date: Tue, 9 Mar 2021 14:57:15 +1100 Subject: [PATCH 1/4] #427 API for getting the last y position and more Including the page positions of all layers. By popular demand! --- .../openhtmltopdf/visualtest/TestSupport.java | 47 ++++ .../issue-427-body-page-positions.pdf | Bin 0 -> 2782 bytes .../html/issue-427-body-page-positions.html | 33 +++ .../NonVisualRegressionTest.java | 93 +++++++- .../openhtmltopdf/pdfboxout/PagePosition.java | 6 + .../pdfboxout/PdfBoxFastOutputDevice.java | 2 - .../pdfboxout/PdfBoxRenderer.java | 223 +++++++++++++++++- 7 files changed, 391 insertions(+), 13 deletions(-) create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/expected/issue-427-body-page-positions.pdf create mode 100644 openhtmltopdf-examples/src/main/resources/visualtest/html/issue-427-body-page-positions.html diff --git a/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/visualtest/TestSupport.java b/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/visualtest/TestSupport.java index 78486e78d..5a5961b8c 100644 --- a/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/visualtest/TestSupport.java +++ b/openhtmltopdf-examples/src/main/java/com/openhtmltopdf/visualtest/TestSupport.java @@ -13,13 +13,19 @@ import java.io.StringWriter; import java.nio.file.Files; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.imageio.ImageIO; import com.openhtmltopdf.util.Diagnostic; + +import org.apache.pdfbox.io.IOUtils; import org.w3c.dom.Element; import com.openhtmltopdf.bidi.support.ICUBidiReorderer; @@ -30,8 +36,11 @@ import com.openhtmltopdf.extend.FSTextBreaker; import com.openhtmltopdf.extend.OutputDevice; import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.TextDirection; +import com.openhtmltopdf.pdfboxout.visualtester.PdfVisualTester; +import com.openhtmltopdf.pdfboxout.visualtester.PdfVisualTester.PdfCompareResult; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.svgsupport.BatikSVGDrawer; +import com.openhtmltopdf.testcases.TestcaseRunner; import com.openhtmltopdf.util.XRLogger; import com.openhtmltopdf.visualtest.Java2DVisualTester.Java2DBuilderConfig; import com.openhtmltopdf.visualtest.VisualTester.BuilderConfig; @@ -230,4 +239,42 @@ public boolean isReplacedObject(Element e) { } public static final BuilderConfig WITH_SHAPES_DRAWER = (builder) -> { builder.useObjectDrawerFactory(new ShapesObjectDrawerFactory()); }; + + public static boolean comparePdfs(byte[] actualPdfBytes, String resource) throws IOException { + File outputPath = new File("target/test/visual-tests/test-output/"); + + byte[] expectedPdfBytes; + try (InputStream expectedIs = TestcaseRunner.class.getResourceAsStream("/visualtest/expected/" + resource + ".pdf")) { + expectedPdfBytes = IOUtils.toByteArray(expectedIs); + } + + List problems = PdfVisualTester.comparePdfDocuments(expectedPdfBytes, actualPdfBytes, resource, false); + + if (!problems.isEmpty()) { + System.err.println("Found problems with test case (" + resource + "):"); + System.err.println(problems.stream().map(p -> p.logMessage).collect(Collectors.joining("\n ", "[\n ", "\n]"))); + + File outPdf = new File(outputPath, resource + "---actual.pdf"); + Files.write(outPdf.toPath(), actualPdfBytes); + } + + if (problems.stream().anyMatch(p -> p.testImages != null)) { + System.err.println("For test case (" + resource + ") writing diff images to '" + outputPath + "'"); + } + + for (PdfCompareResult result : problems) { + if (result.testImages != null) { + File output = new File(outputPath, resource + "---" + result.pageNumber + "---diff.png"); + ImageIO.write(result.testImages.createDiff(), "png", output); + + output = new File(outputPath, resource + "---" + result.pageNumber + "---actual.png"); + ImageIO.write(result.testImages.getActual(), "png", output); + + output = new File(outputPath, resource + "---" + result.pageNumber + "---expected.png"); + ImageIO.write(result.testImages.getExpected(), "png", output); + } + } + + return problems.isEmpty(); + } } diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/expected/issue-427-body-page-positions.pdf b/openhtmltopdf-examples/src/main/resources/visualtest/expected/issue-427-body-page-positions.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7b1862801d256ff14bbcf2e9029917ad6685e1d4 GIT binary patch literal 2782 zcmb_e2}~4M818Ds_&Dl;Vp>~Y?IJ9exsM%PDeUE~WTAL$t6kUu*Y3{X?jUG2O%Tu$ z6RjFG0!FQAtWD6S6&p2134}JQmZ&B5wu-hyOgU+6-fP@5;3zqpJ1OGSv=Jc`FJmjJv#42FEN1aT7M0iNqA z5krtd%UvKV3y6|eRikz4wxH-ykb>Q#h%ntgks>IPpb3FwXoBG;kYpM`q?yo8LD^eY zBnDx+Tq;V7m4IK7OTEQdksL7TwpL9&>zU>Pz-RcpA?RjQPavy3IraGgz-@Awq(EA? ziMlFw6M)YWy*`gsu7GX=BcOUy6dQS>opL=v5pC5MF4|X8&?~aaYxc}f?775{Tox=s zc@b2J&aUd$%d|@(CsDYh3YQw`f0oH;NYrG!RMRTP$h4O5XH9F_*F~*nCt`Z0D3vIS zA;}}|IDLKv;f*`}h#GdWNcM`VR!BjN2_%Aw`c>;E#W!asv^`u|`(0OX;py8q3Qi~g^ptPfS4AsF+ue(fcQj9Y+gSY|Dfx@4j8U~+%&_q{U-!p{ix!$! zDpGY*O+&-Y;hDSV&8pA*%5Xk3<}!g5FLhCtQzLyj7e@76^9xTEqh;*Jxs7m`|y=&;fl6JL(Ut z8$0dM*0EKUy@SX0rnEJhrc- z8sl1W&$X|)0H(Lz_fds};%eZZU@uE7qEDTo_2Q|sxDO`}ahPfB@b{Jn!6 z19xo3>pTs|0uOJL|6w>aZ05NBP}VnrNIE#`g;1smgfW9L1VNCH;W3&+^{6jPio;Y1 zD`14m1D-;xpjB!-En1{yR+pg4kvQg^D&%s6rCpR!>OOyu|Z;0Wp;6k^>$I;0_731D{j^ z@wq-JM+*5O0$mstL9rO17EJ(@|0fsZSe9mCapF@MIu^BWP0|_tLW+`6 zbgYbKV`YpP9oA909D(>1B{Q?Jz6e6herP;G-TPTxk`iKN3?D0F34~pgE*~2kDF`wC zp~);JFBHMW*q{hR)+iekN$KKHf*zk=3~J+}OO{ceL5;@+@M%)947I@l{kKE6h36a& zj&V8&hgq;%&6JH79Hf`{{Ip*eB}97h$;`X>A@3JG-gl~Wd^CKjyX>7 EFUE=~p8x;= literal 0 HcmV?d00001 diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-427-body-page-positions.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-427-body-page-positions.html new file mode 100644 index 000000000..9a9d98817 --- /dev/null +++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-427-body-page-positions.html @@ -0,0 +1,33 @@ + + + + + + +
Page one
+This is a test! + +
Fixed layer
+ +
This is page two.
+ +
Absolute layer on page two
+ +
This is page three.
+ +
+ Relative +
Abs in rel
+
+ + + diff --git a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java index cc0c5bf60..a6619cb8e 100644 --- a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java +++ b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java @@ -6,9 +6,11 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; +import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -24,6 +26,8 @@ import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo; import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; @@ -43,6 +47,8 @@ import org.junit.Test; import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority; +import com.openhtmltopdf.pdfboxout.PagePosition; +import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; import com.openhtmltopdf.testcases.TestcaseRunner; import com.openhtmltopdf.util.Diagnostic; @@ -71,20 +77,30 @@ private static void render(String fileName, String html, BuilderConfig config) t System.err.println("Failed to render resource (" + fileName + ")"); e.printStackTrace(); } - + + writePdfToFile(fileName, actual); + } + + private static void writePdfToFile(String fileName, ByteArrayOutputStream actual) throws IOException { FileUtils.writeByteArrayToFile(new File(OUT_PATH, fileName + ".pdf"), actual.toByteArray()); } - - private static PDDocument run(String fileName, BuilderConfig config) throws IOException { + + private static String loadHtml(String fileName) throws IOException { String absResPath = RES_PATH + fileName + ".html"; - - byte[] htmlBytes = IOUtils - .toByteArray(TestcaseRunner.class.getResourceAsStream(absResPath)); - - String html = new String(htmlBytes, Charsets.UTF_8); + + try (InputStream is = TestcaseRunner.class.getResourceAsStream(absResPath)) { + byte[] htmlBytes = IOUtils + .toByteArray(is); + + return new String(htmlBytes, Charsets.UTF_8); + } + } + + private static PDDocument run(String fileName, BuilderConfig config) throws IOException { + String html = loadHtml(fileName); render(fileName, html, config); - + return load(fileName); } @@ -1093,6 +1109,65 @@ public void testIssue508FileEmbed() throws IOException { } } + /** + * Tests the PdfBoxRenderer::getPagePositions and + * PdfBoxRenderer::getLastYPositionOfContent apis. + * It does this by drawing a rect around each layer and comparing + * with the expected document. + */ + @Test + public void testIssue427GetBodyPagePositions() throws IOException { + String filename = "issue-427-body-page-positions"; + String html = loadHtml(filename); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + PdfRendererBuilder builder = new PdfRendererBuilder(); + + builder.withHtmlContent(html, null); + builder.useFastMode(); + builder.toStream(os); + + float lastContentLine; + + try (PdfBoxRenderer renderer = builder.buildPdfRenderer()) { + renderer.createPDFWithoutClosing(); + + List posList = renderer.getPagePositions(); + lastContentLine = renderer.getLastYPositionOfContent(); + + int i = -1; + PDPageContentStream stream = null; + for (PagePosition pos : posList) { + if (i != pos.getPageNo()) { + if (stream != null) { + stream.close(); + } + + stream = new PDPageContentStream(renderer.getPdfDocument(), + renderer.getPdfDocument().getPage(pos.getPageNo()), AppendMode.APPEND, false, false); + stream.setLineWidth(1f); + stream.setStrokingColor(Color.ORANGE); + + i = pos.getPageNo(); + } + + + stream.addRect(pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight()); + stream.stroke(); + } + + if (stream != null) { + stream.close(); + } + + renderer.getPdfDocument().save(os); + writePdfToFile(filename, os); + } + + assertTrue(TestSupport.comparePdfs(os.toByteArray(), filename)); + assertEquals(111.48, lastContentLine, 0.5); + } + // TODO: // + More form controls. // + Custom meta info. diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java index 3b86fd819..f13d78fd3 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java @@ -74,4 +74,10 @@ public String getId() { public void setId(String id) { _id = id; } + + @Override + public String toString() { + return String.format("PagePosition [_id=%s, _pageNo=%s, _x=%s, _width=%s, _y=%s, _height=%s]", + _id, _pageNo, _x, _width, _y, _height); + } } diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java index 157b2eb02..eea8269ab 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java @@ -53,8 +53,6 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; -import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory; -import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.pdmodel.graphics.shading.PDShading; import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode; diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index 9e91e2c36..ac770fe8d 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -35,23 +35,23 @@ import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority; import com.openhtmltopdf.outputdevice.helper.ExternalResourceType; import com.openhtmltopdf.extend.FSDOMMutator; -import com.openhtmltopdf.outputdevice.helper.NullUserInterface; import com.openhtmltopdf.outputdevice.helper.PageDimensions; import com.openhtmltopdf.outputdevice.helper.UnicodeImplementation; import com.openhtmltopdf.pdfboxout.PdfBoxSlowOutputDevice.Metadata; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder.CacheStore; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder.PdfAConformance; import com.openhtmltopdf.render.BlockBox; +import com.openhtmltopdf.render.Box; import com.openhtmltopdf.render.PageBox; import com.openhtmltopdf.render.RenderingContext; import com.openhtmltopdf.render.ViewportBox; import com.openhtmltopdf.render.displaylist.DisplayListCollector; import com.openhtmltopdf.render.displaylist.DisplayListContainer; import com.openhtmltopdf.render.displaylist.DisplayListPainter; +import com.openhtmltopdf.render.displaylist.PagedBoxCollector; import com.openhtmltopdf.render.displaylist.DisplayListContainer.DisplayListPageContainer; import com.openhtmltopdf.resource.XMLResource; import com.openhtmltopdf.simple.extend.XhtmlNamespaceHandler; -import com.openhtmltopdf.util.Configuration; import com.openhtmltopdf.util.LogMessageId; import com.openhtmltopdf.util.ThreadCtx; import com.openhtmltopdf.util.XRLog; @@ -83,10 +83,15 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.logging.Level; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class PdfBoxRenderer implements Closeable, PageSupplier { // See discussion of units at top of PdfBoxOutputDevice. @@ -1039,6 +1044,10 @@ public float getDotsPerPoint() { return _dotsPerPoint; } + /** + * @deprecated unused, unmaintained and untested. + */ + @Deprecated public List findPagePositionsByID(Pattern pattern) { return _outputDevice.findPagePositionsByID(newLayoutContext(), pattern); } @@ -1110,4 +1119,214 @@ public PDPage requestPage(PDDocument doc, float pageWidth, float pageHeight, int doc.addPage(page); return page; } + + /** + * Start page to end page and then top to bottom on page. + */ + private final Comparator PAGE_POSITION_COMPARATOR = + Comparator.comparingInt(PagePosition::getPageNo) + .thenComparing(Comparator.comparingDouble(PagePosition::getY).reversed()); + + /** + * Returns the last Y postion in bottom-up PDF units + * on the last page of content. + * + * WARNING: NOT transform aware. + */ + public float getLastYPositionOfContent() { + List positions = getPagePositions(); + + if (positions.isEmpty()) { + return 0; + } + + return positions.get(positions.size() - 1).getY(); + } + + /** + * Returns a list of page positions for all layers in the document. + * The page positions are sorted from first page to last and then top to bottom. + * The page position values are in bottom-up PDF units. + * + * WARNING: NOT transform aware. Transformed layers will return page + * positions that are not correct. + */ + public List getPagePositions() { + if (getRootBox() == null) { + this.layout(); + } + + Layer rootLayer = getRootBox().getLayer(); + + int[] whiches = new int[] { Layer.NEGATIVE, Layer.AUTO, Layer.ZERO, Layer.POSITIVE }; + + List layers = + Arrays.stream(whiches) + .mapToObj(rootLayer::collectLayers) + .flatMap(List::stream) + .collect(Collectors.toList()); + + RenderingContext ctx = newRenderingContext(); + List pages = rootLayer.getPages(); + + List ret = new ArrayList<>(); + + ret.addAll(getLayerPagePositions(rootLayer, pages, ctx, "root")); + + layers.stream() + .map(layer -> getLayerPagePositions( + layer, pages, ctx, createLayerId(layer))) + .forEach(ret::addAll); + + Collections.sort(ret, PAGE_POSITION_COMPARATOR); + + return ret; + } + + private String createLayerId(Layer layer) { + CalculatedStyle style = layer.getMaster().getStyle(); + String type; + + if (style.isFixed()) { + type = "fixed"; + } else if (style.isAbsolute()) { + type = "absolute"; + } else if (style.isRelative()) { + type = "relative"; + } else { + type = "layer"; + } + + String element = layer.getMaster().getElement() == null ? "anonymous" : + layer.getMaster().getElement().getNodeName(); + + return type + '#' + element; + } + + /** + * Returns a list of page positions for a single layer. + * The page positions are sorted from first page to last and then top to bottom. + * The page position values are in bottom-up PDF units. + * An id may be supplied to set on the page position. + * Compare to {@link #getPagePositions()} which will return page + * positions for all layers. + * + * WARNING: NOT transform aware. A transformed layer will return page + * positions that are not correct. + */ + public List getLayerPagePositions(Layer layer, String id) { + RenderingContext ctx = newRenderingContext(); + List pages = layer.getPages(); + + List ret = getLayerPagePositions(layer, pages, ctx, id); + + Collections.sort(ret, PAGE_POSITION_COMPARATOR); + + return ret; + } + + private List getLayerPagePositions( + Layer layer, List pages, RenderingContext ctx, String id) { + + // FIXME: This method is not transform aware. + + Box box = layer.getMaster(); + + int start = findStartPage(ctx, layer, pages); + int end = findEndPage(ctx, layer, pages); + + if (box.getStyle().isFixed()) { + PageBox page = pages.get(start); + + float x = box.getAbsX() + page.getMarginBorderPadding(ctx, CalculatedStyle.LEFT); + float w = box.getEffectiveWidth(); + float y = page.getMarginBorderPadding(ctx, CalculatedStyle.BOTTOM) + + (page.getPaintingBottom() - box.getAbsY() - box.getHeight()); + float h = box.getHeight(); + + return IntStream.range(0, pages.size()) + .mapToObj(pageNo -> createPagePosition(id, pageNo, x, w, y, h)) + .collect(Collectors.toList()); + } + + List ret = new ArrayList<>((end - start) + 1); + + for (int i = start; i <= end; i++) { + PageBox page = pages.get(i); + + float x = box.getAbsX() + page.getMarginBorderPadding(ctx, CalculatedStyle.LEFT); + float w = box.getEffectiveWidth(); + + float y; + float h; + + if (start != end) { + if (i != start && i != end) { + y = page.getMarginBorderPadding(ctx, CalculatedStyle.BOTTOM); + h = page.getContentHeight(ctx); + } else if (i == end) { + h = (box.getAbsY() + box.getHeight()) - page.getPaintingTop(); + y = page.getMarginBorderPadding(ctx, CalculatedStyle.BOTTOM) + + page.getContentHeight(ctx) - h; + } else { + assert i == start; + y = page.getMarginBorderPadding(ctx, CalculatedStyle.BOTTOM); + h = page.getPaintingBottom() - box.getAbsY(); + } + } else { + y = page.getMarginBorderPadding(ctx, CalculatedStyle.BOTTOM) + + (page.getPaintingBottom() - box.getAbsY() - box.getHeight()); + h = box.getHeight(); + } + + PagePosition pos = createPagePosition(id, i, x, w, y, h); + + ret.add(pos); + } + + return ret; + } + + private PagePosition createPagePosition( + String id, int pageNo, float x, float w, float y, float h) { + + PagePosition pos = new PagePosition(); + + pos.setId(id); + pos.setPageNo(pageNo); + pos.setX(x / _dotsPerPoint); + pos.setY(y / _dotsPerPoint); + pos.setWidth(w / _dotsPerPoint); + pos.setHeight(h / _dotsPerPoint); + + return pos; + } + + /** + * Returns the start page for a layer. Transform aware. + */ + private int findStartPage(RenderingContext c, Layer layer, List pages) { + int start = PagedBoxCollector.findStartPage(c, layer.getMaster(), pages); + + // Floats maybe outside the master box. + for (BlockBox floater : layer.getFloats()) { + start = Math.min(start, PagedBoxCollector.findStartPage(c, floater, pages)); + } + + return start; + } + + /** + * Returns the end page number for a layer. Transform aware. + */ + private int findEndPage(RenderingContext c, Layer layer, List pages) { + int end = PagedBoxCollector.findEndPage(c, layer.getMaster(), pages); + + // Floats may be outside the master box. + for (BlockBox floater : layer.getFloats()) { + end = Math.max(end, PagedBoxCollector.findEndPage(c, floater, pages)); + } + + return end; + } } From 50a2e8325caff5b4e9905c604d1608761c1068ef Mon Sep 17 00:00:00 2001 From: danfickle Date: Wed, 10 Mar 2021 18:55:13 +1100 Subject: [PATCH 2/4] #427 Let PagePosition directly reference a Layer. As kindly suggested by @stechio. Also: + Make PagePosition immutable. + Rename getPagePositions to getAllLayerPagePositions in case we later want to add methods for boxes, etc. --- .../NonVisualRegressionTest.java | 2 +- .../openhtmltopdf/pdfboxout/PagePosition.java | 68 +++++++++---------- .../pdfboxout/PdfBoxFastOutputDevice.java | 11 +-- .../pdfboxout/PdfBoxRenderer.java | 55 ++++----------- .../pdfboxout/PdfBoxSlowOutputDevice.java | 11 +-- 5 files changed, 49 insertions(+), 98 deletions(-) diff --git a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java index a6619cb8e..8cfcbcf74 100644 --- a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java +++ b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java @@ -1132,7 +1132,7 @@ public void testIssue427GetBodyPagePositions() throws IOException { try (PdfBoxRenderer renderer = builder.buildPdfRenderer()) { renderer.createPDFWithoutClosing(); - List posList = renderer.getPagePositions(); + List posList = renderer.getAllLayerPagePositions(); lastContentLine = renderer.getLastYPositionOfContent(); int i = -1; diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java index f13d78fd3..21c8b862a 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java @@ -19,65 +19,59 @@ */ package com.openhtmltopdf.pdfboxout; +import com.openhtmltopdf.layout.Layer; + public class PagePosition { - private String _id; - private int _pageNo; - private float _x; - private float _width; - private float _y; - private float _height; - + private final String _id; + private final Layer _layer; + private final int _pageNo; + private final float _x; + private final float _y; + private final float _width; + private final float _height; + + public PagePosition(String id, Layer layer, int pageNo, float x, float y, float width, float height) { + this._id = id; + this._layer = layer; + this._pageNo = pageNo; + this._x = x; + this._y = y; + this._width = width; + this._height = height; + } + public int getPageNo() { return _pageNo; } - - public void setPageNo(int pageNo) { - _pageNo = pageNo; - } - + public float getX() { return _x; } - - public void setX(float x) { - _x = x; - } - - public float getWidth() { - return _width; - } - - public void setWidth(float width) { - _width = width; - } - + public float getY() { return _y; } - - public void setY(float y) { - _y = y; + + public float getWidth() { + return _width; } - + public float getHeight() { return _height; } - - public void setHeight(float height) { - _height = height; - } public String getId() { return _id; } - public void setId(String id) { - _id = id; + public Layer getLayer() { + return _layer; } @Override public String toString() { - return String.format("PagePosition [_id=%s, _pageNo=%s, _x=%s, _width=%s, _y=%s, _height=%s]", - _id, _pageNo, _x, _width, _y, _height); + return String.format( + "PagePosition [_id=%s, _layer=%s, _pageNo=%s, _x=%s, _y=%s, _width=%s, _height=%s]", + _id, _layer, _pageNo, _x, _y, _width, _height); } } diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java index eea8269ab..2b710a47f 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java @@ -1218,15 +1218,8 @@ private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { x /= _dotsPerPoint; y /= _dotsPerPoint; - PagePosition result = new PagePosition(); - result.setId(id); - result.setPageNo(page.getPageNo()); - result.setX(x); - result.setY(y); - result.setWidth(box.getEffectiveWidth() / _dotsPerPoint); - result.setHeight(box.getHeight() / _dotsPerPoint); - - return result; + return new PagePosition( + id, null, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); } @Override diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index ac770fe8d..601a6f3e1 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -1134,7 +1134,7 @@ public PDPage requestPage(PDDocument doc, float pageWidth, float pageHeight, int * WARNING: NOT transform aware. */ public float getLastYPositionOfContent() { - List positions = getPagePositions(); + List positions = getAllLayerPagePositions(); if (positions.isEmpty()) { return 0; @@ -1151,7 +1151,7 @@ public float getLastYPositionOfContent() { * WARNING: NOT transform aware. Transformed layers will return page * positions that are not correct. */ - public List getPagePositions() { + public List getAllLayerPagePositions() { if (getRootBox() == null) { this.layout(); } @@ -1171,11 +1171,10 @@ public List getPagePositions() { List ret = new ArrayList<>(); - ret.addAll(getLayerPagePositions(rootLayer, pages, ctx, "root")); + ret.addAll(getLayerPagePositions(rootLayer, pages, ctx)); layers.stream() - .map(layer -> getLayerPagePositions( - layer, pages, ctx, createLayerId(layer))) + .map(layer -> getLayerPagePositions(layer, pages, ctx)) .forEach(ret::addAll); Collections.sort(ret, PAGE_POSITION_COMPARATOR); @@ -1183,42 +1182,22 @@ layer, pages, ctx, createLayerId(layer))) return ret; } - private String createLayerId(Layer layer) { - CalculatedStyle style = layer.getMaster().getStyle(); - String type; - - if (style.isFixed()) { - type = "fixed"; - } else if (style.isAbsolute()) { - type = "absolute"; - } else if (style.isRelative()) { - type = "relative"; - } else { - type = "layer"; - } - - String element = layer.getMaster().getElement() == null ? "anonymous" : - layer.getMaster().getElement().getNodeName(); - - return type + '#' + element; - } - /** * Returns a list of page positions for a single layer. * The page positions are sorted from first page to last and then top to bottom. * The page position values are in bottom-up PDF units. * An id may be supplied to set on the page position. - * Compare to {@link #getPagePositions()} which will return page + * Compare to {@link #getAllLayerPagePositions()} which will return page * positions for all layers. * * WARNING: NOT transform aware. A transformed layer will return page * positions that are not correct. */ - public List getLayerPagePositions(Layer layer, String id) { + public List getLayerPagePositions(Layer layer) { RenderingContext ctx = newRenderingContext(); List pages = layer.getPages(); - List ret = getLayerPagePositions(layer, pages, ctx, id); + List ret = getLayerPagePositions(layer, pages, ctx); Collections.sort(ret, PAGE_POSITION_COMPARATOR); @@ -1226,7 +1205,7 @@ public List getLayerPagePositions(Layer layer, String id) { } private List getLayerPagePositions( - Layer layer, List pages, RenderingContext ctx, String id) { + Layer layer, List pages, RenderingContext ctx) { // FIXME: This method is not transform aware. @@ -1245,7 +1224,7 @@ private List getLayerPagePositions( float h = box.getHeight(); return IntStream.range(0, pages.size()) - .mapToObj(pageNo -> createPagePosition(id, pageNo, x, w, y, h)) + .mapToObj(pageNo -> createPagePosition(null, layer, pageNo, x, y, w, h)) .collect(Collectors.toList()); } @@ -1279,7 +1258,7 @@ private List getLayerPagePositions( h = box.getHeight(); } - PagePosition pos = createPagePosition(id, i, x, w, y, h); + PagePosition pos = createPagePosition(null, layer, i, x, y, w, h); ret.add(pos); } @@ -1288,18 +1267,10 @@ private List getLayerPagePositions( } private PagePosition createPagePosition( - String id, int pageNo, float x, float w, float y, float h) { - - PagePosition pos = new PagePosition(); - - pos.setId(id); - pos.setPageNo(pageNo); - pos.setX(x / _dotsPerPoint); - pos.setY(y / _dotsPerPoint); - pos.setWidth(w / _dotsPerPoint); - pos.setHeight(h / _dotsPerPoint); + String id, Layer layer, int pageNo, float x, float y, float w, float h) { - return pos; + return new PagePosition( + id, layer, pageNo, x / _dotsPerPoint, y / _dotsPerPoint, w / _dotsPerPoint, h / _dotsPerPoint); } /** diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java index ffeb754e0..189c83cb0 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java @@ -1364,15 +1364,8 @@ private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { x /= _dotsPerPoint; y /= _dotsPerPoint; - PagePosition result = new PagePosition(); - result.setId(id); - result.setPageNo(page.getPageNo()); - result.setX(x); - result.setY(y); - result.setWidth(box.getEffectiveWidth() / _dotsPerPoint); - result.setHeight(box.getHeight() / _dotsPerPoint); - - return result; + return new PagePosition( + id, null, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); } public void setRenderingContext(RenderingContext result) { From f809e3cd4cb6373a36533680c8b47cb44d551f98 Mon Sep 17 00:00:00 2001 From: danfickle Date: Fri, 12 Mar 2021 22:08:04 +1100 Subject: [PATCH 3/4] #427 Make PagePosition generic and rename API methods Implementing excellent suggestions made by @stechio in #666. Note: I did not rename findPagePositionsByID as others may be using. --- .../NonVisualRegressionTest.java | 7 ++-- .../openhtmltopdf/pdfboxout/PagePosition.java | 18 ++++----- .../pdfboxout/PdfBoxFastOutputDevice.java | 36 ++++++----------- .../pdfboxout/PdfBoxOutputDevice.java | 2 +- .../pdfboxout/PdfBoxRenderer.java | 40 +++++++++---------- .../pdfboxout/PdfBoxSlowOutputDevice.java | 16 ++++---- 6 files changed, 52 insertions(+), 67 deletions(-) diff --git a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java index 8cfcbcf74..a23dc6599 100644 --- a/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java +++ b/openhtmltopdf-examples/src/test/java/com/openhtmltopdf/nonvisualregressiontests/NonVisualRegressionTest.java @@ -46,6 +46,7 @@ import org.junit.Assert; import org.junit.Test; +import com.openhtmltopdf.layout.Layer; import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority; import com.openhtmltopdf.pdfboxout.PagePosition; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; @@ -1132,12 +1133,12 @@ public void testIssue427GetBodyPagePositions() throws IOException { try (PdfBoxRenderer renderer = builder.buildPdfRenderer()) { renderer.createPDFWithoutClosing(); - List posList = renderer.getAllLayerPagePositions(); - lastContentLine = renderer.getLastYPositionOfContent(); + List> posList = renderer.getLayersPositions(); + lastContentLine = renderer.getLastContentBottom(); int i = -1; PDPageContentStream stream = null; - for (PagePosition pos : posList) { + for (PagePosition pos : posList) { if (i != pos.getPageNo()) { if (stream != null) { stream.close(); diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java index 21c8b862a..f4af94342 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PagePosition.java @@ -19,20 +19,18 @@ */ package com.openhtmltopdf.pdfboxout; -import com.openhtmltopdf.layout.Layer; - -public class PagePosition { +public class PagePosition { private final String _id; - private final Layer _layer; + private final T _element; private final int _pageNo; private final float _x; private final float _y; private final float _width; private final float _height; - public PagePosition(String id, Layer layer, int pageNo, float x, float y, float width, float height) { + public PagePosition(String id, T element, int pageNo, float x, float y, float width, float height) { this._id = id; - this._layer = layer; + this._element = element; this._pageNo = pageNo; this._x = x; this._y = y; @@ -64,14 +62,14 @@ public String getId() { return _id; } - public Layer getLayer() { - return _layer; + public T getElement() { + return _element; } @Override public String toString() { return String.format( - "PagePosition [_id=%s, _layer=%s, _pageNo=%s, _x=%s, _y=%s, _width=%s, _height=%s]", - _id, _layer, _pageNo, _x, _y, _width, _height); + "PagePosition [_id=%s, _element=%s, _pageNo=%s, _x=%s, _y=%s, _width=%s, _height=%s]", + _id, _element, _pageNo, _x, _y, _width, _height); } } diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java index 2b710a47f..0dc93b0c1 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxFastOutputDevice.java @@ -69,6 +69,7 @@ import java.util.Map.Entry; import java.util.logging.Level; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class PdfBoxFastOutputDevice extends AbstractOutputDevice implements OutputDevice, PdfBoxOutputDevice { // @@ -1180,34 +1181,23 @@ protected PDFont mapFont(Font font, IFontTextDrawerEnv env) { } } - public List findPagePositionsByID(CssContext c, Pattern pattern) { + public List> findPagePositionsByID(CssContext c, Pattern pattern) { Map idMap = _sharedContext.getIdMap(); if (idMap == null) { return Collections.emptyList(); } - List result = new ArrayList<>(); - for (Entry entry : idMap.entrySet()) { - String id = (String) entry.getKey(); - if (pattern.matcher(id).find()) { - Box box = (Box) entry.getValue(); - PagePosition pos = calcPDFPagePosition(c, id, box); - if (pos != null) { - result.add(pos); - } - } - } - - Collections.sort(result, new Comparator() { - public int compare(PagePosition p1, PagePosition p2) { - return p1.getPageNo() - p2.getPageNo(); - } - }); - - return result; + return + idMap.entrySet() + .stream() + .filter(entry -> pattern.matcher(entry.getKey()).find()) + .map(entry -> calcPDFPagePosition(c, entry.getKey(), entry.getValue())) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(PagePosition::getPageNo)) + .collect(Collectors.toList()); } - private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { + private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { PageBox page = _root.getLayer().getLastPage(c, box); if (page == null) { return null; @@ -1218,8 +1208,8 @@ private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { x /= _dotsPerPoint; y /= _dotsPerPoint; - return new PagePosition( - id, null, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); + return new PagePosition( + id, box, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); } @Override diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java index ead654683..320adab2b 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxOutputDevice.java @@ -183,7 +183,7 @@ void drawStringFast(String s, float x, float y, JustificationInfo info, void drawWithGraphics(float x, float y, float width, float height, OutputDeviceGraphicsDrawer renderer); - List findPagePositionsByID(CssContext c, Pattern pattern); + List> findPagePositionsByID(CssContext c, Pattern pattern); void setRenderingContext(RenderingContext result); diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index 601a6f3e1..c81cf9eb1 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -1044,11 +1044,7 @@ public float getDotsPerPoint() { return _dotsPerPoint; } - /** - * @deprecated unused, unmaintained and untested. - */ - @Deprecated - public List findPagePositionsByID(Pattern pattern) { + public List> findPagePositionsByID(Pattern pattern) { return _outputDevice.findPagePositionsByID(newLayoutContext(), pattern); } @@ -1123,9 +1119,9 @@ public PDPage requestPage(PDDocument doc, float pageWidth, float pageHeight, int /** * Start page to end page and then top to bottom on page. */ - private final Comparator PAGE_POSITION_COMPARATOR = - Comparator.comparingInt(PagePosition::getPageNo) - .thenComparing(Comparator.comparingDouble(PagePosition::getY).reversed()); + private final Comparator> PAGE_POSITION_COMPARATOR = + Comparator.comparingInt(PagePosition::getPageNo) + .thenComparing(Comparator.comparingDouble(PagePosition::getY).reversed()); /** * Returns the last Y postion in bottom-up PDF units @@ -1133,8 +1129,8 @@ public PDPage requestPage(PDDocument doc, float pageWidth, float pageHeight, int * * WARNING: NOT transform aware. */ - public float getLastYPositionOfContent() { - List positions = getAllLayerPagePositions(); + public float getLastContentBottom() { + List> positions = getLayersPositions(); if (positions.isEmpty()) { return 0; @@ -1151,7 +1147,7 @@ public float getLastYPositionOfContent() { * WARNING: NOT transform aware. Transformed layers will return page * positions that are not correct. */ - public List getAllLayerPagePositions() { + public List> getLayersPositions() { if (getRootBox() == null) { this.layout(); } @@ -1169,7 +1165,7 @@ public List getAllLayerPagePositions() { RenderingContext ctx = newRenderingContext(); List pages = rootLayer.getPages(); - List ret = new ArrayList<>(); + List> ret = new ArrayList<>(); ret.addAll(getLayerPagePositions(rootLayer, pages, ctx)); @@ -1187,24 +1183,24 @@ public List getAllLayerPagePositions() { * The page positions are sorted from first page to last and then top to bottom. * The page position values are in bottom-up PDF units. * An id may be supplied to set on the page position. - * Compare to {@link #getAllLayerPagePositions()} which will return page + * Compare to {@link #getLayersPositions()} which will return page * positions for all layers. * * WARNING: NOT transform aware. A transformed layer will return page * positions that are not correct. */ - public List getLayerPagePositions(Layer layer) { + public List> getLayerPositions(Layer layer) { RenderingContext ctx = newRenderingContext(); List pages = layer.getPages(); - List ret = getLayerPagePositions(layer, pages, ctx); + List> ret = getLayerPagePositions(layer, pages, ctx); Collections.sort(ret, PAGE_POSITION_COMPARATOR); return ret; } - private List getLayerPagePositions( + private List> getLayerPagePositions( Layer layer, List pages, RenderingContext ctx) { // FIXME: This method is not transform aware. @@ -1228,7 +1224,7 @@ private List getLayerPagePositions( .collect(Collectors.toList()); } - List ret = new ArrayList<>((end - start) + 1); + List> ret = new ArrayList<>((end - start) + 1); for (int i = start; i <= end; i++) { PageBox page = pages.get(i); @@ -1258,7 +1254,7 @@ private List getLayerPagePositions( h = box.getHeight(); } - PagePosition pos = createPagePosition(null, layer, i, x, y, w, h); + PagePosition pos = createPagePosition(null, layer, i, x, y, w, h); ret.add(pos); } @@ -1266,11 +1262,11 @@ private List getLayerPagePositions( return ret; } - private PagePosition createPagePosition( - String id, Layer layer, int pageNo, float x, float y, float w, float h) { + private PagePosition createPagePosition( + String id, T element, int pageNo, float x, float y, float w, float h) { - return new PagePosition( - id, layer, pageNo, x / _dotsPerPoint, y / _dotsPerPoint, w / _dotsPerPoint, h / _dotsPerPoint); + return new PagePosition<>( + id, element, pageNo, x / _dotsPerPoint, y / _dotsPerPoint, w / _dotsPerPoint, h / _dotsPerPoint); } /** diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java index 189c83cb0..2156e3bb4 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxSlowOutputDevice.java @@ -1326,26 +1326,26 @@ protected PDFont mapFont(Font font, IFontTextDrawerEnv env) { } } - public List findPagePositionsByID(CssContext c, Pattern pattern) { + public List> findPagePositionsByID(CssContext c, Pattern pattern) { Map idMap = _sharedContext.getIdMap(); if (idMap == null) { return Collections.emptyList(); } - List result = new ArrayList<>(); + List> result = new ArrayList<>(); for (Entry entry : idMap.entrySet()) { String id = (String) entry.getKey(); if (pattern.matcher(id).find()) { Box box = (Box) entry.getValue(); - PagePosition pos = calcPDFPagePosition(c, id, box); + PagePosition pos = calcPDFPagePosition(c, id, box); if (pos != null) { result.add(pos); } } } - Collections.sort(result, new Comparator() { - public int compare(PagePosition p1, PagePosition p2) { + Collections.sort(result, new Comparator>() { + public int compare(PagePosition p1, PagePosition p2) { return p1.getPageNo() - p2.getPageNo(); } }); @@ -1353,7 +1353,7 @@ public int compare(PagePosition p1, PagePosition p2) { return result; } - private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { + private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { PageBox page = _root.getLayer().getLastPage(c, box); if (page == null) { return null; @@ -1364,8 +1364,8 @@ private PagePosition calcPDFPagePosition(CssContext c, String id, Box box) { x /= _dotsPerPoint; y /= _dotsPerPoint; - return new PagePosition( - id, null, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); + return new PagePosition<>( + id, box, page.getPageNo(), x, y, box.getEffectiveWidth() / _dotsPerPoint, box.getHeight() / _dotsPerPoint); } public void setRenderingContext(RenderingContext result) { From d588f1cc1cdd7256ca729866fbcc453008d44eec Mon Sep 17 00:00:00 2001 From: danfickle Date: Fri, 12 Mar 2021 22:17:46 +1100 Subject: [PATCH 4/4] #427 Fix javadoc for API methods --- .../main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java index c81cf9eb1..30720de0f 100644 --- a/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java +++ b/openhtmltopdf-pdfbox/src/main/java/com/openhtmltopdf/pdfboxout/PdfBoxRenderer.java @@ -1124,7 +1124,7 @@ public PDPage requestPage(PDDocument doc, float pageWidth, float pageHeight, int .thenComparing(Comparator.comparingDouble(PagePosition::getY).reversed()); /** - * Returns the last Y postion in bottom-up PDF units + * Returns the bottom Y postion in bottom-up PDF units * on the last page of content. * * WARNING: NOT transform aware. @@ -1182,7 +1182,7 @@ public List> getLayersPositions() { * Returns a list of page positions for a single layer. * The page positions are sorted from first page to last and then top to bottom. * The page position values are in bottom-up PDF units. - * An id may be supplied to set on the page position. + * * Compare to {@link #getLayersPositions()} which will return page * positions for all layers. *