1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package org.openoffice.test.common; 25 26 import java.awt.AWTException; 27 import java.awt.Color; 28 import java.awt.Graphics; 29 import java.awt.Point; 30 import java.awt.Rectangle; 31 import java.awt.Robot; 32 import java.awt.Toolkit; 33 import java.awt.image.BufferedImage; 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.FileOutputStream; 37 import java.io.IOException; 38 39 import javax.imageio.ImageIO; 40 41 42 /** 43 * Utilities related to graphics 44 * 45 */ 46 public class GraphicsUtil { 47 /** 48 * Error tolerance for rectangle 49 */ 50 static final double ERR_RANGLE_RECTANGLE = 0.0; 51 52 /** 53 * Error tolerance for ellipse 54 */ 55 static final double ERR_RANGLE_ELLIPSE = 1; 56 57 static Robot robot = null; 58 59 static { 60 try { 61 robot = new Robot(); 62 } catch (AWTException e) { 63 e.printStackTrace(); 64 } 65 } 66 67 /** 68 * Load a image file as buffered image 69 * @param file 70 * @return 71 */ loadImage(String file)72 public static BufferedImage loadImage(String file) { 73 BufferedImage image = null; 74 FileInputStream in = null; 75 try { 76 in = new FileInputStream(file); 77 image = ImageIO.read(in); 78 } catch (Exception e) { 79 e.printStackTrace(); 80 } finally { 81 try { 82 if (in != null) 83 in.close(); 84 } catch (IOException e) { 85 // ignore 86 } 87 } 88 return image; 89 } 90 91 /** 92 * Store a buffered image in the given file 93 * 94 * @param image 95 * @param imgFile 96 */ storeImage(BufferedImage image, String imgFile)97 public static void storeImage(BufferedImage image, String imgFile) { 98 File file = new File(imgFile); 99 if (!file.getParentFile().exists()) 100 file.getParentFile().mkdirs(); 101 FileOutputStream fos = null; 102 try { 103 fos = new FileOutputStream(file); 104 ImageIO.write(image, FileUtil.getFileExtName(imgFile), fos); 105 } catch (Exception e) { 106 // 107 e.printStackTrace(); 108 } finally { 109 try { 110 if (fos != null) 111 fos.close(); 112 } catch (IOException e) { 113 //ignore 114 } 115 } 116 117 } 118 getScreenRectangle()119 public static Rectangle getScreenRectangle() { 120 return new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 121 } 122 123 /** 124 * Get a BufferedImage including the full current screen shot 125 * @return 126 */ screenshot()127 public static BufferedImage screenshot() { 128 return screenshot(null, null); 129 } 130 131 /** 132 * Get a BufferedImage including the area of current screen shot 133 * @param area 134 * @return 135 */ screenshot(Rectangle area)136 public static BufferedImage screenshot(Rectangle area) { 137 return screenshot(null, area); 138 } 139 140 141 /** 142 * Store the screen shot as a image file 143 * @param filename 144 */ screenShot(String filename)145 public static BufferedImage screenShot(String filename) { 146 return screenshot(filename, null); 147 } 148 149 /** 150 * Store the specified area of the screen as a image file 151 * @param filename 152 * @param area 153 */ screenshot(String filename, Rectangle area)154 public static BufferedImage screenshot(String filename, Rectangle area) { 155 if (area == null) 156 area = getScreenRectangle(); 157 BufferedImage capture = robot.createScreenCapture(area); 158 if (filename != null) 159 storeImage(capture, filename); 160 return capture; 161 } 162 163 164 /** 165 * Find a rectangle in the screen. 166 * Note: The rectangle must be filled with solid color and the color must be different from the background color 167 * 168 * @param rect the area in the screen to search 169 * @param color the rectangle color. 170 * @return The found rectangle's location and size. If no rectangle is 171 * found, return null 172 */ findRectangle(Rectangle rect, int color)173 public static Rectangle findRectangle(Rectangle rect, int color) { 174 return findRectangle(screenshot(rect), color); 175 } 176 177 /** 178 * find a rectangle in an image 179 * Note: The rectangle must be filled with solid color and the color must be different from the background color 180 * @param src 181 * @param color 182 * the rectangle color. 183 * @return The found rectangle's location and size. If no rectangle is 184 * found, return null 185 */ findRectangle(BufferedImage src, int color)186 public static Rectangle findRectangle(BufferedImage src, int color) { 187 Rectangle re = new Rectangle(); 188 189 BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), 190 BufferedImage.TYPE_INT_ARGB); 191 192 for (int x = 0; x < dst.getWidth(); x++) { 193 for (int y = 0; y < dst.getHeight(); y++) { 194 dst.setRGB(x, y, 0xFFFFFFFF); 195 } 196 } 197 198 Graphics g = dst.getGraphics(); 199 g.setColor(Color.black); 200 201 int sx = -1, sy = 0, ex = 0, ey = 0; 202 for (int x = 0; x < src.getWidth(); x++) { 203 for (int y = 0; y < src.getHeight(); y++) { 204 int rgbSrc = src.getRGB(x, y); 205 if (rgbSrc == color) { 206 if (sx == -1) { 207 sx = x; 208 sy = y; 209 } 210 ex = x; 211 ey = y; 212 } 213 } 214 } 215 216 g.fillRect(sx, sy, ex - sx + 1, ey - sy + 1); 217 // g.fillRect(0, 0, dst.getWidth(), dst.getHeight()); 218 int perimeter = 2 * (ex - sx + ey - sy); 219 int errMax = (int)(perimeter * ERR_RANGLE_RECTANGLE); 220 221 if (!(detect(src, color, dst, 0xff000000, errMax) && detect(dst, 0xff000000, 222 src, color, errMax))) 223 return null; 224 re.setBounds(sx, sy, ex - sx, ey - sy); 225 if (re.width < 2 || re.height < 2) { 226 return null; 227 } 228 return re; 229 } 230 231 detect(BufferedImage src, int colorSrc, BufferedImage dst, int colorDst, double errMax)232 protected static boolean detect(BufferedImage src, int colorSrc, 233 BufferedImage dst, int colorDst, double errMax) { 234 int errCount = 0; 235 for (int x = 0; x < src.getWidth(); x++) { 236 for (int y = 0; y < src.getHeight(); y++) { 237 int rgbSrc = src.getRGB(x, y); 238 if (rgbSrc == colorSrc) { 239 int rgbDst = dst.getRGB(x, y); 240 if (!(rgbDst == colorDst)) { 241 errCount++; 242 } 243 } 244 } // end for y 245 }// end for x 246 // System.out.println(errCount); 247 if (errCount <= errMax) 248 return true; 249 return false; 250 } 251 252 getBoundingBox(BufferedImage image, int color)253 public static Rectangle getBoundingBox(BufferedImage image, int color) { 254 return getBoundingBox(image, color, true); 255 } 256 getBoundingBox(BufferedImage image, int color, boolean include)257 public static Rectangle getBoundingBox(BufferedImage image, int color, boolean include) { 258 int w = image.getWidth(); 259 int h = image.getHeight(); 260 int left=w, top=h, right = -1, bottom = -1; 261 for (int i = 0; i < w; i++) { 262 for (int j = 0; j < h; j++) { 263 if ((color == image.getRGB(i, j)) == include) { 264 if (j < top) 265 top = j; 266 if (j > bottom) 267 bottom = j; 268 if (i < left) 269 left = i; 270 if (i > right) 271 right = i; 272 } 273 } 274 275 276 } 277 if (right == -1) 278 return null; 279 return new Rectangle(left, top, right - left + 1, bottom - top + 1); 280 } 281 282 /** 283 * Check if the rectangle in screen is filled with the given color 284 * 285 * @param color 286 * @param rect 287 * @return 288 */ isFilledWith(int color, Rectangle rect)289 public static boolean isFilledWith(int color, Rectangle rect) { 290 BufferedImage capture = screenshot(rect); 291 int w = capture.getWidth(); 292 int h = capture.getHeight(); 293 for (int i = 0; i < w; i++) { 294 for (int j = 0; j < h; j++) { 295 if (color != capture.getRGB(i, j)) 296 return false; 297 } 298 } 299 300 return true; 301 } 302 303 /** 304 * Find a image on the current screen 305 * @param image 306 * @param rect 307 * @return 308 */ findImage(BufferedImage image, Rectangle rect)309 public static Point findImage(BufferedImage image, Rectangle rect) { 310 BufferedImage capture = screenshot(rect); 311 int w = capture.getWidth(); 312 int h = capture.getHeight(); 313 int iw = image.getWidth(); 314 int ih = image.getHeight(); 315 316 for (int i = 0; i < w; i++) { 317 out: for (int j = 0; j < h; j++) { 318 for (int m = 0; m < iw; m++) { 319 for (int n = 0; n < ih; n++) { 320 if (image.getRGB(m, n) != capture.getRGB(i + m, j + n)) 321 continue out; 322 } 323 } 324 return new Point(i, j); 325 } 326 } 327 328 return null; 329 } 330 331 /** 332 * Find a color on the current screen 333 * @param color 334 * @param rect 335 * @return 336 */ findColor(int color, Rectangle rect)337 public static Point findColor(int color, Rectangle rect) { 338 BufferedImage capture = screenshot(rect); 339 int w = capture.getWidth(); 340 int h = capture.getHeight(); 341 for (int i = 0; i < w; i++) { 342 for (int j = 0; j < h; j++) { 343 if (color == capture.getRGB(i, j)) 344 return new Point(i, j); 345 } 346 } 347 return null; 348 } 349 350 351 /** 352 * Check if two BufferedImages equal 353 * 354 * @param expected 355 * @param actual 356 * @return 357 */ imageEquals(BufferedImage expected, BufferedImage actual)358 public static boolean imageEquals(BufferedImage expected, BufferedImage actual) { 359 if (expected == null || actual == null) 360 return false; 361 362 if (expected.getHeight() != actual.getHeight() || expected.getWidth() != actual.getWidth()) 363 return false; 364 365 for (int y = 0; y < expected.getHeight(); ++y) { 366 for (int x = 0; x < expected.getWidth(); ++x) { 367 if (expected.getRGB(x, y) != actual.getRGB(x, y)) 368 return false; 369 } 370 } 371 372 return true; 373 } 374 375 /** 376 * Check if two image files equal 377 * 378 * @param expectedImage 379 * @param actualImage 380 * @return 381 */ imageEquals(String expectedImage, String actualImage)382 public static boolean imageEquals(String expectedImage, String actualImage) { 383 BufferedImage expected = loadImage(expectedImage), actual = loadImage(actualImage); 384 return imageEquals(expected, actual); 385 } 386 387 } 388