1 /*
2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 5076878
27  * @summary Test verifies that ImageIO creates BMP images with correct bpp
28  */
29 
30 import java.awt.Color;
31 import java.awt.Graphics;
32 import java.awt.Transparency;
33 import java.awt.color.ColorSpace;
34 import java.awt.image.BufferedImage;
35 import java.awt.image.ColorModel;
36 import java.awt.image.ComponentColorModel;
37 import java.awt.image.DataBuffer;
38 import java.awt.image.DirectColorModel;
39 import java.awt.image.Raster;
40 import java.awt.image.WritableRaster;
41 import java.io.File;
42 import java.io.FileInputStream;
43 import java.io.IOException;
44 import java.util.Hashtable;
45 
46 import javax.imageio.IIOImage;
47 import javax.imageio.ImageIO;
48 import javax.imageio.ImageReader;
49 import javax.imageio.metadata.IIOMetadata;
50 import javax.imageio.stream.ImageInputStream;
51 
52 import org.w3c.dom.Node;
53 
54 public class NoExtraBytesTest {
55 
56     private static Hashtable<Integer, Integer> tests = null;
57     private static Color[] usedColors = new Color[] { Color.red, Color.green,     Color.blue, Color.yellow, Color.white, Color.black };
58 
59     private static final int TYPE_INT_GRB = 0x100;
60     private static final int TYPE_INT_GBR = 0x101;
61     private static final int TYPE_INT_RBG = 0x102;
62     private static final int TYPE_INT_BRG = 0x103;
63     private static final int TYPE_INT_555_GRB = 0x104;
64     private static final int TYPE_3BYTE_RGB = 0x105;
65     private static final int TYPE_3BYTE_GRB = 0x106;
66 
67     private static final int w = 300;
68     private static final int h = 200;
69     private static final int dx = w / usedColors.length;
70 
main(String[] args)71     public static void main(String[] args) throws IOException {
72         initTests();
73 
74         for (Integer type : tests.keySet()) {
75             new NoExtraBytesTest(type.intValue(), tests.get(type).intValue()).doTest();
76         }
77         System.out.println("Test passed.");
78     }
79 
initTests()80     private static void initTests() {
81         tests = new Hashtable<Integer, Integer>();
82 
83         tests.put(new Integer(BufferedImage.TYPE_INT_RGB), new Integer(24));
84         tests.put(new Integer(BufferedImage.TYPE_INT_BGR), new Integer(24));
85         tests.put(new Integer(BufferedImage.TYPE_3BYTE_BGR), new Integer(24));
86         tests.put(new Integer(TYPE_INT_GRB), new Integer(24));
87         tests.put(new Integer(TYPE_INT_GBR), new Integer(24));
88         tests.put(new Integer(TYPE_INT_RBG), new Integer(24));
89         tests.put(new Integer(TYPE_INT_BRG), new Integer(24));
90         tests.put(new Integer(BufferedImage.TYPE_USHORT_555_RGB), new Integer(16));
91         tests.put(new Integer(BufferedImage.TYPE_USHORT_565_RGB), new Integer(16));
92         tests.put(new Integer(TYPE_INT_555_GRB), new Integer(16));
93         tests.put(new Integer(TYPE_3BYTE_RGB), new Integer(24));
94         tests.put(new Integer(TYPE_3BYTE_GRB), new Integer(24));
95     }
96 
getImageTypeName(int t)97     private static String getImageTypeName(int t) {
98         switch(t) {
99             case BufferedImage.TYPE_INT_RGB:
100                 return "TYPE_INT_RGB";
101             case BufferedImage.TYPE_INT_BGR:
102                 return "TYPE_INT_BGR";
103             case BufferedImage.TYPE_3BYTE_BGR:
104                 return "TYPE_3BYTE_BGR";
105             case BufferedImage.TYPE_USHORT_555_RGB:
106                 return "TYPE_USHORT_555_RGB";
107             case BufferedImage.TYPE_USHORT_565_RGB:
108                 return "TYPE_USHORT_565_RGB";
109             case TYPE_INT_GRB:
110                 return "TYPE_INT_GRB";
111             case TYPE_INT_GBR:
112                 return "TYPE_INT_GBR";
113             case TYPE_INT_RBG:
114                 return "TYPE_INT_RBG";
115             case TYPE_INT_BRG:
116                 return "TYPE_INT_BRG";
117             case TYPE_INT_555_GRB:
118                 return "TYPE_INT_555_GRB";
119             case TYPE_3BYTE_RGB:
120                 return "TYPE_3BYTE_RGB";
121             case TYPE_3BYTE_GRB:
122                 return "TYPE_3BYTE_GRB";
123             default:
124                 throw new IllegalArgumentException("Unknown image type: " + t);
125         }
126     }
createTestImage(int type)127     private static BufferedImage createTestImage(int type) {
128         BufferedImage dst = null;
129         ColorModel colorModel = null;
130         WritableRaster raster = null;
131         ColorSpace cs = null;
132         System.out.println("Create image for " + getImageTypeName(type));
133         switch(type) {
134             case TYPE_INT_GRB:
135                 colorModel = new DirectColorModel(24,
136                     0x0000ff00,
137                     0x00ff0000,
138                     0x000000ff);
139                 break;
140             case TYPE_INT_GBR:
141                 colorModel = new DirectColorModel(24,
142                     0x000000ff,
143                     0x00ff0000,
144                     0x0000ff00);
145                 break;
146             case TYPE_INT_RBG:
147                 colorModel = new DirectColorModel(24,
148                     0x00ff0000,
149                     0x000000ff,
150                     0x0000ff00);
151                 break;
152             case TYPE_INT_BRG:
153                 colorModel = new DirectColorModel(24,
154                     0x0000ff00,
155                     0x000000ff,
156                     0x00ff0000);
157                 break;
158             case TYPE_INT_555_GRB:
159                 colorModel = new DirectColorModel(24,
160                         0x0000001F,
161                         0x000003e0,
162                         0x00007c00);
163                 break;
164             case TYPE_3BYTE_RGB:
165                 cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
166                 int[] nBits = {8, 8, 8};
167                 int[] bOffs = {0, 1, 2};
168                 colorModel = new ComponentColorModel(cs, nBits, false, false,
169                                                      Transparency.OPAQUE,
170                                                      DataBuffer.TYPE_BYTE);
171                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
172                                                         w, h,
173                                                         w*3, 3,
174                                                         bOffs, null);
175                 break;
176             case TYPE_3BYTE_GRB:
177                 cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
178                 //nBits = {8, 8, 8};
179                 //bOffs = {0, 1, 2};
180                 colorModel = new ComponentColorModel(cs, new int[] { 8, 8, 8 }, false, false,
181                                                      Transparency.OPAQUE,
182                                                      DataBuffer.TYPE_BYTE);
183                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
184                         w, h,
185                         w*3, 3,
186                         new int[] { 1, 0, 2}, null);
187                 break;
188             default:
189                 dst = new BufferedImage(w, h, type);
190                 //colorModel = ImageTypeSpecifier.createFromBufferedImageType(type).getColorModel();
191         }
192 
193         if (dst == null) {
194             if (raster == null) {
195                 raster = colorModel.createCompatibleWritableRaster(w, h);
196             }
197 
198             dst = new BufferedImage(colorModel, raster, false, null);
199         }
200         Graphics g = dst.createGraphics();
201         for (int i = 0; i < usedColors.length; i ++) {
202             g.setColor(usedColors[i]);
203             g.fillRect(i * dx, 0, dx, h);
204         }
205         g.dispose();
206 
207         return dst;
208     }
209 
210     private BufferedImage src;
211     private int expectedColorDepth;
212     private int type;
213 
214     private IIOImage iio_dst;
215 
NoExtraBytesTest(int type, int expectedColorDepth)216     public NoExtraBytesTest(int type, int expectedColorDepth) {
217         this.type = type;
218         this.src = createTestImage(type);
219         this.expectedColorDepth = expectedColorDepth;
220     }
221 
doTest()222     public void doTest() throws IOException {
223         // write src as BMP
224         System.out.println("Test for image: " + getImageTypeName(type));
225         System.out.println("image is " + src);
226 
227         File f = File.createTempFile("sizeTest_", ".bmp", new File("."));
228         System.out.println("Use file " + f.getCanonicalPath());
229         ImageIO.write(src, "BMP", f);
230 
231         //read it again
232         read(f);
233 
234         checkColorDepth();
235 
236         checkImageContent();
237     }
238 
read(File f)239     private void read(File f) throws IOException {
240         ImageReader reader = ImageIO.getImageReadersByFormatName("BMP").next();
241 
242         ImageInputStream iis =
243                 ImageIO.createImageInputStream(new FileInputStream(f));
244 
245         reader.setInput(iis);
246 
247         iio_dst = reader.readAll(0, reader.getDefaultReadParam());
248     }
249 
checkColorDepth()250     private void checkColorDepth() {
251         IIOMetadata dst = iio_dst.getMetadata();
252 
253         Node data = dst.getAsTree("javax_imageio_bmp_1.0");
254 
255         Node n = data.getFirstChild();
256 
257         while (n != null && !("BitsPerPixel".equals(n.getNodeName()))) {
258             System.out.println("Node " + n.getNodeName());
259             n = n.getNextSibling();
260         }
261         if (n == null) {
262             throw new RuntimeException("No BitsPerSample node!");
263         }
264 
265         int bpp = 0;
266         String value = n.getNodeValue();
267         System.out.println("value = " + value);
268         try {
269             bpp = Integer.parseInt(value);
270         } catch (NumberFormatException e) {
271             throw new RuntimeException("Wrong bpp value: " + value, e);
272         }
273 
274         if (bpp != this.expectedColorDepth) {
275             throw new RuntimeException("Wrong color depth: " + bpp +
276                     " (should be " + this.expectedColorDepth + ")");
277         }
278     }
279 
checkImageContent()280     private void checkImageContent() {
281         BufferedImage dst =
282                 (BufferedImage)iio_dst.getRenderedImage();
283         int y = h / 2;
284         int x = dx / 2;
285 
286         for (int i = 0; i < usedColors.length; i++, x += dx) {
287             int srcRgb = src.getRGB(x, y);
288             int dstRgb = dst.getRGB(x, y);
289             int rgb = usedColors[i].getRGB();
290 
291             if (dstRgb != srcRgb || dstRgb != rgb) {
292                 throw new RuntimeException("Wrong color at [" + x + ", " + y +
293                         "] " + Integer.toHexString(dstRgb) +
294                         " (srcRgb=" + Integer.toHexString(srcRgb) +
295                         ", original color is " + Integer.toHexString(rgb) + ")");
296             }
297 
298         }
299         System.out.println("Image colors are OK.");
300     }
301 }
302