1 /*
   2  * Copyright (c) 2003, 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 4892194 8014427
  27  * @summary Test checks that we able to encode TYPE_3BYTE_BGR images to bmp
  28  *          format. Test failed if ArrayIndexOutOfBoundsException will be thrown
  29  *          or pixel colors will be changed by the writing/reading.
  30  */
  31 
  32 import java.awt.Color;
  33 import java.awt.Dimension;
  34 import java.awt.Graphics;
  35 import java.awt.Graphics2D;
  36 import java.awt.color.ColorSpace;
  37 import java.awt.image.BufferedImage;
  38 import java.awt.image.ColorModel;
  39 import java.awt.image.ComponentColorModel;
  40 import java.awt.image.DataBuffer;
  41 import java.awt.image.Raster;
  42 import java.awt.image.WritableRaster;
  43 import java.io.ByteArrayInputStream;
  44 import java.io.ByteArrayOutputStream;
  45 import java.io.File;
  46 import java.io.FileOutputStream;
  47 import java.io.IOException;
  48 
  49 import javax.imageio.IIOImage;
  50 import javax.imageio.ImageIO;
  51 import javax.imageio.ImageWriter;
  52 import javax.imageio.stream.ImageOutputStream;
  53 import javax.swing.JComponent;
  54 import javax.swing.JFrame;
  55 
  56 public class Write3ByteBgrTest {
  57     private static int width = 100;
  58     private static int height = 100;
  59     private static Color color = new Color(0x10, 0x20, 0x30);
  60 
  61     static int bufferedImageType[] = {
  62         BufferedImage.TYPE_CUSTOM,
  63         BufferedImage.TYPE_BYTE_BINARY,
  64         BufferedImage.TYPE_3BYTE_BGR
  65     };
  66 
  67     static String bufferedImageStringType[] = {
  68         "BufferedImage.TYPE_CUSTOM: test for BandedSampleModel",
  69         "BufferedImage.TYPE_BYTE_BINARY",
  70         "BufferedImage.TYPE_3BYTE_BGR"
  71     };
  72 
  73     private static String writingFormat = "BMP";
  74     private static ImageWriter writer = (ImageWriter)ImageIO.getImageWritersByFormatName(writingFormat).next();
  75     private int type;
  76 
  77     public static void main(String[] args) {
  78 
  79         //int i = 0;
  80         for(int i=0; i<bufferedImageType.length; i++) {
  81             Write3ByteBgrTest t1 = new Write3ByteBgrTest(bufferedImageType[i]);
  82 
  83             System.out.println("\n\nImage test for type " + bufferedImageStringType[i]);
  84             t1.doImageTest();
  85         }
  86     }
  87 
  88     private Write3ByteBgrTest(int type) {
  89         this.type = type;
  90     }
  91 
  92     private void doImageTest() {
  93         try {
  94             BufferedImage src = createTestImage(type);
  95             BufferedImage dst = writeImage(src);
  96 
  97             compareImages(src, dst);
  98         } catch (ArrayIndexOutOfBoundsException e) {
  99             throw new RuntimeException("Test failed: index out of array bounds!");
 100         }
 101     }
 102 
 103 
 104     private void compareImages(BufferedImage src, BufferedImage dst) {
 105         Object dstPixel = dst.getRaster().getDataElements(width/2, height/2, null);
 106         Object srcPixel = src.getRaster().getDataElements(width/2, height/2, null);
 107 
 108         if ( (src.getColorModel().getRed(srcPixel) != dst.getColorModel().getRed(dstPixel)) ||
 109              (src.getColorModel().getGreen(srcPixel) != dst.getColorModel().getGreen(dstPixel)) ||
 110              (src.getColorModel().getBlue(srcPixel) != dst.getColorModel().getBlue(dstPixel)) ||
 111              (src.getColorModel().getAlpha(srcPixel) != dst.getColorModel().getAlpha(dstPixel)) ) {
 112 
 113             showPixel(src, width/2, height/2);
 114             showPixel(dst, width/2, height/2);
 115 
 116             showRes(dst, src);
 117             throw new RuntimeException(
 118                 "Colors are different: " +
 119                 Integer.toHexString(src.getColorModel().getRGB(srcPixel)) + " and " +
 120                 Integer.toHexString(dst.getColorModel().getRGB(dstPixel)));
 121         }
 122     }
 123 
 124     private BufferedImage writeImage(BufferedImage src) {
 125         try {
 126             BufferedImage dst = null;
 127             if (!writer.getOriginatingProvider().canEncodeImage(src)) {
 128                 throw new RuntimeException(writingFormat+" writer does not support the image type "+type);
 129             }
 130             System.out.println(writingFormat+" writer claims it can encode the image "+type);
 131             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 132             ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
 133             writer.setOutput(ios);
 134             IIOImage img = new IIOImage(src.getRaster(), null, null);
 135             writer.write(img);
 136             ios.close();
 137             baos.close();
 138 
 139             // save to file
 140             File f = new File("test"+src.getType()+".bmp");
 141             FileOutputStream fos = new FileOutputStream(f);
 142             fos.write(baos.toByteArray());
 143             fos.close();
 144 
 145 
 146             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 147             dst = ImageIO.read(bais);
 148             return dst;
 149         } catch (IOException e) {
 150             e.printStackTrace();
 151             throw new RuntimeException(e);
 152         }
 153     }
 154 
 155     private static void showPixel(BufferedImage src, int x, int y) {
 156         System.out.println("Img is " + src);
 157         Object p = src.getRaster().getDataElements(x, y, null);
 158         System.out.println("RGB:   " +
 159                            Integer.toHexString(src.getColorModel().getRGB(p)));
 160         System.out.println("Red:   " +
 161                            Integer.toHexString(src.getColorModel().getRed(p)));
 162         System.out.println("Green: " +
 163                            Integer.toHexString(src.getColorModel().getGreen(p)));
 164         System.out.println("Blue:  " +
 165                            Integer.toHexString(src.getColorModel().getBlue(p)));
 166         System.out.println("Alpha: " +
 167                            Integer.toHexString(src.getColorModel().getAlpha(p)));
 168     }
 169 
 170     private static BufferedImage createTestImage(int type) {
 171         return createTestImage(type, color);
 172     }
 173 
 174     private static BufferedImage createTestImage(int type, Color c) {
 175         BufferedImage i = null;
 176         if (type == BufferedImage.TYPE_CUSTOM) {
 177             WritableRaster wr = Raster.createBandedRaster(
 178                 DataBuffer.TYPE_BYTE,
 179                 width, height,
 180                 width,               // scanlineStride
 181                 new int[] { 0, 1, 2},// bankIndices[],
 182                 new int[] { 1, 2, 0},// bankOffsets[],
 183                 null);
 184 
 185             ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 186 
 187             ColorModel cm = new ComponentColorModel(cs,
 188                                                     new int[] { 8, 8, 8},
 189                                                     false,
 190                                                     false,
 191                                                     ColorModel.OPAQUE,
 192                                                     DataBuffer.TYPE_BYTE);
 193             i = new BufferedImage(cm, wr, false, null);
 194         } else {
 195             i = new BufferedImage(width, height, type);
 196         }
 197 
 198         Graphics2D g = i.createGraphics();
 199 
 200         g.setColor(c);
 201         g.fillRect(0, 0, width, height);
 202         g.setColor(Color.white);
 203         g.drawRect(10,10, width-20, height-20);
 204 
 205         return i;
 206     }
 207 
 208     private static void showRes(final BufferedImage src,
 209                                 final BufferedImage dst)
 210         {
 211         final int w = src.getWidth()+  dst.getWidth();
 212         final int h = Math.max(src.getHeight(), dst.getHeight());
 213 
 214         JFrame f = new JFrame("Test results");
 215         f.getContentPane().add( new JComponent() {
 216                 public Dimension getPreferredSize() {
 217                     return new Dimension(w,h);
 218                 }
 219 
 220                 public void paintComponent(Graphics g) {
 221                     g.drawImage(src,0,0, null);
 222                     g.drawImage(dst, src.getWidth(),0, null);
 223                 }
 224             });
 225         f.pack();
 226         f.setVisible(true);
 227     }
 228 }