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