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

ASF subversion and git services commented on PDFBOX-6235:
---------------------------------------------------------

Commit 1937078 from Tilman Hausherr in branch 'pdfbox/branches/2.0'
[ https://svn.apache.org/r1937078 ]

PDFBOX-6235: optimize

> 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
>            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