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 }