Canvas background to get color

I have a canvas with a background set as lineargradientbrush .... how do I then extract the color from that background at a specific point on the mouse (x, y)?

I can do it with BitmappedImage fine ... as it is about pixels, but not sure about the canvas though ...

Thanks in advance,

U.

+2


a source to share


3 answers


WPF is vector based, so it doesn't really have a concept of "pixel" except in a bitmap data structure. However, you can define the average color of the rectangular area, including the 1x1 rectangular area (which is usually displayed as a single pixel on the physical screen).

Here's how to do it:

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

      

This is how you use it:



Color pixelColor = GetPixelColor(canvas, x, y);

      

How this code works:

  • It fills a 1x1 rectangle with a VisualBrush which displays the selected area of ​​the canvas
  • It maps this rectangle to a single pixel bitmap
  • It gets the color of the pixel from the displayed bitmap.
0


a source


Microsoft Support has an article on finding a pixel color in a mouse cursor:



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

0


a source


The code posted by Ray Burns didn't work for me, but it got me on the right track. After some research and experimentation, I found that the problem lies with the implementation of bitmap.Render (...) and the viewport it uses.

Note. I am using .Net 3.5 and WPF, so his code works in other versions of .Net.

Comments were left here on purpose to help explain the code.

As you can see, the viewport needs to be normalized to its original Visual Height and Width.

A DrawingVisual must be drawn using a DrawingContext before it can be displayed.

In the RenderTargetBitmap method, I tried both PixelFormats.Default and PixelFormats.Pbgra32. My test results were the same with both of them.

Here is the code.

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

      

If you are interested in the getScreenDPI () function, the code:

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

      

And the usage is similar to Ray. I am showing it here for MouseDown on canvas.

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

      

FYI, ImagingTools is the class in which I store the static methods related to image processing.

0


a source







All Articles