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.
   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 package org.jemmy.image;
  24 
  25 
  26 import java.awt.image.BufferedImage;
  27 import java.io.File;
  28 import java.io.IOException;
  29 import org.jemmy.Dimension;
  30 import org.jemmy.JemmyException;
  31 import org.jemmy.control.Wrap;
  32 import org.jemmy.env.Environment;
  33 import org.jemmy.image.pixel.*;
  34 
  35 
  36 /**
  37  *
  38  * @author shura
  39  */
  40 public class AWTImage implements Image, WriteableRaster {
  41 
  42     /**
  43      *
  44      */
  45     public static final String OUTPUT = AWTImage.class.getName() + ".OUTPUT";
  46     public static final String PNG_FILE = ".png";
  47 
  48     /**
  49      * Get the value of imageRoot. The field is used to store images by relative
  50      * path within the root. Images should be pointed out by full file names if
  51      * the value is null.
  52      *
  53      * @return the value of imageRoot
  54      */
  55     public static File getImageRoot() {
  56         ImageStore res = Environment.getEnvironment().getProperty(ImageStore.class);
  57         if(!(res instanceof PNGFileImageStore)) {
  58             throw new IllegalStateException("Unsupported ImageStore: " + res.getClass().getName());
  59         }
  60         return ((PNGFileImageStore)res).getRoot();
  61     }
  62 
  63     /**
  64      * Set the value of imageRoot. If null, an image ID should be full path.
  65      *
  66      * @param imageRoot new value of imageRoot
  67      */
  68     public static void setImageRoot(File imageRoot) {
  69         Environment.getEnvironment().setProperty(ImageStore.class, new PNGFileImageStore(imageRoot));
  70     }
  71 
  72     /**
  73      * Gets comparator to be used by default.
  74      *
  75      * @see Wrap#waitImage(org.jemmy.image.Image, java.lang.String,
  76      * java.lang.String)
  77      * @see ImageComparator
  78      * @return default comparator
  79      */
  80     public static ImageComparator getComparator() {
  81         return Environment.getEnvironment().getProperty(ImageComparator.class);
  82     }
  83 
  84     /**
  85      * Sets comparator to be used by default.
  86      *
  87      * @see Wrap#waitImage(org.jemmy.image.Image, java.lang.String,
  88      * java.lang.String)
  89      * @see ImageComparator
  90      * @param comparator
  91      */
  92     public static void setComparator(ImageComparator comparator) {
  93         Environment.getEnvironment().setProperty(ImageComparator.class, comparator);
  94     }
  95 
  96     static {
  97         Environment.getEnvironment().setPropertyIfNotSet(ImageComparator.class,
  98                 new BufferedImageComparator(Environment.getEnvironment()));
  99         Environment.getEnvironment().setPropertyIfNotSet(ImageStore.class, new PNGFileImageStore());
 100     }
 101 
 102     private final BufferedImage image;
 103 
 104     /**
 105      * Creates an instance
 106      *
 107      * @param img
 108      */
 109     public AWTImage(BufferedImage img) {
 110         this.image = img;
 111     }
 112 
 113     public BufferedImage getTheImage() {
 114         return image;
 115     }
 116 
 117     /**
 118      * Compares using current comparator.
 119      *
 120      * @see AWTImage#getComparator()
 121      * @param img
 122      * @return diff image.
 123      */
 124     public Image compareTo(Image img) {
 125         return getComparator().compare(this, img);
 126     }
 127 
 128     /**
 129      * Saves to a filesystem. fileName is expected to be a full path, unless
 130      * imageRoot is specified. ".png" extension is added automatically if not
 131      * specified.
 132      *
 133      * @see AWTImage#getImageRoot()
 134      * @param fileName full or relative file name
 135      */
 136     public void save(String fileName) {
 137         try {
 138             String fullPath = fileName;
 139             File imageRoot = getImageRoot();
 140             if (imageRoot != null) {
 141                 fullPath = imageRoot.getAbsolutePath() + File.separator + fileName;
 142             }
 143             if (!fullPath.toLowerCase().endsWith(PNG_FILE)) {
 144                 fullPath += PNG_FILE;
 145             }
 146             new PNGImageSaver().save(image, fullPath);
 147             Environment.getEnvironment().getOutput(OUTPUT).println("Image saved to " + fullPath);
 148         } catch (IOException ex) {
 149             throw new JemmyException("Unable to save image", ex, fileName);
 150         }
 151     }
 152 
 153     public Dimension getSize() {
 154         return new Dimension(image.getWidth(), image.getHeight());
 155     }
 156 
 157     public void getColors(int x, int y, double[] colors) {
 158         int orig = image.getRGB(x, y);
 159         int ivalue;
 160         for (Raster.Component c : getSupported()) {
 161             switch (c) {
 162                 case ALPHA:
 163                     ivalue = (orig & 0xFF000000) >>> 0x18;
 164                     break;
 165                 case RED:
 166                     ivalue = (orig & 0xFF0000) >>> 0x10;
 167                     break;
 168                 case GREEN:
 169                     ivalue = (orig & 0xFF00) >>> 0x8;
 170                     break;
 171                 case BLUE:
 172                     ivalue = (orig & 0xFF);
 173                     break;
 174                 default:
 175                     throw new IllegalArgumentException("Unknown color component" + c);
 176             }
 177             colors[PixelImageComparator.arrayIndexOf(getSupported(), c)] = (double) ivalue / 0xFF;
 178         }
 179     }
 180 
 181     public void setColors(int x, int y, double[] colors) {
 182         int rgb = 0;
 183         double value;
 184         int ivalue;
 185         for (Raster.Component c : getSupported()) {
 186             value = colors[PixelImageComparator.arrayIndexOf(getSupported(), c)];
 187             if (value < 0 || value > 1) {
 188                 throw new IllegalArgumentException("Color component value should be within (0, 1). Gotten: " + value);
 189             }
 190             ivalue = (int) Math.round(value * 0xFF);
 191             if (ivalue > 0xFF) {
 192                 throw new IllegalStateException("Component value is greater than 0xFF: " + ivalue);
 193             }
 194             switch (c) {
 195                 case ALPHA:
 196                     rgb |= (ivalue << 0x18);
 197                     break;
 198                 case RED:
 199                     rgb |= (ivalue << 0x10);
 200                     break;
 201                 case GREEN:
 202                     rgb |= (ivalue << 0x8);
 203                     break;
 204                 case BLUE:
 205                     rgb |= ivalue;
 206                     break;
 207                 default:
 208                     throw new IllegalArgumentException("Unknown color component: " + c);
 209             }
 210         }
 211         getTheImage().setRGB(x, y, rgb);
 212     }
 213 
 214     public Component[] getSupported() {
 215         return new Component[]{Component.RED, Component.BLUE, Component.GREEN, Component.ALPHA};
 216     }
 217 }