Selenium: Capture DOM Elements Image - javascript

I have an API to capture the image of a particular element in DOM and return them. For that, I have a list of WebElements which needs to be captured into a single webpage. For that same, I have found the solution here which works fine if an element is visible on the screen (no need to scroll down to see it).
driver.get(urltoconnect);
WebElement ele = getElement();
// 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 = ele.getLocation();
// Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.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);
// Copy the element screenshot to disk
File screenshotLocation = new File("C:\\images\\GoogleLogo_screenshot.png");
FileUtils.copyFile(screenshot, screenshotLocation);
But the cases where I need to scroll down to see element results in java.awt.image.RasterFormatException: (y + height) is outside of Raster. So I have added this.
What I have tried
//All Results in java.awt.image.RasterFormatException: (y + height) is outside of Raster
//scroll the page until the mentioned element is visible on the current page.
js.executeScript("arguments[0].scrollIntoView();",element);
//This will scroll down the page by 450 pixel vertical
js.executeScript("window.scrollBy(0,450)");
//AShot
Screenshot fpScreenshot = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(400)).takeScreenshot(driver);
ImageIO.write(fpScreenshot.getImage(),"png",new File("image.png"));
Question is how can I capture the Image of particular elements where some elements need to be scrolled. Please note that I have multiple elements with there By.id, By.name, By.xpath for multiple sources so I can't set fullImg.getSubimage(x,y,w,h) by y+100 or something as this might work for one webpage but not for others. Any Help will be appreciated.
System.setProperty("webdriver.chrome.driver", "F:\\chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("https://www.testing-whiz.com/demoscripts/basic-element.html");
WebElement ele = getElement();
// 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 = ele.getLocation();
// Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();
// Crop the entire page screenshot to get only element screenshot
try {
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
}catch (Exception e) {
js.executeScript("window.scrollBy(0,450)");
//point.getY() = 732 //From console y = 492.8000183105469 after scroll https://stackoverflow.com/a/38767558/10961238
//raster.getHeight() = 613
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(), eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);
}
// Copy the element screenshot to disk
File screenshotLocation = new File("F:\\Images\\1.png");
FileUtils.copyFile(screenshot, screenshotLocation);
Backend: Spring Boot (Java 11)
Frontend: Angular

WebElement extends TakesScreenshot, which means you can use getScreenshotAs on the WebElement directly. You can
public void takeElementScreenshot(WebElement element) {
driver.executeScript("arguments[0].scrollIntoView();", element);
File screenshot = ele.getScreenshotAs(OutputType.FILE);
//...
}
You can check if the element is in viewport before scrolling, but I don't think it's necessary, just scroll every time

Related

How to scroll web page till that web element appear and perform required actions

I have scenario if we search for any input we will get multiple table data .
we have "show as text link" present in different table row we need click.
i have written a code it is working fine in IE in one machine same script is not working in different machine due to vary of monitor size!
String rawTextXpath = "//table[#id='view518-table']/tbody/tr[1]/td[4]/div[1]/a[text()='Show as raw text']";
boolean exists = false;
exists = driver.findElements(By.xpath(rawTextXpath)).size() != 0;
if (exists == false) {
system.out.println("No Results found!");
}
int i = 1;
while (exists == true) {
try {
driver.findElement(By.xpath(rawTextXpath)).click();
Thread.sleep(3000);
}
catch (Exception e) {
}
String expandXpath = "//table[#id='view518-table']/tbody/tr[" + i + "]/td[1]/a";
driver.findElement(By.xpath(expandXpath)).click();
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("window.scrollBy(0,150)", "");
rawTextXpath = "//table[#id='view518-table']/tbody/tr[" + (i + 1)
+ "]/td[4]/div[1]/a[text()='Show as raw text']";
exists = driver.findElements(By.xpath(rawTextXpath)).size() != 0;
i++;
}
Note : in above script i am scrolling webpage by 150 it will working fine in IE same version in one machine and it is not working same browser in another browsers
Action is
1. click on show as text link in each table row and then click on expand icon
Above code is not working properly in different system in same IE11 browser because monitor size is different!
Try this
WebElement element = driver.findElement(By.id("id_of_element"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500);
you need to subtract the window's height, check the animate jquery library to call another function on scroll down.
$("html, body").animate({ scrollTop: $(document).height()-$(window).height() });

Photoshop JavaScript: options to open a PDF as smart object

I'm trying to open a PDF file as a smart object layer in Photoshop (CS5). Croped to the trimbox.
It works when using openDialog() and open().
But in case the property asSmartObject is true the PDFOpenOptions.cropPage = CropToType.TRIMBOX will be ignored.
There have to be options to open as smart object, like the PDFOpenOptions.
But I can't find them, did you?
My page should be croped to the trimbox with a minimum height/width of 400 px. Open the PDF as rendered pic won't work, because PDFOpenOptions.height ist deprecated for CS5 (and newer).
I don't want to render with a higher resolution, the PDF could be a small business card or a huge poster. Opening a file should be fast. This is why I choosed "open as smart object".
var openPDF = File.openDialog (undefined, undefined, false);
var openPDFoptions = new PDFOpenOptions;
openPDFoptions.antiAlias = true;
openPDFoptions.bitsPerChannel = BitsPerChannelType.EIGHT;
openPDFoptions.cropPage = CropToType.TRIMBOX;
openPDFoptions.mode = OpenDocumentMode.RGB;
openPDFoptions.name = "unnamed";
openPDFoptions.page = 1;
openPDFoptions.resolution = 72;
openPDFoptions.suppressWarnings = true;
openPDFoptions.usePageNumber = true;
app.open (openPDF, openPDFoptions, false)

Is an event triggered when an HTML link element (<a/>) containing base64 data as href is ready?

I have created a webpage that basically displays 2 images side by side.
It has a "download" button, which triggers a vanilla Javascript function, which creates a <canvas> HTML element and concatenates the two images inside of it. It then creates a link with the base64-encoded result image as href and clicks on it:
<a download="image.png" id="dllink" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAAMnCAYAAABhnf9DAAAgAElEQVR4nOzdR48kD3rn96j03pfv6qo21dVd3qT3JryP9Jll281..."></a>
Here is what the function I'm using looks like:
/**
* Create canvas, draw both images in it, create a link with the result
* image in base64 in the "href" field, append the link to the document,
* and click on it
*/
function saveImage() {
// Get left image
var imgLeft = new Image();
imgLeft.setAttribute('crossOrigin', 'anonymous');
imgLeft.src = "imgleft/" + idxImageShownLeft + ".jpg";
imgLeft.onload = function() {
// Once the left image is ready, get right image
var imgRight = new Image()
imgRight.setAttribute('crossOrigin', 'anonymous');
imgRight.src = "imgright/" + idxImageShownRight + ".jpg";
imgRight.onload = function() {
// Once the right image is ready, create the canvas
var canv = document.createElement("canvas");
var widthLeft = parseInt(imgLeft.width);
var widthRight = parseInt(imgRight.width);
var width = widthLeft + widthRight;
var height = imgLeft.height;
canv.setAttribute("width", width);
canv.setAttribute("height", height);
canv.setAttribute("id", "myCanvas");
canv.setAttribute('crossOrigin', 'anonymous');
var ctx = canv.getContext("2d");
// Draw both images in canvas
ctx.drawImage(imgLeft, 0, 0);
ctx.drawImage(imgRight, widthLeft, 0);
// Create PNG image out of the canvas
var img = canv.toDataURL("image/png");
// Create link element
var aHref = document.createElement('a');
aHref.href = img;
aHref.setAttribute("id", "dllink");
aHref.download = "image.png";
// Append link to document
var renderDiv = document.getElementById("render");
renderDiv.replaceChild(aHref, document.getElementById("dllink"));
// Click on link
aHref.click();
}
}
}
My problem is that this works fine on Firefox, but not on Chrome.
After a bit of investigating, I realized that by setting a breakpoint before the aHref.click(); line in Chrome, it worked fine. I think that it means that the aHref.click(); is called before the <a href="data:image/png;base64,...></a> is ready to be clicked, but I don't know for sure.
I couldn't find a duplicate of this topic. What keywords should I use just to be 100% sure?
Am I investigating in the right direction?
Is there an event I could rely on in order to call aHref.click(); only when it is ready?
You could wrap it in an init function that gets called when the window completes loading.
function init() {
aHref.click();
}
window.onload = init;
Its similar to the vanilla equivalent of jQuery's .ready() method.
aHref , document.getElementById("dllink") appear to be same element ? Though "dllink" has not yet been appended to document when .replaceChild called ?
Try substituting
renderDiv.appendChild(aHref);
for
renderDiv.replaceChild(aHref, document.getElementById("dllink"));

How to open target="_blank" full screen?

I am trying to open new page with full screen. Below size is the my screen resolution. Still I have to click on re-sizable button on the browser to expand it to full screen.
How do I open it fill screen without clicking on re-sizeble?
Helper.Redirect("resource.aspx", "_blank",
"menubar=0,scrollbars=1,width=1366,height=768,top=10")
Method
Public Shared Sub Redirect(url As String, target As String, windowFeatures As String)
Dim context As HttpContext = HttpContext.Current
If ([String].IsNullOrEmpty(target) OrElse target.Equals("_self", StringComparison.OrdinalIgnoreCase)) AndAlso [String].IsNullOrEmpty(windowFeatures) Then
context.Response.Redirect(url)
Else
Dim page As Page = DirectCast(context.Handler, Page)
If page Is Nothing Then
Throw New InvalidOperationException("Cannot redirect to new window outside Page context.")
End If
url = page.ResolveClientUrl(url)
Dim script As String
If Not [String].IsNullOrEmpty(windowFeatures) Then
script = "window.open(""{0}"", ""{1}"", ""{2}"");"
Else
script = "window.open(""{0}"", ""{1}"");"
End If
script = [String].Format(script, url, target, windowFeatures)
ScriptManager.RegisterStartupScript(page, GetType(Page), "Redirect", script, True)
End If
End Sub
I tried 'fullscreen=yes, scrollbars=yes,location=yes,resizable=yes' parameters. It did not work.
Try:
window.open('newWin.html','NewWindow','fullscreen=yes');
Source:
Here
I had this same problem is simples just change this
Dim script As String
If Not [String].IsNullOrEmpty(windowFeatures) Then
script = "window.open(""{0}"", ""{1}"", ""{2}"");"
Else
script = "window.open(""{0}"", ""{1}"");"
End If
For this:
if (!String.IsNullOrEmpty(windowFeatures))
{
script = #"var w = window.open(""{0}"", ""{1}"", ""{2}""); w.moveTo(0,0); w.resizeTo(screen.width,screen.height-40);";
}
else
{
script = #"var w = window.open(""{0}"", ""{1}""); w.moveTo(0,0); w.resizeTo(screen.width,screen.height-40);";
if you want to is just put the property resizeto and moveTo

How to listen for layout changes on a specific HTML element?

What are some techniques for listening for layout changes in modern browsers? window.resize won't work because it only fires when the entire window is resized, not when content changes cause reflow.
Specifically, I'd like to know when:
An element's available width changes.
The total height consumed by the in-flow children of an element changes.
There are no native events to hook into for this. You need to set a timer and poll this element's dimensions in your own code.
Here's the basic version. It polls every 100ms. I'm not sure how you want to check the children's height. This assumes they'll just make their wrapper taller.
var origHeight = 0;
var origWidth = 0;
var timer1;
function testSize() {
var $target = $('#target')
if(origHeight==0) {
origWidth = $target.outerWidth();
origHeight = $target.outerHeight();
}
else {
if(origWidth != $target.outerWidth() || origHeight = $target.outerHeight()) {
alert("change");
}
origWidth = $target.outerWidth();
origHeight = $target.outerHeight();
timer1= window.setTimeout(function(){ testSize() }),100)
}
}
New browsers now have ResizeObserver, which fires when the dimensions of an element's content box or border box are changed.
const observer = new ResizeObserver(entries => {
const entry = entries[0];
console.log('contentRect', entry.contentRect);
// do other work hereā€¦
});
observer.observe(element);
From a similar question How to know when an DOM element moves or is resized, there is a jQuery plugin from Ben Alman that does just this. This plugin uses the same polling approach outlined in Diodeus's answer.
Example from the plugin page:
// Well, try this on for size!
$("#unicorns").resize(function(e){
// do something when #unicorns element resizes
});

Categories