Is it possible to take a screenshot with WebDriver of only one frame (not the complete window) within a frameset?
Alternatively, is it possible to define coordinates of a window for the screenshot or crop the image afterwards?
This should work:
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
public class Shooter{
private WebDriver driver;
public void shootWebElement(WebElement element) throws IOException {
File screen = ((TakesScreenshot) this.driver).getScreenshotAs(OutputType.FILE);
Point p = element.getLocation();
int width = element.getSize().getWidth();
int height = element.getSize().getHeight();
BufferedImage img = ImageIO.read(screen);
BufferedImage dest = img.getSubimage(p.getX(), p.getY(), width,
height);
ImageIO.write(dest, "png", screen);
File f = new File("S:\\ome\\where\\over\\the\\rainbow");
FileUtils.copyFile(screen, f);
}
}
Python solution (dependency: PIL or Pillow):
from PIL import Image
from selenium import webdriver
def element_screenshot(driver, element, filename):
bounding_box = (
element.location['x'], # left
element.location['y'], # upper
(element.location['x'] + element.size['width']), # right
(element.location['y'] + element.size['height']) # bottom
)
return bounding_box_screenshot(driver, bounding_box, filename)
def bounding_box_screenshot(driver, bounding_box, filename):
driver.save_screenshot(filename)
base_image = Image.open(filename)
cropped_image = base_image.crop(bounding_box)
base_image = base_image.resize(cropped_image.size)
base_image.paste(cropped_image, (0, 0))
base_image.save(filename)
return base_image
if __name__ == '__main__':
driver = webdriver.Firefox()
driver.get('https://www.google.com/?gws_rd=ssl')
element = driver.find_element_by_id('body')
screenshot = element_screenshot(driver, element, 'element.png') # Screenshot the '#body' element
bounding_box = (100, 100, 600, 600)
screenshot = bounding_box_screenshot(driver, bounding_box, 'box.png') # Screenshot the bounding box (100, 100, 600, 600)
Ruby solution
Setup
Install xvfb
apt-get install xvfb -y
Install headless browser and image manipulation gem
gem install chunky_png
gem install headless
gem install selenium-webdriver
Install chrome driver
wget http://chromedriver.googlecode.com/files/chromedriver_linux64_<latest>.zip
apt-get install unzip
unzip chromedriver_linux64_<latest>.zip
cp chromedriver /usr/local/bin
More info can be found here
Code
#!/usr/bin/env ruby
require "headless"
require "selenium-webdriver"
require 'chunky_png'
headless = Headless.new
headless.start
site = "?_some_site_?"
driver = Selenium::WebDriver.for :chrome
driver.navigate.to site
sleep 1
driver.save_screenshot('screenshot.png')
el= driver.find_element(:xpath, '?_some_xpath_?')
image = ChunkyPNG::Image.from_file('screenshot.png')
image.crop!(el.location.x + 1, el.location.y + 1, el.size.width, el.size.height)
image.save('croped.png')
driver.quit
headless.destroy
Just posting a solution based on C# on taking a specific Html element's screenshot in selenium:
First we need to take the screen shot of entire web page using the GetScreenShot method of selenium web driver as below.
Screenshot screenshot = ((ITakesScreenshot)this.driver).GetScreenshot();
screenshot.SaveAsFile(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
Then create a rectangle from the location , height and width of the specified html element. (This has to be obtained using FindElement() method of selenium by providing id or class name).
Image img = Bitmap.FromFile(uniqueName);
Rectangle rect = new Rectangle();
if (element != null)
{
// Get the Width and Height of the WebElement using
int width = element.Size.Width;
int height = element.Size.Height;
// Get the Location of WebElement in a Point.
// This will provide X & Y co-ordinates of the WebElement
Point p = element.Location;
// Create a rectangle using Width, Height and element location
rect = new Rectangle(p.X, p.Y, width, height);
}
Using this we are going to crop the the screenshot as below and the result will be the screenshot specific web element.
Bitmap bmpImage = new Bitmap(img);
var cropedImag = bmpImage.Clone(rect, bmpImage.PixelFormat);
Full code as a method below:
/// <summary>
/// Captures the element screen shot.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="uniqueName">Name of the unique.</param>
/// <returns>returns the screenshot image </returns>
public Image CaptureElementScreenShot(HTMLElement element, string uniqueName)
{
Screenshot screenshot = ((ITakesScreenshot)this.driver).GetScreenshot();
screenshot.SaveAsFile(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
Image img = Bitmap.FromFile(uniqueName);
Rectangle rect = new Rectangle();
if (element != null)
{
// Get the Width and Height of the WebElement using
int width = element.Size.Width;
int height = element.Size.Height;
// Get the Location of WebElement in a Point.
// This will provide X & Y co-ordinates of the WebElement
Point p = element.Location;
// Create a rectangle using Width, Height and element location
rect = new Rectangle(p.X, p.Y, width, height);
}
// croping the image based on rect.
Bitmap bmpImage = new Bitmap(img);
var cropedImag = bmpImage.Clone(rect, bmpImage.PixelFormat);
return cropedImag;
}
Scala solution:
import javax.imageio.ImageIO
import java.awt.image.BufferedImage
// phone is a case class with witdth and height Int fields
def producer {
[..]
processScreenshot(driver.getScreenshotAs(OutputType.FILE), ph)
}
def processScreenshot(file: File, phone: Phone) = {
val img: BufferedImage = ImageIO.read(file)
val w = math.min(img.getWidth, phone.width)
val h = math.min(img.getHeight, phone.height)
val dest = img.getSubimage(0, 0, w, h)
ImageIO.write(dest, "png", new File(s"/tmp/${un}_${phone.file}.png"))
}
Related
I'm encountering:
Exception in thread "main" java.lang.NullPointerException at org.openqa.selenium.remote.RemoteWebElement.getLocation(RemoteWebElement.java:338)
while trying to get a BufferedImage of the captcha at https://signup.live.com/:
public BufferedImage getCaptchaBufferedImage() throws IOException, InterruptedException {
System.out.println("Looking for captcha image");
this.wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("hipTemplateContainer")));
System.out.println("Found image");
WebElement element = this.driver.findElement(By.id("hipTemplateContainer"));
System.out.println(element.getAttribute("outerHTML"));
List<WebElement> childs = element.findElements(By.xpath(".//*"));
WebElement firstChild = childs.get(0);
System.out.println(firstChild.getAttribute("outerHTML"));
List<WebElement> childs2 = firstChild.findElements(By.xpath(".//*"));
WebElement imageChild = childs2.get(0);
System.out.println(imageChild.getAttribute("outerHTML"));
((JavascriptExecutor) this.driver).executeScript("arguments[0].scrollIntoView(true);", imageChild);
String id = imageChild.getAttribute("id");
this.wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
**Point point = firstChild.getLocation();**
byte[] img_bytes = ((TakesScreenshot) this.driver).getScreenshotAs(OutputType.BYTES);
BufferedImage imageScreen = ImageIO.read(new ByteArrayInputStream(img_bytes));
System.out.println("Downloaded image");
double d = Double.parseDouble(firstChild.getCssValue("height").split("px")[0]);
int height = (int) d;
double e = Double.parseDouble(firstChild.getCssValue("width").split("px")[0]);
int width = (int) e;
BufferedImage captcha = imageScreen.getSubimage(point.getX(), point.getY(), width, height);
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(captcha)));
frame.pack();
frame.setVisible(true);
return captcha;
}
I've looked all over the net, can't figure this one out.. Possible bug in Selenium 3.0? This code works if I skip getting the offset of the image and just hardcode the values in getSubImage()..
I tried for more than 2 hours and guess what? I found the issue.
Issue:
It is because getScreenshotAs is taking only the visible part of the page (after scrolling to the captcha) but not complete the page, hence resulting in all the issues. It resulted in the Y coordinate returned by the Point (1041), is relative to the complete web page, but the screenshot image has different Y-coordinate for the captcha (300) relative to the partial page. hence resulted in the following exception:
java.awt.image.RasterFormatException: (y + height) is outside of Raster
X-coordinate is the same value in both complete web page and partial
web page.
so, hardcoding the Y-coordinate to 300 solved the issue temporararliy. BUt the actual issue is that why screenshot is not taken for the complete page instead of jus visible page. may be the bug in the latest geckodriver (firefox driver). tried in Firefox 49 version with Selenium 3 version, geckodriver v0.1.11 and Java 1.8.
Following is the code. please try and let me know:
driver.get("https://signup.live.com/");
driver.manage().window().maximize();
System.out.println("Looking for captcha image");
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("hipTemplateContainer")));
System.out.println("Found image");
WebElement element = driver.findElement(By.id("hipTemplateContainer"));
System.out.println(element.getAttribute("outerHTML"));
List<WebElement> childs = element.findElements(By.xpath(".//*"));
WebElement firstChild = childs.get(0);
System.out.println(firstChild.getAttribute("outerHTML"));
List<WebElement> childs2 = firstChild.findElements(By.xpath(".//*"));
WebElement imageChild = childs2.get(0);
System.out.println(imageChild.getAttribute("outerHTML"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", imageChild);
String id = imageChild.getAttribute("id");
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
Point point = imageChild.getLocation();
int width = imageChild.getSize().getWidth();
int height = imageChild.getSize().getHeight();
System.out.println("height: " + height + "\t weight : " + width);
System.out.println("X co-ordinate: " + point.getX());
System.out.println("Y co-ordinate: " + point.getY());
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot, new File("G:\\naveen\\screenshot.png"));
BufferedImage imageScreen = ImageIO.read(screenshot);
System.out.println("Downloaded image");
BufferedImage captcha = imageScreen.getSubimage(245, 300, width, height);
ImageIO.write(captcha, "png", screenshot);
FileUtils.copyFile(screenshot, new File("G:\\naveen\\screenshot1.png"));
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new JLabel(new ImageIcon(captcha)));
frame.pack();
frame.setVisible(true);
Following are screenshots saved:
Only visible web page is saved.
sub image - captcha image:
I'm trying to capture the screenshot of all the elements present on a webpage and want to store it in my disk for which i have written the below code.
The only issue is this piece of code is working only for the first iteration and after which some unexpected thing is happening.
List<WebElement> eleId = driver.findElements(By.xpath("//*[#id]")); //fetch all the elements with ID attribute
System.out.println(eleId.size());
for (int i = 0;i < eleId.size();i++) {
// Get entire page screenshot
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
// Get the location of element on the page
Point point = eleId.get(i).getLocation();
// Get width and height of the element
int eleWidth = eleId.get(i).getSize().getWidth();
int eleHeight = eleId.get(i).getSize().getHeight();
// Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot = fullImg.getSubimage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
// Creating variables name for image to be stores in the disk
String fileName = eleId.get(i).getAttribute("id");
String imageLocation = "D:\\" + fileName + ".png";
// System.out.println(imageLocation);
// Copy the element screenshot to disk
File screenshotLocation = new File(imageLocation);
FileUtils.copyFile(screenshot, screenshotLocation);
System.out.println("Screenshot has been stored.");
}
Hi Sandeep try below code. It is working for me. I just added one "if" condition to check the image height and width.
#Test(enabled=true)
public void getIndividualElementScreenShot() throws IOException{
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com/");
driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
driver.manage().window().maximize();
List<WebElement> eles = driver.findElements(By.xpath("//*[#id]"));
System.out.println(eles.size());
for(WebElement ele : eles){
//Get Entire page screen shot
File screenShot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImage = ImageIO.read(screenShot);
//Get the location on the page
Point point = ele.getLocation();
//Get width and height of an element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
//Cropping the entire page screen shot to have only element screen shot
if(eleWidth != 0 && eleHeight != 0){
BufferedImage eleScreenShot = fullImage.getSubimage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(eleScreenShot, "png", screenShot);
//Creating variable name for image to be store in disk
String fileName = ele.getAttribute("id");
String imageLocation = "F:\\ElementImage\\"+fileName+".png";
System.out.println(imageLocation);
//Copy the element screenshot to disk
File screenShotLocation = new File(imageLocation);
org.apache.commons.io.FileUtils.copyFile(screenShot, screenShotLocation);
System.out.println("Screen shot has beed stored");
}
}
driver.close();
driver.quit();
}
Your code is doing fine. But you are overwriting the file in each iteration. Did you get it? Change file name in each iteration by assigning new file name in fileName variable. Use the code below:
List<WebElement> eleId = driver.findElements(By.xpath("//*[#id]")); //fetch all the elements with ID attribute
System.out.println(eleId.size());
for (int i = 0;i < eleId.size();i++) {
// Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
// Get the location of element on the page
Point point = eleId.get(i).getLocation();
// Get width and height of the element
int eleWidth = eleId.get(i).getSize().getWidth();
int eleHeight = eleId.get(i).getSize().getHeight();
// Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot = fullImg.getSubimage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
// Creating variables name for image to be stores in the disk
String fileName = eleId.get(i).getAttribute("id");
String imageLocation = "D:/" + fileName + i + ".png";
// System.out.println(imageLocation);
// Copy the element screenshot to disk
File screenshotLocation = new File(imageLocation);
FileUtils.copyFile(screenshot, screenshotLocation);
System.out.println("Screenshot has been stored.");
}
I am using selenium Web Driver(Java) to automate our web application.
I need to capture and compare the each icon of the application in all browsers.
For that first I've opened the application in Firefox and captured icons images with its xpath and then saving them at a particular path.
Later comparing the saved images when the application opened in another browser.
For this I have used the below code to capture the images, but the element image is not capturing, some unknown region in the screen is saving.
Please help, how to get the correct image of the element.
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
Point point = x.getLocation();
//Get width and height of the element
int eleWidth = x.getSize().getWidth();
int eleHeight = x.getSize().getHeight();
Rectangle rect = new Rectangle(point.getX(),point.getY(),eleWidth, eleHeight);
//Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(), rect.width, rect.height);
ImageIO.write(eleScreenshot, "png", screenshot);
//Copy the element screenshot to disk
FileUtils.copyFile(screenshot, new File("E:\\ICONS\\Icon1.jpg"));
driver.switchTo().defaultContent();
driver.switchTo().frame(driver.findElement(By.xpath("//*[#id='CWinBtn']")));
WebElement ele =driver.findElement(By.xpath("//*[#id='CCDLinkedformToolbar_cmdPrint']"));
try{
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage fullImg = ImageIO.read(screenshot);
Point point = ele.getLocation();
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX()+30, 95, eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
FileUtils.copyFile(screenshot, new File("E:\\ ICONS\\Icon1.png"));
}
catch(Exception e){
e.printStackTrace();
}
Changes that i have made to my previous code are, added value to X coordinate and passed static value to Y coordinate, as per my application resolution.
It seems to me Java3D has a problem redrawing the scene sometimes when the Frame/JPanel/Canvas3D has been resized. I have a problem in my application using Java3D/JUNG3D where if the Frame/JPanel/Canvas3D's horizontal size is of certain size, the entire scene disappears. I was trying to simply the problem then found that a similar problem occurs in the following sample code: http://www.java3d.org/samples.html (The second to last example, "Text 3D Example") I will paste at the bottom for convenience.
Steps:
Install Java3D
Build this example using the 3 Java3D jars.
Run
Stretch the frame horizontally to 500 pixels or so then everything disappears. Shrink it back then it's there again. While things have disappeared, stretch vertically and things appear again.
It certainly seems to have something to do with the Frame/JPanel/Canvas3D aspect ratio and that of the content that it displays. My own problem is slightly different I'm guessing because I'm displaying scene of different aspect ratio and the underlying problem is the same. Can anyone tell me how I might be able to get around this bug/feature so that the scene never disappears when the window is resized?
Here are what I've tried so far with no success:
Catching the JPanel resize event then forcing the Canvas3D to redraw
Playing with double buffering settings
Many other things I can't recall right now - just came back from a vacation :)
Code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
public class Titles {
public static void main(String[] args) {
Titles t = new Titles();
t.setUp();
}
public void setUp() {
JFrame jf = new JFrame("Welcome");
// kill the window on close
jf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent winEvent) {
System.exit(0);
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1, 2, 2));
GraphicsConfiguration config = SimpleUniverse
.getPreferredConfiguration();
Canvas3D canvas3D = new Canvas3D(config);
canvas3D.setSize(360, 160);
SimpleUniverse universe = new SimpleUniverse(canvas3D);
BranchGroup group = new BranchGroup();
addObjects(group);
addLights(group);
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(group);
panel.add(canvas3D);
jf.getContentPane().add(panel, BorderLayout.CENTER);
jf.pack();
jf.setVisible(true);
}
public void addLights(BranchGroup group) {
BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
1000.0);
Color3f light1Color = new Color3f(1.0f, 1.0f, 1.0f);
Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
DirectionalLight light1 = new DirectionalLight(light1Color,
light1Direction);
light1.setInfluencingBounds(bounds);
group.addChild(light1);
// Set up the ambient light
Color3f ambientColor = new Color3f(.1f, .1f, .1f);
AmbientLight ambientLightNode = new AmbientLight(ambientColor);
ambientLightNode.setInfluencingBounds(bounds);
group.addChild(ambientLightNode);
}
private void addObjects(BranchGroup group) {
Font3D f3d = new Font3D(new Font("TestFont", Font.PLAIN, 2),
new FontExtrusion());
Text3D text = new Text3D(f3d, new String("Java3D.org"), new Point3f(-3.5f,
-.5f, -4.5f));
text.setString("Java3D.org");
Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
Color3f blue = new Color3f(.2f, 0.2f, 0.6f);
Appearance a = new Appearance();
Material m = new Material(blue, blue, blue, white, 80.0f);
m.setLightingEnable(true);
a.setMaterial(m);
Shape3D sh = new Shape3D();
sh.setGeometry(text);
sh.setAppearance(a);
TransformGroup tg = new TransformGroup();
Transform3D t3d = new Transform3D();
Transform3D tDown = new Transform3D();
Transform3D rot = new Transform3D();
Vector3f v3f = new Vector3f(-1.6f, -1.35f, -6.5f);
t3d.setTranslation(v3f);
rot.rotX(Math.PI / 5);
t3d.mul(rot);
v3f = new Vector3f(0, -1.4f, 0f);
tDown.setTranslation(v3f);
t3d.mul(tDown);
tg.setTransform(t3d);
tg.addChild(sh);
group.addChild(tg);
}
}
Try setting up a Buffer,Tutorial here. http://www.youtube.com/watch?v=vzfnUSLKUDs&list=ECA331A6709F40B79D
It's been 5 years but try this solution.
I tried it and it worked with lookAt() function.
Is there any way to add Text and Image in SWT label in a single line.
Once I add image, text goes off.
No you can't have an image and text simultaneously in a Label (unless you custom draw it). Else use org.eclipse.swt.custom.CLabel:
Code:
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class LabelTest {
public static void main(String[] args)
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Image image = new Image(display, "next.png");
CLabel label = new CLabel(shell, SWT.BORDER);
label.setImage(image);
label.setText("This is a CLabel !!");
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
if(image != null)
{
image.dispose();
image = null;
}
display.dispose();
}
}
Output:
Button click to open FileDialog Box and selected any image to display with text on specific label.
import org.eclipse.swt.custom.CLabel
A Label which supports aligned text and/or an image and different border styles.
I hope this answer is usefull.
please visit this page:
How to load image to view in RCP?
Yes, using an intermediary composite with the right layout
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new RowLayout(SWT.HORIZONTAL));
Label imageLabel = new Label(composite, SWT.NONE);
mageLabel.setImage(...);
Label textLabel = new Label(composite, SWT.NONE);
textLabel.setText(...)