Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于检索颜色的画布背景_C#_Wpf_Colors_Canvas_Mouse - Fatal编程技术网

C# 用于检索颜色的画布背景

C# 用于检索颜色的画布背景,c#,wpf,colors,canvas,mouse,C#,Wpf,Colors,Canvas,Mouse,我有一个背景设置为lineargradientbrush的画布……然后如何从特定鼠标点(x,y)的背景中提取颜色 我可以用BitmappedImageFine来做这件事…因为这是关于像素的,但不确定画布是什么 提前非常感谢 U.在Microsoft支持上,有一篇关于在鼠标光标处查找像素颜色的文章: WPF是基于向量的,因此除了位图数据结构之外,它实际上没有任何“像素”的概念。但是,您可以确定矩形区域的平均颜色,包括1x1矩形区域(通常在物理屏幕上显示为单个像素) 以下是如何做到这一点: publ

我有一个背景设置为lineargradientbrush的画布……然后如何从特定鼠标点(x,y)的背景中提取颜色

我可以用BitmappedImageFine来做这件事…因为这是关于像素的,但不确定画布是什么

提前非常感谢


U.

在Microsoft支持上,有一篇关于在鼠标光标处查找像素颜色的文章:


WPF是基于向量的,因此除了位图数据结构之外,它实际上没有任何“像素”的概念。但是,您可以确定矩形区域的平均颜色,包括1x1矩形区域(通常在物理屏幕上显示为单个像素)

以下是如何做到这一点:

public Color GetPixelColor(Visual visual, int x, int y)
{
  return GetAverageColor(visual, new Rect(x,y,1,1));
}

public Color GetAverageColor(Visual visual, Rect area)
{
  var bitmap = new RenderTargetBitmap(1,1,96,96,PixelFormats.Pbgra32);
  bitmap.Render(
   new Rectangle
    {
      Width = 1, Height = 1,
      Fill = new VisualBrush { Visual = visual, Viewbox = area }
    });
  var bytes = new byte[4];
  bitmap.CopyPixels(bytes, 1, 0);
  return Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3]);
}
以下是您将如何使用它:

Color pixelColor = GetPixelColor(canvas, x, y);
此代码的工作方式是:

  • 它使用显示画布选定区域的可视化笔刷填充1x1矩形
  • 它将此矩形渲染为1像素位图
  • 它从渲染的位图中获取像素颜色

  • Ray Burns发布的代码对我不起作用,但它确实引导我走上了正确的道路。经过一些研究和实验后,我找到了问题所在:bitmap.Render(…)实现及其使用的Viewbox

    注意:我使用的是.NET3.5和WPF,所以他的代码可能适用于.Net的其他版本

    这些注释是特意留下来帮助解释代码的

        public static Color GetPixelColor(Visual visual, Point pt)
        {
            Point ptDpi = getScreenDPI(visual);
    
            Size srcSize = VisualTreeHelper.GetDescendantBounds(visual).Size;
    
            //Viewbox uses values between 0 & 1 so normalize the Rect with respect to the visual's Height & Width
            Rect percentSrcRec = new Rect(pt.X / srcSize.Width, pt.Y / srcSize.Height,  
                                          1 / srcSize.Width, 1 / srcSize.Height);
    
            //var bmpOut = new RenderTargetBitmap(1, 1, 96d, 96d, PixelFormats.Pbgra32); //assumes 96 dpi
            var bmpOut = new RenderTargetBitmap((int)(ptDpi.X / 96d),
                                                (int)(ptDpi.Y / 96d),
                                                ptDpi.X, ptDpi.Y, PixelFormats.Default); //generalized for monitors with different dpi
    
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                dc.DrawRectangle(new VisualBrush { Visual = visual, Viewbox = percentSrcRec },
                                 null, //no Pen
                                 new Rect(0, 0, 1d, 1d) );
            }
            bmpOut.Render(dv);
    
            var bytes = new byte[4];
            int iStride = 4; // = 4 * bmpOut.Width (for 32 bit graphics with 4 bytes per pixel -- 4 * 8 bits per byte = 32)
            bmpOut.CopyPixels(bytes, iStride, 0); 
    
            return Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3]);
        }
    
    正如您所见,Viewbox需要根据源视觉高度和宽度进行规格化

    需要使用DrawingContext绘制DrawingVisual,然后才能对其进行渲染

    在RenderTargetBitmap方法中,我尝试了PixelFormats.Default和PixelFormats.Pbgra32。我对他们两人的测试结果都一样

    这是代码

        public static Color GetPixelColor(Visual visual, Point pt)
        {
            Point ptDpi = getScreenDPI(visual);
    
            Size srcSize = VisualTreeHelper.GetDescendantBounds(visual).Size;
    
            //Viewbox uses values between 0 & 1 so normalize the Rect with respect to the visual's Height & Width
            Rect percentSrcRec = new Rect(pt.X / srcSize.Width, pt.Y / srcSize.Height,  
                                          1 / srcSize.Width, 1 / srcSize.Height);
    
            //var bmpOut = new RenderTargetBitmap(1, 1, 96d, 96d, PixelFormats.Pbgra32); //assumes 96 dpi
            var bmpOut = new RenderTargetBitmap((int)(ptDpi.X / 96d),
                                                (int)(ptDpi.Y / 96d),
                                                ptDpi.X, ptDpi.Y, PixelFormats.Default); //generalized for monitors with different dpi
    
            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                dc.DrawRectangle(new VisualBrush { Visual = visual, Viewbox = percentSrcRec },
                                 null, //no Pen
                                 new Rect(0, 0, 1d, 1d) );
            }
            bmpOut.Render(dv);
    
            var bytes = new byte[4];
            int iStride = 4; // = 4 * bmpOut.Width (for 32 bit graphics with 4 bytes per pixel -- 4 * 8 bits per byte = 32)
            bmpOut.CopyPixels(bytes, iStride, 0); 
    
            return Color.FromArgb(bytes[0], bytes[1], bytes[2], bytes[3]);
        }
    
    如果您对getScreenDPI()函数感兴趣,代码是:

        public static Point getScreenDPI(Visual v)
        {
            //System.Windows.SystemParameters
            PresentationSource source = PresentationSource.FromVisual( v );
            Point ptDpi;
            if (source != null)
            {
                ptDpi = new Point( 96.0 * source.CompositionTarget.TransformToDevice.M11,
                                   96.0 * source.CompositionTarget.TransformToDevice.M22  );
            }
            else
                ptDpi = new Point(96d, 96d); //default value.
    
            return ptDpi;
        }
    
    其用法与Ray的类似。我在这里展示它,在画布上进行鼠标向下移动

        private void cvsTest_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Point ptClicked = e.GetPosition(cvsTest);
    
            if (e.LeftButton.Equals(MouseButtonState.Pressed))
            {
                Color pxlColor = ImagingTools.GetPixelColor(cvsTest, ptClicked);
                MessageBox.Show("Color String = " + pxlColor.ToString());
            }
        }
    

    仅供参考,ImagingTools是我保存与成像相关的静态方法的类。

    我尝试使用您的代码,但我得到一个System.ArgumentOutOfRangeException:类似于:bitmap.CopyPixels(字节,1,0)的“参数值不能小于4”。我的参数是x=57,y=78。然而,使用bitmap.CopyPixels(字节,4,0)是可行的,那么“字节”只包含“0”,这将始终给出一个透明的黑色。