1 /*
   2  * Copyright (c) 2018, 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     6574555 5109146
  27  * @summary Test verifies that PNGImageWriter encodes the R, G, B
  28  *          values of bKGD chunk properly.
  29  * @run     main VerifyRGBValuesFromBKGDChunk
  30  */
  31 
  32 import java.awt.image.BufferedImage;
  33 import java.io.IOException;
  34 import java.util.Iterator;
  35 import javax.imageio.ImageTypeSpecifier;
  36 import javax.imageio.ImageWriter;
  37 import javax.imageio.ImageReader;
  38 import javax.imageio.ImageIO;
  39 import javax.imageio.ImageWriteParam;
  40 import javax.imageio.metadata.IIOInvalidTreeException;
  41 import javax.imageio.metadata.IIOMetadata;
  42 import javax.imageio.metadata.IIOMetadataNode;
  43 import javax.imageio.IIOImage;
  44 import javax.imageio.stream.ImageInputStream;
  45 import javax.imageio.stream.ImageOutputStream;
  46 import java.io.ByteArrayInputStream;
  47 import java.io.ByteArrayOutputStream;
  48 import java.io.InputStream;
  49 
  50 public class VerifyRGBValuesFromBKGDChunk {
  51 
  52     private static IIOMetadata encodeMetadata;
  53     private static ImageWriter writer;
  54     private static ImageReader reader;
  55     private static BufferedImage img;
  56     private static ImageWriteParam param;
  57     private static boolean nativeBKGDFail, standardBKGDFail;
  58     private static IIOMetadataNode bKGD_RGBNode;
  59     private static final String BKGDRED = "100";
  60     private static final String BKGDGREEN = "150";
  61     private static final String BKGDBLUE = "200";
  62 
  63     private static void mergeStandardMetadata() throws IIOInvalidTreeException {
  64         IIOMetadataNode background_rgb = new IIOMetadataNode("BackgroundColor");
  65 
  66         background_rgb.setAttribute("red", BKGDRED);
  67         background_rgb.setAttribute("green", BKGDGREEN);
  68         background_rgb.setAttribute("blue", BKGDBLUE);
  69 
  70         IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
  71         chroma.appendChild(background_rgb);
  72         IIOMetadataNode encodeRoot = new IIOMetadataNode("javax_imageio_1.0");
  73         encodeRoot.appendChild(chroma);
  74 
  75         ImageTypeSpecifier specifier =
  76             ImageTypeSpecifier.
  77                 createFromBufferedImageType(BufferedImage.TYPE_INT_BGR);
  78         encodeMetadata = writer.getDefaultImageMetadata(specifier, param);
  79         encodeMetadata.mergeTree("javax_imageio_1.0", encodeRoot);
  80     }
  81 
  82     private static void mergeNativeMetadata() throws IIOInvalidTreeException {
  83         IIOMetadataNode bKGD_rgb = new IIOMetadataNode("bKGD_RGB");
  84 
  85         bKGD_rgb.setAttribute("red", BKGDRED);
  86         bKGD_rgb.setAttribute("green", BKGDGREEN);
  87         bKGD_rgb.setAttribute("blue", BKGDBLUE);
  88 
  89         IIOMetadataNode bKGD = new IIOMetadataNode("bKGD");
  90         bKGD.appendChild(bKGD_rgb);
  91         IIOMetadataNode encodeRoot =
  92             new IIOMetadataNode("javax_imageio_png_1.0");
  93         encodeRoot.appendChild(bKGD);
  94 
  95         ImageTypeSpecifier specifier =
  96             ImageTypeSpecifier.
  97                 createFromBufferedImageType(BufferedImage.TYPE_INT_BGR);
  98         encodeMetadata = writer.getDefaultImageMetadata(specifier, param);
  99         encodeMetadata.mergeTree("javax_imageio_png_1.0", encodeRoot);
 100     }
 101 
 102     private static void writeAndReadMetadata() throws IOException {
 103         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 104         ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
 105         writer.setOutput(ios);
 106 
 107         writer.write(encodeMetadata,
 108                      new IIOImage(img, null, encodeMetadata), param);
 109 
 110         baos.flush();
 111         byte[] imageByteArray = baos.toByteArray();
 112         baos.close();
 113 
 114         // Get bKGD chunk from image and verify the values
 115         InputStream input= new ByteArrayInputStream(imageByteArray);
 116         ImageInputStream iis = ImageIO.createImageInputStream(input);
 117         reader.setInput(iis, false, false);
 118 
 119         IIOMetadata decodeMetadata = reader.getImageMetadata(0);
 120         IIOMetadataNode decodeRoot =
 121             (IIOMetadataNode) decodeMetadata.
 122                 getAsTree("javax_imageio_png_1.0");
 123         bKGD_RGBNode = (IIOMetadataNode)
 124             decodeRoot.getElementsByTagName("bKGD_RGB").item(0);
 125     }
 126 
 127     private static boolean verifyRGBValues() {
 128         return (!(BKGDRED.equals(bKGD_RGBNode.getAttribute("red")) &&
 129                   BKGDGREEN.equals(bKGD_RGBNode.getAttribute("green")) &&
 130                   BKGDBLUE.equals(bKGD_RGBNode.getAttribute("blue"))));
 131     }
 132 
 133     private static void VerifyNativeRGBValuesFromBKGDChunk()
 134         throws IOException {
 135 
 136         mergeNativeMetadata();
 137         writeAndReadMetadata();
 138         nativeBKGDFail = verifyRGBValues();
 139     }
 140 
 141     private static void VerifyStandardRGBValuesFromBKGDChunk()
 142         throws IOException {
 143 
 144         mergeStandardMetadata();
 145         writeAndReadMetadata();
 146         standardBKGDFail = verifyRGBValues();
 147     }
 148 
 149     public static void main(String[] args) throws IOException {
 150         int width = 1;
 151         int height = 1;
 152         img = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
 153         Iterator<ImageWriter> iterWriter =
 154             ImageIO.getImageWritersBySuffix("png");
 155         writer = iterWriter.next();
 156 
 157         param = writer.getDefaultWriteParam();
 158 
 159         Iterator<ImageReader> iterReader =
 160             ImageIO.getImageReadersBySuffix("png");
 161         reader = iterReader.next();
 162         // Verify bKGD RGB values after merging metadata using native tree
 163         VerifyNativeRGBValuesFromBKGDChunk();
 164 
 165         // Verify bKGD RGB values after merging metadata using standard tree
 166         VerifyStandardRGBValuesFromBKGDChunk();
 167 
 168         writer.dispose();
 169         reader.dispose();
 170 
 171         if (nativeBKGDFail || standardBKGDFail) {
 172             throw new RuntimeException("bKGD RGB values are not stored" +
 173                 " properly");
 174         }
 175     }
 176 }
 177