Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.shaft.gui.internal.image.ScreenshotManager Maven / Gradle / Ivy
Go to download
SHAFT is a unified test automation engine. Powered by best-in-class frameworks, SHAFT provides a
wizard-like syntax to drive your automation efficiently, maximize your ROI, and minimize your learning curve.
Stop reinventing the wheel. Upgrade now!
package com.shaft.gui.internal.image;
import com.epam.healenium.SelfHealingDriver;
import com.shaft.cli.FileActions;
import com.shaft.driver.SHAFT;
import com.shaft.driver.internal.DriverFactoryHelper;
import com.shaft.enums.internal.Screenshots;
import com.shaft.gui.browser.internal.JavaScriptWaitManager;
import com.shaft.gui.element.internal.ElementActionsHelper;
import com.shaft.gui.element.internal.ElementInformation;
import com.shaft.properties.internal.Properties;
import com.shaft.tools.io.ReportManager;
import com.shaft.tools.io.internal.ReportManagerHelper;
import org.imgscalr.Scalr;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.*;
import org.openqa.selenium.support.locators.RelativeLocator;
import org.sikuli.script.App;
import org.sikuli.script.Pattern;
import org.sikuli.script.Screen;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.nio.file.FileSystems;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
public class ScreenshotManager {
private static final String SCREENSHOT_FOLDER_PATH = SHAFT.Properties.paths.allureResults() + "/screenshots/";
private static final String SCREENSHOT_FOLDER_NAME = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date());
private static final String SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT = SHAFT.Properties.visuals.screenshotParamsWhenToTakeAScreenshot();
private static final Boolean SCREENSHOT_PARAMS_HIGHLIGHT_ELEMENTS = SHAFT.Properties.visuals.screenshotParamsHighlightElements();
private static final String SCREENSHOT_PARAMS_SKIPPED_ELEMENTS_FROM_SCREENSHOT = SHAFT.Properties.visuals.screenshotParamsSkippedElementsFromScreenshot();
private static final Float SCREENSHOT_PARAMS_WATERMARK_OPACITY = SHAFT.Properties.visuals.screenshotParamsWatermarkOpacity();
private static final Boolean SCREENSHOT_PARAMS_WATERMARK = SHAFT.Properties.visuals.screenshotParamsWatermark();
private static final int RETRIES_BEFORE_THROWING_ELEMENT_NOT_FOUND_EXCEPTION = 1;
private static final Boolean CREATE_GIF = SHAFT.Properties.visuals.createAnimatedGif();
private static Screenshots SCREENSHOT_PARAMS_SCREENSHOT_TYPE = setScreenshotType();
private static final int GIF_FRAME_DELAY = SHAFT.Properties.visuals.animatedGifFrameDelay();
private static String SCREENSHOT_PARAMS_HIGHLIGHT_METHOD = SHAFT.Properties.visuals.screenshotParamsHighlightMethod();
private static Screenshots setScreenshotType() {
switch (SHAFT.Properties.visuals.screenshotParamsScreenshotType().toLowerCase()) {
case "element" -> {
return Screenshots.ELEMENT;
}
case "regular" -> {
return Screenshots.VIEWPORT;
}
case "fullpage" -> {
return Screenshots.FULL;
}
default -> {
return null;
}
}
}
private static final int GIF_SIZE = 1280;
// TODO: parameterize the detailed gif value
private static final Boolean DETAILED_GIF = true;
private static final String DETAILED_GIF_REGEX = "(verify.*)|(assert.*)|(click.*)|(tap.*)|(key.*)|(navigate.*)";
private static String AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH = "";
private static String screenshotFileName = "Screenshot";
private static By targetElementLocator;
private static boolean globalPassFailStatus = false;
private static String globalPassFailAppendedText = "";
private static String testCaseName = "";
private static String gifRelativePathWithFileName = "";
private static ThreadLocal gifOutputStream = new ThreadLocal<>();
private static ThreadLocal gifWriter = new ThreadLocal<>();
private ScreenshotManager() {
throw new IllegalStateException("Utility class");
}
public static String getAiAidedElementIdentificationFolderPath() {
if (AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH.isEmpty()) {
// fixes https://github.com/ShaftHQ/SHAFT_ENGINE/issues/808 by respecting OS/Platform information for mobile native
AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH = Properties.paths.dynamicObjectRepository()
+ Properties.platform.targetPlatform() + "/";
if (DriverFactoryHelper.isMobileNativeExecution()) {
if (!Properties.mobile.platformVersion().isEmpty()) {
AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH += Properties.mobile.platformVersion() + "/";
}
} else {
//mobile web, or desktop web
AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH += Properties.web.targetBrowserName() + "/";
}
return AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH.replace(".", "_").replace(" ", "_");
} else {
return AI_AIDED_ELEMENT_IDENTIFICATION_FOLDER_PATH;
}
}
/**
* Used if there is no element locator. passFailStatus; true means pass and
* false means fail.
*
* @param driver the current instance of Selenium WebDriver
* @param actionName the name of the triggering action
* @param passFailStatus A flag to determine whether the action has passed or
* failed
* @return a screenshot object
*/
public static List captureScreenShot(WebDriver driver, String actionName, boolean passFailStatus) {
globalPassFailStatus = passFailStatus;
if (passFailStatus) {
globalPassFailAppendedText = "passed";
} else {
globalPassFailAppendedText = "failed";
}
return internalCaptureScreenShot(driver, null, actionName, globalPassFailAppendedText,
takeScreenshot(actionName, passFailStatus));
}
/**
* Used if there is an element locator. passFailStatus; true means pass and
* false means fail.
*
* @param driver the current instance of Selenium WebDriver
* @param elementLocator the locator of the webElement under test (By xpath, id,
* selector, name ...etc)
* @param actionName the name of the triggering action
* @param passFailStatus A flag to determine whether the action has passed or
* failed
* @return a screenshot object
*/
public static List captureScreenShot(WebDriver driver, By elementLocator, String actionName,
boolean passFailStatus) {
globalPassFailStatus = passFailStatus;
targetElementLocator = elementLocator;
if (passFailStatus) {
globalPassFailAppendedText = "passed";
} else {
globalPassFailAppendedText = "failed";
}
return internalCaptureScreenShot(driver, targetElementLocator, actionName, globalPassFailAppendedText,
takeScreenshot(actionName, passFailStatus));
}
private static boolean takeScreenshot(String actionName, boolean passFailStatus) {
return (SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT.equals("Always"))
|| (SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT.equals("ValidationPointsOnly")
&& (actionName.toLowerCase().contains("assert")
|| actionName.toLowerCase().contains("verify")
|| actionName.toLowerCase().contains("validate")))
|| (SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT.equals("FailuresOnly") && (!passFailStatus))
|| (!passFailStatus);
// take screenshot if set to always,
//OR if set to validation points only and actionName contains verify or assert
//OR if set to failures only and the test failed
}
public static List captureScreenShotUsingSikuliX(Screen screen, App applicationWindow, Pattern element, String actionName,
boolean passFailStatus) {
globalPassFailStatus = passFailStatus;
if (passFailStatus) {
globalPassFailAppendedText = "passed";
} else {
globalPassFailAppendedText = "failed";
}
boolean takeScreenshot = "Always".equals(SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT)
|| ("ValidationPointsOnly".equals(SCREENSHOT_PARAMS_WHEN_TO_TAKE_A_SCREENSHOT)
&& (actionName.toLowerCase().contains("assert")
|| actionName.toLowerCase().contains("verify")))
|| !passFailStatus;
if (takeScreenshot || (CREATE_GIF && (DETAILED_GIF || actionName.matches(DETAILED_GIF_REGEX)))) {
/*
* Force screenshot link to be shown in the results as a link not text
*/
System.setProperty("org.uncommons.reportng.escape-output", "false");
/*
* Take the screenshot and store it as a file
*/
byte[] src = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
switch (SCREENSHOT_PARAMS_SCREENSHOT_TYPE) {
case ELEMENT:
if (element != null) {
try {
ImageIO.write(screen.capture(screen.wait(element).getRect()).getImage(), "png", byteArrayOutputStream);
src = byteArrayOutputStream.toByteArray();
break;
} catch (org.sikuli.script.FindFailed e) {
//do nothing and fall into the next type of screenshot
}
}
case VIEWPORT:
if (applicationWindow != null) {
ImageIO.write(screen.capture(applicationWindow.waitForWindow()).getImage(), "png", byteArrayOutputStream);
src = byteArrayOutputStream.toByteArray();
break;
}
case FULL:
ImageIO.write(screen.capture().getImage(), "png", byteArrayOutputStream);
src = byteArrayOutputStream.toByteArray();
break;
default:
break;
}
} catch (IOException e) {
ReportManager.logDiscrete("Failed to create attachment.");
ReportManagerHelper.logDiscrete(e);
}
startOrAppendToAnimatedGif(src);
if (takeScreenshot) {
return prepareImageForReport(src, actionName);
} else {
return null;
}
}
return null;
}
public static byte[] takeViewportScreenshot(WebDriver driver) {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
public static byte[] takeFullPageScreenshot(WebDriver driver) {
try {
if (!SHAFT.Properties.testNG.parallel().equals("NONE")) {
//in case of parallel execution, force regular screenshots
return takeViewportScreenshot(driver);
} else if (SCREENSHOT_PARAMS_SKIPPED_ELEMENTS_FROM_SCREENSHOT.length() > 0) {
List skippedElementsList = new ArrayList<>();
String[] skippedElementLocators = SCREENSHOT_PARAMS_SKIPPED_ELEMENTS_FROM_SCREENSHOT.split(";");
for (String locator : skippedElementLocators) {
if (ElementActionsHelper.getElementsCount(driver, By.xpath(locator),
RETRIES_BEFORE_THROWING_ELEMENT_NOT_FOUND_EXCEPTION) == 1) {
skippedElementsList.add(((WebElement) ElementActionsHelper.identifyUniqueElementIgnoringVisibility(driver, By.xpath(locator)).get(1)));
}
}
WebElement[] skippedElementsArray = new WebElement[skippedElementsList.size()];
skippedElementsArray = skippedElementsList.toArray(skippedElementsArray);
return ScreenshotHelper.makeFullScreenshot(driver, skippedElementsArray);
} else {
return ScreenshotHelper.makeFullScreenshot(driver);
}
} catch (Exception e) {
ReportManagerHelper.logDiscrete(e);
return ScreenshotManager.takeViewportScreenshot(driver);
}
}
public static byte[] takeElementScreenshot(WebDriver driver, By targetElementLocator) {
return takeElementScreenshot(driver, targetElementLocator, false);
}
public static String attachAnimatedGif() {
// stop and attach
if (Boolean.TRUE.equals(CREATE_GIF) && !"".equals(gifRelativePathWithFileName)) {
try {
ReportManagerHelper.attach("Animated Gif", testCaseName, new FileInputStream(gifRelativePathWithFileName));
if (!gifWriter.equals(new ThreadLocal<>())) {
gifWriter.get().close();
}
if (!gifOutputStream.equals(new ThreadLocal<>())) {
gifOutputStream.get().close();
}
gifOutputStream = new ThreadLocal<>();
gifWriter = new ThreadLocal<>();
String gifRelativePath = gifRelativePathWithFileName;
gifRelativePathWithFileName = "";
return gifRelativePath;
} catch (FileNotFoundException e) {
// this happens when the gif fails to start, maybe the browser window was
// already closed
} catch (IOException | NullPointerException | IllegalStateException e) {
ReportManagerHelper.logDiscrete(e);
}
}
return "";
}
/**
* Internal use only. Considers the screenshotParams_whenToTakeAScreenshot
* parameter.
*
* @param driver the current instance of Selenium WebDriver
* @param elementLocator the locator of the webElement under test (By xpath, id,
* selector, name ...etc)
* @param appendedText the text that needs to be appended to the name of the
* screenshot to make it more recognizable
* @param takeScreenshot determines whether to take a screenshot given
* the screenshotParams_whenToTakeAScreenshot parameter
* from the pom.xml file
* @return screenshot list object
*/
private static List internalCaptureScreenShot(WebDriver driver, By elementLocator,
String actionName, String appendedText, boolean takeScreenshot) {
// if (!actionName.toLowerCase().contains("get")) {
// Suggested: add to animated gif only in case of click, navigation, or validation actions.
if (takeScreenshot || (CREATE_GIF && (DETAILED_GIF || actionName.matches(DETAILED_GIF_REGEX)))) {
/*
* Force screenshot link to be shown in the results as a link not text
*/
System.setProperty("org.uncommons.reportng.escape-output", "false");
/*
* Declare regularElementStyle, the WebElement, and Javascript Executor to
* highlight and unhighlight the WebElement
*/
String regularElementStyle = "";
JavascriptExecutor js = null;
WebElement element = null;
Rectangle elementLocation = null;
/*
* If an elementLocator was passed, store regularElementStyle and highlight that
* element before taking the screenshot
*/
if (takeScreenshot && Boolean.TRUE.equals(SCREENSHOT_PARAMS_HIGHLIGHT_ELEMENTS) && elementLocator != null) {
try {
// catching https://github.com/ShaftHQ/SHAFT_ENGINE/issues/640
@SuppressWarnings("unused") Mat img = Imgcodecs.imdecode(new MatOfByte(), Imgcodecs.IMREAD_COLOR);
} catch (java.lang.UnsatisfiedLinkError unsatisfiedLinkError) {
ReportManagerHelper.logDiscrete(unsatisfiedLinkError);
ReportManager.logDiscrete("Caught an UnsatisfiedLinkError, switching element highlighting method to JavaScript instead of AI.");
SCREENSHOT_PARAMS_HIGHLIGHT_METHOD = "JavaScript";
} catch (Exception exception) {
//do nothing in case of any other exception
//expected to throw org.opencv.core.CvException if removed
}
int elementCount = ElementActionsHelper.getElementsCount(driver, elementLocator, RETRIES_BEFORE_THROWING_ELEMENT_NOT_FOUND_EXCEPTION);
boolean isRelativeLocator = elementLocator instanceof RelativeLocator.RelativeBy;
if ((!isRelativeLocator && elementCount == 1) || (isRelativeLocator && elementCount >= 1)) {
if ("JavaScript".equals(SCREENSHOT_PARAMS_HIGHLIGHT_METHOD)) {
element = ((WebElement) ElementActionsHelper.identifyUniqueElementIgnoringVisibility(driver, elementLocator).get(1));
js = (JavascriptExecutor) driver;
regularElementStyle = highlightElementAndReturnDefaultStyle(element, js,
setHighlightedElementStyle());
} else {
// default to using AI
elementLocation = ElementInformation.fromList(ElementActionsHelper.identifyUniqueElementIgnoringVisibility(driver, elementLocator)).getElementRect();
}
}
}
/*
* Take the screenshot and store it as a file
*/
byte[] src;
/*
* Attempt to take a full page screenshot, take a regular screenshot upon
* failure
*/
try {
src = takeScreenshot(driver);
/*
* Declare screenshot file name
*/
testCaseName = ReportManagerHelper.getTestMethodName();
screenshotFileName = System.currentTimeMillis() + "_" + testCaseName + "_" + actionName;
if (!"".equals(appendedText)) {
screenshotFileName = screenshotFileName + "_" + appendedText;
}
/*
* If an elementLocator was passed, unhighlight that element after taking the
* screenshot
*
*/
if (takeScreenshot && SCREENSHOT_PARAMS_HIGHLIGHT_METHOD.equals("JavaScript") && js != null) {
js.executeScript("arguments[0].setAttribute('style', arguments[1]);", element, regularElementStyle);
}
if (takeScreenshot && !SCREENSHOT_PARAMS_HIGHLIGHT_METHOD.equals("JavaScript") && elementLocation != null) {
Color color;
if (globalPassFailStatus) {
color = new Color(67, 176, 42); // selenium-green
} else {
color = new Color(255, 255, 153); // yellow
}
src = ImageProcessingActions.highlightElementInScreenshot(src, elementLocation, color);
}
startOrAppendToAnimatedGif(src);
if (takeScreenshot) {
return prepareImageForReport(src, actionName);
} else {
return new ArrayList<>();
}
} catch (WebDriverException e) {
// this happens when a browser session crashes mid-execution, or the docker is
// unregistered
ReportManagerHelper.logDiscrete(e);
}
}
// }
return new ArrayList<>();
}
private static byte[] takeScreenshot(WebDriver driver) {
if (driver instanceof SelfHealingDriver selfHealingDriver) {
driver = selfHealingDriver.getDelegate();
}
if (DriverFactoryHelper.isWebExecution()) {
return switch (SCREENSHOT_PARAMS_SCREENSHOT_TYPE) {
case FULL -> {
try {
yield takeFullPageScreenshot(driver);
} catch (Exception throwable) {
ReportManagerHelper.logDiscrete(throwable);
SCREENSHOT_PARAMS_SCREENSHOT_TYPE = Screenshots.VIEWPORT;
yield takeScreenshot(driver);
}
}
case ELEMENT -> takeElementScreenshot(driver, targetElementLocator, true);
default -> ScreenshotManager.takeViewportScreenshot(driver);
};
}else {
if (SCREENSHOT_PARAMS_SCREENSHOT_TYPE.equals(Screenshots.ELEMENT)) {
return takeElementScreenshot(driver, targetElementLocator, true);
} else {
return ScreenshotManager.takeViewportScreenshot(driver);
}
}
}
private static byte[] takeElementScreenshot(WebDriver driver, By targetElementLocator, Boolean
returnRegularScreenshotInCaseOfFailure) {
try {
if (targetElementLocator != null && ElementActionsHelper.getElementsCount(driver, targetElementLocator,
RETRIES_BEFORE_THROWING_ELEMENT_NOT_FOUND_EXCEPTION) == 1) {
return ((WebElement) ElementActionsHelper.identifyUniqueElementIgnoringVisibility(driver, targetElementLocator).get(1)).getScreenshotAs(OutputType.BYTES);
} else {
if (returnRegularScreenshotInCaseOfFailure) {
return ScreenshotManager.takeViewportScreenshot(driver);
} else {
return new byte[]{};
}
}
} catch (Exception e) {
ReportManagerHelper.logDiscrete(e);
if (returnRegularScreenshotInCaseOfFailure) {
return ScreenshotManager.takeViewportScreenshot(driver);
} else {
return new byte[]{};
}
}
}
public static String generateAttachmentFileName(String actionName) {
testCaseName = ReportManagerHelper.getTestMethodName();
var fileName = System.currentTimeMillis() + "_" + testCaseName + "_" + actionName;
if (!"".equals(globalPassFailAppendedText)) {
fileName = fileName + "_" + globalPassFailAppendedText;
}
return fileName;
}
public static List prepareImageForReport(byte[] image, String actionName) {
if (image != null && image.length > 0) {
/*
* Declare screenshot file name
*/
screenshotFileName = generateAttachmentFileName(actionName);
/*
* Adding Screenshot to the Report.
*
*/
try {
// add SHAFT_Engine logo overlay
InputStream in = new ByteArrayInputStream(image);
BufferedImage screenshotImage = ImageIO.read(in);
overlayShaftEngineLogo(screenshotImage);
ByteArrayOutputStream screenshotOutputStream = new ByteArrayOutputStream();
ImageIO.write(screenshotImage, "png", screenshotOutputStream);
return Arrays.asList("Screenshot", screenshotFileName,
new ByteArrayInputStream(screenshotOutputStream.toByteArray()));
} catch (IOException e) {
ReportManagerHelper.logDiscrete(e);
return null;
}
} else{
//empty image byte array
return null;
}
}
private static String highlightElementAndReturnDefaultStyle(WebElement element, JavascriptExecutor js,
String highlightedElementStyle) {
String regularElementStyle = element.getAttribute("style");
if (regularElementStyle != null && !regularElementStyle.equals("")) {
js.executeScript("arguments[0].style.cssText = arguments[1];", element,
regularElementStyle + highlightedElementStyle);
} else {
js.executeScript("arguments[0].setAttribute('style', arguments[1]);", element, highlightedElementStyle);
}
try {
JavaScriptWaitManager.waitForLazyLoading();
} catch (Exception e) {
ReportManagerHelper.logDiscrete(e);
}
return regularElementStyle;
}
private static String setHighlightedElementStyle() {
String background;
String backgroundColor;
if (globalPassFailStatus) {
background = "#46aad2";
backgroundColor = "#A5D2A5";
} else {
background = "#FFFF99";
backgroundColor = "#FFFF99";
}
return "outline-offset:-3px !important; outline:3px solid #808080 !important; background:" + background
+ " !important; background-color:" + backgroundColor
+ " !important; color:#000000 !important; -webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;";
}
private static void startAnimatedGif(byte[] screenshot) {
// TODO: refactor performance to reduce severe drop when enabling this option
if (Boolean.TRUE.equals(CREATE_GIF) && screenshot != null) {
try {
testCaseName = ReportManagerHelper.getTestMethodName();
String gifFileName = FileSystems.getDefault().getSeparator() + System.currentTimeMillis() + "_"
+ testCaseName + ".gif";
gifRelativePathWithFileName = SCREENSHOT_FOLDER_PATH + SCREENSHOT_FOLDER_NAME + gifFileName;
// get the width and height of the current window of the browser
var height = DriverFactoryHelper.getTARGET_WINDOW_SIZE().getHeight();
var width = DriverFactoryHelper.getTARGET_WINDOW_SIZE().getWidth();
// grab the output image type from the first image in the sequence
BufferedImage firstImage = ImageIO.read(new ByteArrayInputStream(screenshot));
//scaling it down
firstImage = Scalr.resize(firstImage, Scalr.Method.BALANCED, GIF_SIZE);
// create a new BufferedOutputStream
FileActions.getInstance().createFile(SCREENSHOT_FOLDER_PATH + SCREENSHOT_FOLDER_NAME, gifFileName);
gifOutputStream.set(new FileImageOutputStream(new File(gifRelativePathWithFileName)));
// create a gif sequence with the type of the first image, 500 milliseconds
// between frames, which loops infinitely
gifWriter.set(
new AnimatedGifManager(gifOutputStream.get(), firstImage.getType(), GIF_FRAME_DELAY));
// draw initial blank image to set the size of the GIF...
BufferedImage initialImage = new BufferedImage(width, height, firstImage.getType());
Graphics2D initialImageGraphics = initialImage.createGraphics();
initialImageGraphics.setBackground(Color.WHITE);
initialImageGraphics.setColor(Color.WHITE);
initialImageGraphics.clearRect(0, 0, width, height);
// write out initialImage to the sequence...
gifWriter.get().writeToSequence(initialImage);
initialImageGraphics.dispose();
// write out first image to the sequence...
gifWriter.get().writeToSequence(overlayShaftEngineLogo(toBufferedImage(firstImage)));
} catch (NullPointerException | NoSuchSessionException e) {
// this happens in case the start animated Gif is triggered in a none-test
// method
// or this happens when the window is already closed
} catch (IOException | WebDriverException e) {
ReportManagerHelper.logDiscrete(e);
}
}
}
private static BufferedImage overlayShaftEngineLogo(BufferedImage screenshot) {
if (Boolean.TRUE.equals(SCREENSHOT_PARAMS_WATERMARK)) {
try {
// create graphics object
Graphics2D screenshotGraphics = screenshot.createGraphics();
screenshotGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
screenshotGraphics.drawImage(screenshot, 0, 0, null);
screenshotGraphics.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, SCREENSHOT_PARAMS_WATERMARK_OPACITY));
BufferedImage shaftLogo;
// read from custom location
String watermarkImagePath = Properties.internal.watermarkImagePath();
shaftLogo = ImageIO.read(new URL(watermarkImagePath));
shaftLogo = toBufferedImage(
shaftLogo.getScaledInstance(screenshot.getWidth() / 8, -1, Image.SCALE_SMOOTH));
screenshotGraphics.drawImage(shaftLogo, screenshot.getWidth() - shaftLogo.getWidth(),
screenshot.getHeight() - shaftLogo.getHeight(), null);
screenshotGraphics.dispose();
} catch (IOException e) {
// do nothing and proceed to return the original screenshot
}
}
return screenshot;
}
private static BufferedImage toBufferedImage(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bufferedImage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bufferedImage;
}
private static void startOrAppendToAnimatedGif(byte[] screenshot) {
// ensure that animatedGif is started, else force start it
if (Boolean.TRUE.equals(CREATE_GIF)) {
if ("".equals(gifRelativePathWithFileName)) {
startAnimatedGif(screenshot);
} else {
appendToAnimatedGif(screenshot);
}
}
}
private static void appendToAnimatedGif(byte[] screenshot) {
try {
BufferedImage image;
if (screenshot != null) {
image = ImageIO.read(new ByteArrayInputStream(screenshot));
//scaling it down
image = Scalr.resize(image, Scalr.Method.BALANCED, GIF_SIZE);
gifWriter.get().writeToSequence(overlayShaftEngineLogo(image));
}
} catch (NoSuchSessionException e) {
// this happens when attempting to append to a non-existing gif, expected
// solution is to recreate the gif
// removed the old solution, the new fix is to ignore this exception, this will
// leave the gif intact and will attach it even after failing to append to it
} catch (WebDriverException | IOException | IllegalStateException | IllegalArgumentException | NullPointerException e) {
ReportManagerHelper.logDiscrete(e);
}
}
}