Selenium webdriver C# - Taking full page screenshot
Asked Answered
P

10

7

Can anyone help me to take a full page screenshot using Selenium webdriver. I am using c#/Nunit. The current method i am using is not taking the full browser page.

I am using the code below to take the screenshot.

public void TakeScreenShot(IWebDriver webDriver,string testName,string className)
{          

string folderName = String.Format("{0}.{1}", className, testName);

// Create Screenshot folder
string createdFolderLocation = CreateFolder(folderName);

// Take the screenshot            
Screenshot ss = ((ITakesScreenshot)webDriver).GetScreenshot();            
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;

// Save the screenshot
ss.SaveAsFile((string.Format("{0}\\{1}",createdFolderLocation,testName + ".Jpeg")), System.Drawing.Imaging.ImageFormat.Jpeg);
ss.ToString();

}
Pelmas answered 9/5, 2012 at 5:28 Comment(6)
Post the code you are currently using.Rhachis
What do you consider to be the full browser page?Maddocks
What exactly is the issue? Your code looks fine.Rhachis
Thanks for the reply. I am not able to see the URL and the other top section of the browser. I was able to take the entire page using the Selenium RC earlier.Pelmas
What do you need the URL bar etc for?Rhachis
In our application the URL's provides some valuable information to diagnose the test failures. So, it would be great if my screenshot contains that information too.Pelmas
S
6

You can use this package https://www.nuget.org/packages/Noksa.WebDriver.ScreenshotsExtensions/

In order to take a screenshot of the entire page, use the VerticalCombineDecorator:

var vcs = new VerticalCombineDecorator(new ScreenshotMaker());
var screen = _driver.TakeScreenshot(vcs);
Serval answered 22/10, 2018 at 7:27 Comment(1)
I started using it recently and I liked it, but it seems to have memory issues sometimes and its getting hung while generating HTML reportsCottager
A
4

"Full-page" screenshots are defined by WebDriver to include the entirety of the page displayed in the browser, not the browser chrome (URL bar, toolbar, window resizing handles, and so on). If you don't care about getting the full DOM in your screenshot, you don't need to use WebDriver to get your screenshot. You can use the API of your operating system to handle that instead.

Actino answered 15/5, 2012 at 20:1 Comment(1)
Thank you all for the answers.Pelmas
T
2

This one I used in our solution:

 public byte[] TakeScreenshot()
    {
      try
      {
        var getMaxSide = "return Math.max(document.body.scroll{0}, document.body.offset{0}, document.documentElement.client{0}, document.documentElement.scroll{0}, document.documentElement.offset{0})";
        var scrollHeight = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Height"));
        var scrollWidth = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Width"));
        Driver.Manage().Window.Size = new Size(int.Parse(scrollWidth.ToString()), int.Parse(scrollHeight.ToString()));
        return (Driver as ITakesScreenshot).GetScreenshot().AsByteArray;
      }
      catch
      {
        return Array.Empty<byte>();
      }
    }

Then you can use the result to attach it to e.g. Allure or NUnit test results:

 private void AttachScreenshot()
    {
      var screenshot = _browser?.TakeScreenshot();
      if (screenshot.Length > 0)
      {
        // add screenshot to test results
        var path = DateTime.Now.Ticks.ToString() + ".png";
        File.WriteAllBytes(path, screenshot);
        TestContext.AddTestAttachment(path, "screenshot");

        // attach screenshot to Allure report
        AllureLifecycle.Instance.AddAttachment("screenshot", "image/png", screenshot);
      }
    }
Twayblade answered 4/9, 2020 at 6:59 Comment(0)
M
1

Try changing the size of the browser window to something huge before taking your screen shot. I have the size to 10 less than the width, and 10 less than the height. Try adding rather than subtracting.

    driver = new FirefoxDriver(firefoxProfile);

    if (Config.MAXIMIZE_BROWSER_WINDOW)
    {
        driver.Manage().Window.Size = new System.Drawing.Size(System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - 10, System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - 10);
    }
Mascagni answered 12/5, 2012 at 0:57 Comment(0)
B
1

you may try this

IWebDriver driver = new PhantomJSDriver();
driver.Navigate().GoToUrl("http://www.google.com");
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile("image.png", ImageFormat.Png);
Balakirev answered 19/10, 2015 at 11:7 Comment(2)
this is for taking a screenshot using selenium webdriver with phantomjs. If you wish to use firefox or chrome. you may just change PhantomJSDriver() to the driver which you wish to use.Balakirev
@Salih I was able to get a screenshot capture to work with the ((ITakesScreenshot)driver).GetScreenshot().SaveAsFile(); approach, thank you for sharing that!Alcaide
S
1

Greetings from 2017))!

If the page size is larger than the screen size - you can use the PhantomJS driver (PhantomJS download page)

var fileName = "test.png";
var size = new Size(800, 2000);
var url = "https://stackoverflow.com/";

using (var driver = new PhantomJSDriver())
{
    driver.Manage().Window.Size = size;
    driver.Navigate().GoToUrl(url);
    ((ITakesScreenshot)driver)
        .GetScreenshot()
        .SaveAsFile(fileName, ImageFormat.Png);

    driver.Close();
}
Skinhead answered 1/12, 2017 at 16:25 Comment(0)
G
0

I remeber that ((ITakesScreenshot)webDriver).GetScreenshot(); takes full page screenshot but if you have some ajax request and other loading elements you can add scrolling and at the end to wait some seconds, after that you will know that it took full loaded page screenshot.

        for (int second = 0;; second++)
        {
            if (second >= 4)
            {
                break;
            }

            ((IJavaScriptExecutor)Global.Driver).ExecuteScript("window.scrollBy(0,800)", string.Empty);
            Thread.Sleep(500);
        }

        Thread.Sleep(3000);
Geller answered 17/5, 2013 at 13:54 Comment(0)
U
0

Try this hope it will work fine for u.

public void TakeScreenshot(string SSName)
        {
            try
            {
                string path = "D:\\WorkSpace\\Screenshot\\";
                Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
                ss.SaveAsFile((path + SSName), System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }
Urethrectomy answered 1/4, 2015 at 21:17 Comment(0)
F
0

Changing browser height doesn't always work. This is the solution I used. It scrolls through the page and composes the full-page screenshot.

public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
    {
        Bitmap fullPageScreenshot = null;
        using (var fullMs = new MemoryStream((driver.GetScreenshot()).AsByteArray)) { 
            fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
        }
        var originalPageOffset = driver.GetPageOffset();

        var prevPageOffset = 0;
        var currentPageOffset = 0;
        var scrollLength = (int)(driver.Manage().Window.Size.Height / 1.5);
        while (fullPageScreenshot.Height < maxHeight)
        {
            prevPageOffset = driver.GetPageOffset().Y;
                       
            driver.ScrollPageBy(0, scrollLength);
            System.Threading.Thread.Sleep(500);

            currentPageOffset = driver.GetPageOffset().Y;

            if (prevPageOffset == currentPageOffset)
            {
                break;
            }
            var pageMovedBy = currentPageOffset - prevPageOffset;
            using (var ms = new MemoryStream(driver.GetScreenshot().AsByteArray))
            {
                using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                {
                    var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
                    var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
                    fullPageScreenshot.Dispose();
                    fullPageScreenshot = newFullPage;
                }
            }
        }
        driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
        return fullPageScreenshot;
    }

    public static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
    {
        Bitmap nb = new Bitmap(r.Width, r.Height);
        using (Graphics g = Graphics.FromImage(nb))
        {
            g.DrawImage(b, -r.X, -r.Y);
            return nb;
        }
    }

    public static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
    {
        int w = Math.Max(source.Width, target.Width);
        int h = source.Height + target.Height + spacing;
        Bitmap bmp = new Bitmap(w, h);

        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(source, 0, 0);
            g.DrawImage(target, 0, source.Height + spacing);
        }

        return bmp;
    }

    public static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
    }

    public static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
    }

    public static Point GetPageOffset(this RemoteWebDriver driver)
    {
        var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
        var x = (long)offsetArray[0];
        var y = (long)offsetArray[1];
        return new Point((int)x, (int)y);
    }
Falsehood answered 23/2, 2021 at 15:4 Comment(0)
D
0

based on the answer from @Michal Kalous I created an etension class. This also takes into account the font size currently set in widows and the real viewport size and removes the vertical scrollbar by setting body.style.overflowY to hidden.

Usage

RemoteWebDriver driver = new EdgeDriver();
driver.SetViewportSize(1200, 1200);

driver.Navigate().GoToUrl("https://www.bikereview.info/en/ktm-1290-super-duke-rr-innerhalb-von-48-minuten-ausverkauft.html");
Image tempImage = driver.TakeFullPageScreenshot();
tempImage.Save(@"c:\full.png", ImageFormat.Png);
driver.Close();
driver.Quit();

Extension-Class

using System;
using System.Drawing;
using System.IO;
using OpenQA.Selenium.Remote;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using OpenQA.Selenium;

namespace TestRenderHtmlToPng
{


    public static class RemoteWebDriverExtensions
    {

        public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
        {

            //Screenshots depend on fontscaleing-property in windows
            double DpiScalingFactor = GetDpiScalingFactor();

            Bitmap fullPageScreenshot = null;
            using (var fullMs = new MemoryStream((driver.GetScreenshotOverflowHidden()).AsByteArray))
            {
                fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
            }
            var originalPageOffset = driver.GetPageOffset();

            var prevPageOffset = 0;
            var currentPageOffset = 0;
            var scrollLength = driver.GetWindowInnerHeight();

            while (fullPageScreenshot.Height < maxHeight)
            {
                prevPageOffset = driver.GetPageOffset().Y;

                driver.ScrollPageBy(0, scrollLength);
                System.Threading.Thread.Sleep(100);

                currentPageOffset = driver.GetPageOffset().Y;

                if (prevPageOffset == currentPageOffset)
                {
                    break;
                }
                var pageMovedBy = currentPageOffset - prevPageOffset;
                pageMovedBy = (int)(pageMovedBy * DpiScalingFactor);

                using (var ms = new MemoryStream(driver.GetScreenshotOverflowHidden().AsByteArray))
                {
                    Bitmap fullPageScreenshot1 = Image.FromStream(ms) as Bitmap;
                    using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                    {
                        var s = driver.Manage().Window.Size;

                        var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));

                        var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);

                        fullPageScreenshot.Dispose();
                        fullPageScreenshot = newFullPage;
                    }
                }
            }
            driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
            return fullPageScreenshot;
        }



        private static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
        {
            Bitmap nb = new Bitmap(r.Width, r.Height);
            using (Graphics g = Graphics.FromImage(nb))
            {
                g.DrawImage(b, -r.X, -r.Y);
                return nb;
            }
        }

        private static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
        {
            int w = Math.Max(source.Width, target.Width);
            int h = source.Height + target.Height + spacing;
            Bitmap bmp = new Bitmap(w, h);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.DrawImage(source, 0, 0);
                g.DrawImage(target, 0, source.Height + spacing);
            }

            return bmp;
        }

        private static Screenshot GetScreenshotOverflowHidden(this RemoteWebDriver driver)
        {
            driver.ExecuteScript(@" document.body.style.overflowY = ""hidden"";");
            var s = driver.GetScreenshot();
            driver.ExecuteScript(@" document.body.style.overflowY = """";");
            return s;
        }

        private static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
        }
        private static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
        }

        public static void SetViewportSize(this RemoteWebDriver driver, int width, int height)
        {
            var jsGetPadding = @"return [ window.outerWidth - window.innerWidth,window.outerHeight - window.innerHeight ];";
            var paddingArray = driver.ExecuteScript(jsGetPadding) as ReadOnlyCollection<object>;
            driver.Manage().Window.Size = new Size(width + int.Parse(paddingArray[0].ToString()), height + int.Parse(paddingArray[1].ToString()));

        }

        private static Point GetPageOffset(this RemoteWebDriver driver)
        {
            var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
            var x = int.Parse(offsetArray[0].ToString());
            var y = int.Parse(offsetArray[1].ToString().Split(',')[0]);
            return new Point((int)x, (int)y);
        }
        private static int GetWindowInnerHeight(this RemoteWebDriver driver)
        {
            var Value = driver.ExecuteScript(@"return [window.innerHeight];") as ReadOnlyCollection<object>;
            return int.Parse(Value[0].ToString());

        }

        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
        public enum DeviceCap
        {
            VERTRES = 10,
            DESKTOPVERTRES = 117,

            // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
            // https://mcmap.net/q/237469/-how-to-get-windows-display-settings#answer-21450169
        }


        private static float GetDpiScalingFactor()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
            int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
            int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);

            float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;

            return ScreenScalingFactor; // 1.25 = 125%
        }

    }
}
Daugavpils answered 12/4, 2021 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.