diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index 6118dd2b920..8c1096d04ec 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -1033,6 +1033,19 @@ 0d7160a4af04bf2f785bf4155f69876da4b7ff7a196e7eda1eb904c02c35aa03c31041d9339fda90322cb58bde16b87bae8460c617bfe5b8dc0670ddab102f62 + + PDFBOX-5250 + generate-test-resources + + wget + + + https://issues.apache.org/jira/secure/attachment/13073765/PDFBOX-5250-pattern-reduced3.pdf + ${project.build.directory}/pdfs + PDFBOX-5250-pattern-reduced3.pdf + fef1da8db49531a3bf017c6872b2032cac2d3c7e431f5529a80f87886b2d06455d086c9228ad35aee80d824ffb9e65e5ea302327b7feada001ede66f83199101 + + PDFBOX-5960 generate-test-resources diff --git a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java index fee2aaeff53..d8cc36d2c65 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java @@ -239,13 +239,13 @@ protected void processTransparencyGroup(PDTransparencyGroup group) throws IOExce Matrix parentMatrix = initialMatrix; PDGraphicsState graphicsState = getGraphicsState(); - // the stream's initial matrix includes the parent CTM, e.g. this allows a scaled form - initialMatrix = graphicsState.getCurrentTransformationMatrix().clone(); - // transform the CTM using the stream's matrix graphicsState.getCurrentTransformationMatrix().concatenate(group.getMatrix()); - // Before execution of the transparency group XObject’s content stream, + // the stream's initial matrix includes the parent CTM, e.g. this allows a scaled form + initialMatrix = graphicsState.getCurrentTransformationMatrix().clone(); + + // Before execution of the transparency group XObject’s content stream, // the current blend mode in the graphics state shall be initialized to Normal, // the current stroking and nonstroking alpha constants to 1.0, and the current soft mask to None. graphicsState.setBlendMode(BlendMode.NORMAL); diff --git a/pdfbox/src/test/java/org/apache/pdfbox/rendering/TestQuality.java b/pdfbox/src/test/java/org/apache/pdfbox/rendering/TestQuality.java index 4e7fd637481..cb98cd0ff76 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/rendering/TestQuality.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/rendering/TestQuality.java @@ -134,6 +134,38 @@ void testPDFBox5403() throws IOException } } + /** + * PDFBOX-5250: a mesh shading pattern used inside a transparency group that has its own + * non-trivial /Matrix must be positioned using that group's own initial matrix, not the + * parent's. Before the fix, the transparency group's /Matrix was concatenated into the CTM + * only after the initial matrix had already been captured, so any pattern painted inside the + * group (here, a colored tiling pattern whose cell is itself a transparency group filled + * with a type 7 shading) was placed using the wrong reference matrix. That shifted the mesh + * shading far out of position, so instead of the intended multicolor gradient, only a + * single, mostly-green sliver of it ever landed on the visible glyphs. + * + * @throws IOException + */ + @Test + void testPDFBox5250() throws IOException + { + File file = new File(TARGET_PDF_DIR, "PDFBOX-5250-pattern-reduced3.pdf"); + try (PDDocument doc = Loader.loadPDF(file)) + { + PDFRenderer renderer = new PDFRenderer(doc); + BufferedImage renderedImage = renderer.renderImageWithDPI(0, 100); + // a pixel within the shading-pattern-filled text; before the fix, the mesh shading + // was shifted out of view here, leaving this pixel blank white instead of the + // gradient's red-ish color. Checking red without also ruling out green isn't enough + // because white also has a maxed-out red channel. + int rgb = renderedImage.getRGB(190, 331); + int red = (rgb >> 16) & 0xFF; + int green = (rgb >> 8) & 0xFF; + Assertions.assertTrue(red > 150 && green < 150, + "expected a red-ish gradient pixel but was: " + Integer.toHexString(rgb)); + } + } + /** * PDFBOX-5876: rendering a page containing a very large JPEG 2000 (JPX) image at reduced * scale must not decode the image at full resolution first just to read its width, height