swtbot: Introducing ImageHelper
authorMatthew Khouzam <matthew.khouzam@ericsson.com>
Wed, 25 Mar 2015 19:58:57 +0000 (15:58 -0400)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Fri, 27 Mar 2015 01:08:46 +0000 (21:08 -0400)
The ImageHelper is a way to compare screenshots quickly and efficiently.
It has many helpers made to aid in comparisson. Each pixel is queried as
an RGB, the image can give the following info:

* its dimensions and place in the screen
* its pixels
* all the pixel values of a query (for sampling)
* a row of the image
* a column of the image

Change-Id: Id7a4c168cad18448a4d0d5c14ef395e05b6f018b
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/44635
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-by: Hudson CI
org.eclipse.tracecompass.tmf.ui.swtbot.tests/META-INF/MANIFEST.MF
org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/ImageHelper.java [new file with mode: 0644]

index 08e48254b9d59cf9df7ba3a8491568941a0cce3b..5976495ba1aca48f5ac5e102e70ddbaa06b6b629 100644 (file)
@@ -18,7 +18,8 @@ Require-Bundle: org.junit;bundle-version="4.0.0",
  org.eclipse.tracecompass.tmf.core.tests,
  org.eclipse.swtbot.junit4_x,
  org.eclipse.swtbot.swt.finder
-Import-Package: org.apache.log4j,
+Import-Package: com.google.common.collect,
+ org.apache.log4j,
  org.apache.log4j.varia,
  org.eclipse.swtbot.eclipse.finder,
  org.eclipse.swtbot.eclipse.finder.matchers,
diff --git a/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/ImageHelper.java b/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/ImageHelper.java
new file mode 100644 (file)
index 0000000..33763d0
--- /dev/null
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Matthew Khouzam - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared;
+
+import java.awt.AWTException;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
+import org.eclipse.swtbot.swt.finder.results.Result;
+
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+
+/**
+ * Test helpers, allow looking up the frame buffer and testing what is really
+ * displayed
+ */
+public final class ImageHelper {
+
+    private final int[] fPixels;
+    private final Rectangle fBounds;
+
+    /**
+     * Constructor
+     *
+     * @param pixels
+     *            the pixel map
+     * @param bounds
+     *            the bounds
+     */
+    private ImageHelper(int[] pixels, Rectangle bounds) {
+        if (pixels.length != bounds.height * bounds.width) {
+            throw new IllegalArgumentException("Incoherent image");
+        }
+        fPixels = Arrays.copyOf(pixels, pixels.length);
+        fBounds = bounds;
+    }
+
+    /**
+     * Gets a screen grab of the rectangle r; the way to access a given pixel is
+     * <code>pixel = rect.width * y + x;</code>
+     *
+     * @param rect
+     *            the area to grab in display relative coordinates (top left is
+     *            the origin)
+     * @return an ImageHelper, cannot be null
+     */
+    public static ImageHelper grabImage(final Rectangle rect) {
+        return UIThreadRunnable.syncExec(new Result<ImageHelper>() {
+            @Override
+            public ImageHelper run() {
+                try {
+                    // note: awt is explicitly called until we can use SWT to
+                    // replace it.
+                    java.awt.Robot rb = new java.awt.Robot();
+                    java.awt.image.BufferedImage bi = rb.createScreenCapture(new java.awt.Rectangle(rect.x, rect.y, rect.width, rect.height));
+                    return new ImageHelper(bi.getRGB(0, 0, rect.width, rect.height, null, 0, rect.width), rect);
+                } catch (AWTException e) {
+                }
+                return new ImageHelper(new int[0], new Rectangle(0, 0, 0, 0));
+            }
+        });
+    }
+
+    /**
+     * Get the bounds
+     *
+     * @return the bounds
+     */
+    public Rectangle getBounds() {
+        return fBounds;
+    }
+
+    /**
+     * Get the pixel for a given set of coordinates
+     *
+     * @param x
+     *            x
+     * @param y
+     *            y
+     * @return the RGB, can return an {@link ArrayIndexOutOfBoundsException}
+     */
+    public RGB getPixel(int x, int y) {
+        return getRgbFromRGBPixel(fPixels[x + y * fBounds.width]);
+    }
+
+    /**
+     * Sample an image at n points
+     *
+     * @param samplePoints
+     *            a list of points to sample at
+     * @return a list of RGBs corresponding to the pixel coordinates. Can throw
+     *         an {@link IllegalArgumentException} if the point is outside of
+     *         the image bounds
+     */
+    public List<RGB> sample(List<Point> samplePoints) {
+        for (Point p : samplePoints) {
+            if (!getBounds().contains(p)) {
+                throw new IllegalArgumentException("Point outside of the image");
+            }
+
+        }
+        List<RGB> retVal = new ArrayList<>(samplePoints.size());
+        for (Point p : samplePoints) {
+            retVal.add(getPixel(p.x, p.y));
+        }
+        return retVal;
+    }
+
+    /**
+     * Get the color histogram of the image
+     *
+     * @return The color density of the image
+     */
+    public Multiset<RGB> getHistogram() {
+        Multiset<RGB> colors = HashMultiset.create();
+        for (int pixel : fPixels) {
+            RGB pixelColor = getRgbFromRGBPixel(pixel);
+            colors.add(pixelColor);
+        }
+        return colors;
+    }
+
+    /**
+     * Get the color histogram of the row of the image
+     *
+     * @param row
+     *            the row to lookup
+     *
+     * @return The x oriented line
+     */
+    public List<RGB> getPixelRow(int row) {
+        List<RGB> retVal = new ArrayList<>();
+        for (int x = 0; x < getBounds().width; x++) {
+            retVal.add(getPixel(x, row));
+        }
+        return retVal;
+    }
+
+    /**
+     * Get the color histogram of a column of the image
+     *
+     * @param col
+     *            the column to lookup
+     *
+     * @return The y oriented line
+     */
+    public List<RGB> getPixelColumn(int col) {
+        List<RGB> retVal = new ArrayList<>();
+        for (int y = 0; y < getBounds().height; y++) {
+            retVal.add(getPixel(col, y));
+        }
+        return retVal;
+    }
+
+    /**
+     * Difference between two images (this - other)
+     *
+     * @param other
+     *            the other image to compare
+     * @return an {@link ImageHelper} that is the per pixel difference between
+     *         the two images
+     *
+     */
+    public ImageHelper diff(ImageHelper other) {
+        if (other.getBounds().width != fBounds.width && other.getBounds().height != fBounds.height) {
+            throw new IllegalArgumentException("Different sized images");
+        }
+        int[] fBuffer = new int[fPixels.length];
+        for (int i = 0; i < fPixels.length; i++) {
+            RGB local = getRgbFromRGBPixel(fPixels[i]);
+            RGB otherPixel = getRgbFromRGBPixel(other.fPixels[i]);
+            byte r = (byte) (local.red - otherPixel.red);
+            byte g = (byte) (local.green - otherPixel.green);
+            byte b = (byte) (local.blue - otherPixel.blue);
+            fBuffer[i] = r << 16 + g << 8 + b;
+        }
+        return new ImageHelper(fBuffer, getBounds());
+    }
+
+    /**
+     * Write the image to disk in PNG form
+     *
+     * @param outputFile
+     *            the file to write it to
+     * @throws IOException
+     *             file not found and such
+     */
+    public void writePng(File outputFile) throws IOException {
+        java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(fBounds.width, fBounds.height, java.awt.image.BufferedImage.TYPE_INT_RGB);
+        image.setRGB(0, 0, fBounds.width, fBounds.height, fPixels, 0, fBounds.width);
+        ImageIO.write(image, "png", outputFile);
+    }
+
+    private static RGB getRgbFromRGBPixel(int pixel) {
+        return new RGB(((pixel >> 16) & 0xff), ((pixel >> 8) & 0xff), ((pixel) & 0xff));
+    }
+}
This page took 0.031708 seconds and 5 git commands to generate.