1 /*
   2  * Copyright (c) 2007, 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. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package org.jemmy.image;
  26 
  27 
  28 import java.awt.image.BufferedImage;
  29 import java.io.File;
  30 import java.io.IOException;
  31 import org.jemmy.Dimension;
  32 import org.jemmy.JemmyException;
  33 import org.jemmy.control.Wrap;
  34 import org.jemmy.env.Environment;
  35 import org.jemmy.image.pixel.*;
  36 
  37 
  38 /**
  39  *
  40  * @author shura
  41  */
  42 public class AWTImage implements Image, WriteableRaster {
  43 
  44     /**
  45      *
  46      */
  47     public static final String OUTPUT = AWTImage.class.getName() + ".OUTPUT";
  48     public static final String PNG_FILE = ".png";
  49 
  50     /**
  51      * Get the value of imageRoot. The field is used to store images by relative
  52      * path within the root. Images should be pointed out by full file names if
  53      * the value is null.
  54      *
  55      * @return the value of imageRoot
  56      */
  57     public static File getImageRoot() {
  58         ImageStore res = Environment.getEnvironment().getProperty(ImageStore.class);
  59         if(!(res instanceof PNGFileImageStore)) {
  60             throw new IllegalStateException("Unsupported ImageStore: " + res.getClass().getName());
  61         }
  62         return ((PNGFileImageStore)res).getRoot();
  63     }
  64 
  65     /**
  66      * Set the value of imageRoot. If null, an image ID should be full path.
  67      *
  68      * @param imageRoot new value of imageRoot
  69      */
  70     public static void setImageRoot(File imageRoot) {
  71         Environment.getEnvironment().setProperty(ImageStore.class, new PNGFileImageStore(imageRoot));
  72     }
  73 
  74     /**
  75      * Gets comparator to be used by default.
  76      *
  77      * @see Wrap#waitImage(org.jemmy.image.Image, java.lang.String,
  78      * java.lang.String)
  79      * @see ImageComparator
  80      * @return default comparator
  81      */
  82     public static ImageComparator getComparator() {
  83         return Environment.getEnvironment().getProperty(ImageComparator.class);
  84     }
  85 
  86     /**
  87      * Sets comparator to be used by default.
  88      *
  89      * @see Wrap#waitImage(org.jemmy.image.Image, java.lang.String,
  90      * java.lang.String)
  91      * @see ImageComparator
  92      * @param comparator
  93      */
  94     public static void setComparator(ImageComparator comparator) {
  95         Environment.getEnvironment().setProperty(ImageComparator.class, comparator);
  96     }
  97 
  98     static {
  99         Environment.getEnvironment().setPropertyIfNotSet(ImageComparator.class,
 100                 new BufferedImageComparator(Environment.getEnvironment()));
 101         Environment.getEnvironment().setPropertyIfNotSet(ImageStore.class, new PNGFileImageStore());
 102     }
 103 
 104     private BufferedImage image;
 105 
 106     /**
 107      * Creates an instance
 108      *
 109      * @param img
 110      */
 111     public AWTImage(BufferedImage img) {
 112         this.image = img;
 113     }
 114 
 115     public BufferedImage getTheImage() {
 116         return image;
 117     }
 118 
 119     /**
 120      * Compares using current comparator.
 121      *
 122      * @see AWTImage#getComparator()
 123      * @param img
 124      * @return diff image.
 125      */
 126     public Image compareTo(Image img) {
 127         return getComparator().compare(this, img);
 128     }
 129 
 130     /**
 131      * Saves to a filesystem. fileName is expected to be a full path, unless
 132      * imageRoot is specified. ".png" extension is added automatically if not
 133      * specified.
 134      *
 135      * @see AWTImage#getImageRoot()
 136      * @param fileName full or relative file name
 137      */
 138     public void save(String fileName) {
 139         try {
 140             String fullPath = fileName;
 141             File imageRoot = getImageRoot();
 142             if (imageRoot != null) {
 143                 fullPath = imageRoot.getAbsolutePath() + File.separator + fileName;
 144             }
 145             if (!fullPath.toLowerCase().endsWith(PNG_FILE)) {
 146                 fullPath += PNG_FILE;
 147             }
 148             new PNGImageSaver().save(image, fullPath);
 149             Environment.getEnvironment().getOutput(OUTPUT).println("Image saved to " + fullPath);
 150         } catch (IOException ex) {
 151             throw new JemmyException("Unable to save image", ex, fileName);
 152         }
 153     }
 154 
 155     public Dimension getSize() {
 156         return new Dimension(image.getWidth(), image.getHeight());
 157     }
 158 
 159     public void getColors(int x, int y, double[] colors) {
 160         int orig = image.getRGB(x, y);
 161         int ivalue;
 162         for (Raster.Component c : getSupported()) {
 163             switch (c) {
 164                 case ALPHA:
 165                     ivalue = (orig & 0xFF000000) >>> 0x18;
 166                     break;
 167                 case RED:
 168                     ivalue = (orig & 0xFF0000) >>> 0x10;
 169                     break;
 170                 case GREEN:
 171                     ivalue = (orig & 0xFF00) >>> 0x8;
 172                     break;
 173                 case BLUE:
 174                     ivalue = (orig & 0xFF);
 175                     break;
 176                 default:
 177                     throw new IllegalArgumentException("Unknown color component" + c);
 178             }
 179             colors[PixelImageComparator.arrayIndexOf(getSupported(), c)] = (double) ivalue / 0xFF;
 180         }
 181     }
 182 
 183     public void setColors(int x, int y, double[] colors) {
 184         int rgb = 0;
 185         double value;
 186         int ivalue;
 187         for (Raster.Component c : getSupported()) {
 188             value = colors[PixelImageComparator.arrayIndexOf(getSupported(), c)];
 189             if (value < 0 || value > 1) {
 190                 throw new IllegalArgumentException("Color component value should be within (0, 1). Gotten: " + value);
 191             }
 192             ivalue = (int) Math.round(value * 0xFF);
 193             if (ivalue > 0xFF) {
 194                 throw new IllegalStateException("Component value is greater than 0xFF: " + ivalue);
 195             }
 196             switch (c) {
 197                 case ALPHA:
 198                     rgb |= (ivalue << 0x18);
 199                     break;
 200                 case RED:
 201                     rgb |= (ivalue << 0x10);
 202                     break;
 203                 case GREEN:
 204                     rgb |= (ivalue << 0x8);
 205                     break;
 206                 case BLUE:
 207                     rgb |= ivalue;
 208                     break;
 209                 default:
 210                     throw new IllegalArgumentException("Unknown color component: " + c);
 211             }
 212         }
 213         getTheImage().setRGB(x, y, rgb);
 214     }
 215 
 216     public Component[] getSupported() {
 217         return new Component[]{Component.RED, Component.BLUE, Component.GREEN, Component.ALPHA};
 218     }
 219 }