back to the repository
The AShot
is WebDriver screenshot library in Java. My com.kazurayam.ashotwrapper.AShotWrapper
is a thin wrapper class of the AShot library.
The com.kazurayam.ashotwrapper.AShotWrapper
class simplifies using AShot in the Visual Inspection in Katalon Studio project.
The com.kazurayam.ashotwrapper.AShotWrapper
class provides some additional features that the AShot library doesn’t.
AShotWrapper
optionally enables you to save screenshots in JPEG format while specifying compression quality. This is helpful in some cases to reduce the size of output files.
AShotWrapper
optionally enables you to “censor” screenshots. You can paint the HTML elements in the screenshot with grey color. Effectively the painted HTML elements are ignored when you perform visual comparisons.
AShotWrapper
The artifact is available at the Maven Central repository:
You can use Gradle or Maven to use this library in your Java/Groovy project. Assuming you use Gradle, you just want to wraite your `build.gradle:
implementation group: 'com.kazurayam', name: 'ashotwrapper', version: '0.2.0'
If you want to use this library in your Katalon Studio project, you want to download 2 jars into the Drivers
folder of your Katalon Studio project.
visit the page of ashotwrapper in the Maven Central, find the latest version and click the jar
link to download it.
Javadoc is here
Here I will present a JUnit5 test class com.kazurayam.ashotwrapper.samples.AShotWrapperDemo
to demonstrate how to use the AShotWrapper
class.
The test class starts with the package statement, import statements, class declaration and some common boilerplate methods; it is as follows:
package com.kazurayam.ashotwrapper.samples;
import com.kazurayam.ashotwrapper.AShotWrapper;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
public class AShotWrapperDemo {
private static final Path outputDir =
Paths.get(".").resolve("docs/samples")
.resolve(AShotWrapperDemo.class.getName());
private static WebDriver driver;
private static final int timeout = 500;
private AShotWrapper.Options options = null;
@BeforeAll
static void beforeAll() throws IOException {
Path dir = outputDir;
if (Files.exists(dir)) {
// delete the directory to clear out using Java8 API
Files.walk(dir)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
Files.createDirectories(dir);
}
@BeforeEach
void beforeEach(){
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--headless");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(timeout, TimeUnit.MILLISECONDS);
driver.manage().window().setSize(new Dimension(800, 400));
//
float dpr = AShotWrapper.DevicePixelRatioResolver.resolveDPR(driver);
this.options = new AShotWrapper.Options.Builder().devicePixelRatio(dpr).build();
}
@AfterEach
void tearDown(){
if (driver != null) {
driver.quit();
}
}
Now I will show each test methods that demonstrates how to use AShotWrapper, with resulting image files.
The following code takes a screenshot of entire page view of the target URL, save the image in a PNG file.
@Test
void test_saveEntirePageImage() throws IOException {
driver.navigate().to("https://www.iana.org/domains/reserved");
File file = outputDir.resolve("test_saveEntirePageImage.png").toFile();
AShotWrapper.saveEntirePageImage(driver, file);
assertTrue(file.exists());
}
OUTPUT: entire page screenshot in PNG
The following code takes a screenshot of current viewport of the target web page in the browser (not the entire page screenshot), save the image in a PNG file.
@Test
void test_savePageImage() throws IOException {
driver.navigate().to("https://www.iana.org/domains/reserved");
File file = outputDir.resolve("test_savePageImage.png").toFile();
AShotWrapper.savePageImage(driver, file);
assertTrue(file.exists());
}
OUTPUT: current viewport screenshot in PNG
You can select a single HTML element in the target web page, take the screenshot of the element, and save the image into a PNG file.
@Test
void test_takeElementImage() throws IOException {
driver.navigate().to("http://example.com");
BufferedImage image = AShotWrapper.takeElementImage(driver,
By.xpath("//body/div"),
options);
assertNotNull(image);
File file = outputDir.resolve("test_takeWebElementImage.png").toFile();
ImageIO.write(image, "PNG", file);
assertTrue(file.exists());
}
OUTPUT: element screenshot in PNG
You can save screenshot images into files in JPEG format. In some cases, a screenshot in JPEG of a web page can be much smaller than PNG.
@Test
void test_saveEntirePageImageAsJpeg() throws IOException {
driver.navigate().to("https://www.iana.org/domains/reserved");
File file = outputDir.resolve("test_saveEntirePageImageAsJpeg.jpg").toFile();
AShotWrapper.saveEntirePageImageAsJpeg(driver, file, 0.7f);
assertTrue(file.exists());
}
OUTPUT: entire page screenshot in JPEG
You can also take screenshot of current viewport and selected HTML element in JPEG as well.
Selenium WebDriver supports taking screenshot of the browser window. See tutorials. WebDriver produces files always in PNG format. Sometimes, screenshots in PNG format can be very large in byte size. For example, this sample screenshot in PNG is as large as 6.5 Mega bytes. If you are going to take many screenshots in your testing project, the size of screenshot images matters. Large image files are difficult to manage and utilize. So I want to make the screenshot image files as small as possible. But how to?
I found some libraries that compress a PNG file into another PNG file of smaller size, for example Pngquant. But I do not like to depend on those external libraries. I want a solution that I can use on top of Java8. A well-know resolution is to save screenshots in JPEG, not PNG, while specifying compression quality.
I have written a method writeJPEG
which does this. With this method, AShotWrapper
can save any BufferedImage
object into JPEG file which specifying compression quality like 1.0f, 0.9f, 0.8f, 0.7f, … , 0.1f.
/**
* write a BufferedImage object into a file in JPEG format with some compression applied
*
* @param image BufferedImage
* @param file File
* @param compressionQuality [0.0f, 1.0f]
* @throws IOException when some io failed
*/
public static void writeJPEG(BufferedImage image, File file, float compressionQuality)
throws IOException {
Objects.requireNonNull(image);
Objects.requireNonNull(file);
if (compressionQuality < 0.1f || 1.0f < compressionQuality) {
throw new IllegalArgumentException("compressionQuality must be in the range of [0.1f, 1.0f]");
}
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(compressionQuality);
//
ImageOutputStream outputStream = new FileImageOutputStream(file);
jpgWriter.setOutput(outputStream);
IIOImage outputImage =
new IIOImage(removeAlphaChannel(image), null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
}
In theory, the smaller the compression quality is, we can expect the resulting JPEG file will have smaller size at the cost of poorer quality of image view.
Practically, how large the screenshots of web pages will be in PNG, in JPEG with 1.0f, 0.9f, … , 0.1f? Different design of web pages may result different file sizes. My ultimate question is, given a URL to take screenshot, which format should I use: PNG or JPEG? If I choose JPEG, then what value of compression quality should I specify?
In order to answer to the question, I have created a JUnit5 test, named FileSizeTest. This test targets 3 public URL, take screenshots in PNG and JPEG with varying compression quality; the test compiles tables where you can find how large in % each JPEG files are against the baseline PNG file.
A web page that is composed of lots of eye-catching photos
File | Quality | Size(bytes) | % to PNG |
---|---|---|---|
1.0 |
6,588,545 |
100% |
|
1.0 |
3,041,837 |
47% |
|
0.9 |
1,187,056 |
19% |
|
0.8 |
843,636 |
13% |
|
0.7 |
692,684 |
11% |
|
0.6 |
595,758 |
10% |
|
0.5 |
531,487 |
9% |
|
0.4 |
469,988 |
8% |
|
0.3 |
404,645 |
7% |
|
0.2 |
324,059 |
5% |
|
0.1 |
223,726 |
4% |
Photo-rich page results in the screenshots of very large size. PNG is surprisingly lager than JPEG of the compression quality 1.0. PNG is not suitable for photo-rich pages. You should save the screenshots of photo-rich pages in JPEG, seriously.
Text-rich page without eye-catching photos
File | Quality | Size(bytes) | % to PNG |
---|---|---|---|
1.0 |
295,798 |
100% |
|
1.0 |
569,674 |
192% |
|
0.9 |
280,978 |
95% |
|
0.8 |
214,878 |
73% |
|
0.7 |
182,895 |
62% |
|
0.6 |
161,678 |
55% |
|
0.5 |
146,857 |
50% |
|
0.4 |
133,145 |
46% |
|
0.3 |
117,464 |
40% |
|
0.2 |
98,488 |
34% |
|
0.1 |
73,360 |
25% |
Text-rich page results in the screenshots of small size. PNG is smaller than JPEG of the compression quality 1.0. PNG is suitable for text-rich pages.
Mixture of texts and small number of images. There are a lot of web sites on the net like this.
File | Quality | Size(bytes) | % to PNG |
---|---|---|---|
1.0 |
582,684 |
100% |
|
1.0 |
1,288,390 |
221% |
|
0.9 |
562,293 |
97% |
|
0.8 |
410,043 |
71% |
|
0.7 |
340,999 |
59% |
|
0.6 |
295,414 |
51% |
|
0.5 |
264,916 |
46% |
|
0.4 |
236,851 |
41% |
|
0.3 |
206,214 |
36% |
|
0.2 |
169,583 |
30% |
|
0.1 |
121,342 |
21% |
PNG has smaller file size than JPEG of the compression quality 1.0. The JPEG of compression quality 0.9f is quite similar to PNG. Yes, JPEG could tuned to be smaller than PNG but is not so much significant.
Many websites contain <div>
elements that display commercial advertisements that keep on changing dynamically everytime inquired. These dynamic HTML elements disturb visual comparison of 2 screenshots taken at different timings. These dynamic `<div>`s will result significant % of image difference. However, I am not interested in the image difference caused by the advertisements. Therefore, I want to ignore those dynamic HTML elements for more accurate image comparison. How can I do it?
You can optionally gray paint the square regions of the selected HTML elements in the screenshot images. I would call it : Censoring (検閲、塗りつぶし). See an example of censored page image as follows:
@Test
void test_censor_on_insensitive_page() throws IOException {
driver.manage().window().setSize(new Dimension(1024, 600));
driver.navigate().to("http://devadmin.kazurayam.com/");
// no censor
File file1 = outputDir.resolve("no_censor.png").toFile();
AShotWrapper.saveEntirePageImage(driver, file1);
// with censor
AShotWrapper.Options options =
new AShotWrapper.Options.Builder()
.addIgnoredElement(
By.xpath("//span[@id='clock']"))
.build();
File file2 = outputDir.resolve("with_censor.png").toFile();
AShotWrapper.saveEntirePageImage(driver, options, file2);
}
original | with censoring |
---|---|
Censoring example
Please find the clock area is painted gray. if you do image comparison of 2 screenshots both of which are censored, the painted area would be the same. It would no longer cause any significant image difference.