4

I have a code I took from this tutorial. It goes to a learn-selenium-easy.blogspot.com website, looks for Most Read/Popular Posts section and takes a picture of it:

 class SshotofElement {

    public static void screenShotElement() throws InterruptedException,IOException {
        System.setProperty("webdriver.chrome.driver", "chromedriver.exe");

        DesiredCapabilities capabilities = DesiredCapabilities.chrome();
        capabilities.setCapability("marionette", true);
        WebDriver driver = new ChromeDriver(capabilities);

        driver.get("http://learn-selenium-easy.blogspot.com/");
        driver.manage().window().maximize();

        // Xpath of element to take screen shot
        WebElement element=driver.findElement(By.xpath("//*[@id='PopularPosts1']"));
        System.out.println(element.getSize());
        File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

        // Take full screen screenshot
        BufferedImage  fullImg = ImageIO.read(screenshot);
        Point point = element.getLocation();
        int elementWidth = element.getSize().getWidth();
        int elementHeight = element.getSize().getHeight();
        BufferedImage elementScreenshot= fullImg.getSubimage(point.getX(), point.getY(), elementWidth,elementHeight);  //exception here

        // crop the image to required
        ImageIO.write(elementScreenshot, "png", screenshot);
        FileUtils.copyFile(screenshot, new File("mostread_screenshot.png"));//path to save screen shot

        driver.close();
    }
}

I get a java.awt.image.RasterFormatException: (y + height) is outside of Raster exception, however on line BufferedImage elementScreenshot= fullImg.getSubimage(point.getX(), point.getY(), elementWidth,elementHeight);. I'm not sure why it would be the case, since the points and size of the image are taken from the element itself.

JeffC
  • 22,180
  • 5
  • 32
  • 55
parsecer
  • 4,758
  • 13
  • 71
  • 140
  • This is quite possible scenario if your element is not currently within the screenshot. It may visually look to be there, but its bounding box will tell you do that. What you want do is put a check `elementWidth + X` <= Image width, if not then you need to truncate the same to avoid the exception – Tarun Lalwani Jul 17 '19 at 16:04
  • 1
    The targeted element is not visible in the viewport and `getScreenshotAs` captures the viewport only. Either call `((TakesScreenshot)element).getScreenshotAs(...);` or scroll the element into view and crop the screenshot from the location returned by `((Coordinates)element).inViewPort()`. – Florent B. Jul 17 '19 at 18:29
  • Oh I thought seleriom would solve all your problems! – gpasch Jul 22 '19 at 09:49

2 Answers2

3
  1. The element image you are cropping is not present in the screenshot taken by the code. If you put debug and print full screen shot path and manually view it then you can see desired element to be cropped from image is not present in it.

  2. So first we need to scroll page to bring desired element into view and then take the screenshot. Then we need to crop the image based on element's location.

  3. Also, Point class is not very reliable to give element's exact location.

  4. Secondly if we see below values

    ImageIO.read(screenshot).getHeight() // ~ 943 => Total height
    element.getSize().getHeight() // ~ 511 => Element height 
    point.getY() // ~ 743 => start top side y coordinate of element
    
  5. So I believe when rectangle is drawn from x,y with height of 743 it went out of original screenshot coordinates.

So we need to perform some adjustments while passing coordinates.

@Test
public void subImageTest() throws InterruptedException, IOException {
    driver.get("http://learn-selenium-easy.blogspot.com/");
    ((JavascriptExecutor)driver).executeScript("window.scrollBy(0,600)");
   File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

    WebElement element=driver.findElement(By.xpath("//*[@id='PopularPosts1']"));
    System.out.println(element.getSize());

  // Take full screen screenshot
    BufferedImage  fullImg = ImageIO.read(screenshot);
    ImageIO.read(screenshot).getHeight()
    System.out.println(fullImg.getHeight()); 
    System.out.println(fullImg.getWidth());

    Point point = element.getLocation();
    int elementWidth = element.getSize().getWidth(); 
    int elementHeight = element.getSize().getHeight();

    // Now no exception here
    BufferedImage elementScreenshot= fullImg.getSubimage(220, 170,elementWidth+150,elementHeight+100);

    // crop the image to required
    ImageIO.write(elementScreenshot, "png", screenshot);
    FileUtils.copyFile(screenshot, new File("C:\\Users\\AppData\\Local\\Temp\\mostread_screenshot.png"));//path to save screen shot

}

Final sub image here of element after program executed enter image description here

Amit Jain
  • 4,389
  • 2
  • 18
  • 21
1

RasterFormatException

As per the Java Docs RasterFormatException is thrown if there is invalid layout information in the Raster.


getLocation()

As per the Selenium Documentation getLocation() returns the point containing the location of the top left-hand corner of the element.


getSubimage()

As per the Java Docs getSubimage() returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image and is defined as:

getSubimage
public BufferedImage getSubimage(int x,
                 int y,
                 int w,
                 int h)
Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.

Parameters: 
    x - the X coordinate of the upper-left corner of the specified rectangular region 
    y - the Y coordinate of the upper-left corner of the specified rectangular region 
    w - the width of the specified rectangular region 
    h - the height of the specified rectangular region 

Returns: 
    a BufferedImage that is the subimage of this BufferedImage. 

Throws: 
    RasterFormatException - if the specified area is not contained within this BufferedImage. 

I have taken your own code, added a couple of System.out.println() lines to showcase what exactly going wrong.

  • Code Block:

    public class A_demo 
    {
        public static void main(String[] args) throws Exception 
        {
                System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
                ChromeOptions options = new ChromeOptions();
                options.addArguments("start-maximized");
                options.addArguments("disable-infobars");
                WebDriver driver = new ChromeDriver(options);
                driver.get("http://learn-selenium-easy.blogspot.com/");
                // Xpath of element to take screen shot
                WebElement element=driver.findElement(By.xpath("//*[@id='PopularPosts1']"));
                System.out.println("Element size is:"+element.getSize());
                File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
                FileUtils.copyFile(screenshot, new File("./Screenshots/mostread_TakesScreenshot.png")); //path to save screen shot
    
                // Take full screen screenshot
                BufferedImage  fullImg = ImageIO.read(screenshot);
                Point point = element.getLocation();
                System.out.println("Co-ordinates where on the page is the top left-hand corner of the rendered element:"+point);
                int elementWidth = element.getSize().getWidth();
                System.out.println("Element width is:"+elementWidth);
                int elementHeight = element.getSize().getHeight();
                System.out.println("Element height is:"+elementHeight);
                BufferedImage elementScreenshot= fullImg.getSubimage(point.getX(), point.getY(), elementWidth,elementHeight);  //exception here
    
                // crop the image to required
                ImageIO.write(elementScreenshot, "png", screenshot);
                FileUtils.copyFile(screenshot, new File("./Screenshots/mostread_BufferedImage.png"));//path to save screen shot
        }    
    }
    
  • Console Output:

    INFO: Detected dialect: W3C
    Element size is:(340, 486)
    Co-ordinates where on the page is the top left-hand corner of the rendered element:(104, 744)
    Element width is:340
    Element height is:486
    Exception in thread "main" java.awt.image.RasterFormatException: (y + height) is outside of Raster
        at sun.awt.image.ByteInterleavedRaster.createWritableChild(Unknown Source)
        at java.awt.image.BufferedImage.getSubimage(Unknown Source)
        at demo.A_demo.main(A_demo.java:78)
    

Explanation

As discussed earlier, as per your code block fullImg.getSubimage() will try to return a BufferedImage i.e. elementScreenshot which will be a subimage defined by a specified by the rectangular region:

  • x: the X coordinate of the upper-left corner of the specified rectangular region - point.getX() - 104
  • y: the Y coordinate of the upper-left corner of the specified rectangular region - point.getY() - 744
  • w: the width of the specified rectangular region - elementWidth - 340
  • h: the height of the specified rectangular region - elementHeight - 486

So, the expected height of the BufferedImage is turning out to be 744 + 486 = 1230 which is pretty much out of the Raster. Hence you see the error.


Solution

To take a screenshot of a specific element or a particular div using and you can use the AShot() method importing ashot-1.4.4.jar while working with Selenium Java Client v3.14.0, ChromeDriver v2.41, Chrome v 68.0.

Note: AShot() method from ashot-1.4.4.jar works only with jQuery enabled Web Applications.

  • Code Block:

    import ru.yandex.qatools.ashot.AShot;
    import ru.yandex.qatools.ashot.Screenshot;
    
    public class A_demo 
    {
        public static void main(String[] args) throws Exception 
        {
            System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
            ChromeOptions options = new ChromeOptions();
            options.addArguments("start-maximized");
            options.addArguments("disable-infobars");
            WebDriver driver = new ChromeDriver(options);
            driver.get("http://learn-selenium-easy.blogspot.com/");
            WebElement myWebElement = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='PopularPosts1']")));
            ((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView();", myWebElement);
            Screenshot myScreenshot = new AShot().takeScreenshot(driver, myWebElement);
            ImageIO.write(myScreenshot.getImage(),"PNG",new File("./Screenshots/elementAShotScreenshot.png"));
            driver.quit();
        }    
    }
    

References

You can find a couple of relevant discussions in:


Outro

You can find a detailed discussion of all the Java based methods of taking screenshot in How to take screenshot with Selenium WebDriver

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Thank you for answering, Amit Jain was faster and his code doesn't include any other libraries, so I accepted his answer. I'll try to make up by upvoting some of your stuff. Or not...there's something weird about your reputation. – parsecer Jul 24 '19 at 15:21