1 /*
   2  * Copyright (c) 2016, 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     8149028
  27  * @author  a.stepanov
  28  * @summary a simple write-read test for TIFFDirectory
  29  * @run     main TIFFDirectoryWriteReadTest
  30  */
  31 
  32 import java.awt.*;
  33 import java.awt.color.*;
  34 import java.awt.image.BufferedImage;
  35 import java.io.*;
  36 import javax.imageio.*;
  37 import javax.imageio.metadata.*;
  38 import javax.imageio.stream.*;
  39 import javax.imageio.plugins.tiff.*;
  40 
  41 
  42 public class TIFFDirectoryWriteReadTest {
  43 
  44     private final static String FILENAME = "test.tiff";
  45     private final static int SZ = 100;
  46     private final static Color C = Color.RED;
  47 
  48     private static final String COPYRIGHT[] = {"Copyright 123ABC.."};
  49     private static final String DESCRIPTION[] = {"Test Image", "Description"};
  50     private static final String SOFTWARE[] = {"test", "software", "123"};
  51 
  52     private static final long RES_X[][] = {{2, 1}}, RES_Y[][] = {{1, 1}};
  53 
  54     private static final byte[] ICC_PROFILE =
  55         ICC_ProfileRGB.getInstance(ColorSpace.CS_sRGB).getData();
  56 
  57 
  58     private ImageWriter getTIFFWriter() {
  59 
  60         java.util.Iterator<ImageWriter> writers =
  61             ImageIO.getImageWritersByFormatName("TIFF");
  62         if (!writers.hasNext()) {
  63             throw new RuntimeException("No writers available for TIFF format");
  64         }
  65         return writers.next();
  66     }
  67 
  68     private ImageReader getTIFFReader() {
  69 
  70         java.util.Iterator<ImageReader> readers =
  71             ImageIO.getImageReadersByFormatName("TIFF");
  72         if (!readers.hasNext()) {
  73             throw new RuntimeException("No readers available for TIFF format");
  74         }
  75         return readers.next();
  76     }
  77 
  78     private void addASCIIField(TIFFDirectory d,
  79                                String        name,
  80                                String        data[],
  81                                int           num) {
  82 
  83         d.addTIFFField(new TIFFField(
  84             new TIFFTag(name, num, 1 << TIFFTag.TIFF_ASCII),
  85                 TIFFTag.TIFF_ASCII, data.length, data));
  86     }
  87 
  88     private void checkASCIIField(TIFFDirectory d,
  89                                  String        what,
  90                                  String        data[],
  91                                  int           num) {
  92 
  93         String notFound = what + " field was not found";
  94         check(d.containsTIFFField(num), notFound);
  95         TIFFField f = d.getTIFFField(num);
  96         check(f.getType() == TIFFTag.TIFF_ASCII, "field type != ASCII");
  97         check(f.getCount() == data.length, "invalid " + what + " data count");
  98         for (int i = 0; i < data.length; i++) {
  99             check(f.getValueAsString(i).equals(data[i]),
 100                 "invalid " + what + " data");
 101         }
 102     }
 103 
 104     private void writeImage() throws Exception {
 105 
 106         OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME));
 107         try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) {
 108 
 109             ImageWriter writer = getTIFFWriter();
 110             writer.setOutput(ios);
 111 
 112             BufferedImage img = new BufferedImage(
 113                 SZ, SZ, BufferedImage.TYPE_INT_RGB);
 114             Graphics g = img.getGraphics();
 115             g.setColor(C);
 116             g.fillRect(0, 0, SZ, SZ);
 117             g.dispose();
 118 
 119             IIOMetadata metadata = writer.getDefaultImageMetadata(
 120                 new ImageTypeSpecifier(img), writer.getDefaultWriteParam());
 121 
 122             TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
 123 
 124             addASCIIField(dir, "Copyright",
 125                 COPYRIGHT, BaselineTIFFTagSet.TAG_COPYRIGHT);
 126 
 127             addASCIIField(dir, "ImageDescription",
 128                 DESCRIPTION, BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION);
 129 
 130             addASCIIField(dir, "Software",
 131                 SOFTWARE, BaselineTIFFTagSet.TAG_SOFTWARE);
 132 
 133             dir.addTIFFField(new TIFFField(
 134                 new TIFFTag("XResolution", BaselineTIFFTagSet.TAG_X_RESOLUTION,
 135                 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_X));
 136             dir.addTIFFField(new TIFFField(
 137                 new TIFFTag("YResolution", BaselineTIFFTagSet.TAG_Y_RESOLUTION,
 138                 1 << TIFFTag.TIFF_RATIONAL), TIFFTag.TIFF_RATIONAL, 1, RES_Y));
 139 
 140             dir.addTIFFField(new TIFFField(
 141             new TIFFTag("ICC Profile", BaselineTIFFTagSet.TAG_ICC_PROFILE,
 142                 1 << TIFFTag.TIFF_UNDEFINED),
 143                 TIFFTag.TIFF_UNDEFINED, ICC_PROFILE.length, ICC_PROFILE));
 144 
 145             IIOMetadata data = dir.getAsMetadata();
 146             writer.write(new IIOImage(img, null, data));
 147 
 148             ios.flush();
 149             writer.dispose();
 150         }
 151         s.close();
 152     }
 153 
 154 
 155 
 156     private void readAndCheckImage() throws Exception {
 157 
 158         ImageReader reader = getTIFFReader();
 159 
 160         ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
 161         reader.setInput(s);
 162 
 163         int ni = reader.getNumImages(true);
 164         check(ni == 1, "invalid number of images");
 165 
 166         // check image
 167         BufferedImage img = reader.read(0);
 168         check(img.getWidth() == SZ && img.getHeight() == SZ,
 169             "invalid image size");
 170 
 171         Color c = new Color(img.getRGB(SZ / 2, SZ / 2));
 172         check(C.equals(c), "invalid image color");
 173 
 174         IIOMetadata metadata = reader.readAll(0, null).getMetadata();
 175         TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
 176 
 177         reader.dispose();
 178         s.close();
 179 
 180         // ===== perform tag checks =====
 181 
 182         checkASCIIField(dir, "copyright", COPYRIGHT,
 183             BaselineTIFFTagSet.TAG_COPYRIGHT);
 184 
 185         checkASCIIField(dir, "description", DESCRIPTION,
 186             BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION);
 187 
 188         checkASCIIField(dir, "software", SOFTWARE,
 189             BaselineTIFFTagSet.TAG_SOFTWARE);
 190 
 191         TIFFField f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
 192         check(f.getCount() == 1, "invalid width field count");
 193         int w = f.getAsInt(0);
 194         check(w == SZ, "invalid width");
 195 
 196         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH);
 197         check(f.getCount() == 1, "invalid height field count");
 198         int h = f.getAsInt(0);
 199         check(h == SZ, "invalid height");
 200 
 201         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
 202         // RGB: 3 x 8 bits for R, G and B components
 203         int bps[] = f.getAsInts();
 204         check((f.getCount() == 3) && (bps.length == 3), "invalid BPS count");
 205         for (int b: bps) { check(b == 8, "invalid bits per sample"); }
 206 
 207         // RGB: PhotometricInterpretation = 2
 208         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
 209         check(f.getCount() == 1, "invalid count");
 210         check(f.getAsInt(0) == 2, "invalid photometric interpretation for RGB");
 211 
 212         String rat = " resolution must be rational";
 213         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION);
 214         check(f.getType() == TIFFTag.TIFF_RATIONAL, "x" + rat);
 215         check(f.getCount() == 1 &&
 216               f.getAsInt(0) == (int) (RES_X[0][0] / RES_X[0][1]),
 217               "invalid x resolution");
 218 
 219         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
 220         check(f.getType() == TIFFTag.TIFF_RATIONAL, "y" + rat);
 221         check(f.getCount() == 1 &&
 222               f.getAsInt(0) == (int) (RES_Y[0][0] / RES_Y[0][1]),
 223               "invalid y resolution");
 224 
 225         f = dir.getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE);
 226         check(f.getType() == TIFFTag.TIFF_UNDEFINED,
 227             "invalid ICC profile field type");
 228         int cnt = f.getCount();
 229         byte icc[] = f.getAsBytes();
 230         check((cnt == ICC_PROFILE.length) && (cnt == icc.length),
 231                 "invalid ICC profile");
 232         for (int i = 0; i < cnt; i++) {
 233             check(icc[i] == ICC_PROFILE[i], "invalid ICC profile");
 234         }
 235     }
 236 
 237     public void run() {
 238 
 239         try {
 240             writeImage();
 241             readAndCheckImage();
 242         } catch (Exception e) {
 243             throw new RuntimeException(e);
 244         }
 245 
 246     }
 247 
 248     private void check(boolean ok, String msg) {
 249         if (!ok) { throw new RuntimeException(msg); }
 250     }
 251 
 252     public static void main(String[] args) {
 253         (new TIFFDirectoryWriteReadTest()).run();
 254     }
 255 }