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 import org.jemmy.Dimension;
  26 import org.jemmy.env.Environment;
  27 import org.jemmy.env.TestOut;
  28 import org.jemmy.image.pixel.ResizeComparator;
  29 
  30 import java.awt.Graphics2D;
  31 import java.awt.image.BufferedImage;
  32 
  33 /**
  34  * Comparator that makes image sizes equal to compare them with other comparator
  35  * most of them work only for the images with equal dimensions.
  36  *
  37  * It is controlled by three parameters: <li>Resize Mode - defines way of
  38  * resizing images that are being compared. One of the following constants: <ul> <li>{@linkplain ResizeMode#NO_RESIZE NO_RESIZE},</li> <li>{@linkplain ResizeMode#PROPORTIONAL_RESIZE PROPORTIONAL_RESIZE},</li> <li>{@linkplain ResizeMode#ARBITRARY_RESIZE ARBITRARY_RESIZE}.</li></ul>
  39  * Default value is {@linkplain ResizeMode#PROPORTIONAL_RESIZE}.</li> <li>Resize
  40  * Hint - defines the way of images scaling that is specified when {@linkplain java.awt.Image#getScaledInstance(int, int, int)
  41  * Image.getScaledInstance()} method is invoked. One of the Image.SCALE_XXX is
  42  * expected. Default value is
  43  * {@linkplain java.awt.Image#SCALE_DEFAULT SCALE_DEFAULT}.</li> <li>Proportion
  44  * Distortion Threshold - defines maximum proportion distortion that is used in {@linkplain ResizeMode#PROPORTIONAL_RESIZE
  45  * PROPORTIONAL_RESIZE} mode to deal with cases when rounding and other problems
  46  * could cause sizes to be not ideally proportional.<p/>
  47  * Threshold value is applied in the following way: {@code Math.abs(image.getSize() * scale
  48  * - size) / image.getSize() > PROPORTION_DISTORTION_THRESHOLD}, where {@code image.getSize()}
  49  * is both image dimensions and {@code size} is target width and height (which
  50  * is defined as mininum of sizes of two images) and scale is the scale factor
  51  * that scales the particular image to fit the width and height.
  52  * <p/>
  53  * Default value is 0.02 so as much as 2% of width/height could differ (around 5
  54  * in 0-255 color component values).</li>
  55  *
  56  * @author mrkam
  57  */
  58 public class ResizeImageComparator extends ResizeComparator {
  59 
  60     /**
  61      * Indentifies output where resize details are printed. Output is disabled
  62      * by default.
  63      *
  64      * @see Environment#getOutput(java.lang.String)
  65      */
  66     public static final String OUTPUT = ResizeImageComparator.class.getName()
  67             + ".OUTPUT";
  68 
  69     static {
  70         Environment.getEnvironment().setOutput(OUTPUT, TestOut.getNullOutput());
  71     }
  72 
  73     private final ResizeMode resizeMode;
  74     private final int hint;
  75     private final double propDistThreshold;
  76 
  77     /**
  78      * Resize Modes
  79      *
  80      * @see
  81      * #ResizeImageComparator(org.jemmy.image.ResizeImageComparator.ResizeMode,
  82      * org.jemmy.image.ImageComparator)
  83      * @see
  84      * #ResizeImageComparator(org.jemmy.image.ResizeImageComparator.ResizeMode,
  85      * int, double, org.jemmy.image.ImageComparator)
  86      */
  87     public static enum ResizeMode {
  88 
  89         /**
  90          * Images are never resized. Original images are always compared.
  91          */
  92         NO_RESIZE,
  93         /**
  94          * Images are resized only if they have exactly or almost proportional
  95          * sizes which is controlled by {@code proportionDistortion} parameter.
  96          * If images have different proportions no resize is done and original
  97          * images are compared.
  98          *
  99          * @see
 100          * #ResizeImageComparator(org.jemmy.image.ResizeImageComparator.ResizeMode,
 101          * int, double, org.jemmy.image.ImageComparator)
 102          */
 103         PROPORTIONAL_RESIZE,
 104         /**
 105          * Images are always resized to match both width and height and then
 106          * compared.
 107          */
 108         ARBITRARY_RESIZE
 109     }
 110 
 111     /**
 112      * Creates ResizeImageComparator with default resize settings: <li>resize
 113      * mode: {@linkplain ResizeMode#PROPORTIONAL_RESIZE ResizeMode.PROPORTIONAL_RESIZE}.</li>
 114      * <li>proportion distortion threshold: 0.02.</li> <li>resize hint: {@linkplain java.awt.Image#SCALE_DEFAULT Image.SCALE_DEFAULT}.</li>
 115      *
 116      * @param subComparator comparator to compare images after resize.
 117      * @see java.awt.Image#getScaledInstance(int, int, int)
 118      * @see ResizeMode
 119      * @see ResizeImageComparator
 120      */
 121     public ResizeImageComparator(ImageComparator subComparator) {
 122         this(ResizeMode.PROPORTIONAL_RESIZE, 0.02,
 123                 java.awt.Image.SCALE_DEFAULT, subComparator);
 124     }
 125 
 126     /**
 127      * Creates ResizeImageComparator with the specified resize mode and default
 128      * settings for other parameters: <li>proportion distortion threshold:
 129      * 0.02.</li> <li>resize hint: {@linkplain java.awt.Image#SCALE_DEFAULT Image.SCALE_DEFAULT}.</li>
 130      *
 131      * @param resizeMode resize mode for this comparator.
 132      * @param subComparator comparator to compare images after resize.
 133      * @see ResizeMode
 134      * @see ResizeImageComparator
 135      */
 136     public ResizeImageComparator(ResizeMode resizeMode,
 137             ImageComparator subComparator) {
 138         this(resizeMode, 0.02,
 139                 java.awt.Image.SCALE_DEFAULT, subComparator);
 140     }
 141 
 142     /**
 143      * Creates ResizeImageComparator with the following settings: <li>resize
 144      * mode: {@linkplain ResizeMode#PROPORTIONAL_RESIZE ResizeMode.PROPORTIONAL_RESIZE}.</li>
 145      * <li>specified proportion distortion threshold.</li> <li>resize hint: {@linkplain java.awt.Image#SCALE_DEFAULT Image.SCALE_DEFAULT}.</li>
 146      *
 147      * @param propDistThreshold proportion distortion threshold.
 148      * @param subComparator comparator to compare images after resize.
 149      * @see ResizeImageComparator
 150      */
 151     public ResizeImageComparator(double propDistThreshold,
 152             ImageComparator subComparator) {
 153         this(ResizeMode.PROPORTIONAL_RESIZE, propDistThreshold,
 154                 java.awt.Image.SCALE_DEFAULT, subComparator);
 155     }
 156 
 157     /**
 158      * Creates ResizeImageComparator with specified settings.
 159      *
 160      * @param resizeMode Resize mode.
 161      * @param propDistThreshold Proportion distortion threshold.
 162      * @param hint Resize hint.
 163      * @param subComparator comparator to compare images after resize.
 164      * @see ResizeImageComparator
 165      * @see ResizeMode
 166      */
 167     public ResizeImageComparator(ResizeMode resizeMode, double propDistThreshold,
 168             int hint, ImageComparator subComparator) {
 169         super(subComparator, ResizeComparator.Mode.LEFT);
 170         this.resizeMode = resizeMode;
 171         this.hint = hint;
 172         this.propDistThreshold = propDistThreshold;
 173     }
 174 
 175     @Override
 176     public Image resize(Image image, Dimension size) {
 177         Dimension isize = getSize(image);
 178         double scalex = (double) size.width / isize.width;
 179         double scaley = (double) size.height / isize.height;
 180         switch (resizeMode) {
 181             case NO_RESIZE:
 182                 return image;
 183             case PROPORTIONAL_RESIZE:
 184                 if (Math.abs(scalex - scaley) > propDistThreshold) {
 185                     return null;
 186                 }
 187             case ARBITRARY_RESIZE:
 188                 BufferedImage res = new BufferedImage(size.width, size.height, ((AWTImage) image).getTheImage().getType());
 189                 java.awt.Image scaled = ((AWTImage) image).getTheImage().getScaledInstance(
 190                         size.width, size.height, hint);
 191                 Graphics2D g = res.createGraphics();
 192                 g.drawImage(scaled, 0, 0, null);
 193                 g.dispose();
 194                 return new AWTImage(res);
 195             default:
 196                 return null;
 197         }
 198     }
 199     @Override
 200     public String getID() {
 201         return ResizeImageComparator.class.getName() + "("
 202                 + getSubComparator().getID() + ")";
 203     }
 204 
 205     @Override
 206     public Dimension getSize(Image image) {
 207         BufferedImage bi = ((AWTImage)image).getTheImage();
 208         return new Dimension(bi.getWidth(), bi.getHeight());
 209     }
 210 
 211     public ResizeMode getResizeMode() {
 212         return resizeMode;
 213     }
 214 }