Height and Width of path data - wpf

I am new to WPF and have a Path data like:
M44.3364,36.7461C42.2004,42.9021,36.3504,47.3241,29.4644,47.3241C20.7724,47.3241,13.7244,40.2761,13.7244,31.5851
Now I want to get height and width of this path data, how to do it?

You may get the Bounds of the Path's Data:
<Path x:Name="path" Stroke="Black"
Data="M44.3364,36.7461C42.2004,42.9021,36.3504,47.3241,29.4644,47.3241C20.7724,47.3241,13.7244,40.2761,13.7244,31.5851"/>
Code:
Rect bounds = path.Data.Bounds;

Related

In WPF what is the proper method for drawing a line and PNGs on a bitmap that is attached to a canvas?

I don't do that much with WPF anymore and I always seem at a loss for the most basic things. I've tried the Googles but they're not helping.
I've got a canvas (maybe I shouldn't use a canvas?) and I want to attach an image. The only way that I could find to do this was like so:
<Canvas Grid.Column="2" HorizontalAlignment="Right" Height="822" VerticalAlignment="Top" Width="1198" Name="MainCanvas">
<Canvas.Background>
<ImageBrush ImageSource="/MapDesignModule;component/MapFrame.bmp" Stretch="None" AlignmentY="Top" AlignmentX="Right"/>
</Canvas.Background>
</Canvas>
Now, I need to draw lines on the image attached to the canvas (later I will also have to place transparent PNGs, or BMPs with white set to Alpha 0, on the image as well).
In the past I would get a writeablebitmap from the image.source but you apparently can't do that from an ImageBrush?
What is the 'proper way' to put an image on the screen and draw and blit images onto it?
Just put multiple Image and Line elements on top of each other in a common Panel, e.g. a Canvas:
<Canvas>
<Image Source="/MapDesignModule;component/MapFrame.bmp" />
<Image Source="/MapDesignModule;component/Overlay.png" />
<Line X1="100" Y1="100" X2="200" Y2="200" Stroke="Black" />
</Canvas>
You could also assign a name to the Canvas
<Canvas x:Name="canvas">
to access it in code behind:
canvas.Children.Add(new Image
{
Source = new BitmapImage(new Uri(
"pack://application:,,,/MapDesignModule;component/MapFrame.bmp"))
});
canvas.Children.Add(new Line
{
X1 = 100,
Y1 = 100,
X2 = 200,
Y2 = 200
});
In case you later want to add multiple shape overlays, you may consider using an ItemsControl with an appropriate view model, e.g. as shown here: https://stackoverflow.com/a/40190793/1136211

WPF Transform Rectangle in Canvas to Selection in Image

I have a rectangle on a canvas that the user can resize, move and so on to make a selection.
I also have an image the size of the screen behind the canvas (basically a screenshot).
I'd like to translate the selection (the rectangle) in the canvas to a 1:1 selection in the image (I want the image directly behind the rectangle) given I have the rectangle's Canvas.Top, Canvas.Left, Width, Height.
<Grid Name="MainGrid" SnapsToDevicePixels="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Image x:Name="MainImage" Stretch="None" RenderOptions.BitmapScalingMode="HighQuality"/>
<Border Background="Black" Opacity="0.4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Canvas Name="MainCanvas" Width="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}}" Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}}" Background="Transparent">
<ContentControl Name="SelectionRect" />
</ContentControl>
</Canvas>
</Grid>
I tried doing this: (MainImage is the image under the canvas)
Rect rect = new Rect(Canvas.GetLeft(SelectionRect), Canvas.GetTop(SelectionRect), SelectionRect.Width, SelectionRect.Height);
Rect from_rect = SelectionRect.TransformToVisual(this).TransformBounds(rect);
BitmapSource cropped_bitmap = new CroppedBitmap(MainImage.Source as BitmapSource,
new Int32Rect((int)from_rect.X, (int)from_rect.Y, (int)from_rect.Width, (int)from_rect.Height));
SelectionRectImageSource = cropped_bitmap;
But the image I get (SelectionRectImageSource) is a moved aside version of the actual pixels behind the selection rectangle.
So basically, I don't understand how these transformations work and how I should use them if at all.
Example:
Thanks a lot!
Dolev.
Looks like you need to correct for the DPI difference between the image (usually 72dpi) and the presentation source (usually 96dpi). Additionally, your first Rect should not be offset by Canvas.Left and Canvas.Top; TransformToVisual will take care of the relative offset for you.
var source = (BitmapSource)MainImage.Source;
var selectionRect = new Rect(SelectionRect.RenderSize);
var sourceRect = SelectionRect.TransformToVisual(MainImage)
.TransformBounds(selectionRect);
var xMultiplier = source.PixelWidth / MainImage.ActualWidth;
var yMultiplier = source.PixelHeight / MainImage.ActualHeight;
sourceRect.Scale(xMultiplier, yMultiplier);
var croppedBitmap = new CroppedBitmap(
source,
new Int32Rect(
(int)sourceRect.X,
(int)sourceRect.Y,
(int)sourceRect.Width,
(int)sourceRect.Height));
SelectionRectImageSource= croppedBitmap;
Depending on where this code resides, you may also need to transform the selection rectangle to MainImage instead of this (as I did).
Also, in case MainImage.Source is smaller than the actual MainImage control, you should probably set the horizontal and vertical alignments of MainImage to Left and Top, respectively, less your translated rectangle end up outside the bounds of the source image. You'll need to clamp the selection rectangle to the dimensions of MainImage too.

Get scaling factor of an image when the image goes out of grid

I have a grid that contains an image.
<Grid Name="grid1">
<Image Name="image1" Stretch="None" Source="C:\Users\User\Desktop\image.jpg"/>
</Grid>
If the size of image was greater than the size of the grid, I want to scale it manually by render transform to fit the grid. I don't want to use Stretch="Fill" because I need the scale factor.
Is there any way to detect the situation that an UIElement goes out of view?
I need your help.
You could simply set the Stretch property to Uniform (or perhaps Fill) and calculate the scaling factor from the ActualWidth of the Image and the Width of the ImageSource, whenever you need it. The sample below does the calculation in a SizeChanged handler, but it could be anywhere else.
<Image Name="image1" Stretch="Uniform" Source="C:\Users\User\Desktop\image.jpg"
SizeChanged="ImageSizeChanged"/>
The calculation looks like this:
private void ImageSizeChanged(object sender, SizeChangedEventArgs e)
{
var scale = image1.ActualWidth / image1.Source.Width;
}
As Uniform is the default value of the Stretch property, you wouldn't have to set it at all.
I'm not sure why you would want to rescale your image manually when WPF can do it for you...
Instead of putting the image straight into the grid, use a Viewbox control:
<Grid Name="grid1">
<Viewbox>
<Image Name="image1" Stretch="None" Source="C:\Users\User\Desktop\image.jpg"/>
</Viewbox>
</Grid>
The Viewbox will automatically scale the picture to fit inside the grid...

How to zoom image inside rectangle WPF

I am trying to zoom in and out image inside Rectangle control. But while doing so my entire Rectangle is getting zoomed in instead of just image inside that. for doing so I am using ScaleTransform and TranslateTranform on Rectangle. I should do the same on image instead of Rectangle but I dont know how? Could anyone please help me out.
XAML :
<Rectangle x:Name="LiveViewWindow" Fill="#FFF4F4F5" HorizontalAlignment="Right"
ClipToBounds="True" />
Code:
InteropBitmap m_LiveViewBitmapSource =Imaging.CreateBitmapSourceFromMemorySection(
section, width, height, PixelFormats.Bgr32, width*4, 0) as InteropBitmap;
ImageBrush m_BackgroundFrame = new ImageBrush(m_LiveViewBitmapSource);
RenderOptions.SetBitmapScalingMode(m_BackgroundFrame, BitmapScalingMode.LowQuality);
LiveViewWindow.Fill = m_BackgroundFrame;
n then for I am using Invalidate() property to render InteropBitmap to Rectangle.
You may set the Transform property of the ImageBrush. Get more information in Brush Transformation Overview.

Why ActualWidth and ActualHeight start from 0,0?

I want to add WPF Path to InkCanvas and use selection to select WPF Path.
So, I use this code.
System.Windows.Shapes.Path path = drawCanvas.Children[i] as System.Windows.Shapes.Path;
drawCanvas.Children.RemoveAt(i);
inkCanvas.Children.Add(path);
This is the output. I have to select WPF Path from 0,0 because Actualwidth and ActualHeight start from 0,0.
How do I select absolute WPF Path?
Thanks
Edit:
Now, I can select it absolutely by using this code.
System.Windows.Shapes.Path path = drawCanvas.Children[i] as System.Windows.Shapes.Path;
drawCanvas.Children.RemoveAt(i);
path.Margin = new Thickness(-getMinX(path), -getMinY(path), 0, 0);
containPath.Children.Add(path);
containPath.Width = getMaxX(path) - getMinX(path);
containPath.Height = getMaxY(path) - getMinY(path);
containPath.Margin = new Thickness(getMinX(path), getMinY(path), 0, 0);
inkCanvas.Children.Add(containPath);
You can use the UIElement.UpdateLayout Method on the InkCanvas to update the FrameworkElement.ActualWidth Property and ActualHeight. See the ActualWidth link for background information on why this is needed.
Edit:
I misunderstood the question. It wasn't that ActualWidth and ActualHeight were zero but that their values were relative to (0, 0) on the InkCanvas. A pretty good solution to the problem is to wrap the Path in a Canvas and position it using Margin like this:
<Canvas Width="50" Height="50" Margin="200,200,0,0">
<Line
X1="0" Y1="0"
X2="50" Y2="50"
Stroke="Black"
StrokeThickness="4" />
</Canvas>
which behaves like:
The disadvantage of this approach is the user has to lasso the Canvas which is a rectangle, not an arbitrary shape. Nevertheless, it's a lot better than having to lasso the object and the origin.
For elements that can only be defined via control points (eg Line, Path etc as against Rectangle, Ellipse etc) when you add it to an items control (which I assume the InkCanvas is since it supports selection), first a canvas is added to the panel at 0,0. The width and the Height of the canvas are determined from the maximum X and Y coordinates of the control points. After this the element is added as a child of this canvas.
You will also see that whenever you see this kind of behaviors with an element, the element wont support Layout Properties like Horizontal/Vertical alignment etc.
The only way I see around this is to find the ActualWidth and ActualHeight manually from the coordinates in the path.
Edit: This is from personal experience and not from any documentation.

Resources