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