C#裁剪图像返回错误的坐标

Posted

技术标签:

【中文标题】C#裁剪图像返回错误的坐标【英文标题】:C# Cropping image return wrong coordinates 【发布时间】:2017-07-13 00:58:39 【问题描述】:

几天来,我一直在尝试使用 Selenium 和不同的裁剪方法裁剪特定图像。

我的代码之前的重要说明 - 以下方法在 2 周前使用,但由于某种原因,它现在返回一个坐标错误的图像

// Go to site
Driver.Navigate().GoToUrl("http://google.com");
Screenshot screenshot = driver.GetScreenshot();

using (var ms = new MemoryStream(screenshot.AsByteArray))
using (var imgShot = Image.FromStream(ms))
using (var src = new Bitmap(imgShot))
      
        IWebElement element = driver.FindElement(By.XPath("//canvas"));
        Rectangle cropRect = new Rectangle(element.Location.X, element.Location.Y, element.Size.Width, element.Size.Height);

        var clone = src.Clone(cropRect, src.PixelFormat);
        clone.Save(filePath);
      

我尝试过的事情:

1)我通常为此使用Firefox驱动程序,我尝试使用ChromeDriver并得到相同的结果。

2) 我使用以下控制台命令检查了元素的坐标:$0.getBoundingClientRect(),并且我在代码中得到的位置与之匹配。

3) 我尝试了 4 种不同的裁剪方法,包括这个:

IWebElement element = Driver.FindElement(By.XPath("//canvas"));
string filename = @"C:\Users\User\Desktop\test.png";
Screenshot screenshot = Driver.GetScreenshot();
screenshot.SaveAsFile(filename, ImageFormat.Png);

Rectangle cropRect = new Rectangle(element.Location.X, element.Location.Y,
    element.Size.Width, element.Size.Height);

using (Image imgShot = Image.FromFile(filename))
using (Bitmap original = new Bitmap(imgShot))
using (Bitmap target = new Bitmap(original, new Size(cropRect.Width, cropRect.Height)))
using (Graphics g = Graphics.FromImage(target))

    g.DrawImage(original, new Rectangle(0, 0, target.Width, target.Height),
        cropRect,
        GraphicsUnit.Pixel);
    target.Save(@"C:\Users\User\Desktop\test1.png", ImageFormat.Png);

为了清楚起见,我得到的图像完全是空白的。在不同的网站上,我得到的图像不是空白的,所以我可以看出它只是在错误的坐标中。

4) 我尝试了不同的网站和不同的元素,但它们都在错误的坐标中。

5) 我尝试用 Google 搜索,发现很多不同的方法都不起作用。然而,这个answer 说了一些关于分辨率的信息,这是我的最佳猜测。我尝试同时使用原始分辨率和目标分辨率,但没有发现任何区别。在创建 Graphics 变量之前或之后调用 set resolution 方法,但仍然是零变化。

有趣的是,它曾经在 2 周前工作,但我从未更改过代码...

【问题讨论】:

【参考方案1】:

您得到一个空白图像可能是因为调用GetScreenshot 时该区域尚未渲染。 试试看是不是这样:

Thread.Sleep(3000);
Screenshot screenshot = ((ITakesScreenshot)element).GetScreenshot();

这也可能是由于页面中的实现阻止了网络爬虫,在这种情况下,如果不挖掘代码,您将无能为力。

请注意,您不应使用element.Location,因为它返回的是相对于文档而不是视口的坐标。 如果驱动程序支持,您还应该考虑直接在IWebElement 上调用GetScreenshot

这是一个捕获页脚的工作示例:

var options = new ChromeOptions();
options.AddArgument("disable-infobars");

var driver = new ChromeDriver(options);

driver.Url = "https://***.com/questions";

IWebElement element = driver.FindElement(By.CssSelector("#footer"));

string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), @"screenshot.png");

try 
    Thread.Sleep(500);
    Screenshot screenshot = ((ITakesScreenshot)element).GetScreenshot();
    screenshot.SaveAsFile(filePath, ScreenshotImageFormat.Png);

catch (WebDriverException) 

    var result = ((IjavascriptExecutor)driver).ExecuteScript(
      "var elm = arguments[0];" +
      "elm.scrollIntoView(true);" +
      "var rect = elm.getBoundingClientRect();" +
      "return [rect.left, rect.top, rect.width, rect.height];"
      , element);

    int[] pts = Array.ConvertAll(((IReadOnlyCollection<object>)result).ToArray(), Convert.ToInt32);
    var rect = new Rectangle(pts[0], pts[1], pts[2], pts[3]);

    Screenshot screenshot = ((ITakesScreenshot)driver).GetScreenshot();

    using (var mstream = new MemoryStream(screenshot.AsByteArray))
    using (var bitmap = (Bitmap)Image.FromStream(mstream, false, false)) 
        rect.Intersect(new Rectangle(0, 0, bitmap.Width, bitmap.Height));

        if (rect.IsEmpty)
            throw new ArgumentOutOfRangeException("Cropping rectangle is out of range.");

        var clone = bitmap.Clone(rect, bitmap.PixelFormat);
        clone.Save(filePath);
    

【讨论】:

我只是想知道,上面的例子对你有用吗?我试过这个确切的例子。似乎我的驱动程序不支持从直接元素中截取屏幕截图,而且我仍然在错误的坐标中得到一个元素。 是的,这个例子对我有用。 chrome 驱动程序尚不支持元素屏幕截图,但 gecko 驱动程序支持。您应该首先尝试确定是由于 getBoundingClientRect() 返回的坐标还是由于屏幕截图本身。还要确保您选择了正确的元素并且您的所有驱动程序都是最新的。根据您提供的信息,无法准确判断出了什么问题。 我的 Firefox 版本是最新的,我的 GeckoDriver 也是。请您提供您的版本,所以我尝试一下,最终可能会看到不同 我在 windows 10 x64 上使用 chromedriver v2.30.477700 和 Chrome v59.0.3071.86。【参考方案2】:

显然,两周前真正改变的不是我的代码,而是我机器上安装的 Firefox 版本。当前版本 - v52,返回错误坐标的元素。 卸载它并重新安装以前的版本 - v47 解决了这个问题

【讨论】:

以上是关于C#裁剪图像返回错误的坐标的主要内容,如果未能解决你的问题,请参考以下文章

从两点裁剪图像(C#)

Bootstrap Modal 中的 Jcrop 裁剪错误的坐标

等待图像的格式更改

PyAutoGUI 定位命令返回错误的图像识别坐标

使用 .net 按给定坐标裁剪 pdf

如何使用 jcrop 裁剪正确的图像