Skip to content

Commit 00a4456

Browse files
anna-shchurokglibas
authored andcommitted
Chrome full size screenshot without sticky header (#38)
Add new scrolling strategy for chrome; Chrome dev tools used to take screenshot
1 parent dfe23ac commit 00a4456

File tree

4 files changed

+79
-7
lines changed

4 files changed

+79
-7
lines changed

src/main/java/com/assertthat/selenium_shutterbug/core/Shutterbug.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ public static PageSnapshot shootPage(WebDriver driver, ScrollStrategy scroll, in
9696
break;
9797
case BOTH_DIRECTIONS:
9898
pageScreenshot.setImage(browser.takeScreenshotEntirePage());
99+
break;
100+
case WHOLE_PAGE_CHROME:
101+
pageScreenshot.setImage(browser.takeScreenshotEntirePageUsingChromeCommand());
102+
break;
99103
}
100104
return pageScreenshot;
101105
}

src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,28 @@
66
package com.assertthat.selenium_shutterbug.utils.web;
77

88
import com.assertthat.selenium_shutterbug.utils.file.FileUtil;
9+
import com.google.common.collect.ImmutableMap;
910
import org.openqa.selenium.Dimension;
1011
import org.openqa.selenium.*;
1112
import org.openqa.selenium.Point;
13+
import org.openqa.selenium.chrome.ChromeDriver;
14+
import org.openqa.selenium.remote.CommandInfo;
15+
import org.openqa.selenium.remote.HttpCommandExecutor;
16+
import org.openqa.selenium.remote.RemoteWebDriver;
17+
import org.openqa.selenium.remote.Response;
18+
import org.openqa.selenium.remote.http.HttpMethod;
1219

1320
import javax.imageio.ImageIO;
1421
import java.awt.*;
1522
import java.awt.image.BufferedImage;
23+
import java.io.ByteArrayInputStream;
1624
import java.io.File;
1725
import java.io.IOException;
26+
import java.io.InputStream;
27+
import java.lang.reflect.InvocationTargetException;
28+
import java.lang.reflect.Method;
1829
import java.util.ArrayList;
19-
20-
import static java.lang.Math.toIntExact;
30+
import java.util.Map;
2131

2232
/**
2333
* Created by Glib_Briia on 17/06/2016.
@@ -34,6 +44,7 @@ public class Browser {
3444
public static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js";
3545
public static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js";
3646
public static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js";
47+
public static final String ALL_METRICS = "js/all-metrics.js";
3748

3849
private WebDriver driver;
3950
private int docHeight = -1;
@@ -50,7 +61,14 @@ public Browser(WebDriver driver, boolean useDevicePixelRatio) {
5061
this.devicePixelRatio = devicePixelRatio instanceof Double? (Double)devicePixelRatio: (Long)devicePixelRatio*1.0;
5162
}
5263
}
53-
64+
public Browser(ChromeDriver driver) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
65+
this.driver = driver;
66+
CommandInfo cmd = new CommandInfo("/session/:sessionId/chromium/send_command_and_get_result", HttpMethod.POST);
67+
Method defineCommand = HttpCommandExecutor.class.getDeclaredMethod("defineCommand", String.class, CommandInfo.class);
68+
defineCommand.setAccessible(true);
69+
defineCommand.invoke(driver.getCommandExecutor(), "sendCommand", cmd);
70+
}
71+
5472
public Double getDevicePixelRatio() {
5573
return devicePixelRatio;
5674
}
@@ -79,7 +97,7 @@ public BufferedImage takeScreenshot() {
7997
srcFile.delete();
8098
}
8199
}
82-
100+
83101
}
84102

85103
public BufferedImage takeScreenshotEntirePage() {
@@ -90,12 +108,12 @@ public BufferedImage takeScreenshotEntirePage() {
90108
int _viewportWidth = this.getViewportWidth();
91109
int _viewportHeight = this.getViewportHeight();
92110
final int scrollBarMaxWidth = 40; // this is probably too high, but better to be safe than sorry
93-
111+
94112
if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth))
95113
_viewportHeight-=scrollBarMaxWidth; // some space for a scrollbar
96114
if (_viewportHeight < _docHeight)
97115
_viewportWidth-=scrollBarMaxWidth; // some space for a scrollbar
98-
116+
99117
int horizontalIterations = (int) Math.ceil(((double) _docWidth) / _viewportWidth);
100118
int verticalIterations = (int) Math.ceil(((double) _docHeight) / _viewportHeight);
101119
outer_loop:
@@ -115,6 +133,36 @@ public BufferedImage takeScreenshotEntirePage() {
115133
return combinedImage;
116134
}
117135

136+
public BufferedImage takeScreenshotEntirePageUsingChromeCommand() {
137+
if(!(this.driver instanceof ChromeDriver))
138+
throw new UnsupportedOperationException("You must use Chrome driver for this operation");
139+
140+
Browser driver;
141+
try {
142+
driver = new Browser((ChromeDriver) this.driver);
143+
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
144+
throw new RuntimeException(e);
145+
}
146+
147+
int verticalIterations = (int) Math.ceil(((double) this.getDocHeight()) / this.getViewportHeight());
148+
for (int j = 0; j < verticalIterations; j++) {
149+
this.scrollTo(0, j * this.getViewportHeight());
150+
wait(scrollTimeout);
151+
}
152+
Object metrics = driver.evaluate(FileUtil.getJsScript(ALL_METRICS));
153+
driver.sendCommand("Emulation.setDeviceMetricsOverride", metrics);
154+
Object result = driver.sendCommand("Page.captureScreenshot", ImmutableMap.of("format", "png", "fromSurface", true));
155+
String base64EncodedPng = (String) ((Map<String, ?>) result).get("data");
156+
InputStream in = new ByteArrayInputStream(OutputType.BYTES.convertFromBase64Png(base64EncodedPng));
157+
BufferedImage bImageFromConvert;
158+
try {
159+
bImageFromConvert = ImageIO.read(in);
160+
} catch (IOException e) {
161+
throw new RuntimeException("Error while converting results from bytes to BufferedImage");
162+
}
163+
return bImageFromConvert;
164+
}
165+
118166
public BufferedImage takeScreenshotScrollHorizontally() {
119167
BufferedImage combinedImage = new BufferedImage(this.getDocWidth(), this.getViewportHeight(), BufferedImage.TYPE_INT_ARGB);
120168
Graphics2D g = combinedImage.createGraphics();
@@ -198,4 +246,21 @@ public Object executeJsScript(String filePath, Object... arg) {
198246
JavascriptExecutor js = (JavascriptExecutor) driver;
199247
return js.executeScript(script, arg);
200248
}
249+
250+
public Object sendCommand(String cmd, Object params) {
251+
try {
252+
Method execute = RemoteWebDriver.class.getDeclaredMethod("execute", String.class, Map.class);
253+
execute.setAccessible(true);
254+
Response res = (Response) execute.invoke(driver, "sendCommand", ImmutableMap.of("cmd", cmd, "params", params));
255+
return res.getValue();
256+
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
257+
throw new RuntimeException(e);
258+
}
259+
}
260+
261+
public Object evaluate(String script) {
262+
Object response = sendCommand("Runtime.evaluate", ImmutableMap.of("returnByValue", true, "expression", script));
263+
Object result = ((Map<String, ?>) response).get("result");
264+
return ((Map<String, ?>) result).get("value");
265+
}
201266
}

src/main/java/com/assertthat/selenium_shutterbug/utils/web/ScrollStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
* Created by Glib_Briia on 17/06/2016.
1010
*/
1111
public enum ScrollStrategy {
12-
HORIZONTALLY, VERTICALLY, BOTH_DIRECTIONS
12+
HORIZONTALLY, VERTICALLY, BOTH_DIRECTIONS, WHOLE_PAGE_CHROME
1313
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
({width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0,
2+
height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0,
3+
deviceScaleFactor: window.devicePixelRatio || 1,mobile: typeof window.orientation !== 'undefined'})

0 commit comments

Comments
 (0)