1

I am getting the mouse coordinates using e.GetPosition. It returns the right coordinates when it is close to 0, however, the further I click from the top right of the image, the more inaccurate it gets.

I want to be able to click on a pixel and change the colour of it. But now it changes another pixel, not the one I click (except at 0,0).

 private void image_MouseDown(object sender, MouseButtonEventArgs e)
 {
       // coordinates are now available in p.X and p.Y
       var p = e.GetPosition(image);

       System.Drawing.Color red = System.Drawing.Color.FromArgb(255, 0, 0);

       //converting to bitmap
       MemoryStream outStream = new MemoryStream();

       BitmapEncoder enc = new BmpBitmapEncoder();
       enc.Frames.Add(BitmapFrame.Create(wBitmap));
       enc.Save(outStream);
       System.Drawing.Bitmap img = new System.Drawing.Bitmap(outStream);

       //calculating pixel position
       double pixelWidth = image.Source.Width;
       double pixelHeight = image.Source.Height;
       double dx = pixelWidth * p.X / image.ActualWidth;
       double dy = pixelHeight * p.Y / image.ActualHeight;

       //converting to int
       int x = Convert.ToInt32(dx);
       int y = Convert.ToInt32(dy);
           
       img.SetPixel(x, y, red);

       //putting it back to writable bitmap and image    
       wBitmap = BitmapToImageSource(img);
       image.Source = wBitmap;
}

image with changed pixel

I want to change a pixel like this in the image. However, it doesn't change the pixel I click at, but another one a bit further up.

Rina
  • 13
  • 4
  • Please explain what exactly your code is supposed to do. What exactly is the "*correct position*"? And why are you creating a System.Drawing.Bitmap from a WriteableBitmap and then a WriteableBitmap back from the Bitmap? That does not seem to make much sense. – Clemens Jan 11 '21 at 07:37
  • @Clemens I want to be able to click on the image and change the colour of the pixel I clicked on. I am creating a bitmap because that has the `SetPixel` function and I wanted to use that. I convert it back to a WriteableBitmap because I want to update the image source and I haven't found any way to convert a bitmap into an image. I know this is probably really messy but it does what I want it to do and performance is not an issue for this project. – Rina Jan 11 '21 at 15:22
  • That makes no sense. You are using a WritableBitmap because you can *write pixels* with it, also a single one. Besides that, it is still unclear whate exactly you mean with "*correct position*". Is that supposed to be a pixel position? What if the image has a lot higher resolution than your screen? Do you want to set multiple pixels? – Clemens Jan 11 '21 at 16:35
  • @Clemens Yes I want to get the pixel position. The image is downsampled to a very small size, so you can see the pixels easily. I just want to set one pixel, as I click on it. I couldn't figure out how to do it with a WritableBitmap. `SetPixel` seems to do what I want. – Rina Jan 11 '21 at 17:21
  • See my answer here for the pixel position. See e.g. [this answer](https://stackoverflow.com/a/16761994/1136211) for how to write a single pixel value. – Clemens Jan 11 '21 at 17:22

1 Answers1

0

In order to get the pixel position inside the Source bitmap for a mouse event on an Image element, you have to use the BitmapSource's PixelWidth and PixelHeight instead of Width and Height:

private void ImageMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var image = (Image)sender;
    var source = (BitmapSource)image.Source;
    var mousePos = e.GetPosition(image);

    var pixelX = (int)(mousePos.X / image.ActualWidth * source.PixelWidth);
    var pixelY = (int)(mousePos.Y / image.ActualHeight * source.PixelHeight);

    ...
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • This works much better! But it is still inaccurate sometimes, especially in very small images (15 pixels height). – Rina Jan 11 '21 at 17:26
  • See the edit, you would have to round floating point values of course. – Clemens Jan 11 '21 at 17:40
  • I casted it to int, instead of using `Convert.ToInt32` and it works perfectly now! Thank you! – Rina Jan 11 '21 at 17:45
  • If I use `(int)Math.Round(...)` it is not accurate for some reason. If I use just `(int)dx` it works. I know it truncates the value but it works better for some reason. – Rina Jan 11 '21 at 17:51
  • 1
    I upvoted it! I just don't have enough reputation. – Rina Jan 11 '21 at 17:58