Canvas position to image pixel - wpf

I want to draw rectangles over an image to markup specific regions.
I saw this question: Draw Rectangle over Image and it worked. I get a rectangle over the image. Now i want to get the real pixel position on the image. I know i get some data over Canvas.Left, Canvas.Top but where is the relationship between Canvas and image position?
Thanks Lyror

To make this work you can easily put it in a viewbox like this:
<Viewbox> <!-- I will make this construct fit everywhere -->
<Grid> <!-- I will be exactly the size of the image -->
<Image Source="/MyImagegeWithResolutionOf1080x720p.jpg"
Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}"
Height="{Binding Source.PixelHeight, RelativeSource={RelativeSource Self}}"
Stretch="Fill"/>
<Canvas> <!-- use me to draw your stuff -->
<Rectangle Width="10" Height="10" Canvas.Bottom="360" Canvas.Left="540"/> <!-- I will be in the center -->
</Canvas>
</Grid>
</Viewbox>

Related

Helix3d WPF draw text at the top/left of HelixViewport3D

I want to show some text information at the top/left of HelixViewport3D like "ShowCameraInfo" does, which display camera information at the bottom/left of the Viewport. BillboardTextVisual3D requires a 3D point, but what I want is just like TextBlock on Canvas, which just need a 2D coordinate.
I can use TextBlock, but it cannot be captured as part of HelixViewport3D.
Any idea?
Literally a Textblock placed over the HelixViewport3D should be what you need.
There is only one problem: Viewport will not recognize if you try to manipulate the camera by initiating the mouse click on the Stackpanel.
<Grid>
<hx:HelixViewport3D>
<hx:DefaultLights/>
<hx:CubeVisual3D SideLength="7"/>
<hx:CubeVisual3D SideLength="5" Fill="Red" Center="-5,3,0"/>
</hx:HelixViewport3D>
<StackPanel Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel.Background>
<SolidColorBrush Color="#FFB6B6B6" Opacity="0.4"/>
</StackPanel.Background>
<TextBlock Text="asdhfasdvfmnas" Margin="5,2"/>
<TextBlock Text="mvcbnxcvjhbkdaf" Margin="5,2"/>
<TextBlock Text="vbkjsdvj" Margin="5,2"/>
</StackPanel>
</Grid>

Canvas with VisualBrush not rendering Image correctly

I've got a Canvas that I'm setting the Background property to a VisualBrush consisting of an Image. I'm data binding the Canvas' Width and Height to the Images' Width and Height. Here's the XAML:
<Canvas x:Name="imageCanvas" ClipToBounds="True" Width="{Binding ActualWidth, ElementName=dataImage}" Height="{Binding ActualHeight, ElementName=dataImage}"
Loaded="imageCanvas_Loaded" MouseMove="imageCanvas_MouseMove">
<Canvas.Background>
<VisualBrush Stretch="Uniform">
<VisualBrush.Visual>
<Image x:Name="dataImage" ClipToBounds="True" RenderOptions.BitmapScalingMode="HighQuality" Stretch="Uniform" Source="{Binding DataImage, Mode=OneWay}" LayoutTransform="{Binding DataImageLayoutTransform, Mode=OneWay}"/>
</VisualBrush.Visual>
</VisualBrush>
</Canvas.Background>
</Canvas>
Note that Image is using a LayoutTransform. I'm using this to stretch the width of the image. If I disable the LayoutTransform binding and run I get the following (properly) rendered output:
However, when I add the LayoutTransform to stretch the width of the image by a factor of 6, the image looks stretched correctly but it is too small i.e. it is not filling the Canvas uniformly:
I suspect this may have something to do with binding the Canvas Height/Width to the image height width, but it's not clear what the exact problem is. Can anyone provide some insight? Thank you in advance.

Canvas is clipped when size is too big

I am using a canvas with the an ImageBrush to dispaly an image. I am setting the size of the canvas to the original size of the image so I can get the coordinates when I move the mouse etc.
The problem is that when I put the canvas in a control (Grid for example) with a smaller size the Canvas is clipped.
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
Is there a way to keep the canvas size without being clipped?
I've been meaning to dig deeper in to the source to work out where the clipping occurs for a while now, but never get around to doing it. I've been using a not-so-nice trick of inserting a Canvas into the visual tree when this happens as a workaround.
There are a number of controls that clip the child visuals; Grid, StackPanel, etc. As I mentioned the usual quick fix is to use a Canvas after the container that causes the clip.
In your snippet are there more containers higher up the visual tree?
If the depth was actually something like this:-
<StackPanel>
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
</StackPanel>
Then this might cause clipping. If you insert another Canvas further up the visual tree then this clipping is removed.
<StackPanel>
<Canvas>
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
</Canvas>
</StackPanel>
This workaround can then become problematic if it alters other layout needs for other controls.

wpf stretch a line when resizing the canvas parent

I have a vertical line and a horizontal one that i want to resize when i dynamically resize my canvas parent. (landmark)
i'd like to have the horizontal line always 25 away from the left and right borders of my canvas and 13 away from the bottom border.
and the same for the vertical line, 25 away from the top and bottom borders and 13 from the left border.
Is there a simple solution?
May I have to change my canvas to another control?
Just stick the lines in a grid on top of your canvas to get the right behaviour
<Grid Width="600" Height="600">
<Canvas Background="LightBlue">
// stuff here
</Canvas>
<Grid>
<Rectangle Fill="Black" Height="1"
Stroke="Black" VerticalAlignment="Bottom" Margin="25,0,25,13"/>
<Rectangle Fill="Black"
HorizontalAlignment="Left" Stroke="Black" Width="1" Margin="13,25,0,25"/>
</Grid>
</Grid>
I would use Converters based on the ActualHeight and ActualWidth of your Canvas to set the height, width, and position of your Line objects
To avoid writing a bunch of individual converters, I have a MathConverter posted on my blog that can be used for all the calculations.
<Canvas x:Name="MyCanvas">
<!-- Horizontal Line: 25 from each side, and 13 from bottom -->
<!-- May need to adjust the Canvas.Top ConverterParameter based on Line height -->
<Line Height="1"
Canvas.Left="25"
Canvas.Top="{Binding ElementName=MyCanvas, Path=ActualHeight,
Converter={StaticResource MathConverter},
ConverterParameter=#VALUE-14}"
Width="{Binding ElementName=MyCanvas, Path=ActualWidth,
Converter={StaticResource MathConverter},
ConverterParameter=#VALUE-50}" ... />
<!-- Vertical Line: 25 from top and bottom, and 13 from left -->
<Line Canvas.Left="13" Canvas.Top="25"
Height="{Binding ElementName=MyCanvas, Path=ActualHeight,
Converter={StaticResource MathConverter},
ConverterParameter=#VALUE-50}" ... />
</Canvas>
Because these are all Bindings, they will get refreshed anytime the bound property changes (MyCanvas.ActualHeight and MyCanvas.ActualWidth)
Use Grid instead of Canvas in the case you need to set Margin.
For your lines to have space from the borders, go to Properties and use Margin in the Layout Area to set the spaces. For your horizontal line set the VerticalAlignment to Bottom and HorizontalAlignment to Stretch. The Margin shall be 25,0,25,13 in this case.
for your vertical line set the VerticalAlignment to Stretch an the HorizontalAlignment to Left. Margin should be 13,25,0,25
have luck

How can you align a canvas background in WPF?

I have set a canvas' background to an image of a company logo. I would like for this image to be aligned to the bottom right corner of the canvas.
Is it possible to do this, or would it require for the image to be added into the canvas as a child? That would not work with this program as all children of the canvas are handled differently.
Thank You
Will this work? (It worked for me, anyway.)
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="someimage.jpg" AlignmentX="Right"
AlignmentY="Bottom" Stretch="None" />
</Canvas.Background>
</Canvas>
AFAIK The WPF Canvas needs child UI elements to be positioned using absolute co-ordinates.
To achieve the right-bottom-anchored effect, I think you'd need to handle the window resize event, recalculate and apply the Top,Left co-ordinates for the child Image element to always stick to the right buttom corner.
<Window x:Class="HelloWPF.Window1" xmlns...
Title="Window1" Height="300" Width="339">
<Canvas>
<Image Canvas.Left="195" Canvas.Top="175" Height="87" Name="image1" Stretch="Fill" Width="122" Source="dilbert2666700071126ni1.gif"/>
</Canvas>
</Window>
How about containing the canvas and image inside of a Grid control like so?
<Window ...>
<Grid>
<Canvas/>
<Image HorizontalAlignment="Right" VerticalAlignment="Bottom" .../>
<Grid>
</Window>
This is my solution using a border inside the canvas to align the image. This solution works well when canvas is resized:
<Canvas x:Name="MiCanvas" Height="250" Width="500" Background="Aqua">
<Border x:Name="MiBorderImage"
Width="{Binding ElementName=MiCanvas, Path=ActualWidth}"
Height="{Binding ElementName=MiCanvas, Path=ActualHeight}"
Background="Transparent">
<Image x:Name="MiImage" Source="/GraphicsLibrary/Logos/MiLogo.png"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Stretch="None" />
</Border>
</Canvas>

Resources