blob: 9e75c2c74ceebbabf22d2d21609f7811ff20ecc8 [file] [log] [blame]
/**************************************************************
*
* 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);
}
}