WPF: Detect Image click only on non-transparent portion

后端 未结 2 1183
無奈伤痛
無奈伤痛 2020-12-19 04:54

I have an Image control in WPF which contains an image with lots of transparent pixels. Right now, the MouseDown event on Image fires

相关标签:
2条回答
  • 2020-12-19 05:28
    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);
            if (pixels[3] < 1) return null;
            return new PointHitTestResult(this, hitTestParameters.HitPoint);
        }
    }
    
    0 讨论(0)
  • 2020-12-19 05:40

    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"/>
    
    0 讨论(0)
提交回复
热议问题