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