View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.imaging.formats.png;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.awt.image.BufferedImage;
27  import java.io.File;
28  import java.io.IOException;
29  import java.util.List;
30  
31  import org.apache.commons.imaging.ImageInfo;
32  import org.apache.commons.imaging.Imaging;
33  import org.apache.commons.imaging.ImagingException;
34  import org.apache.commons.imaging.bytesource.ByteSource;
35  import org.apache.commons.imaging.common.GenericImageMetadata;
36  import org.apache.commons.imaging.common.ImageMetadata;
37  import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
38  import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants;
39  import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
40  import org.apache.commons.imaging.internal.Debug;
41  import org.apache.commons.imaging.test.TestResources;
42  import org.junit.jupiter.api.Test;
43  
44  public class PngReadTest extends AbstractPngTest {
45  
46      @Test
47      public void test() throws Exception {
48          Debug.debug("start");
49  
50          final List<File> images = getPngImages();
51          for (final File imageFile : images) {
52  
53              Debug.debug("imageFile", imageFile);
54              if (isInvalidPngTestFile(imageFile)) {
55                  assertThrows(Exception.class, () -> Imaging.getMetadata(imageFile), "Image read should have failed.");
56  
57                  assertThrows(Exception.class, () -> Imaging.getImageInfo(imageFile), "Image read should have failed.");
58  
59                  assertThrows(Exception.class, () -> Imaging.getBufferedImage(imageFile), "Image read should have failed.");
60              } else {
61                  final ImageMetadata metadata = Imaging.getMetadata(imageFile);
62                  assertFalse(metadata instanceof File); // Dummy check to avoid unused warning (it may be null)
63  
64                  final ImageInfo imageInfo = Imaging.getImageInfo(imageFile);
65                  assertNotNull(imageInfo);
66  
67                  Debug.debug("ICC profile", Imaging.getIccProfile(imageFile));
68  
69                  final BufferedImage image = Imaging.getBufferedImage(imageFile);
70                  assertNotNull(image);
71              }
72          }
73      }
74  
75      /**
76       * Test reading EXIF from the 'eXIf' chunk in PNG file.
77       *
78       * @throws IOException if it fails to read the test image
79       * @throws ImagingException if it fails to read the test image
80       */
81      @Test
82      public void testReadExif() throws IOException, ImagingException {
83          final String input = "/images/png/IMAGING-340/image-with-exif.png";
84          final String file = PngReadTest.class.getResource(input).getFile();
85          final PngImageParser parser = new PngImageParser();
86  
87          final PngImageMetadata pngMetadata = (PngImageMetadata) parser.getMetadata(new File(file));
88  
89          final TiffImageMetadata exifMetadata = pngMetadata.getExif();
90          assertEquals("Glavo",
91                  exifMetadata.findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT)
92                          .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION));
93  
94          final PngImageMetadata metadata = (PngImageMetadata) parser.getMetadata(new File(file));
95          assertTrue(metadata.getTextualInformation().getItems().isEmpty());
96          assertEquals("Glavo",
97                  metadata.getExif()
98                          .findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT)
99                          .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION));
100     }
101 
102     /**
103      * Test reading metadata from PNG file with UTF-8 characters in the text chunks.
104      *
105      * @see <a href="https://issues.apache.org/jira/browse/IMAGING-342">IMAGING-342</a>
106      * @throws IOException      if it fails to read the test image
107      * @throws ImagingException if it fails to read the test image
108      */
109     @Test
110     public void testReadMetadataFromItxtChunk() throws IOException, ImagingException {
111         final File file = TestResources.resourceToFile("/images/png/IMAGING-342/utf8-comment.png");
112         final PngImageParser parser = new PngImageParser();
113 
114         final ImageMetadata metadata = parser.getMetadata(file);
115         final List<?> items = metadata.getItems();
116         assertEquals(1, items.size());
117 
118         final GenericImageMetadata.GenericImageMetadataItem item = (GenericImageMetadata.GenericImageMetadataItem) items.get(0);
119         assertEquals("Comment", item.getKeyword());
120         assertEquals("\u2192 UTF-8 Test", item.getText());
121     }
122 
123     /**
124      * If the PNG image data contains an invalid ICC Profile, previous versions would simply rethrow the IAE. This test verifies we are instead raising the
125      * documented {@literal ImageReadException}.
126      *
127      * <p>
128      * See Google OSS Fuzz issue 33691
129      * </p>
130      *
131      * @throws IOException if it fails to read the test image
132      */
133     @Test
134     public void testUncaughtExceptionOssFuzz33691() throws IOException {
135         final File file = TestResources.resourceToFile("/images/png/oss-fuzz-33691/clusterfuzz-testcase-minimized-ImagingPngFuzzer-6177282101215232");
136         final PngImageParser parser = new PngImageParser();
137         assertThrows(ImagingException.class, () -> parser.getBufferedImage(ByteSource.file(file), new PngImagingParameters()));
138     }
139 
140     /**
141      * Test that a PNG image using indexed color type but no PLTE chunks does not throw a {@code NullPointerException}.
142      *
143      * <p>
144      * See Google OSS Fuzz issue 37607
145      * </p>
146      *
147      * @throws IOException if it fails to read the test image
148      */
149     @Test
150     public void testUncaughtExceptionOssFuzz37607() throws IOException {
151         final File file = TestResources.resourceToFile("/images/png/IMAGING-317/clusterfuzz-testcase-minimized-ImagingPngFuzzer-6242400830357504");
152         final PngImageParser parser = new PngImageParser();
153         assertThrows(ImagingException.class, () -> parser.getBufferedImage(ByteSource.file(file), new PngImagingParameters()));
154     }
155 }