Question

According to msdn in Silverlight images are hit testable over their image/media display areas, basically their Height and Width. Transparent / full alpha pixels in the image file are still hit testable. My question is now, what is the best way to have only non-transparent pixel hit testable in images in Silverlight?

Was it helpful?

Solution

This is not going to be possible using the normal hit testing capability, as you found out with the MSDN reference.

The only idea I had was to convert your image to the WritableBitmap class and use the Pixels property to do alpha channel hit testing. I have not actually tried this and I can't imagine it's trivial to do, but it should work in theory.

The pixels are one large int[] with the 4 bytes of each integer corresponding to ARGB. It uses the premultiplied ARGB32 format, so if there is any alpha transparency besides full 255 the other RGB values are scaled accordingly. I am assuming you want anything NOT full alpha to be considered a "hit" so you could just check against the alpha byte to see if it is 255.

You would access the row/col pixel you are looking to check by array index like this:

int pixel = myBitmap.Pixels[row * myBitmap.PixelWidth + col];

Check out this post for some more ideas.

EDIT:

I threw together a quick test, it works and it's pretty straightforward:

public MainPage()
{
    InitializeComponent();

    this.image = new BitmapImage(new Uri("my_tranny_image.png", UriKind.Relative));
    this.MyImage.Source = image;

    this.LayoutRoot.MouseMove += (sender, e) =>
    {
        bool isHit = ImageHitTest(image, e.GetPosition(this.MyImage));
        this.Result.Text = string.Format("Hit Test Result: {0}", isHit);
    };
}

bool ImageHitTest(BitmapSource image, Point point)
{
    var writableBitmap = new WriteableBitmap(image);

    // check bounds
    if (point.X < 0.0 || point.X > writableBitmap.PixelWidth - 1 ||
        point.Y < 0.0 || point.Y > writableBitmap.PixelHeight - 1)
        return false;

    int row = (int)Math.Floor(point.Y);
    int col = (int)Math.Floor(point.X);

    int pixel = writableBitmap.Pixels[row * writableBitmap.PixelWidth + col];
    byte[] pixelBytes = BitConverter.GetBytes(pixel);

    if (pixelBytes[0] != 0x00)
        return true;
    else
        return false;
}

You would probably want to make some optimizations like not create the WritableBitmap on every MouseMove event but this is just a proof of concept to show that it works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top