Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to take screenshot of a web page

What is the best way to take screenshot of a web page? At the moment I just start an selenium instance of firefox and using winapi bring it to the front and make a screenshot. I ask similar question already.

There is two points:

  • Slowness.
  • If any window occurently gets higher than our web browser's window, this window will imprint in our screenshot.

Is there any method to take screenshot more 'programmly'?

Here is some code I use now:

class FirefoxDriverEx : FirefoxDriver
{
    public Process GetFirefoxProcess()
    {
        var fi = typeof(FirefoxBinary).GetField("process", BindingFlags.NonPublic | BindingFlags.Instance);
        return fi.GetValue(this.Binary) as Process;
    }
}

Here is the code illustrating process of taking screenshot itself:

using (FirefoxDriverEx driver = new FirefoxDriverEx())
{
    driver.Navigate().GoToUrl(url);

    var process = driver.GetFirefoxProcess();

    if (process != null)
    {
        var screenCapture = new ScreenCapture();
        Win.SetForegroundWindow(process.MainWindowHandle.ToInt32());
    }
}

Right now, I'm thinking about some manager that will control a queue of windows to take the screenshots from.

Question edit.

I'm not looking for a solution to just get screenshot 'in memory' and return it back to HTTP stream. So any ways to save screenshot and save it to file and then get it from there is very ambiguous for that purpose.

Question edit #2.

I forgot to mention. Needed screenshot should be made as it seen by user. So, screenshot should have browser window and a site inside of web browser window's bounds. I can't find any way to change mode of taking a screenshot in WebDriver of selenium. WebDriver just take screenshot of a page without any browser window.

like image 251
kseen Avatar asked Jul 28 '12 04:07

kseen


1 Answers

I'd recommend getScreenshotAs. It gets even the 'out of view' part of the screen.

Here is some sample code in gr0ovy.

import java.io.IOException
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.text.SimpleDateFormat

import org.openqa.selenium.Capabilities
import org.openqa.selenium.TakesScreenshot
import org.openqa.selenium.WebDriverException
import org.openqa.selenium.remote.CapabilityType
import org.openqa.selenium.remote.DriverCommand
import org.openqa.selenium.remote.RemoteWebDriver
import org.openqa.selenium.OutputType
import org.openqa.selenium.WebDriver



public class Selenium2Screenshot {
private WebDriver driver
private String browserType
private boolean skipScreenshots

public Selenium2Screenshot(WebDriver webDriver, String browserType, boolean skipScreenshots) {
    this.driver = webDriver
    this.browserType = browserType
    this.skipScreenshots = skipScreenshots
}
public void takeScreenshot(String filenameBase) {
    if (!skipScreenshots) {
        Date today
        String formattedDate
        SimpleDateFormat formatter
        Locale currentLocale
        File scrFile
        currentLocale = new Locale("en", "US")
        formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS", currentLocale)
        today = new Date()
        formattedDate = formatter.format(today)
        String filename = getUiAutomationDir() + filenameBase + "_" + browserType + formattedDate + ".png"
        Log.logger.info("Screenshot filename = " + filename)

        try {
            scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE)
            JavaIO.copy(scrFile.getAbsolutePath(), filename)
        } catch (Exception e) {
            Log.logger.error(e.message, e)
        }
    } else {
        Log.logger.info("Skipped Screenshot")
    }
}
private String getUiAutomationDir()
{
    String workingDir = System.getProperty("user.dir")
    Path workingDirPath = Paths.get(workingDir)
    String returnString = workingDirPath.toString() + "\\"
    return returnString
}

}

Edited on 8/1/12:

Get application handle code. I am surely duplicating code that is on stackoverflow several times, but hopefully this is not the exact same code as in other posts :-)

public static IntPtr FindWindowByPartialCaption(String partialCaption)
    {
        var desktop = User32.GetDesktopWindow();
        var children = EnumerateWindows.GetChildWindows(desktop);
        foreach (var intPtr in children)
        {
            var current = GetText(intPtr);
            if (current.Contains(partialCaption))
                return intPtr;
        }
        return IntPtr.Zero;
    }

    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
    public static extern IntPtr GetDesktopWindow();

    [DllImport("user32.dll")]
    public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);

    public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    public static List<IntPtr> GetChildWindows(IntPtr parent)
    {
        return GetChildWindows(parent, false);
    }
    public static List<IntPtr> GetChildWindows(IntPtr parent, bool reverse)
    {
        List<IntPtr> result = new List<IntPtr>();
        GCHandle listHandle = GCHandle.Alloc(result);
        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
        }
        finally
        {
            if (listHandle.IsAllocated)
                listHandle.Free();
        }
        if (reverse)
        {
            List<IntPtr> resultList = result.Reverse<IntPtr>().ToList();
            return resultList;
        } 
        else
            return result;
    }

    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
        GCHandle gch = GCHandle.FromIntPtr(pointer);
        List<IntPtr> list = gch.Target as List<IntPtr>;
        if (list == null)
        {
            throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
        }
        list.Add(handle);
        //  You can modify this to check to see if you want to cancel the operation, then return a null here
        return true;
    }
}

http://www.pinvoke.net/ is also a great resource.

like image 82
chrismead Avatar answered Oct 19 '22 23:10

chrismead