wpf 用于检索颜色的画布背景

6ojccjat  于 2023-05-19  发布在  其他
关注(0)|答案(2)|浏览(145)

我有一个背景设置为lineargradientbrush的画布....我如何在特定的鼠标点(x,y)从这个背景中提取颜色?
我可以用一个bitmapedimage很好地做到这一点...因为这是处理像素,不确定画布虽然...

pvcm50d1

pvcm50d11#

Ray Burns发布的代码对我不起作用,但它确实引导我走上了正确的道路。经过一些研究和实验,我发现问题出在bitmap.Render(...)实现和它使用的Viewbox上。
注意:我使用的是.Net 3.5和WPF,所以他的代码可能在其他版本的. Net中也能工作。
这里特意留下了注解,以帮助解释代码。
正如你所看到的,Viewbox需要相对于源视觉高度和宽度进行标准化。
在呈现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;
    }

用法和雷的相似。我在这里展示的是画布上的鼠标按下。

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

hujrc8aj

hujrc8aj2#

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填充1x1Rectangle,显示画布的选定区域
1.它将此矩形呈现为1像素位图
1.它从渲染的位图中获取像素颜色

相关问题