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