裁剪图像时出现OutofMemory错误

时间:2016-05-03 06:08:43

标签: c# image selenium bitmap out-of-memory

以下是我正在尝试的代码,但是会出现内存异常。

我正在尝试从通过硒获取的屏幕截图中仅裁剪元素的图像。

            byte[] image= driver.GetScreenshot().AsByteArray;
                using (MemoryStream sourceStream = new MemoryStream(image))
                {
                    using (Bitmap source = new Bitmap(sourceStream))
                    {

                        Rectangle cropzone = new Rectangle(element.Location.X, element.Location.Y, element.Size.Width, element.Size.Height);
                        using (Bitmap croppedBitmap = source.Clone(cropzone, source.PixelFormat))
                        {
                            croppedBitmap.Save(file_name, System.Drawing.Imaging.ImageFormat.Png);
                        }
                    }
                }

2 个答案:

答案 0 :(得分:2)

当裁剪矩形位于屏幕截图之外时,会引发Out of memory异常。如果屏幕截图包含整页,则需要使用相对于页面的位置裁剪元素。如果没有,则需要将目标元素滚动到视图中并使用相对于视图的位置进行裁剪。

以下是一种获取WebElement的屏幕截图的扩展方法:

static class WebElementExt {

    public static Bitmap TakeScreenshot(this OpenQA.Selenium.IWebElement element) {
        RemoteWebDriver driver = (RemoteWebDriver)((RemoteWebElement)element).WrappedDriver;

        if (((IHasCapabilities)driver).Capabilities.HasCapability("takesElementScreenshot")) {

            byte[] bytes = ((RemoteWebElement)element).GetScreenshot().AsByteArray;
            return (Bitmap)Bitmap.FromStream(new MemoryStream(bytes, 0, bytes.Length, false, true), false, false);

        } else {
            var dict = (Dictionary<String, Object>)driver.ExecuteScript(@"
                arguments[0].scrollIntoView(true);
                var r = arguments[0].getBoundingClientRect(), scrollX = 0, scrollY = 0;
                for(var e = arguments[0]; e; e=e.parentNode) {
                  scrollX += e.scrollLeft || 0;
                  scrollY += e.scrollTop || 0;
                }
                return {left: r.left|0, top: r.top|0, width: r.width|0, height: r.height|0
                       , scrollX: scrollX, scrollY: scrollY, innerHeight: window.innerHeight}; "
                , element);

            var rect = new System.Drawing.Rectangle(
                Convert.ToInt32(dict["left"]),
                Convert.ToInt32(dict["top"]),
                Convert.ToInt32(dict["width"]),
                Convert.ToInt32(dict["height"]));

            byte[] bytes = driver.GetScreenshot().AsByteArray;
            using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(bytes, 0, bytes.Length, false, true), false, false)) {

                if (bitmap.Height > Convert.ToInt32(dict["innerHeight"]))
                    rect.Offset(Convert.ToInt32(dict["scrollX"]), Convert.ToInt32(dict["scrollY"]));

                rect.Intersect(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
                if (rect.Height == 0 || rect.Width == 0)
                    throw new WebDriverException("WebElement is outside of the screenshot.");

                return bitmap.Clone(rect, bitmap.PixelFormat);
            }
        }
    }
}

一个用法示例:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://stackoverflow.com");

driver.FindElementById("svnrev")
      .TakeScreenshot()
      .Save(@"screenshot-element.png", ImageFormat.Png);

driver.Quit();

答案 1 :(得分:0)

我曾经为我的代码共享工作selenium:

public static Bitmap GetEntereScreenshot(IWebDriver driver)
        {
            Bitmap stitchedImage = null;
            try
            {
                var jse = (IJavaScriptExecutor)driver;
                jse.ExecuteScript("window.scrollTo(0, 0);");

                var jqueryLibrary = TestExtensions.GetConfigValue("jquery_library", "");
                var js = new JqueryExtension(driver, jqueryLibrary);
                var driverBrowser = ((RemoteWebDriver)driver).Capabilities.BrowserName;
                //driver_browser= 1: Internet Explorer, 2: Firefox, 3: Google Chrome
                int totalWidth;
                int totalHeight;
                if (driverBrowser.Equals("internet explorer"))
                {
                    var totalwidth1 = (Int64)((IJavaScriptExecutor)driver).ExecuteScript("return document.body.offsetWidth;");
                    var totalHeight1 = (Int64)((IJavaScriptExecutor)driver).ExecuteScript("return document.body.parentNode.scrollHeight;");
                    totalWidth = (int)totalwidth1;
                    totalHeight = (int)totalHeight1;
                }
                else
                {
                    totalWidth = js.GetSizePage("$(document).width();");
                    totalHeight = js.GetSizePage("$(document).height();");
                }

                // Get the Size of the Viewport
                var viewportWidth1 = js.GetSizePage("$(window).width();");
                //var viewportHeight1 = driverBrowser == "2" ? totalHeight : js.GetSizePage("$(window).height();");
                int viewportHeight1;

                switch (driverBrowser)
                {
                    case "internet explorer":
                        if (((RemoteWebDriver)driver).Capabilities.Version == "8" || ((RemoteWebDriver)driver).Capabilities.Version == "9")
                        {
                            viewportHeight1 = totalHeight;
                        }
                        else
                        {
                            viewportHeight1 = js.GetSizePage("$(window).height();");
                        }
                        break;
                    case "firefox":
                        viewportHeight1 = totalHeight;
                        break;
                    default:
                        viewportHeight1 = js.GetSizePage("$(window).height();");
                        break;
                }

                var viewportWidth = viewportWidth1;
                var viewportHeight = viewportHeight1;
                // Split the Screen in multiple Rectangles
                var rectangles = new List<Rectangle>();
                // Loop until the Total Height is reached
                for (var i = 0; i < totalHeight; i += viewportHeight)
                {
                    var newHeight = viewportHeight;

                    // Fix if the Height of the Element is too big
                    if (i + viewportHeight > totalHeight)
                    {
                        newHeight = totalHeight - i;
                    }
                    // Loop until the Total Width is reached
                    for (var ii = 0; ii < totalWidth; ii += viewportWidth)
                    {
                        var newWidth = viewportWidth;
                        // Fix if the Width of the Element is too big
                        if (ii + viewportWidth > totalWidth)
                        {
                            newWidth = totalWidth - ii;
                        }

                        // Create and add the Rectangle
                        var currRect = new Rectangle(ii, i, newWidth, newHeight);
                        rectangles.Add(currRect);
                    }
                }
                // Build the Image
                stitchedImage = new Bitmap(totalWidth, totalHeight);
                // Get all Screenshots and stitch them together
                var previous = Rectangle.Empty;
                foreach (var rectangle in rectangles)
                {
                    // Calculate the Scrolling (if needed)
                    if (previous != Rectangle.Empty)
                    {
                        var xDiff = rectangle.Right - previous.Right;
                        var yDiff = previous.Height;//rectangle.Bottom - previous.Bottom;
                       ((IJavaScriptExecutor)driver).ExecuteScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));

                        System.Threading.Thread.Sleep(500);
                    }

                    // Take Screenshot
                    var screenshot = ((ITakesScreenshot)driver).GetScreenshot();

                    // Build an Image out of the Screenshot
                    Image screenshotImage;
                    using (var memStream = new MemoryStream(screenshot.AsByteArray))
                    {
                        screenshotImage = Image.FromStream(memStream);
                    }

                    // Calculate the Source Rectangle  
                    var sourceRectangle = new Rectangle(viewportWidth - rectangle.Width, viewportHeight - rectangle.Height, rectangle.Width, rectangle.Height);

                    // Copy the Image
                    using (var g = Graphics.FromImage(stitchedImage))
                    {
                        g.DrawImage(screenshotImage, rectangle, sourceRectangle, GraphicsUnit.Pixel);
                    }
                    // Set the Previous Rectangle
                    previous = rectangle;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            return stitchedImage;
        }