代码之家  ›  专栏  ›  技术社区  ›  KhiladiBhaiyya

Selenium Grid中不同PC上大小不同的屏幕截图

  •  3
  • KhiladiBhaiyya  · 技术社区  · 7 年前

    我正在使用Selenium网格在不同的PC上执行GWT web应用程序的跨浏览器测试。我面临的问题是,对于不同的电脑,生成的屏幕截图(在测试期间拍摄)的大小不同,我想让我的代码通用,即设置一些默认的屏幕截图大小。这是我的代码,我用它拍摄屏幕截图,然后将生成的图像与本地存储在电脑上的图像进行比较。

    首先,我将调用CallScreenshotAndCompareImage方法 参数(画布、类名)。

    这里canvas是WebElement 在GWT应用程序中表示HTML5画布。

    FileBase是本地存储在我的项目中的文件,fileActual是生成的屏幕截图。

    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...!!!");
                }
            }
    }
    

    运行此代码后,当我比较基本(局部)图像和实际(生成)图像的属性时,这两个图像之间有一点差异。

    基础图纸 :大小->253 KB,位深度->32,尺寸->1570 x 873像素

    实际图纸 :大小->232 KB,位深度->24,尺寸->1570 x 873像素

    这两幅图像的其他属性都是一样的。

    我应该在代码中添加什么,以便从不同电脑生成的屏幕截图大小始终相同?

    3 回复  |  直到 7 年前
        1
  •  1
  •   Florent B.    7 年前

    问题不是图像的大小,而是Alpha通道(透明度),它出现在基础图形中,并且在屏幕截图中缺失。

    驱动程序应该返回PNG Base64编码的字符串。但没有指定是24位RGB还是32位RGBA PNG。 因此,为了能够比较缓冲区,首先必须将每个缓冲区转换为所需的颜色空间。

    举个例子:

    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();
    }
    
        2
  •  0
  •   KhiladiBhaiyya    7 年前

    虽然@Florent B.的回答给了我解决问题的方向,但以下是我为解决这个问题所做的。

    1. 检查图像的位深度是24还是32。
    2. 如果是32,则从中删除所有alpha通道。
    3. 接下来,我设置了一个范围,如果两个对应图像的像素的RGB值之间的差异小于10,则将这些图像视为相同。
        3
  •  -1
  •   Arno Don Calzone    7 年前

    我认为您必须使用命令来设置已执行驱动程序的分辨率。 为此,添加Java

    driver.manage().window().setSize(new Dimension (1280, 1024));
    

    在测试步骤之前。 现在,屏幕截图将始终具有相同的分辨率。