| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| package org.openoffice.test.common; |
| |
| import java.awt.AWTException; |
| import java.awt.Color; |
| import java.awt.Graphics; |
| import java.awt.Point; |
| import java.awt.Rectangle; |
| import java.awt.Robot; |
| import java.awt.Toolkit; |
| import java.awt.image.BufferedImage; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| |
| import javax.imageio.ImageIO; |
| |
| |
| /** |
| * Utilities related to graphics |
| * |
| */ |
| public class GraphicsUtil { |
| /** |
| * Error tolerance for rectangle |
| */ |
| static final double ERR_RANGLE_RECTANGLE = 0.0; |
| |
| /** |
| * Error tolerance for ellipse |
| */ |
| static final double ERR_RANGLE_ELLIPSE = 1; |
| |
| static Robot robot = null; |
| |
| static { |
| try { |
| robot = new Robot(); |
| } catch (AWTException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Load a image file as buffered image |
| * @param file |
| * @return |
| */ |
| public static BufferedImage loadImage(String file) { |
| BufferedImage image = null; |
| FileInputStream in = null; |
| try { |
| in = new FileInputStream(file); |
| image = ImageIO.read(in); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } finally { |
| try { |
| if (in != null) |
| in.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| return image; |
| } |
| |
| /** |
| * Store a buffered image in the given file |
| * |
| * @param image |
| * @param imgFile |
| */ |
| public static void storeImage(BufferedImage image, String imgFile) { |
| File file = new File(imgFile); |
| if (!file.getParentFile().exists()) |
| file.getParentFile().mkdirs(); |
| FileOutputStream fos = null; |
| try { |
| fos = new FileOutputStream(file); |
| ImageIO.write(image, FileUtil.getFileExtName(imgFile), fos); |
| } catch (Exception e) { |
| // |
| e.printStackTrace(); |
| } finally { |
| try { |
| if (fos != null) |
| fos.close(); |
| } catch (IOException e) { |
| //ignore |
| } |
| } |
| |
| } |
| |
| public static Rectangle getScreenRectangle() { |
| return new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); |
| } |
| |
| /** |
| * Get a BufferedImage including the full current screen shot |
| * @return |
| */ |
| public static BufferedImage screenshot() { |
| return screenshot(null, null); |
| } |
| |
| /** |
| * Get a BufferedImage including the area of current screen shot |
| * @param area |
| * @return |
| */ |
| public static BufferedImage screenshot(Rectangle area) { |
| return screenshot(null, area); |
| } |
| |
| |
| /** |
| * Store the screen shot as a image file |
| * @param filename |
| */ |
| public static BufferedImage screenShot(String filename) { |
| return screenshot(filename, null); |
| } |
| |
| /** |
| * Store the specified area of the screen as a image file |
| * @param filename |
| * @param area |
| */ |
| public static BufferedImage screenshot(String filename, Rectangle area) { |
| if (area == null) |
| area = getScreenRectangle(); |
| BufferedImage capture = robot.createScreenCapture(area); |
| if (filename != null) |
| storeImage(capture, filename); |
| return capture; |
| } |
| |
| |
| /** |
| * Find a rectangle in the screen. |
| * Note: The rectangle must be filled with solid color and the color must be different from the background color |
| * |
| * @param rect the area in the screen to search |
| * @param color the rectangle color. |
| * @return The found rectangle's location and size. If no rectangle is |
| * found, return null |
| */ |
| public static Rectangle findRectangle(Rectangle rect, int color) { |
| return findRectangle(screenshot(rect), color); |
| } |
| |
| /** |
| * find a rectangle in an image |
| * Note: The rectangle must be filled with solid color and the color must be different from the background color |
| * @param src |
| * @param color |
| * the rectangle color. |
| * @return The found rectangle's location and size. If no rectangle is |
| * found, return null |
| */ |
| public static Rectangle findRectangle(BufferedImage src, int color) { |
| Rectangle re = new Rectangle(); |
| |
| BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), |
| BufferedImage.TYPE_INT_ARGB); |
| |
| for (int x = 0; x < dst.getWidth(); x++) { |
| for (int y = 0; y < dst.getHeight(); y++) { |
| dst.setRGB(x, y, 0xFFFFFFFF); |
| } |
| } |
| |
| Graphics g = dst.getGraphics(); |
| g.setColor(Color.black); |
| |
| int sx = -1, sy = 0, ex = 0, ey = 0; |
| for (int x = 0; x < src.getWidth(); x++) { |
| for (int y = 0; y < src.getHeight(); y++) { |
| int rgbSrc = src.getRGB(x, y); |
| if (rgbSrc == color) { |
| if (sx == -1) { |
| sx = x; |
| sy = y; |
| } |
| ex = x; |
| ey = y; |
| } |
| } |
| } |
| |
| g.fillRect(sx, sy, ex - sx + 1, ey - sy + 1); |
| // g.fillRect(0, 0, dst.getWidth(), dst.getHeight()); |
| int perimeter = 2 * (ex - sx + ey - sy); |
| int errMax = (int)(perimeter * ERR_RANGLE_RECTANGLE); |
| |
| if (!(detect(src, color, dst, 0xff000000, errMax) && detect(dst, 0xff000000, |
| src, color, errMax))) |
| return null; |
| re.setBounds(sx, sy, ex - sx, ey - sy); |
| if (re.width < 2 || re.height < 2) { |
| return null; |
| } |
| return re; |
| } |
| |
| |
| protected static boolean detect(BufferedImage src, int colorSrc, |
| BufferedImage dst, int colorDst, double errMax) { |
| int errCount = 0; |
| for (int x = 0; x < src.getWidth(); x++) { |
| for (int y = 0; y < src.getHeight(); y++) { |
| int rgbSrc = src.getRGB(x, y); |
| if (rgbSrc == colorSrc) { |
| int rgbDst = dst.getRGB(x, y); |
| if (!(rgbDst == colorDst)) { |
| errCount++; |
| } |
| } |
| } // end for y |
| }// end for x |
| // System.out.println(errCount); |
| if (errCount <= errMax) |
| return true; |
| return false; |
| } |
| |
| |
| public static Rectangle getBoundingBox(BufferedImage image, int color) { |
| return getBoundingBox(image, color, true); |
| } |
| |
| public static Rectangle getBoundingBox(BufferedImage image, int color, boolean include) { |
| int w = image.getWidth(); |
| int h = image.getHeight(); |
| int left=w, top=h, right = -1, bottom = -1; |
| for (int i = 0; i < w; i++) { |
| for (int j = 0; j < h; j++) { |
| if ((color == image.getRGB(i, j)) == include) { |
| if (j < top) |
| top = j; |
| if (j > bottom) |
| bottom = j; |
| if (i < left) |
| left = i; |
| if (i > right) |
| right = i; |
| } |
| } |
| |
| |
| } |
| if (right == -1) |
| return null; |
| return new Rectangle(left, top, right - left + 1, bottom - top + 1); |
| } |
| |
| /** |
| * Check if the rectangle in screen is filled with the given color |
| * |
| * @param color |
| * @param rect |
| * @return |
| */ |
| public static boolean isFilledWith(int color, Rectangle rect) { |
| BufferedImage capture = screenshot(rect); |
| int w = capture.getWidth(); |
| int h = capture.getHeight(); |
| for (int i = 0; i < w; i++) { |
| for (int j = 0; j < h; j++) { |
| if (color != capture.getRGB(i, j)) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Find a image on the current screen |
| * @param image |
| * @param rect |
| * @return |
| */ |
| public static Point findImage(BufferedImage image, Rectangle rect) { |
| BufferedImage capture = screenshot(rect); |
| int w = capture.getWidth(); |
| int h = capture.getHeight(); |
| int iw = image.getWidth(); |
| int ih = image.getHeight(); |
| |
| for (int i = 0; i < w; i++) { |
| out: for (int j = 0; j < h; j++) { |
| for (int m = 0; m < iw; m++) { |
| for (int n = 0; n < ih; n++) { |
| if (image.getRGB(m, n) != capture.getRGB(i + m, j + n)) |
| continue out; |
| } |
| } |
| return new Point(i, j); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Find a color on the current screen |
| * @param color |
| * @param rect |
| * @return |
| */ |
| public static Point findColor(int color, Rectangle rect) { |
| BufferedImage capture = screenshot(rect); |
| int w = capture.getWidth(); |
| int h = capture.getHeight(); |
| for (int i = 0; i < w; i++) { |
| for (int j = 0; j < h; j++) { |
| if (color == capture.getRGB(i, j)) |
| return new Point(i, j); |
| } |
| } |
| return null; |
| } |
| |
| |
| /** |
| * Check if two BufferedImages equal |
| * |
| * @param expected |
| * @param actual |
| * @return |
| */ |
| public static boolean imageEquals(BufferedImage expected, BufferedImage actual) { |
| if (expected == null || actual == null) |
| return false; |
| |
| if (expected.getHeight() != actual.getHeight() || expected.getWidth() != actual.getWidth()) |
| return false; |
| |
| for (int y = 0; y < expected.getHeight(); ++y) { |
| for (int x = 0; x < expected.getWidth(); ++x) { |
| if (expected.getRGB(x, y) != actual.getRGB(x, y)) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Check if two image files equal |
| * |
| * @param expectedImage |
| * @param actualImage |
| * @return |
| */ |
| public static boolean imageEquals(String expectedImage, String actualImage) { |
| BufferedImage expected = loadImage(expectedImage), actual = loadImage(actualImage); |
| return imageEquals(expected, actual); |
| } |
| |
| } |