Холст фон для получения цвета - PullRequest
2 голосов
/ 14 мая 2010

У меня есть холст с фоном, установленным как линейная кисть .... как мне затем извлечь цвет из этого фона в определенной точке мыши (x, y)?

Я могу сделать это с помощью BitmappedImage ... так как это касается пикселей, хотя и не уверен насчет холста ...

Большое спасибо заранее,

U.

Ответы [ 3 ]

0 голосов
/ 15 мая 2010

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. Он заполняет прямоугольник 1x1, используя VisualBrush, который показывает выбранную область холста
  2. Отображает этот прямоугольник на растровом изображении с 1 пикселем
  3. Получает цвет пикселя из отрисованного растрового изображения
0 голосов
/ 15 августа 2015

Код, опубликованный Рэй Бернс, не сработал для меня, но привел меня на правильный путь.После некоторых исследований и экспериментов я обнаружил, что проблемы заключаются в реализации bitmap.Render (...) и используемом им Viewbox.

Примечание: я использую .Net 3.5 и WPF, так что, возможно, его код работает вдругие версии .Net.

Здесь намеренно оставлены комментарии, чтобы помочь объяснить код.

Как вы можете видеть, Viewbox должен быть нормализован относительно исходной высоты и ширины Visual.

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 - это класс, в котором я храню статические методы, связанные с отображением.

0 голосов
/ 14 мая 2010

В службе поддержки Microsoft есть статья о поиске цвета пикселя у курсора мыши:

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

...