WPF Zooming with Slider Changing ScrollViewer Size - c#

I currently have the following code:
<ScrollViewer DockPanel.Dock="Top">
<InkCanvas Name="InkCanvasOnImage" Height="203">
<InkCanvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=ZoomSlider,Path=Value}" ScaleY="{Binding ElementName=ZoomSlider,Path=Value}"></ScaleTransform>
</InkCanvas.LayoutTransform>
</InkCanvas>
</ScrollViewer>
<Slider DockPanel.Dock="Top" Name="ZoomSlider" Value="1" Minimum="0.3" Maximum="3" Height="20" />
When I adjust the slider, the entire ScrollViewer is changing sizes, and moving the slider up and down in the application. What I intended was just the image that is inside the InkCanvas to zoom in and out. Am I using the right WPF control for this, or did I mess up somewhere? My understanding is that I'm altering the scale of the InkCanvas and not the ScrollViewer Dimensions with the Slider.

Apply Scale Transformation On Image Instead Of InkCanvas
<ScrollViewer DockPanel.Dock="Top">
<InkCanvas Name="InkCanvasOnImage" Height="203">
<Image Source="AddImageSourceHere">
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=ZoomSlider,Path=Value}" ScaleY="{Binding ElementName=ZoomSlider,Path=Value}"></ScaleTransform>
</Image.LayoutTransform>
</Image>
</InkCanvas>
</ScrollViewer>
<Slider DockPanel.Dock="Top" Name="ZoomSlider" Value="1" Minimum="0.3" Maximum="3" Height="20" />

Related

Crop content of rounded-corner border with image out of border

I need to move and rotate the image outside of the rounded border
example:
In How to make the contents of a round-cornered border be also round-cornered? find answer:
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Border1}" />
</Grid.OpacityMask>
<Border x:Name="Border1" CornerRadius="30" Background="Green" />
<TextBlock Text="asdas das d asd a sd a sda" />
</Grid>
This works if the elements do not go out of bounds.
If using rotate and/or margin like this:
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=_border1}" />
</Grid.OpacityMask>
<Border x:Name="_border1"
BorderThickness="0"
CornerRadius="30"
Background="Green" />
<TextBlock Text="SomeText"
Foreground="Yellow" />
<Image Source="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
Margin="-5 0 0 0"
Height="20"
Width="55"
Stretch="UniformToFill"
VerticalAlignment="Top"
HorizontalAlignment="Left"
RenderTransformOrigin="0.5 0.5">
<Image.RenderTransform>
<RotateTransform Angle="-7" />
</Image.RenderTransform>
</Image>
</Grid>
The rounding is displaced
How can I crop the image like in the first example? Thanks for your help.
Something is going wrong with the viewport calculation of the VisualBrush. Not sure if that is a bug in WPF.
A workaround could be setting the viewport in absolute units, with Rectangle instead of a Border:
<Grid.OpacityMask>
<VisualBrush
Visual="{Binding ElementName=rect}"
ViewportUnits="Absolute"
Viewport="{Binding ElementName=rect, Path=RenderedGeometry.Rect}"/>
</Grid.OpacityMask>
<Rectangle x:Name="rect" RadiusX="30" RadiusY="30" Fill="Green"/>
Or simpler, with setting the Clip property instead of OpacityMask, but still supporting resize:
<Grid Clip="{Binding ElementName=rect, Path=RenderedGeometry}">
<Rectangle RadiusX="30" RadiusY="30" Fill="Green" x:Name="rect"/>
...
</Grid>
I managed to achieve the desired result using Clip instead of OpacityMask. Then all the elements that need to be cropped must be children of the Border. If your Border needs to be dynamic, you need to bind the dimensions of the RectangleGeometry to the dimensions of the Border using Converter.
<Grid>
<Border BorderThickness="0"
CornerRadius="30"
Background="Green">
<Border.Clip>
<RectangleGeometry RadiusX="30" RadiusY="30" Rect="0,0,500,400"/>
</Border.Clip>
<Grid>
<TextBlock Text="SomeText"
Foreground="Yellow"/>
<Image Source="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
Margin="-5 0 0 0"
Height="20"
Width="55"
Stretch="UniformToFill"
VerticalAlignment="Top"
HorizontalAlignment="Left"
RenderTransformOrigin="0.5 0.5">
<Image.RenderTransform>
<RotateTransform Angle="-7"/>
</Image.RenderTransform>
</Image>
</Grid>
</Border>
</Grid>

How can I copy a Region of Interest into an image in WPF? [duplicate]

I want to show a specific area of an image in my WPF control.
Let's say the original image dimensions are 600x400 and I'm trying to show a rectangle inside that image, positioned on X=420,Y=330 with width=60, height=40.
So I tried to use ScaleTransform and calculate the scale factor as 10, and the RenderTransformOrigin to 0.75, 0.85.
But when I view the control I don't get the image I expected. (only the red rectangle).
The is the code:
<Grid>
<Button Width="600" Height="400">
<Button.Template>
<ControlTemplate>
<Grid ClipToBounds="True">
<Image Source="c:\temp\sample.bmp" Stretch="Uniform" RenderTransformOrigin="0.75, 0.85">
<Image.RenderTransform>
<ScaleTransform ScaleX="10" ScaleY="10" />
</Image.RenderTransform>
</Image>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
That the result:
You could use a CroppedBitmap:
<Image>
<Image.Source>
<CroppedBitmap Source="c:\temp\sample.bmp" SourceRect="420,330,60,40"/>
</Image.Source>
</Image>
Or you use an ImageBrush with an appropriate Viewbox:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="c:\temp\sample.bmp"
ViewboxUnits="Absolute" Viewbox="420,330,60,40"/>
</Grid.Background>
</Grid>

Pinch to Resize, Drag to Move the Image control - Implementation WP 8.1

My code for moving the image control is:
<Grid Name="grid" Width="400" Height="400" ManipulationMode="All"
ManipulationDelta="Grid_ManipulationDelta_1" Margin="0,58,0,182">
<Grid.RenderTransform>
<CompositeTransform x:Name="transform" />
</Grid.RenderTransform>
<Image x:Name="Image1" Source="Assets/SmallLogo.png" Stretch="None"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
Manipulation delta has code:
private void Grid_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (e.PointerDeviceType == PointerDeviceType.Touch)
{
this.transform.TranslateX += e.Delta.Translation.X;
this.transform.TranslateY += e.Delta.Translation.Y;
OutText.Text = sender.ToString();
}
else
{
e.Handled = true;
}
}
This works perfect when I move image wherever on my grid.
Now for resizing the image control I have different implementation,
<ScrollViewer x:Name="scrl2" SizeChanged="scrl_SizeChanged" ZoomMode="Enabled"
HorizontalScrollMode="Enabled" VerticalScrollMode="Enabled"
HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"
MinZoomFactor="0.1" MaxZoomFactor="10" Margin="0" VerticalAlignment="Bottom">
<Image Source="Assets/SmallLogo.png" Stretch="None"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ScrollViewer>
The scroll viewer can be resized here and image is child so it also can. And it changes size on runtime perfectly, but note that this is different code.
I want to implement both scenarios on image control, which seems logical, so I edit my xaml like this:
<Grid Name="grid" Width="400" Height="400" ManipulationMode="All"
ManipulationStarted="Grid_ManipulationStarted_1"
ManipulationCompleted="Grid_ManipulationCompleted_1"
ManipulationDelta="Grid_ManipulationDelta_1" Margin="0,58,0,182">
<Grid.RenderTransform>
<CompositeTransform x:Name="transform" />
</Grid.RenderTransform>
<ScrollViewer x:Name="scrl2" SizeChanged="scrl_SizeChanged"
ZoomMode="Enabled" HorizontalScrollMode="Enabled"
VerticalScrollMode="Enabled" HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
MinZoomFactor="0.1" MaxZoomFactor="10" Margin="0" VerticalAlignment="Bottom">
<Image x:Name="Image1" Source="Assets/SmallLogo.png" Stretch="None"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</ScrollViewer>
</Grid>
The RenderTransform should take care of movement and ScrollViewer should do pinch thing. But that does not work. In separate code when image is in scroll viewer only - pinch to zoom works, when image is in grid - drag to move works.
In the above code where I put image in ScrollViewer and that ScrollViewer in grid, only pinch to zoom works, movement does not work. I tried to undo the Horizontal Vertical alignment settings (set them to something null) but that is not possible. The image resizes, but remains always in the position it is set in alignment settings.
What is wrong in this implementation?

How to get the showing size of current image or image control

<ScrollViewer x:Name="imagescrollviewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<!--<Viewbox>-->
<Image x:Name="im" Source="{Binding JpgImageSource}" RenderTransformOrigin="0.5,0.5" Stretch="{Binding stretchstate}" >
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding Value,ElementName=scaleslider}" ScaleY="{Binding Value,ElementName=scaleslider}" CenterX="0.5" CenterY="0.5"/>
</Image.LayoutTransform>
</Image>
<!--</Viewbox>-->
</ScrollViewer>
<ToggleButton Width="80" Margin="5" IsChecked="{Binding checkstate}" Content="{Binding checkstate}">
<Slider x:Name="scaleslider" Orientation="Vertical" Height="100" Margin="5" HorizontalAlignment="Center" Maximum="4" Minimum="0.2" Value="1"/>
i use the slider to change the size showing , the togglebutton used to change size showing to adapt current window , but there is a problem , when the size larger than size when it adapts the window, i cannot make it apadt the window , while it is smaller ,it works.
Or is there any ways to get the size of current image control ,while resizing the window?

Prevent image crop when rotating using transform

I'm binding following XAML to RotateAngle property and it works great with one "but". Image displays cropped. Image control doesn't seem to be refreshing/resizing after rotation. Is there any way to force resize on image and scrollviewer?
<ScrollViewer Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" BorderThickness="0" HorizontalScrollBarVisibility="Auto">
<Image
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RotateAngle}"></RotateTransform>
</Image.RenderTransform>
</Image>
</ScrollViewer>
http://www.silverlight.net/content/samples/sl3/toolkitcontrolsamples/run/default.html
Go to this page, there is a control called LayoutTransformer. See the sample of that control. It handles rotation, scaling and skewing of images, textbox, listbox, etc.
You will get the code there.
Hope that helps.!
You can try:
<Image x:name="ctrl"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding DataContext.RotateAngle, ElementName=ctrl}"></RotateTransform>
</Image.RenderTransform>
</Image>
Or you can use:
<Image
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding DataContext.RotateAngle, RelativeSource={RelativeSource Self}}"></RotateTransform>
</Image.RenderTransform>
</Image>
Assuming you want to scale your image down to fit the original image space, you could use my CalculateConstraintScale method from here:
Silverlight Rotate & Scale a bitmap image to fit within rectangle without cropping to scale the image down based on the rotation.
Click here for a working testbed app created for that answer (looks like the image below):

Categories

Resources