xref: /trunk/test/testcommon/source/org/openoffice/test/common/GraphicsUtil.java (revision 3309286857f19787ae62bd793a98b5af4edd2ad3)
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