blob: 0e11111a82589bb1ce3ec390c6d385b7851b5330 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed 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 android.theme.cts;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.device.ITestDevice;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.String;
import java.util.concurrent.Callable;
import javax.imageio.ImageIO;
/**
* Compares the images generated by the device with the reference images.
*/
public class ComparisonTask implements Callable<Boolean> {
private static final String TAG = "ComparisonTask";
private static final int IMAGE_THRESHOLD = 2;
private final ITestDevice mDevice;
private final File mExpected;
private final File mActual;
public ComparisonTask(ITestDevice device, File expected, File actual) {
mDevice = device;
mExpected = expected;
mActual = actual;
}
public Boolean call() {
boolean success = false;
try {
final BufferedImage expected = ImageIO.read(mExpected);
final BufferedImage actual = ImageIO.read(mActual);
if (compare(expected, actual, IMAGE_THRESHOLD)) {
success = true;
} else {
final File diff = File.createTempFile("diff_" + mExpected.getName(), ".png");
createDiff(expected, actual, diff);
Log.logAndDisplay(LogLevel.INFO, TAG, "Diff created: " + diff.getPath());
}
} catch (IOException e) {
Log.logAndDisplay(LogLevel.ERROR, TAG, e.toString());
e.printStackTrace();
}
return success;
}
/**
* Verifies that the pixels of reference and generated images are similar
* within a specified threshold.
*
* @param expected expected image
* @param actual actual image
* @param threshold maximum difference per channel
* @return {@code true} if the images are similar, false otherwise
*/
private static int getAlphaScaledBlue(final int color) {
return (color & 0x000000FF) * getAlpha(color) / 255;
}
private static int getAlphaScaledGreen(final int color) {
return ((color & 0x0000FF00) >> 8) * getAlpha(color) / 255;
}
private static int getAlphaScaledRed(final int color) {
return ((color & 0x00FF0000) >> 16) * getAlpha(color) / 255;
}
private static int getAlpha(final int color) {
// use logical shift for keeping an unsigned value
return (color & 0xFF000000) >>> 24;
}
private static boolean compare(BufferedImage reference, BufferedImage generated, int threshold) {
final int w = generated.getWidth();
final int h = generated.getHeight();
if (w != reference.getWidth() || h != reference.getHeight()) {
return false;
}
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
final int p1 = reference.getRGB(i, j);
final int p2 = generated.getRGB(i, j);
final int dr = getAlphaScaledRed(p1) - getAlphaScaledRed(p2);
final int dg = getAlphaScaledGreen(p1) - getAlphaScaledGreen(p2);
final int db = getAlphaScaledBlue(p1) - getAlphaScaledBlue(p2);
if (Math.abs(db) > threshold ||
Math.abs(dg) > threshold ||
Math.abs(dr) > threshold) {
return false;
}
}
}
return true;
}
private static void createDiff(BufferedImage expected, BufferedImage actual, File out)
throws IOException {
final int w1 = expected.getWidth();
final int h1 = expected.getHeight();
final int w2 = actual.getWidth();
final int h2 = actual.getHeight();
final int width = Math.max(w1, w2);
final int height = Math.max(h1, h2);
// The diff will contain image1, image2 and the difference between the two.
final BufferedImage diff = new BufferedImage(
width * 3, height, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
final boolean inBounds1 = i < w1 && j < h1;
final boolean inBounds2 = i < w2 && j < h2;
int colorExpected = Color.WHITE.getRGB();
int colorActual = Color.WHITE.getRGB();
int colorDiff;
if (inBounds1 && inBounds2) {
colorExpected = expected.getRGB(i, j);
colorActual = actual.getRGB(i, j);
colorDiff = colorExpected == colorActual ? colorExpected : Color.RED.getRGB();
} else if (inBounds1 && !inBounds2) {
colorExpected = expected.getRGB(i, j);
colorDiff = Color.BLUE.getRGB();
} else if (!inBounds1 && inBounds2) {
colorActual = actual.getRGB(i, j);
colorDiff = Color.GREEN.getRGB();
} else {
colorDiff = Color.MAGENTA.getRGB();
}
int x = i;
diff.setRGB(x, j, colorExpected);
x += width;
diff.setRGB(x, j, colorActual);
x += width;
diff.setRGB(x, j, colorDiff);
}
}
ImageIO.write(diff, "png", out);
}
}