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