【问题标题】:Canvas background for retrieving color用于检索颜色的画布背景
【发布时间】:2010-05-14 15:43:23
【问题描述】:

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

我可以用 BitmappedImage 很好地做到这一点......因为这涉及像素,但不确定画布......

提前非常感谢,

U.

【问题讨论】:

    标签: c# wpf colors canvas mouse


    【解决方案1】:

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

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

    这些 cmets 特意留在这里帮助解释代码。

    如您所见,需要根据源视觉高度和宽度对视图框进行规范化。

    DrawingVisual 需要先使用 DrawingContext 进行绘制,然后才能呈现。

    在 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;
        }
    

    而且用法和雷的差不多。我在这里为画布上的 MouseDown 展示它。

        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 是我保留与成像相关的静态方法的类。

    【讨论】:

      【解决方案2】:

      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);
      

      这段代码的工作方式是:

      1. 它使用显示画布选定区域的 VisualBrush 填充 1x1 矩形
      2. 它将这个矩形渲染到一个 1 像素的位图上
      3. 它从渲染的位图中获取像素颜色

      【讨论】:

      • 我尝试使用您的代码,但在 bitmap.CopyPixels(bytes, 1, 0) 处出现 System.ArgumentOutOfRangeException: Sth like: "Parameter value can not be less than 4"。我的参数是 x=57,y=78。使用 bitmap.CopyPixels(bytes, 4, 0) 可以,但是,“bytes”只包含“0”,这将始终给出透明的黑色。
      【解决方案3】:

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

      http://support.microsoft.com/kb/892462

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多