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 
  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 
  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 
  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     }
 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 
 216     public NoExtraBytesTest(int type, int expectedColorDepth) {
 217         this.type = type;
 218         this.src = createTestImage(type);
 219         this.expectedColorDepth = expectedColorDepth;
 220     }
 221 
 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 
 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 
 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 
 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 }