8

I have an Image control in WPF which contains an image with lots of transparent pixels. Right now, the MouseDown event on Image fires whenever I click within the full rectangular region of the Image control. I would like some way to detect if the mouse click occurred on a nontransparent portion of the image.

What would be the best way of doing this?

Bradley
  • 257
  • 3
  • 9

2 Answers2

15

Using the technique in this answer you can derive from Image to create an OpaqueClickableImage that only responds to hit-testing in sufficiently non-transparent areas of the image:

public class OpaqueClickableImage : Image
{
    protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
    {
        var source = (BitmapSource)Source;

        // Get the pixel of the source that was hit
        var x = (int)(hitTestParameters.HitPoint.X / ActualWidth * source.PixelWidth);
        var y = (int)(hitTestParameters.HitPoint.Y / ActualHeight * source.PixelHeight);

        // Copy the single pixel into a new byte array representing RGBA
        var pixel = new byte[4];
        source.CopyPixels(new Int32Rect(x, y, 1, 1), pixel, 4, 0);

        // Check the alpha (transparency) of the pixel
        // - threshold can be adjusted from 0 to 255
        if (pixel[3] < 10)
            return null;

        return new PointHitTestResult(this, hitTestParameters.HitPoint);
    }
}

after adding this class, just use it like a regular image:

<utils:OpaqueClickableImage Name="image" Source="http://entropymine.com/jason/testbed/pngtrans/rgb8_t_bk.png" Stretch="None"/>
Community
  • 1
  • 1
Rick Sladkey
  • 33,988
  • 6
  • 71
  • 95
  • 1
    Thanks! This works perfectly. I must have missed that other post. – Bradley Jan 26 '11 at 04:38
  • 2
    I've actually seen this fail because `x` or `y` will be outside the the `PixelWidth` or `PixelHeight` of the `source`. Could either round down the calculation, or say, if `x>= PixelWidth: x = PixelWidth` – Kelly Elton May 29 '15 at 17:20
  • 1
    `CopyPixels` throws `System.ArgumentException` (out of bounds). What's the problem? – JustLogin Apr 01 '17 at 17:37
4
public class OpaqueClickableImage : Image
{
    protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
    {
        var source = (BitmapSource)Source;
        var x = (int)(hitTestParameters.HitPoint.X / ActualWidth * source.PixelWidth);
        var y = (int)(hitTestParameters.HitPoint.Y / ActualHeight * source.PixelHeight);
        if (x == source.PixelWidth)
            x--;
        if (y == source.PixelHeight)
            y--;

        var pixels = new byte[4];
        source.CopyPixels(new Int32Rect(x, y, 1, 1), pixels, 4, 0);
        
        return (pixels[3] < 1) ? null : new PointHitTestResult(this, hitTestParameters.HitPoint);
    }
}
Jackdaw
  • 7,626
  • 5
  • 15
  • 33
Adam D
  • 191
  • 1
  • 8