【问题标题】:C# Efficent way to get color at point on screenC#在屏幕上获取颜色的有效方法
【发布时间】:2014-08-13 02:53:54
【问题描述】:

我确实有一种工作方法,但是它相当耗费资源,我正在寻找一种更好的方法。在对类似问题here 的回复中建议运行以下代码。

但是运行上述代码会产生System.OutOfMemoryException

异常发生@using (Graphics gdest = Graphics.FromImage(screenPixel)) {

当前代码:

Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format16bppArgb1555);
using (Graphics gdest = Graphics.FromImage(screenPixel)) {
    using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero)) {
        IntPtr hSrcDC = gsrc.GetHdc();
        IntPtr hDC = gdest.GetHdc();
        int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, x, y, (int)CopyPixelOperation.SourceCopy);
        gdest.ReleaseHdc();
        gsrc.ReleaseHdc();
        }
   }
    return screenPixel.GetPixel(0, 0);

编辑:

好的,我已经使用以下代码解决了上面遇到的问题。但是现在我只返回黑色 (0,0,0)。

this.screenPixel = new Bitmap(1, 1, PixelFormat.Format16bppRgb555);
using (Graphics gdest = Graphics.FromImage(this.screenPixel)) {
    using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero)) {
        IntPtr hSrcDC = gsrc.GetHdc();
        IntPtr hDC = gdest.GetHdc();
        int retval = BitBlt(hDC, 0, 0, width, height, hSrcDC, x, y, (int)CopyPixelOperation.SourceCopy);
        gdest.ReleaseHdc();
        gsrc.ReleaseHdc();
        }
}
Color result = screenPixel.GetPixel(0, 0);
Console.WriteLine(result.R + " " + result.G + " " + result.B);
GC.SuppressFinalize(this.screenPixel);
this.screenPixel.Dispose();
return result;

【问题讨论】:

  • 你为什么使用Format16bppArgb1555?哪一行抛出异常?
  • 我试过有无,我只有它,因为我只需要 8 位颜色精度。我将更新帖子,说明哪一行引发了异常。
  • screenPixel 是类成员还是局部变量?在链接的解决方案中,它是一个被重用的类成员(并希望在表单的 Dispose 方法中处理掉)。
  • 顺便说一句:using 已经调用了Dispose,你为什么要显式调用它。尝试删除它们....
  • 只需在 .NET 中查找 EyeDropper 示例并根据您的需要进行更改:bobpowell.net/eyedropper.aspx

标签: c# .net colors screen


【解决方案1】:

这似乎在这里工作:

using System.Runtime.InteropServices;
//... 


[DllImport("gdi32.dll")]
public static extern int BitBlt(IntPtr hObject, int nXDest, int nYDest, 
   int nWidth, int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, int  dwRop);

//..

    Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppRgb);
    using (Graphics gdest = Graphics.FromImage(screenPixel))
    {
        using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
        {
            IntPtr hSrcDC = gsrc.GetHdc();
            IntPtr hDC = gdest.GetHdc();
            int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, x, y,
                                    (int) CopyPixelOperation.SourceCopy);
            gdest.ReleaseHdc();
            gsrc.ReleaseHdc();
        }
    }
    Color c =  screenPixel.GetPixel(0, 0);
    return c;

注1:

  • 我已更改像素格式以匹配我的屏幕。
  • 我修改了 BitBlt 声明

注2:

根据this post,您不妨直接使用 Graphics.CopyFromScreen,因为它无论如何都会使用 BitBlt。这会更安全,而且麻烦更少。

【讨论】:

  • 你能告诉我(int)0x00CC0020的值是从哪里来的吗?
  • Here on pinvoke 是对 bitBlt 和 enum TernaryRasterOperations 的描述。因为我认为它丢失了,所以我复制了SRCCOPY 的值。傻我!请注意,您可能希望使用int bpp = Screen.PrimaryScreen.BitsPerPixel; 来确定屏幕的颜色深度。
猜你喜欢
  • 2013-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
  • 2011-06-07
  • 1970-01-01
  • 2015-05-18
相关资源
最近更新 更多