Selenium Grid 中不同 PC 上的屏幕截图大小不同
Screenshots having different sizes on different PCs in Selenium Grid
我正在使用 Selenium Grid 在不同的 PC 上执行 GWT Web 应用程序的跨浏览器测试。我面临的问题是生成的屏幕截图(在测试期间拍摄)的大小对于不同的 PC 是不同的,我想让我的代码通用,即设置屏幕截图的一些默认大小。这是我用来截取屏幕截图然后将生成的图像与本地存储在我的 PC 上的图像进行比较的代码。
Firstly I will call the CallScreenshotAndCompareImage method with
arguments (canvas,className).
Here canvas is the WebElement
representing the HTML5 canvas in the GWT application.
FileBase is the file stored locally in my project and fileActual is the generated screenshot image.
public class Browser {
//ThreadLocal will provide thread-safe tests
protected ThreadLocal<RemoteWebDriver> threadLocal = null;
String serverMachine = "xxx.xxx.xxx.xxx:xxx/hub"; //IP Address of hub
@BeforeTest
@Parameters("browser")
public void setup(String browser) throws MalformedURLException{
if(browser.equalsIgnoreCase("chrome")) {
System.setProperty("webdriver.chrome.driver", ".src/Drivers/chromedriver.exe");
DesiredCapabilities capability = null;
capability = DesiredCapabilities.chrome();
capability.setPlatform(Platform.WINDOWS);
capability.setBrowserName("chrome");
createRemoteWebDriver(capability);
}
else if(browser.equalsIgnoreCase("firefox")) {
System.setProperty("webdriver.gecko.driver", ".src/Drivers/geckodriver.exe");
DesiredCapabilities capability = null;
capability = DesiredCapabilities.firefox();
capability.setPlatform(Platform.WINDOWS);
capability.setBrowserName("firefox");
createRemoteWebDriver(capability);
}
}
public void createRemoteWebDriver(DesiredCapabilities capability) throws MalformedURLException {
threadLocal = new ThreadLocal<RemoteWebDriver>();
threadLocal.set(new RemoteWebDriver(new URL(serverMachine), capability));
}
public WebDriver getDriver() {
return threadLocal.get();
}
public void CallScreenshotAndCompareImage(WebElement element, String className) throws IOException, InterruptedException {
File fileBase1 = new File("./src/Images/baseDrawing"+className+"Chrome.png");
File fileBase2 = new File("./src/Images/baseDrawing"+className+"Firefox.png");
Capabilities cap = ((RemoteWebDriver) getDriver()).getCapabilities();
String browserName = cap.getBrowserName().toLowerCase();
File fileActual = new File("./src/Images/actualDrawing"+className+browserName+".png");
File elementImage = this.takeElementScreenshot(element,"png");
FileUtils.copyFile(elementImage, fileActual);
if(browserName.equalsIgnoreCase("chrome"))
this.compareImage(fileBase1,fileActual);
else if(browserName.equalsIgnoreCase("firefox"))
this.compareImage(fileBase2,fileActual);
Thread.sleep(3000);
}
public File takeElementScreenshot(WebElement element, String imageFormat) throws IOException{
Point elementXY = element.getLocation();
int elementHeight = element.getSize().getHeight();
int elementWidth = element.getSize().getWidth();
Rectangle elementRectArea = new Rectangle(elementWidth,elementHeight);
WrapsDriver wrapsDriver = (WrapsDriver) element;
File pageImage = ((TakesScreenshot)wrapsDriver.getWrappedDriver()).getScreenshotAs(OutputType.FILE);
BufferedImage bufferedImage = ImageIO.read(pageImage);
BufferedImage elementImage = bufferedImage.getSubimage(elementXY.getX(), elementXY.getY(), elementRectArea.width, elementRectArea.height);
ImageIO.write(elementImage, imageFormat, pageImage);
return pageImage;
}
public void compareImage(File fileBase, File fileActual) {
/*
STEPS:
1) For first image file, recognize the contents of the file and decodes it into a BufferedImage which can be directly used by Java 2D.
2) Get the raster from the bufferedImage object which is a copy of image data.
3) Get the DataBuffer associated with the raster.
4) Get the size of the all the banks(data arrays) for the DataBuffer object.
5) Repeat steps 1-4 for the second image file.
6) If sizes of both of the images are different, then images won't be same.
7) If sizes are same, then compare all the data array elements for both of the DataBuffer objects. If they are same. then both images will be same.
*/
try {
BufferedImage bufferedImage = ImageIO.read(fileBase);
DataBuffer dataBufferFirst = bufferedImage.getData().getDataBuffer();
int sizeFirst = dataBufferFirst.getSize();
BufferedImage bufferedImage2 = ImageIO.read(fileActual);
DataBuffer dataBufferSecond = bufferedImage2.getData().getDataBuffer();
int sizeSecond = dataBufferSecond.getSize();
int count=0;
Assert.assertEquals(sizeFirst, sizeSecond,"Size of Base Drawing and actual Drawing is not same");
if(sizeFirst == sizeSecond)
{
for(int i=0; i<sizeFirst; i++)
{
if(dataBufferFirst.getElem(i) != dataBufferSecond.getElem(i)) //getElem() returns the data array element at the specified index.
{
count++;
}
}
Assert.assertEquals(count, 0,"Both images are not same");
}
} catch (Exception e) {
Assert.fail("Failed to compare image files...!!!");
}
}
}
在 运行 这段代码之后,当我比较基本(本地)图像和实际(生成的)图像的属性时,这两个图像之间存在一些差异。
Base Drawing: Size -> 253 KB, Bit Depth -> 32, Dimensions -> 1570 x 873 pixels
Actual Drawing: Size -> 232 KB, Bit Depth -> 24, Dimensions -> 1570 x 873 pixels
Everything else was same in the properties of both of these images.
我应该在我的代码中添加什么,以便从不同 PC 生成的屏幕截图始终具有相同的大小?
我想你必须使用命令来设置执行的驱动程序的分辨率。
为此添加 Java
driver.manage().window().setSize(new Dimension (1280, 1024));
在你的测试步骤之前。
现在屏幕截图将始终具有相同的分辨率。
问题不是图像的大小,而是基础绘图中存在而屏幕截图中缺失的 Alpha 通道(透明度)。
驱动程序应该return PNG Base64 编码字符串。但是没有指定它应该是 24 位 RGB 还是 32 位 RGBA PNG。
因此,为了能够比较缓冲区,您首先必须将每个缓冲区转换为所需的颜色 space。
这是一个例子:
public static void main(String[] args) throws Exception {
BufferedImage imageA = ImageIO.read(new File("C:\temp\img_24bits.png"));
BufferedImage imageB = ImageIO.read(new File("C:\temp\img_32bits.png"));
boolean same = isSameImage(imageA, imageB);
}
public static boolean isSameImage(BufferedImage imageA, BufferedImage imageB) throws IOException {
DataBufferInt bufferA = getImageBuffer(imageA);
DataBufferInt bufferB = getImageBuffer(imageB);
if (bufferA.getSize() != bufferB.getSize() || bufferA.getNumBanks() != bufferB.getNumBanks())
return false;
for (int i = 0; i < bufferA.getNumBanks(); ++i) {
if (!Arrays.equals(bufferA.getData(i), bufferB.getData(i)))
return false;
}
return true;
}
private static DataBufferInt getImageBuffer(BufferedImage img) throws IOException {
BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
ColorConvertOp cco = new ColorConvertOp(bi.getColorModel().getColorSpace(), img.getColorModel().getColorSpace(), null);
cco.filter(img, bi);
return (DataBufferInt)bi.getRaster().getDataBuffer();
}
尽管@Florent B. 的回答为我提供了接近解决方案的方向,但这是我为解决此问题所做的工作。
- 查看图片的位深是24位还是32位
- 如果是 32,则从中移除所有 alpha 通道。
- 接下来,我设置一个范围,如果对应的两张图片的像素RGB值之差小于10,则认为这两张图片相同。
我正在使用 Selenium Grid 在不同的 PC 上执行 GWT Web 应用程序的跨浏览器测试。我面临的问题是生成的屏幕截图(在测试期间拍摄)的大小对于不同的 PC 是不同的,我想让我的代码通用,即设置屏幕截图的一些默认大小。这是我用来截取屏幕截图然后将生成的图像与本地存储在我的 PC 上的图像进行比较的代码。
Firstly I will call the CallScreenshotAndCompareImage method with arguments (canvas,className).
Here canvas is the WebElement representing the HTML5 canvas in the GWT application.
FileBase is the file stored locally in my project and fileActual is the generated screenshot image.
public class Browser {
//ThreadLocal will provide thread-safe tests
protected ThreadLocal<RemoteWebDriver> threadLocal = null;
String serverMachine = "xxx.xxx.xxx.xxx:xxx/hub"; //IP Address of hub
@BeforeTest
@Parameters("browser")
public void setup(String browser) throws MalformedURLException{
if(browser.equalsIgnoreCase("chrome")) {
System.setProperty("webdriver.chrome.driver", ".src/Drivers/chromedriver.exe");
DesiredCapabilities capability = null;
capability = DesiredCapabilities.chrome();
capability.setPlatform(Platform.WINDOWS);
capability.setBrowserName("chrome");
createRemoteWebDriver(capability);
}
else if(browser.equalsIgnoreCase("firefox")) {
System.setProperty("webdriver.gecko.driver", ".src/Drivers/geckodriver.exe");
DesiredCapabilities capability = null;
capability = DesiredCapabilities.firefox();
capability.setPlatform(Platform.WINDOWS);
capability.setBrowserName("firefox");
createRemoteWebDriver(capability);
}
}
public void createRemoteWebDriver(DesiredCapabilities capability) throws MalformedURLException {
threadLocal = new ThreadLocal<RemoteWebDriver>();
threadLocal.set(new RemoteWebDriver(new URL(serverMachine), capability));
}
public WebDriver getDriver() {
return threadLocal.get();
}
public void CallScreenshotAndCompareImage(WebElement element, String className) throws IOException, InterruptedException {
File fileBase1 = new File("./src/Images/baseDrawing"+className+"Chrome.png");
File fileBase2 = new File("./src/Images/baseDrawing"+className+"Firefox.png");
Capabilities cap = ((RemoteWebDriver) getDriver()).getCapabilities();
String browserName = cap.getBrowserName().toLowerCase();
File fileActual = new File("./src/Images/actualDrawing"+className+browserName+".png");
File elementImage = this.takeElementScreenshot(element,"png");
FileUtils.copyFile(elementImage, fileActual);
if(browserName.equalsIgnoreCase("chrome"))
this.compareImage(fileBase1,fileActual);
else if(browserName.equalsIgnoreCase("firefox"))
this.compareImage(fileBase2,fileActual);
Thread.sleep(3000);
}
public File takeElementScreenshot(WebElement element, String imageFormat) throws IOException{
Point elementXY = element.getLocation();
int elementHeight = element.getSize().getHeight();
int elementWidth = element.getSize().getWidth();
Rectangle elementRectArea = new Rectangle(elementWidth,elementHeight);
WrapsDriver wrapsDriver = (WrapsDriver) element;
File pageImage = ((TakesScreenshot)wrapsDriver.getWrappedDriver()).getScreenshotAs(OutputType.FILE);
BufferedImage bufferedImage = ImageIO.read(pageImage);
BufferedImage elementImage = bufferedImage.getSubimage(elementXY.getX(), elementXY.getY(), elementRectArea.width, elementRectArea.height);
ImageIO.write(elementImage, imageFormat, pageImage);
return pageImage;
}
public void compareImage(File fileBase, File fileActual) {
/*
STEPS:
1) For first image file, recognize the contents of the file and decodes it into a BufferedImage which can be directly used by Java 2D.
2) Get the raster from the bufferedImage object which is a copy of image data.
3) Get the DataBuffer associated with the raster.
4) Get the size of the all the banks(data arrays) for the DataBuffer object.
5) Repeat steps 1-4 for the second image file.
6) If sizes of both of the images are different, then images won't be same.
7) If sizes are same, then compare all the data array elements for both of the DataBuffer objects. If they are same. then both images will be same.
*/
try {
BufferedImage bufferedImage = ImageIO.read(fileBase);
DataBuffer dataBufferFirst = bufferedImage.getData().getDataBuffer();
int sizeFirst = dataBufferFirst.getSize();
BufferedImage bufferedImage2 = ImageIO.read(fileActual);
DataBuffer dataBufferSecond = bufferedImage2.getData().getDataBuffer();
int sizeSecond = dataBufferSecond.getSize();
int count=0;
Assert.assertEquals(sizeFirst, sizeSecond,"Size of Base Drawing and actual Drawing is not same");
if(sizeFirst == sizeSecond)
{
for(int i=0; i<sizeFirst; i++)
{
if(dataBufferFirst.getElem(i) != dataBufferSecond.getElem(i)) //getElem() returns the data array element at the specified index.
{
count++;
}
}
Assert.assertEquals(count, 0,"Both images are not same");
}
} catch (Exception e) {
Assert.fail("Failed to compare image files...!!!");
}
}
}
在 运行 这段代码之后,当我比较基本(本地)图像和实际(生成的)图像的属性时,这两个图像之间存在一些差异。
Base Drawing: Size -> 253 KB, Bit Depth -> 32, Dimensions -> 1570 x 873 pixels
Actual Drawing: Size -> 232 KB, Bit Depth -> 24, Dimensions -> 1570 x 873 pixels
Everything else was same in the properties of both of these images.
我应该在我的代码中添加什么,以便从不同 PC 生成的屏幕截图始终具有相同的大小?
我想你必须使用命令来设置执行的驱动程序的分辨率。 为此添加 Java
driver.manage().window().setSize(new Dimension (1280, 1024));
在你的测试步骤之前。 现在屏幕截图将始终具有相同的分辨率。
问题不是图像的大小,而是基础绘图中存在而屏幕截图中缺失的 Alpha 通道(透明度)。
驱动程序应该return PNG Base64 编码字符串。但是没有指定它应该是 24 位 RGB 还是 32 位 RGBA PNG。 因此,为了能够比较缓冲区,您首先必须将每个缓冲区转换为所需的颜色 space。
这是一个例子:
public static void main(String[] args) throws Exception {
BufferedImage imageA = ImageIO.read(new File("C:\temp\img_24bits.png"));
BufferedImage imageB = ImageIO.read(new File("C:\temp\img_32bits.png"));
boolean same = isSameImage(imageA, imageB);
}
public static boolean isSameImage(BufferedImage imageA, BufferedImage imageB) throws IOException {
DataBufferInt bufferA = getImageBuffer(imageA);
DataBufferInt bufferB = getImageBuffer(imageB);
if (bufferA.getSize() != bufferB.getSize() || bufferA.getNumBanks() != bufferB.getNumBanks())
return false;
for (int i = 0; i < bufferA.getNumBanks(); ++i) {
if (!Arrays.equals(bufferA.getData(i), bufferB.getData(i)))
return false;
}
return true;
}
private static DataBufferInt getImageBuffer(BufferedImage img) throws IOException {
BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
ColorConvertOp cco = new ColorConvertOp(bi.getColorModel().getColorSpace(), img.getColorModel().getColorSpace(), null);
cco.filter(img, bi);
return (DataBufferInt)bi.getRaster().getDataBuffer();
}
尽管@Florent B. 的回答为我提供了接近解决方案的方向,但这是我为解决此问题所做的工作。
- 查看图片的位深是24位还是32位
- 如果是 32,则从中移除所有 alpha 通道。
- 接下来,我设置一个范围,如果对应的两张图片的像素RGB值之差小于10,则认为这两张图片相同。