[ 
https://issues.apache.org/jira/browse/PDFBOX-6235?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18114898#comment-18114898
 ] 

Andreas Lehmkühler commented on PDFBOX-6235:
--------------------------------------------

I assume the test itself is most likely valid, but the used JDK seems to be the 
issue. 

How do we proceed? Catch that exception and skip the test? Detect the java 
version and skip the test?

> JPEGFactory.createFromImage() throws NullPointerException for 4-component 
> (CMYK) BufferedImages
> -----------------------------------------------------------------------------------------------
>
>                 Key: PDFBOX-6235
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-6235
>             Project: PDFBox
>          Issue Type: Bug
>          Components: PDModel
>    Affects Versions: 2.0.36, 3.0.1 PDFBox, 3.0.7 PDFBox
>         Environment: PDFBox 3.0.1
> Java: Amazon Corretto 21.0.8+9-LTS (aarch64)
> OS: macOS (Apple Silicon)
>            Reporter: Seungmin Lee
>            Assignee: Tilman Hausherr
>            Priority: Minor
>              Labels: CMYK
>             Fix For: 2.0.38, 3.0.9 PDFBox, 4.0.0
>
>         Attachments: PDFBOX-6235-cmyk.jpg, PDFBOX-6235-cmyk.pdf, 
> PDFBOX-6235-decode-comparison.png, PDFBOX-6235.patch
>
>
> JPEGFactory.createFromImage() fails with a NullPointerException for any 
> BufferedImage backed by a 4-component CMYK color space -- for example the 
> result of ImageIO.read() on a CMYK JPEG, which is common for print-ready 
> assets.
> Reproduced on 2.0.36, 3.0.1 and 3.0.7 (same failure, only the line number 
> differs: 396 / 372 / 376). The same unguarded dereference is still present on 
> trunk.
> h3. Root cause
> encodeImageToJPEGStream() dereferences the app0JFIF metadata node without a 
> null check:
> {code:java}
> Element tree = (Element) data.getAsTree("javax_imageio_jpeg_image_1.0");
> Element jfif = (Element) tree.getElementsByTagName("app0JFIF").item(0);
> String dpiString = Integer.toString(dpi);
> jfif.setAttribute("Xdensity", dpiString);   // <-- NPE
> jfif.setAttribute("Ydensity", dpiString);
> jfif.setAttribute("resUnits", "1");
> {code}
> The JFIF APP0 segment is only defined for 1-component (grayscale) and 
> 3-component (YCbCr) JPEGs. When the ImageIO JPEG writer encodes a 4-component 
> image it emits an Adobe APP14 marker instead, so the default metadata tree 
> contains no "app0JFIF" node and item(0) returns null.
> Note that the NPE comes from the metadata of the *re-encoded output*, not 
> from the input file -- a CMYK input JPEG that does carry a JFIF APP0 marker 
> fails just the same.
> This appears to be an oversight rather than intentionally unsupported input: 
> getColorSpaceFromAWT() explicitly handles ColorSpace.TYPE_CMYK, so the 
> factory otherwise looks intended to accept 4-component images.
> h3. Steps to reproduce
> 1. Create a 4-component CMYK JPEG (no attachment needed):
> {noformat}
> magick -size 200x200 gradient:red-blue -colorspace CMYK cmyk.jpg
> {noformat}
> Verify with {{file cmyk.jpg}} -> "JPEG image data, baseline, precision 8, 
> 200x200, components 4"
> 2. Run:
> {code:java}
> BufferedImage src = ImageIO.read(new File("cmyk.jpg"));
> // src.getType() == TYPE_CUSTOM (0)
> // src.getColorModel().getNumComponents() == 4
> // src.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_CMYK (9)
> try (PDDocument doc = new PDDocument()) {
>     JPEGFactory.createFromImage(doc, src);
> }
> {code}
> h3. Actual result
> {noformat}
> java.lang.NullPointerException: Cannot invoke 
> "org.w3c.dom.Element.setAttribute(String, String)" because "jfif" is null
>       at 
> org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory.encodeImageToJPEGStream(JPEGFactory.java:376)
>       at 
> org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory.createJPEG(JPEGFactory.java:312)
>       at 
> org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory.createFromImage(JPEGFactory.java:278)
>       at 
> org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory.createFromImage(JPEGFactory.java:255)
>       at 
> org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory.createFromImage(JPEGFactory.java:233)
> {noformat}
> (stack trace from 3.0.7)
> h3. Expected result
> Either a PDImageXObject is created with a DeviceCMYK color space, or a 
> descriptive exception is thrown stating that 4-component images are not 
> supported.
> h3. Suggested fix
> Guard the dereference. The DPI metadata simply cannot be expressed in a 
> non-JFIF stream, so skipping those three attributes when jfif is null seems 
> sufficient:
> {code:java}
> Element jfif = (Element) tree.getElementsByTagName("app0JFIF").item(0);
> if (jfif != null)
> {
>     String dpiString = Integer.toString(dpi);
>     jfif.setAttribute("Xdensity", dpiString);
>     jfif.setAttribute("Ydensity", dpiString);
>     jfif.setAttribute("resUnits", "1"); // 1 = dots/inch
> }
> {code}
> h3. Workaround
> When the image does not need resampling, embedding the original bytes with 
> JPEGFactory.createFromByteArray() avoids the re-encode entirely and also 
> preserves the DeviceCMYK color space. This is not an option when the image 
> must be resized.
> Possibly related (all older, different symptoms): PDFBOX-2057, PDFBOX-2128, 
> PDFBOX-3823.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to