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     6788458
  27  * @summary Test verifies that PNGImageReader takes tRNS chunk values
  28  *          into consideration while reading non-indexed Gray PNG images.
  29  * @run     main ReadPngGrayImageWithTRNSChunk
  30  */
  31 
  32 import java.awt.Graphics2D;
  33 import java.awt.image.BufferedImage;
  34 import java.awt.Color;
  35 import java.io.ByteArrayInputStream;
  36 import java.io.ByteArrayOutputStream;
  37 import java.io.IOException;
  38 import java.io.InputStream;
  39 import java.util.Iterator;
  40 import javax.imageio.ImageTypeSpecifier;
  41 import javax.imageio.ImageWriter;
  42 import javax.imageio.ImageIO;
  43 import javax.imageio.ImageWriteParam;
  44 import javax.imageio.metadata.IIOInvalidTreeException;
  45 import javax.imageio.metadata.IIOMetadata;
  46 import javax.imageio.metadata.IIOMetadataNode;
  47 import javax.imageio.stream.ImageOutputStream;
  48 import javax.imageio.IIOImage;
  49 
  50 public class ReadPngGrayImageWithTRNSChunk {
  51 
  52     private static BufferedImage img;
  53     private static ImageWriter writer;
  54     private static ImageWriteParam param;
  55     private static IIOMetadata metadata;
  56     private static byte[] imageByteArray;
  57 
  58     private static void initialize(int type) {
  59         int width = 2;
  60         int height = 1;
  61         img = new BufferedImage(width, height, type);
  62         Graphics2D g2D = img.createGraphics();
  63 
  64         // transparent first pixel
  65         g2D.setColor(new Color(255, 255, 255));
  66         g2D.fillRect(0, 0, 1, 1);
  67         // non-transparent second pixel
  68         g2D.setColor(new Color(128, 128,128));
  69         g2D.fillRect(1, 0, 1, 1);
  70         g2D.dispose();
  71 
  72         Iterator<ImageWriter> iterWriter =
  73         ImageIO.getImageWritersBySuffix("png");
  74         writer = iterWriter.next();
  75 
  76         param = writer.getDefaultWriteParam();
  77         ImageTypeSpecifier specifier =
  78         ImageTypeSpecifier.
  79         createFromBufferedImageType(type);
  80         metadata = writer.getDefaultImageMetadata(specifier, param);
  81     }
  82 
  83     private static void createTRNSNode(String tRNS_value)
  84         throws IIOInvalidTreeException {
  85         IIOMetadataNode tRNS_gray = new IIOMetadataNode("tRNS_Grayscale");
  86         tRNS_gray.setAttribute("gray", tRNS_value);
  87 
  88         IIOMetadataNode tRNS = new IIOMetadataNode("tRNS");
  89         tRNS.appendChild(tRNS_gray);
  90         IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
  91         root.appendChild(tRNS);
  92         metadata.mergeTree("javax_imageio_png_1.0", root);
  93     }
  94 
  95     private static void writeImage() throws IOException {
  96         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  97         ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
  98         writer.setOutput(ios);
  99         writer.write(metadata, new IIOImage(img, null, metadata), param);
 100         writer.dispose();
 101 
 102         baos.flush();
 103         imageByteArray = baos.toByteArray();
 104         baos.close();
 105     }
 106 
 107     private static boolean verifyAlphaValue(BufferedImage img) {
 108         Color firstPixel = new Color(img.getRGB(0, 0), true);
 109         Color secondPixel = new Color(img.getRGB(1, 0), true);
 110 
 111         return firstPixel.getAlpha() != 0 ||
 112         secondPixel.getAlpha() != 255;
 113     }
 114 
 115     private static boolean read8BitGrayPNGWithTRNSChunk() throws IOException {
 116         initialize(BufferedImage.TYPE_BYTE_GRAY);
 117         // Create tRNS node and merge it with default metadata
 118         createTRNSNode("255");
 119 
 120         writeImage();
 121 
 122         InputStream input= new ByteArrayInputStream(imageByteArray);
 123         // Read 8 bit PNG Gray image with tRNS chunk
 124         BufferedImage verify_img = ImageIO.read(input);
 125         input.close();
 126         // Verify alpha values present in first & second pixel
 127         return verifyAlphaValue(verify_img);
 128     }
 129 
 130     private static boolean read16BitGrayPNGWithTRNSChunk() throws IOException {
 131         initialize(BufferedImage.TYPE_USHORT_GRAY);
 132         // Create tRNS node and merge it with default metadata
 133         createTRNSNode("65535");
 134 
 135         writeImage();
 136 
 137         InputStream input= new ByteArrayInputStream(imageByteArray);
 138         // Read 16 bit PNG Gray image with tRNS chunk
 139         BufferedImage verify_img = ImageIO.read(input);
 140         input.close();
 141         // Verify alpha values present in first & second pixel
 142         return verifyAlphaValue(verify_img);
 143     }
 144 
 145     public static void main(String[] args) throws IOException {
 146         boolean read8BitFail, read16BitFail;
 147         // read 8 bit PNG Gray image with tRNS chunk
 148         read8BitFail = read8BitGrayPNGWithTRNSChunk();
 149 
 150         // read 16 bit PNG Gray image with tRNS chunk
 151         read16BitFail = read16BitGrayPNGWithTRNSChunk();
 152 
 153         if (read8BitFail || read16BitFail) {
 154             throw new RuntimeException("PNGImageReader is not using" +
 155             " transparent pixel information from tRNS chunk properly");
 156         }
 157     }
 158 }
 159