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.pixel; 26 27 import java.util.Arrays; 28 import org.jemmy.Dimension; 29 import org.jemmy.env.Environment; 30 import org.jemmy.image.Image; 31 import org.jemmy.image.ImageComparator; 32 import org.jemmy.image.pixel.Raster.Component; 33 34 /** 35 * 36 * @author shura 37 */ 38 public abstract class PixelImageComparator implements ImageComparator { 39 40 static { 41 Environment.getEnvironment().setPropertyIfNotSet(RasterComparator.class, 42 new PixelEqualityRasterComparator(0)); 43 // new MaxDistanceComparator((double)1/0x8f)); 44 } 45 46 private RasterComparator comparator = null; 47 private Environment env = null; 48 49 /** 50 * 51 * @param comparator 52 */ 53 public PixelImageComparator(RasterComparator comparator) { 54 this.comparator = comparator; 55 } 56 57 public PixelImageComparator(Environment env) { 58 this.env = env; 59 } 60 61 public synchronized RasterComparator getRasterComparator() { 62 if(comparator == null) { 63 return env.getProperty(RasterComparator.class); 64 } else { 65 return comparator; 66 } 67 } 68 69 /** 70 * 71 * @param one 72 * @param two 73 * @return 74 */ 75 public static Dimension computeDiffSize(Raster one, Raster two) { 76 if (one.getSize().equals(two.getSize())) { 77 return one.getSize(); 78 } else { 79 return null; 80 } 81 } 82 83 public Image compare(Image image1, Image image2) { 84 Raster pi1 = toRaster(image1); 85 Raster pi2 = toRaster(image2); 86 if (!getRasterComparator().compare(pi1, pi2)) { 87 return toImage(computeDifference(pi1, pi2)); 88 } else { 89 return null; 90 } 91 } 92 93 /** 94 * 95 * @param image1 96 * @param image2 97 * @return 98 */ 99 public WriteableRaster computeDifference(Raster image1, Raster image2) { 100 Dimension size = computeDiffSize(image1, image2); 101 if (size == null) { 102 size = new Dimension(Math.max(image1.getSize().width, image2.getSize().width), 103 Math.max(image1.getSize().height, image2.getSize().height)); 104 } 105 WriteableRaster res = createDiffRaster(image1, image2); 106 double[] colors1 = new double[image1.getSupported().length]; 107 double[] colors2 = new double[image2.getSupported().length]; 108 double[] colorsRes = new double[res.getSupported().length]; 109 for (int x = 0; x < size.width; x++) { 110 for (int y = 0; y < size.height; y++) { 111 if (x < image1.getSize().width && y < image1.getSize().height) { 112 image1.getColors(x, y, colors1); 113 } else { 114 Arrays.fill(colors1, 0); 115 } 116 if (x < image2.getSize().width && y < image2.getSize().height) { 117 image2.getColors(x, y, colors2); 118 } else { 119 Arrays.fill(colors2, 1); 120 } 121 calcDiffColor(image1.getSupported(), colors1, image2.getSupported(), colors2, 122 res.getSupported(), colorsRes); 123 res.setColors(x, y, colorsRes); 124 } 125 } 126 return res; 127 } 128 129 private static final Component[] diffComponents = { 130 Component.RED, Component.BLUE, Component.GREEN 131 }; 132 /** 133 * 134 * @param comps1 135 * @param colors1 136 * @param comps2 137 * @param colors2 138 * @param compsRes 139 * @param colorsRes 140 */ 141 protected void calcDiffColor(Raster.Component[] comps1, double[] colors1, 142 Raster.Component[] comps2, double[] colors2, Raster.Component[] compsRes, double[] colorsRes) { 143 double square1, square2; 144 double dist = 0; 145 146 for (Component c : diffComponents) { 147 square1 = getComponentValue(comps1, colors1, c); 148 square2 = getComponentValue(comps2, colors2, c); 149 dist += (square2 - square1) * (square2 - square1); 150 } 151 for (Component c : diffComponents) { 152 colorsRes[arrayIndexOf(compsRes, c)] = Math.sqrt(dist) / Math.sqrt(3); 153 } 154 colorsRes[arrayIndexOf(compsRes, Component.ALPHA)] = 1; 155 } 156 157 public String getID() { 158 return getRasterComparator().getID(); 159 } 160 161 /** 162 * 163 * @param image 164 * @return 165 */ 166 protected abstract Image toImage(Raster image); 167 168 /** 169 * 170 * @param image 171 * @return 172 */ 173 protected abstract Raster toRaster(Image image); 174 175 /** 176 * 177 * @param r1 178 * @param r2 179 * @return 180 */ 181 protected abstract WriteableRaster createDiffRaster(Raster r1, Raster r2); 182 183 /** 184 * 185 * @param comps 186 * @param comp 187 * @return 188 */ 189 public static int arrayIndexOf(Raster.Component[] comps, Raster.Component comp) { 190 for (int i = 0; i < comps.length; i++) { 191 if (comp == comps[i]) { 192 return i; 193 } 194 } 195 throw new IllegalArgumentException("Unknown component " + comp); 196 } 197 198 /** 199 * Returns color component value using its alpha information 200 * 201 * @param components available color components 202 * @param colors color components values 203 * @param comp required color component 204 * 205 * @return value of the required color component. 206 * If pixel is not opaque, then it is blended with white 207 * opaque background 208 */ 209 protected double getComponentValue(Component[] components, double[] colors, Component comp) { 210 211 double result = colors[arrayIndexOf(components, comp)]; 212 213 if(result < 0.0 || result > 1.0) throw new IllegalStateException("Component value = " + result); 214 215 //Find alpha index if exists 216 int idxAlpha = -1; 217 try { 218 idxAlpha = arrayIndexOf(components, Component.ALPHA); 219 } catch (IllegalArgumentException ex) { 220 } 221 222 //If alpha component is available 223 if (idxAlpha != -1) { 224 double alpha = colors[idxAlpha]; 225 226 if(alpha < 0.0 || alpha > 1.0) throw new IllegalStateException("Alpha value = " + alpha); 227 228 //If not opaque 229 if (alpha < 1.0) { 230 //Blend with opaque white 231 result = Math.min(1.0, alpha * result + 1 - alpha); 232 } 233 } 234 235 return result; 236 } 237 }