1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
12 package org
.eclipse
.tracecompass
.tmf
.ui
.swtbot
.tests
.shared
;
14 import java
.awt
.AWTException
;
16 import java
.io
.IOException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Arrays
;
19 import java
.util
.List
;
21 import javax
.imageio
.ImageIO
;
23 import org
.eclipse
.swt
.events
.PaintEvent
;
24 import org
.eclipse
.swt
.events
.PaintListener
;
25 import org
.eclipse
.swt
.graphics
.Color
;
26 import org
.eclipse
.swt
.graphics
.Point
;
27 import org
.eclipse
.swt
.graphics
.RGB
;
28 import org
.eclipse
.swt
.graphics
.Rectangle
;
29 import org
.eclipse
.swt
.widgets
.Display
;
30 import org
.eclipse
.swt
.widgets
.Shell
;
31 import org
.eclipse
.swtbot
.swt
.finder
.SWTBot
;
32 import org
.eclipse
.swtbot
.swt
.finder
.finders
.UIThreadRunnable
;
33 import org
.eclipse
.swtbot
.swt
.finder
.results
.Result
;
34 import org
.eclipse
.swtbot
.swt
.finder
.utils
.SWTUtils
;
35 import org
.eclipse
.swtbot
.swt
.finder
.waits
.DefaultCondition
;
37 import com
.google
.common
.collect
.HashMultiset
;
38 import com
.google
.common
.collect
.Multiset
;
41 * Test helpers, allow looking up the frame buffer and testing what is really
44 public final class ImageHelper
{
46 private final int[] fPixels
;
47 private final Rectangle fBounds
;
57 private ImageHelper(int[] pixels
, Rectangle bounds
) {
58 if (pixels
.length
!= bounds
.height
* bounds
.width
) {
59 throw new IllegalArgumentException("Incoherent image");
61 fPixels
= Arrays
.copyOf(pixels
, pixels
.length
);
66 * Gets a screen grab of the rectangle r; the way to access a given pixel is
67 * <code>pixel = rect.width * y + x;</code>
70 * the area to grab in display relative coordinates (top left is
72 * @return an ImageHelper, cannot be null
74 public static ImageHelper
grabImage(final Rectangle rect
) {
75 return UIThreadRunnable
.syncExec(new Result
<ImageHelper
>() {
77 public ImageHelper
run() {
79 // note: awt is explicitly called until we can use SWT to
81 java
.awt
.Robot rb
= new java
.awt
.Robot();
82 java
.awt
.image
.BufferedImage bi
= rb
.createScreenCapture(new java
.awt
.Rectangle(rect
.x
, rect
.y
, rect
.width
, rect
.height
));
83 return new ImageHelper(bi
.getRGB(0, 0, rect
.width
, rect
.height
, null, 0, rect
.width
), rect
);
84 } catch (AWTException e
) {
86 return new ImageHelper(new int[0], new Rectangle(0, 0, 0, 0));
96 public Rectangle
getBounds() {
101 * Get the pixel for a given set of coordinates
107 * @return the RGB, can return an {@link ArrayIndexOutOfBoundsException}
109 public RGB
getPixel(int x
, int y
) {
110 return getRgbFromRGBPixel(fPixels
[x
+ y
* fBounds
.width
]);
114 * Sample an image at n points
116 * @param samplePoints
117 * a list of points to sample at
118 * @return a list of RGBs corresponding to the pixel coordinates. Can throw
119 * an {@link IllegalArgumentException} if the point is outside of
122 public List
<RGB
> sample(List
<Point
> samplePoints
) {
123 for (Point p
: samplePoints
) {
124 if (!getBounds().contains(p
)) {
125 throw new IllegalArgumentException("Point outside of the image");
129 List
<RGB
> retVal
= new ArrayList
<>(samplePoints
.size());
130 for (Point p
: samplePoints
) {
131 retVal
.add(getPixel(p
.x
, p
.y
));
137 * Get the color histogram of the image
139 * @return The color density of the image
141 public Multiset
<RGB
> getHistogram() {
142 Multiset
<RGB
> colors
= HashMultiset
.create();
143 for (int pixel
: fPixels
) {
144 RGB pixelColor
= getRgbFromRGBPixel(pixel
);
145 colors
.add(pixelColor
);
151 * Get the color histogram of the row of the image
156 * @return The x oriented line
158 public List
<RGB
> getPixelRow(int row
) {
159 List
<RGB
> retVal
= new ArrayList
<>();
160 for (int x
= 0; x
< getBounds().width
; x
++) {
161 retVal
.add(getPixel(x
, row
));
167 * Get the color histogram of a column of the image
170 * the column to lookup
172 * @return The y oriented line
174 public List
<RGB
> getPixelColumn(int col
) {
175 List
<RGB
> retVal
= new ArrayList
<>();
176 for (int y
= 0; y
< getBounds().height
; y
++) {
177 retVal
.add(getPixel(col
, y
));
183 * Difference between two images (this - other)
186 * the other image to compare
187 * @return an {@link ImageHelper} that is the per pixel difference between
191 public ImageHelper
diff(ImageHelper other
) {
192 if (other
.getBounds().width
!= fBounds
.width
&& other
.getBounds().height
!= fBounds
.height
) {
193 throw new IllegalArgumentException("Different sized images");
195 int[] fBuffer
= new int[fPixels
.length
];
196 for (int i
= 0; i
< fPixels
.length
; i
++) {
197 RGB local
= getRgbFromRGBPixel(fPixels
[i
]);
198 RGB otherPixel
= getRgbFromRGBPixel(other
.fPixels
[i
]);
199 byte r
= (byte) (local
.red
- otherPixel
.red
);
200 byte g
= (byte) (local
.green
- otherPixel
.green
);
201 byte b
= (byte) (local
.blue
- otherPixel
.blue
);
202 fBuffer
[i
] = r
<< 16 + g
<< 8 + b
;
204 return new ImageHelper(fBuffer
, getBounds());
208 * Write the image to disk in PNG form
211 * the file to write it to
212 * @throws IOException
213 * file not found and such
215 public void writePng(File outputFile
) throws IOException
{
216 java
.awt
.image
.BufferedImage image
= new java
.awt
.image
.BufferedImage(fBounds
.width
, fBounds
.height
, java
.awt
.image
.BufferedImage
.TYPE_INT_RGB
);
217 image
.setRGB(0, 0, fBounds
.width
, fBounds
.height
, fPixels
, 0, fBounds
.width
);
218 ImageIO
.write(image
, "png", outputFile
);
221 private static RGB
getRgbFromRGBPixel(int pixel
) {
222 return new RGB(((pixel
>> 16) & 0xff), ((pixel
>> 8) & 0xff), ((pixel
) & 0xff));
226 public int hashCode() {
227 final int prime
= 31;
229 result
= prime
* result
+ ((fBounds
== null) ?
0 : fBounds
.hashCode());
230 result
= prime
* result
+ Arrays
.hashCode(fPixels
);
235 public boolean equals(Object obj
) {
242 if (getClass() != obj
.getClass()) {
245 ImageHelper other
= (ImageHelper
) obj
;
246 if (fBounds
== null) {
247 if (other
.fBounds
!= null) {
250 } else if (!fBounds
.equals(other
.fBounds
)) {
253 if (!Arrays
.equals(fPixels
, other
.fPixels
)) {
260 * On Mac, RGB values that are captured with ImageHelper are affected by
261 * monitor color profiles. To account for this, we can draw the expected
262 * color in a simple shell and use that color as expected value instead.
265 * original color to adjust
266 * @return adjusted color
268 public static RGB
adjustExpectedColor(RGB original
) {
269 if (!SWTUtils
.isMac()) {
273 /* Create shell with desired color as background */
274 boolean painted
[] = new boolean[1];
275 final Shell shell
= UIThreadRunnable
.syncExec(new Result
<Shell
>() {
278 Shell s
= new Shell(Display
.getDefault());
280 Color color
= new Color(Display
.getDefault(), original
);
281 s
.setBackground(color
);
282 s
.addPaintListener(new PaintListener() {
284 public void paintControl(PaintEvent e
) {
293 /* Make sure the shell has been painted before getting the color */
294 new SWTBot().waitUntil(new DefaultCondition() {
297 public boolean test() throws Exception
{
302 public String
getFailureMessage() {
303 return "Shell was not painted";
308 return UIThreadRunnable
.syncExec(new Result
<RGB
>() {
312 RGB rgb
= ImageHelper
.grabImage(shell
.getBounds()).getPixel(50, 50);
This page took 0.041279 seconds and 5 git commands to generate.