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