Jonathan Kittell
Jonathan Kittell

Reputation: 7493

How to capture entire page screenshot with Selenium and C#

I am using the following method to take screenshots and noticed that all of the screenshot images are not capturing the full window but instead cropping the window. For example I will get a .jpg where I cannot see the entire webpage that is visible on the screen. I suspect that this happens when certain elements are not visible in the DOM and therefore not included in the screenshot. Is this expected behavior? If this is expected, is there a way to program the driver to take a full screen capture with the Selenium 32 bit Internet Explorer Driver consistently? Here is the method I am calling to take the screenshots.

public static void TakeScreenshot(IWebDriver driver, string saveLocation)
{
    ITakesScreenshot ssdriver = driver as ITakesScreenshot;
    Screenshot screenshot = ssdriver.GetScreenshot();
    screenshot.SaveAsFile(saveLocation, ImageFormat.png);
}

Upvotes: 1

Views: 8678

Answers (3)

Xin Wang
Xin Wang

Reputation: 29

the resolution:

  1. Detect if the web page can be display on current browser
    1. If current window screenshot is enough then use screenshot of current browser window
    2. If the current page include scroll bar, then take screen shot of each window by scroll the page accordingly, and cut the screenshot to combine all screenshot together

Put code for whole page screenshot:

using System.Linq;
using System.Threading;
using OpenQA.Selenium;
using DotRez.Utilities.WebDriver;
using System.Drawing;
using System.Drawing.Imaging;
// decide take full screenshot and take current window screenshot according to the height 
public static void TakeSnapshot()
        {

            IJavaScriptExecutor js = Driver as IJavaScriptExecutor;
            var fileName = ScenarioContext.Current.ScenarioInfo.Title.ToIdentifier() + DateTime.Now.ToString("HH_mm_ss") + "JS" + ".png";
            var fileLocation = Path.Combine(Configuration.SCREEN_SHOT_LOCATION, fileName);
            Image finalImage;
            // get the full page height and current browser height
            string getCurrentBrowserSizeJS =
                @"

                window.browserHeight = (window.innerHeight || document.body.clientHeight);
                window.headerHeight= document.getElementById('site-header').clientHeight;;
                window.fullPageHeight = document.body.scrollHeight;
            ";
            js.ExecuteScript(getCurrentBrowserSizeJS);


            // * This is async operation. So we have to wait until it is done.
            string getSizeHeightJS = @"return window.browserHeight;";
            int contentHeight = 0;
            while (contentHeight == 0)
            {
                contentHeight = Convert.ToInt32(js.ExecuteScript(getSizeHeightJS));
                if (contentHeight == 0) System.Threading.Thread.Sleep(10);
            }

            string getContentHeightJS = @"return window.headerHeight;";
            int siteHeaderHeight = 0;
            while (siteHeaderHeight == 0)
            {
                siteHeaderHeight = Convert.ToInt32(js.ExecuteScript(getContentHeightJS));
                if (siteHeaderHeight == 0) System.Threading.Thread.Sleep(10);
            }

            string getFullPageHeightJS = @"return window.fullPageHeight";
            int fullPageHeight = 0;
            while (fullPageHeight == 0)
            {
                fullPageHeight = Convert.ToInt32(js.ExecuteScript(getFullPageHeightJS));
                if (fullPageHeight == 0) System.Threading.Thread.Sleep(10);
            }

            if (contentHeight == fullPageHeight)
            {
                TakeSnapshotCurrentPage();

            }
            else
            {
                int scollEachHeight = contentHeight - siteHeaderHeight;
                int shadowAndBorder = 3;
                int scollCount = 0;
                int existsIf = (fullPageHeight - siteHeaderHeight) % scollEachHeight;
                bool cutIf = true;

                if (existsIf == 0)
                {
                    scollCount = (fullPageHeight - siteHeaderHeight) / scollEachHeight;
                    cutIf = false;
                }
                else
                {
                    scollCount = (fullPageHeight - siteHeaderHeight) / scollEachHeight + 1;
                    cutIf = true;
                }


                // back to top start screenshot
                string scollToTopJS = "window.scrollTo(0, 0)";
                js.ExecuteScript(scollToTopJS);

                Byte[] imageBaseContent = ((ITakesScreenshot)Driver).GetScreenshot().AsByteArray;
                Image imageBase;
                using (var ms = new MemoryStream(imageBaseContent))
                {
                    imageBase = Image.FromStream(ms);
                }

                finalImage = imageBase;

                string scrollBar = @"window.scrollBy(0, window.browserHeight-window.headerHeight);";
                for (int count = 1; count < scollCount; count++)
                {

                    js.ExecuteScript(scrollBar);
                    Thread.Sleep(500);
                    Byte[] imageContentAdd = ((ITakesScreenshot)Driver).GetScreenshot().AsByteArray;
                    Image imageAdd;
                    using (var msAdd = new MemoryStream(imageContentAdd))
                    {
                        imageAdd = Image.FromStream(msAdd);
                    }

                    imageAdd.Save(fileLocation, ImageFormat.Png);
                    Bitmap source = new Bitmap(imageAdd);
                    int a = imageAdd.Width;
                    int b = imageAdd.Height - siteHeaderHeight;
                    PixelFormat c = source.PixelFormat;


                    // cut the last screen shot if last screesshot override with sencond last one
                    if ((count == (scollCount - 1)) && cutIf)
                    {

                        Bitmap imageAddLastCut =
                            source.Clone(new System.Drawing.Rectangle(0, contentHeight - existsIf, imageAdd.Width, existsIf), source.PixelFormat);

                        finalImage = combineImages(finalImage, imageAddLastCut);

                        source.Dispose();
                        imageAddLastCut.Dispose();
                    }
                    //cut the site header from screenshot
                    else
                    {
                        Bitmap imageAddCutHeader =
                            source.Clone(new System.Drawing.Rectangle(0, (siteHeaderHeight + shadowAndBorder), imageAdd.Width, (imageAdd.Height - siteHeaderHeight - shadowAndBorder)), source.PixelFormat);
                        finalImage = combineImages(finalImage, imageAddCutHeader);

                        source.Dispose();
                        imageAddCutHeader.Dispose();
                    }

                    imageAdd.Dispose();

                }

                finalImage.Save(fileLocation, ImageFormat.Png);
                imageBase.Dispose();
                finalImage.Dispose();

            }
        }

//combine two pictures
        public static Bitmap combineImages(Image image1, Image image2)
        {
            Bitmap bitmap = new Bitmap(image1.Width, image1.Height + image2.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.DrawImage(image1, 0, 0);
                g.DrawImage(image2, 0, image1.Height);
            }

            return bitmap;
        }

// take current window screenshot  
      private static void TakeSnapshotCurrentPage()
        {
            try
            {
                var screenshot = ((ITakesScreenshot)Driver).GetScreenshot();
                var urlStr = Driver.Url;
                var fileName = ScenarioContext.Current.ScenarioInfo.Title.ToIdentifier() + DateTime.Now.ToString("HH_mm_ss") + ".png";
                var fileLocation = Path.Combine(Configuration.SCREEN_SHOT_LOCATION, fileName);

                if (!Directory.Exists(Configuration.SCREEN_SHOT_LOCATION))
                {
                    Directory.CreateDirectory(Configuration.SCREEN_SHOT_LOCATION);
                }

                screenshot.SaveAsFile(fileLocation, ScreenshotImageFormat.Png);
                Console.WriteLine(urlStr);
                Console.WriteLine("SCREENSHOT[{0}]SCREENSHOT", Path.Combine("Screenshots", fileName));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

Upvotes: 2

Bret
Bret

Reputation: 2291

Indeed, Richard's answer will work to take a screenshot of the entire current desktop area - if that is what you are after, it will work. If you are actually after having a specific application (e.g. Internet Explorer) that is not 'maximized' while using Selenium, then you might need to take a different approach. Consider forcing the application to be maximized and maybe even have it get focus before taking the screenshot using Richard's method above - or use the Selenium's ITakesScreenshot interface ...

In order to use the System.Windows.Forms namespace in a Console application, you will need to "Add Reference..." to the project. In the Solution Explorer, right-click on "References" and select "Add Reference..."; scroll to System.Windows.Forms, check it and click Okay. After doing that, you will be able to type "using System.Windows.Forms;" at the top of your class file.

Upvotes: 2

Richard
Richard

Reputation: 9019

This is what I use for capturing the entire screen:

Rectangle bounds = Screen.GetBounds(Point.Empty);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }
    bitmap.Save(saveLocation, System.Drawing.Imaging.ImageFormat.Png);
}

Upvotes: 2

Related Questions