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