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.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.awt.image.BufferedImage;
26  import java.io.ByteArrayOutputStream;
27  import java.io.IOException;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.Random;
31  
32  import org.apache.commons.imaging.AbstractImagingTest;
33  import org.apache.commons.imaging.ImageFormats;
34  import org.apache.commons.imaging.Imaging;
35  import org.apache.commons.imaging.ImagingException;
36  import org.apache.commons.imaging.common.GenericImageMetadata;
37  import org.apache.commons.imaging.common.ImageMetadata;
38  import org.junit.jupiter.api.Test;
39  
40  public class PngWriteReadTest extends AbstractImagingTest {
41  
42      private int[][] bufferedImageToImageData(final BufferedImage image) {
43          final int width = image.getWidth();
44          final int height = image.getHeight();
45          final int[][] result = new int[height][width];
46  
47          for (int y = 0; y < height; y++) {
48              for (int x = 0; x < width; x++) {
49                  result[y][x] = image.getRGB(x, y);
50              }
51          }
52          return result;
53      }
54  
55      private int[][] getAscendingRawData(final int width, final int height) {
56          final int[][] result = new int[height][width];
57          for (int y = 0; y < height; y++) {
58              for (int x = 0; x < width; x++) {
59                  final int alpha = (x + y) % 256;
60                  final int value = (x + y) % 256;
61                  final int argb = (0xff & alpha) << 24 | (0xff & value) << 16 | (0xff & value) << 8 | (0xff & value) << 0;
62  
63                  result[y][x] = argb;
64              }
65          }
66          return result;
67      }
68  
69      private int[][] getSimpleRawData(final int width, final int height, final int value) {
70          final int[][] result = new int[height][width];
71          for (int y = 0; y < height; y++) {
72              for (int x = 0; x < width; x++) {
73                  result[y][x] = value;
74              }
75          }
76          return result;
77      }
78  
79      private BufferedImage imageDataToBufferedImage(final int[][] rawData) {
80          final int width = rawData[0].length;
81          final int height = rawData.length;
82          final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
83          for (int y = 0; y < height; y++) {
84              for (int x = 0; x < width; x++) {
85                  image.setRGB(x, y, rawData[y][x]);
86              }
87          }
88          return image;
89      }
90  
91      private int[][] randomRawData(final int width, final int height) {
92          final Random random = new Random();
93          final int[][] result = new int[height][width];
94          for (int y = 0; y < height; y++) {
95              for (int x = 0; x < width; x++) {
96                  final int argb = random.nextInt();
97                  result[y][x] = argb;
98              }
99          }
100         return result;
101     }
102 
103     @Test
104     public void test() throws Exception {
105         final int[][] smallBlackPixels = getSimpleRawData(256, 256, 0);
106         final int[][] singleBlackPixel = getSimpleRawData(1, 1, 0);
107         final int[][] smallRedPixels = getSimpleRawData(256, 256, 0xffff0000);
108         final int[][] singleRedPixel = getSimpleRawData(1, 1, 0xffff0000);
109         final int[][] smallAscendingPixels = getAscendingRawData(256, 256);
110         final int[][] smallRandomPixels = randomRawData(256, 256);
111 
112         final int[][][] testData = { smallBlackPixels, singleBlackPixel, smallRedPixels, singleRedPixel, smallAscendingPixels, smallRandomPixels, };
113 
114         for (final int[][] rawData : testData) {
115             writeAndReadImageData(rawData);
116         }
117     }
118 
119     @Test
120     public void testMultipletEXt() throws Exception {
121         final int[][] smallBlackPixels = getSimpleRawData(256, 256, 0);
122 
123         writeAndReadMultipleEXt(smallBlackPixels);
124     }
125 
126     @Test
127     public void testPhysicalScaleMeters() throws Exception {
128         final PngImageParser pngImageParser = new PngImageParser();
129         final PngImagingParameters optionalParams = new PngImagingParameters();
130         optionalParams.setPhysicalScale(PhysicalScale.createFromMeters(0.01, 0.02));
131 
132         final int[][] smallAscendingPixels = getAscendingRawData(256, 256);
133         final byte[] pngBytes;
134         try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
135             pngImageParser.writeImage(imageDataToBufferedImage(smallAscendingPixels), baos, optionalParams);
136             pngBytes = baos.toByteArray();
137         }
138         final PngImageInfo imageInfo = (PngImageInfo) Imaging.getImageInfo(pngBytes);
139         final PhysicalScale physicalScale = imageInfo.getPhysicalScale();
140         assertTrue(physicalScale.isInMeters());
141         assertEquals(0.01, physicalScale.getHorizontalUnitsPerPixel(), 0.001);
142         assertEquals(0.02, physicalScale.getVerticalUnitsPerPixel(), 0.001);
143     }
144 
145     @Test
146     public void testPhysicalScaleRadians() throws Exception {
147         final PngImageParser pngImageParser = new PngImageParser();
148         final PngImagingParameters optionalParams = new PngImagingParameters();
149         optionalParams.setPhysicalScale(PhysicalScale.createFromRadians(0.01, 0.02));
150 
151         final int[][] smallAscendingPixels = getAscendingRawData(256, 256);
152         final byte[] pngBytes;
153         try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
154             pngImageParser.writeImage(imageDataToBufferedImage(smallAscendingPixels), baos, optionalParams);
155             pngBytes = baos.toByteArray();
156         }
157         final PngImageInfo imageInfo = (PngImageInfo) Imaging.getImageInfo(pngBytes);
158         final PhysicalScale physicalScale = imageInfo.getPhysicalScale();
159         assertTrue(physicalScale.isInRadians());
160         assertEquals(0.01, physicalScale.getHorizontalUnitsPerPixel(), 0.001);
161         assertEquals(0.02, physicalScale.getVerticalUnitsPerPixel(), 0.001);
162     }
163 
164     @Test
165     public void testTransparency() throws Exception {
166         // Test for https://issues.apache.org/jira/browse/SANSELAN-52
167         final int[][] smallAscendingPixels = getAscendingRawData(256, 256);
168         final byte[] pngBytes = Imaging.writeImageToBytes(imageDataToBufferedImage(smallAscendingPixels), ImageFormats.PNG);
169         assertTrue(Imaging.getImageInfo(pngBytes).isTransparent());
170     }
171 
172     private void writeAndReadImageData(final int[][] rawData) throws IOException, ImagingException, ImagingException {
173         final BufferedImage srcImage = imageDataToBufferedImage(rawData);
174 
175         final byte[] bytes = Imaging.writeImageToBytes(srcImage, ImageFormats.PNG);
176 
177         final BufferedImage dstImage = Imaging.getBufferedImage(bytes);
178 
179         assertNotNull(dstImage);
180         assertEquals(srcImage.getWidth(), dstImage.getWidth());
181         assertEquals(srcImage.getHeight(), dstImage.getHeight());
182 
183         final int[][] dstData = bufferedImageToImageData(dstImage);
184         assertArrayEquals(rawData, dstData);
185     }
186 
187     private void writeAndReadMultipleEXt(final int[][] rawData) throws IOException, ImagingException, ImagingException {
188         final BufferedImage srcImage = imageDataToBufferedImage(rawData);
189 
190         final List<AbstractPngText.Text> textChunks = new LinkedList<>();
191         textChunks.add(new AbstractPngText.Text("a", "b"));
192         textChunks.add(new AbstractPngText.Text("c", "d"));
193         final PngImagingParameters writeParams = new PngImagingParameters();
194         writeParams.setTextChunks(textChunks);
195 
196         final PngImageParser pngImageParser = new PngImageParser();
197         final byte[] bytes;
198         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
199             pngImageParser.writeImage(srcImage, os, writeParams);
200             bytes = os.toByteArray();
201         }
202 
203         final BufferedImage dstImage = Imaging.getBufferedImage(bytes);
204 
205         assertNotNull(dstImage);
206         assertEquals(srcImage.getWidth(), dstImage.getWidth());
207         assertEquals(srcImage.getHeight(), dstImage.getHeight());
208 
209         final int[][] dstData = bufferedImageToImageData(dstImage);
210         assertArrayEquals(rawData, dstData);
211 
212         final ImageMetadata imageMetadata = Imaging.getMetadata(bytes);
213         assertEquals(imageMetadata.getItems().size(), 2);
214         final GenericImageMetadata.GenericImageMetadataItem item0 = (GenericImageMetadata.GenericImageMetadataItem) imageMetadata.getItems().get(0);
215         assertEquals(item0.getKeyword(), "a");
216         assertEquals(item0.getText(), "b");
217         final GenericImageMetadata.GenericImageMetadataItem item1 = (GenericImageMetadata.GenericImageMetadataItem) imageMetadata.getItems().get(1);
218         assertEquals(item1.getKeyword(), "c");
219         assertEquals(item1.getText(), "d");
220     }
221 }