Currently, I'm using a WPF Image control to display images. I want to do the following: On a MouseUp, MouseDown or MouseMove event, I want to get the coordinates of the point under the cursor, not with reference to the top-left corner of the control, but with respect to the actual coordinates of the displayed bitmap, which may have been re-scaled, or may have a different aspect ratio than the control itself. If an alternate control provides this functionality, I'd be equally happy to hear about it. Thanks in advance.
EDIT: I'd also like so may to know it if the coordinates of the control were out of range of the image, due to a different aspect ratio.
you can get the coordinates of the mouse by this way :
private void image1_MouseDown(object sender, MouseButtonEventArgs e)
{
Point point = e.GetPosition(image1); //position relative to the image
Point point2 = e.GetPosition(this); //position relative to the window
}
Hope that answered a part of your question.
You can use the various TransformTo* methods of the Visual class to get, coordnates relative to a sepcific control, it will take all transformation applied to the visual tree into account.
Also, if you attach MouseUp, MouseDown and MouseMove to the Image control itself, you should already get the correct coordinates from the MouseButtonEventArgs and if you use the mouse outside of the visual bounds of the control, you will not get those events, so you don't need extra code check for coordinates being out of bounds.
If your actual goal is to find out which acutal pixel of your bitmap image has been touched by the mouse (as you would need for a bitmap/pixel editing software) things get much harder because WPF uses virtual device indendent pixels that do not directly relate to pixels on the screen or pixels in a bitmap that has been rendered in an Image control. The Image control internally scales a bitmap image based on the DPI settings of the bitmap file itself and based on the DPI settings of operating system.
Related
I'm developing drawing tool control using inkcanvs in wpf.
When i draw rectangle, this is original image.
Original Image
And i set that editing mode is erase by point. When i erase rectangle, this is image after working.
Erased Image
I want that erase function works as well as default drawing tool in windows. It would be worked by pixel. Erase shape by pixel.
Part of Source Codes
public class Label : Stroke
{
protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
Rect rect = new Rect((Point)this.StylusPoints[0], (Point)this.StylusPoints[1]);
drawingContext.DrawRectangle(...)
This is not possible with the standard API.
Only by translating an ink image (strokes, which are enhanced vectors) to a bitmap image (which contains pixels) individual pixels can be manipulated but the stroke information will be lost.
With quite some effort an application could be created that keeps track of all its user's actions (draw some strokes, add a pixel, remove a pixel) and replays them all every time the UI needs a redraw, injecting the transformation from vector to bitmap where needed.
This is a nice exercise but might prove to be too slow and/or complex.
I am drawing lines on a background image in a c# panel. The panel is anchored to the form so as the form resizes the panel resizes. The background image is set to be stretched so all you see as you resize the form is the background image.
My initial problem:
The lines drawn on the panel (via the OnPaint event) stay where they were originally drawn as the image resizes.
My current solution:
Record the location of the line and redraw it on a new bitmap by scaling the X and Y coordinates (works fine).
My new problem:
As you continually resize the window and draw lines you can't calculate the scaling factor from any point in time and apply it to all lines since the lines were originall drawn in different size images.
The two options I think I have:
After I redraw the line go through my array of lines and update the coordinate information so it now matches the current scale.
Or
In addition to storing the coordinate information of the line also store the size information of the panel at the time it was drawn so I can always calculate the scale for each line based on when it was drawn and the new panel size.
What I'm hoping for:
If you have thoughts on either of the two approaches that would be greatly appreciated....Even better would be to point me in the direction of a far better method to do this (I am fairly new to graphics processing in c#).
Can't write a comment, much as I want to. You do have a few options:
Draw your lines directly on the original Bitmap. This might not be an option for you, depending on the task.
Do it as you're doing now, keeping track of the lines' coordinates, updating them on resize, and redrawing them on Paint - if you use this, you'll be able to move and delete them, too,
Or do it by introducing a "scale factor" (float) which you update on every resize, and in your Paint event handler you draw everything using that scale factor. As you create a line, you calculate its coordinates using the scale factor BACK TO an unified coordinate system (scale factor 1) and then you don't have to modify your coordinates at all. This might be easy to debug due to that unified coordinate system. This is what I'd recommend, but it again depends on your task.
Draw to a full transparent Bitmap of the same size as your original image, use a scale factor like in the previous option. On creating a line, calculate its coordinates in the unified coordinate system, draw it on the Bitmap, and then on every Paint, draw the entire Bitmap over your original one. This, again, might not be an option if you need to delete or move your lines, or if you're tight on memory, or you don't want your lines to be blurred when you scale up, but somehow many ppl like this because it's like a "layer in Photoshop". :)
I have made a program that reads voltage and current values of some diode curves from an xml file and draws them on screen (Just using plain 2D graphics and some simple commands like DrawCurve and stuff like that).
My main image frame is 800 by 800 pixels (you can see a smaller screenshot down below). Now I want to add a zoom function that when I hover the mouse over this image area, a flying smaller square pops up and zooms in + moves when I move the mouse over this area.
I have no idea how to approach this. Ofcourse I don't ask the full working code but please help me to get closer and closer!
For instance, can I make the zoom to work, without reading the curve data and painting real time? or there is no escape from it? How can I have a hovering image box when I move mouse over the orginal image?
Thanks!
Have you timed how long DrawCurve takes? Perhaps it's fast enough to do in real time. Don't forget, the GDI will clip the drawing primitives to the drawing area. You just need to set up a clipping rectangle as you move the mouse around.
To speed up the redraw, create the main window image (the one you pasted) as an off-screen bitmap, and just DrawImage the off-screen version to the window in the paint events. That way you reduce the impact of the DrawCurve.
Finally, to get good looking results, overload the OnPaintBackground (can't remember the name exactly but it's something like that) so it does nothing (not even call the base class) and do all your painting in the OnPaint method using a BufferedGraphics object.
Update
Your paint function might look like this:
OnPaint (...)
{
the_graphics_object.DrawImage (the background image);
the_graphics_object.Clip = new Region (new Rectangle (coords relative to mouse position));
the_graphics_object.TranslateTransform (drawing offset based on mouse position);
RenderScene (the_graphics_object, scale_factor); // draws grid and curve, etc
the_graphics_object.DrawRectangle (zoom view rectangle); // draw a frame around the zoomed view
}
This will produce a floating 'window' relative to the mouse position.
Typically, cases where redrawing can be time consuming, zooming is usually tackled by providing a "quick but ugly" implementation, alongside the "correct but slow" implementation. While the zoom operation is actively in progress (say, while the user has a slider clicked, or until a 50ms since the last change in zoom value has happened), you use the quick and ugly mode, so the user can see a preview of what the final image will be. Once they let go of the zoom slider (or whatever mechanism you provided), you can recalculate the image in detail. The quick version is usually calculated based on the original image that you are working with.
In your case, you could simply take the original image, work out the bounding box of the new, zoomed image, and scale the relevant part of the original image up to the full image size. If say 100ms has passed with no change in zoom, recalculate the entire image.
Examples of this kind of functionality are quite widespread: most fractal generators use exactly this technique, and even unrelated things like Google StreetView (which provides a very ugly distorted version of the previous image when you move around, until the actual image has downloaded).
How would I draw something on a Canvas in C# for Windows Phone?
Okay, let me be a little more clear.
Say the user taps his finger down at 386,43 on the canvas. (the canvas is 768 by 480)
I would like my application to be able to respond by placing a red dot at 386,43 on the canvas.
I have no prior experience with Canvas whatsoever.
If this is too complex to be answered in one question (which it probably is), please give me links to other websites with Canvas and Drawing articles.
There are various ways of doing this. Depending on the nature of the red dot, you could make it a UserControl. For a basic circle, you can simply handle your canvas' ManipulationStarted event.
private void myCanvas_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
Ellipse el = new Ellipse();
el.Width = 10;
el.Height = 10;
el.Fill = new SolidColorBrush(Colors.Red);
Canvas.SetLeft(el, e.ManipulationOrigin.X);
Canvas.SetTop(el, e.ManipulationOrigin.Y);
myCanvas.Children.Add(el);
}
I think you need to approach the problem differently. (I'm not including code on purpose, because of that).
Forms and controls in an Windows applications (including Phone) can be refreshed for several reasons, at any time. If you draw on a canvas in response to a touch action, you have an updated canvas until the next refresh. If a refresh occurs the canvas repaints itself, you end up with a blank canvas.
I have no idea what your end goal is, but you likely want to either keep track of what the user has done and store that state somewhere and show it in a canvas on the repaint of the canvas. This could be done with storing all the actions and "replaying" them on the canvas, or simply storing the view of the canvas as a bitmap and reload the canvas with that bitmap when refreshed. But, in the later case I think using a canvas isn't the right solution.
I'm doing a software where I need to put squary bordering fields on a satelite map (.png image), so that the fields can be clicked.
What is the best way to add shapes on a picture and associate them with data ?
Overlay a custom-draw UserControl on top of the Image control. Make part of it transparent to reveal the underlying image, but still be able to capture the mouse interaction.
You will have to calculate the exact position (pixel offset from the map top-left corner) of your control to overlay the proper map area. How you calculate that offset and the actual size of your custom control depends on the map zoom level and whether you use GPS coordinates or image recognition to determine which area needs to be overlayed.
Graphics.FillPolygon()
Is your friend. Hit testing is relatively trivial, with several algorithms available
You want to use the System.Drawing namespace to initially create a graphics object from your source image..then you want to draw on top of it, and finally export your edited graphics object to the filesystem...
Image image = Image.FromFile(Server.MapPath(String.Format("~/{0}.jpg", "YourImageNameHere")));
Graphics MyGraphic = Graphics.FromImage(LabelImage);
MyGraphic.DrawRectangle(SomePenObject, Point1, Point2, Point3, Point4);
Image.Save("C:\somepath.jpg",ImageFormat.Jpeg);