tags:

views:

85

answers:

1

When I'm testing with WatiN, I like to save screenshots. Sometimes I don't really need a picture of the whole browser window though - I just want a picture of the element that I'm testing.

My attempt to save a picture of an element with the code below resulted in a picture of a block box, because elementBounds.Top points to a pixel position way past the bottom of the screen. The elementBounds.Width and .Height values also appear to be about half what they should be.

Is this a WatiN bug, or are these properties in a different unit of measure that I have to convert to pixels somehow?

public static void SaveElementScreenshot
    (WatiN.Core.IE ie, WatiN.Core.Element element, string screenshotPath)
{
    ScrollIntoView(ie, element);
    ie.BringToFront();

    var ieClass = (InternetExplorerClass) ie.InternetExplorer;

    Rectangle elementBounds = element.NativeElement.GetElementBounds();
    int left = ieClass.Left + elementBounds.Left;
    int top = ieClass.Top + elementBounds.Top;
    int width = elementBounds.Width;
    int height = elementBounds.Height;

    using (var bitmap = new Bitmap(width, height))
    {
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen
                (new Point(left, top), Point.Empty, new Size(width, height));
        }

        bitmap.Save(screenshotPath, ImageFormat.Jpeg);
    }
}
A: 

Looks like it is a WatiN bug. As discussed on the WatiN issue tracker site, the "get bounds" method for Internet Explorer elements looks like this:

internal static Rectangle GetHtmlElementBounds(IHTMLElement element)
{
    int offsetLeft = element.offsetLeft;
    int offsetTop = element.offsetTop;
    for (IHTMLElement element2 = element.parentElement; element2 != null; element2 = element2.parentElement)
    {
        offsetLeft += element2.offsetLeft;
        offsetTop += element2.offsetTop;
    }
    int width = element.offsetWidth / 2;
    return new Rectangle(offsetLeft, offsetTop, width, element.offsetHeight / 2);
}

The bug is that it's dividing the offsetWidth and offsetHeight by 2.

I replaced the call to element.NativeElement.GetElementBounds to call my own "GetElementBounds" method, and it works the way I want it to:

private static Rectangle GetElementBounds(Element element)
{
    var ieElem = element.NativeElement as WatiN.Core.Native.InternetExplorer.IEElement;
    IHTMLElement elem = ieElem.AsHtmlElement;

    int left = elem.offsetLeft;
    int top = elem.offsetTop;

    for (IHTMLElement parent = elem.offsetParent; parent != null; parent = parent.offsetParent)
    {
        left += parent.offsetLeft;
        top += parent.offsetTop;
    }

    return new Rectangle(left, top, elem.offsetWidth, elem.offsetHeight);
}

The only remaining problem is that the top and left properties don't compensate for the size of the browser window's "chrome", so the element screenshot is farther down and to the right than it should be.

Until I figure out how to compensate for that, I'm avoiding it by setting the browser to "full screen" mode before taking the screenshot.

Brian Schroer