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.awt;
  26 
  27 
  28 import java.awt.Color;
  29 import java.awt.image.BufferedImage;
  30 import java.io.File;
  31 import java.io.FileInputStream;
  32 import java.io.FileNotFoundException;
  33 import java.io.FileOutputStream;
  34 import java.io.IOException;
  35 import javax.imageio.ImageIO;
  36 
  37 
  38 /**
  39  * Contains util methods to work with images.
  40  *
  41  * @author Alexandre Iline (alexandre.iline@sun.com)
  42  */
  43 class ImageTool {
  44 
  45     /**
  46      * Increases image.
  47      * @param image an image to enlarge.
  48      * @param zoom A scale.
  49      * @return a result image.
  50      */
  51     public static BufferedImage enlargeImage(BufferedImage image, int zoom) {
  52         int wight = image.getWidth();
  53         int height = image.getHeight();
  54         BufferedImage result = new BufferedImage(wight * zoom,
  55                 height * zoom,
  56                 image.getType());
  57         int rgb;
  58         for (int x = 0; x < wight; x++) {
  59             for (int y = 0; y < height; y++) {
  60                 rgb = image.getRGB(x, y);
  61                 for (int i = 0; i < zoom; i++) {
  62                     for (int j = 0; j < zoom; j++) {
  63                         result.setRGB(x * zoom + i,
  64                                 y * zoom + j,
  65                                 rgb);
  66                     }
  67                 }
  68             }
  69         }
  70         return (result);
  71     }
  72 
  73     /**
  74      * Subtracts second image from first one.
  75      * Could be used to save file difference for future analysis.
  76      * @param minuend an image to subtract from.
  77      * @param deduction an image to subtract.
  78      * @return a result image.
  79      */
  80     public static BufferedImage subtractImage(BufferedImage minuend, BufferedImage deduction) {
  81         return (subtractImage(minuend, deduction, 0, 0, null));
  82     }
  83 
  84     /**
  85      * Subtracts second image from first one.
  86      * Could be used to save file difference for future analysis.
  87      * @param minuend an image to subtract from.
  88      * @param deduction an image to subtract.
  89      * @param highlight - a color to highlight the difference. If null,
  90      * color difference is shown.
  91      * @return a result image.
  92      */
  93     public static BufferedImage subtractImage(BufferedImage minuend, BufferedImage deduction, Color highlight) {
  94         return (subtractImage(minuend, deduction, 0, 0, highlight));
  95     }
  96 
  97     /**
  98      * Subtracts subimage from image.
  99      * Could be used to save file difference for future analysis.
 100      * @param minuend an image to subtract from.
 101      * @param deduction an image to subtract.
 102      * @param relativeX - deduction-in-minuend X coordinate
 103      * @param relativeY - deduction-in-minuend Y coordinate
 104      * @return a result image.
 105      */
 106     public static BufferedImage subtractImage(BufferedImage minuend, BufferedImage deduction, int relativeX, int relativeY) {
 107         return subtractImage(minuend, deduction, relativeX, relativeY, null);
 108     }
 109 
 110     /**
 111      * Subtracts subimage from image.
 112      * Could be used to save file difference for future analysis.
 113      * @param minuend an image to subtract from.
 114      * @param deduction an image to subtract.
 115      * @param relativeX - deduction-in-minuend X coordinate
 116      * @param relativeY - deduction-in-minuend Y coordinate
 117      * @param highlight - a color to highlight the difference. If null,
 118      * color difference is shown.
 119      * @return a result image.
 120      */
 121     public static BufferedImage subtractImage(BufferedImage minuend, BufferedImage deduction, int relativeX, int relativeY, Color highlight) {
 122         int mWidth = minuend.getWidth();
 123         int mHeight = minuend.getHeight();
 124         int dWidth = deduction.getWidth();
 125         int dHeight = deduction.getHeight();
 126 
 127         int maxWidth = (mWidth > relativeX + dWidth) ? mWidth : (relativeX + dWidth);
 128         int maxHeight = (mHeight > relativeY + dHeight) ? mHeight : (relativeY + dHeight);
 129 
 130         BufferedImage result = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
 131         int mColor, dColor;
 132         for (int x = 0; x < maxWidth; x++) {
 133             for (int y = 0; y < maxHeight; y++) {
 134                 if (x >= mWidth ||
 135                         y >= mHeight) {
 136                     mColor = 0;
 137                 } else {
 138                     mColor = minuend.getRGB(x, y);
 139                 }
 140                 if (x >= dWidth + relativeX ||
 141                         y >= dHeight + relativeY ||
 142                         x < relativeX ||
 143                         y < relativeY) {
 144                     dColor = 0;
 145                 } else {
 146                     dColor = deduction.getRGB(x - relativeX, y - relativeY);
 147                 }
 148                 result.setRGB(x, y, (mColor != dColor) ? subtractColor((highlight != null) ? highlight.getRGB() : 0, mColor, dColor) : 0);
 149             }
 150         }
 151         return (result);
 152     }
 153 
 154     public static double distance(int rgb1, int rgb2) {
 155         float [] buffer1 = new float[3];
 156         float [] buffer2 = new float[3];
 157         Color c1 = new Color(rgb1);
 158         Color c2 = new Color(rgb2);
 159         c1.getRGBColorComponents(buffer1);
 160         c2.getRGBColorComponents(buffer2);
 161         double distSquare = 0;
 162         for (int i = 0; i < 3; i++) {
 163             distSquare += (buffer1[i] - buffer2[i]) * (buffer1[i] - buffer2[i]);
 164         }
 165         return Math.sqrt(distSquare);
 166     }
 167 
 168     private static int subtractColor(int highlight, int m, int d) {
 169         if (highlight == 0) {
 170             float scale = (float) (distance(m, d) / Math.sqrt(3));
 171             return new Color(scale, scale, scale).getRGB();
 172         } else {
 173             return highlight;
 174         }
 175     }
 176     /**
 177      * @param args the command line arguments
 178      */
 179     public static void main(String[] args) throws IOException {
 180         if (args.length != 2) {
 181             usage();
 182             System.exit(1);
 183         }
 184         compare(new File(args[0]).getAbsoluteFile(), new File(args[1]).getAbsoluteFile());
 185     }
 186 
 187     private static void compare(File golden, File results) throws IOException {
 188         if (golden.isDirectory()) {
 189             File rfl;
 190             for (File fl : golden.listFiles()) {
 191                 compare(fl, new File(results.getAbsolutePath() + File.separator + fl.getName()));
 192             }
 193             for (File fl : results.listFiles()) {
 194                 rfl = new File(golden.getAbsolutePath() + File.separator + fl.getName());
 195                 if (!rfl.exists()) {
 196                     compare(rfl, fl);
 197                 }
 198             }
 199         } else {
 200             DiffDialog dialog = new DiffDialog();
 201             dialog.setImages(golden.exists() ? ImageIO.read(golden) : null, results.exists() ? ImageIO.read(results) : null);
 202             dialog.setVisible(true);
 203             switch (dialog.status) {
 204                 case -2:
 205                     System.exit(0);
 206                 case -1:
 207                     copy(results, golden);
 208                     break;
 209                 case 1:
 210                     golden.delete();
 211                     break;
 212             }
 213         }
 214     }
 215 
 216     private static void usage() {
 217         System.out.println("java -jar JemmyAWTInput.jar <golden image set> <test result image set>");
 218     }
 219 
 220     private static void copy(File results, File golden) throws FileNotFoundException, IOException {
 221         if (golden.exists()) {
 222             golden.delete();
 223         }
 224         FileInputStream from = new FileInputStream(results);
 225         FileOutputStream to = new FileOutputStream(golden);
 226         byte[] buffer = new byte[4096];
 227         int bytesRead;
 228 
 229         while ((bytesRead = from.read(buffer)) != -1) {
 230             to.write(buffer, 0, bytesRead); // write
 231         }
 232     }
 233 }