I am working on a gallery app where i need show the images on Flipview. When in Flipview, i would like to zoom in/out of the image. Here's my code where i am trying to display an image and performing a composite transform on it.
<Image Source="Assets/WP_20150914_11_30_50_Pro.jpg"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
ManipulationDelta="img_intro_ManipulationDelta"
ManipulationMode="All">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
private void img_intro_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < 1.0) ct.ScaleX = 1.0;
if (ct.ScaleY < 1.0) ct.ScaleY = 1.0;
if (ct.ScaleX > 4.0) ct.ScaleX = 4.0;
if (ct.ScaleY > 4.0) ct.ScaleY = 4.0;
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
if (ct.TranslateY > (((img.ActualHeight * ct.ScaleY) - img.ActualHeight) / 2))
{
ct.TranslateY = (((img.ActualHeight * ct.ScaleY) - img.ActualHeight) / 2);
}
if (ct.TranslateY < 0 - ((((img.ActualHeight * ct.ScaleY) - img.ActualHeight)) / 2))
{
ct.TranslateY = 0 - ((((img.ActualHeight * ct.ScaleY) - img.ActualHeight)) / 2);
}
if (ct.TranslateX > (((img.ActualWidth * ct.ScaleX) - img.ActualWidth) / 2))
{
ct.TranslateX = (((img.ActualWidth * ct.ScaleX) - img.ActualWidth) / 2);
}
if (ct.TranslateX < 0 - ((((img.ActualWidth * ct.ScaleX) - img.ActualWidth)) / 2))
{
ct.TranslateX = 0 - ((((img.ActualWidth * ct.ScaleX) - img.ActualWidth)) / 2);
}
}
This works well without a Flipview. But when i add it to a flipview i won't be able to flip to the next item or previous item.
Any suggestions how to fix this ?
Rather than making use of manipulation delta put the image inside a scrollviewer, as it wont fire an event every time for manipulation to occur on the ui thread.
try some thing like
<Flipview>
<ScrollViewer MaxZoomFactor="4">
<Image>
</Image>
</Scrollviewer>
</Flipview>
Since m not having an IDE currently this is the best possible help, give a try and let me know.
Related
My requirement is to do pinch zooming in WPF platform. For that, i have created simple POC sample according to my requirement and it can be reproduced. Please find the snippets below
XAML:
<Grid>
<Image x:Name="JPGImage"
Source="TestImage.jpg"
IsManipulationEnabled="True"
ManipulationDelta="Image_ManipulationDelta"
ManipulationStarted="JPGImage_ManipulationStarted"
ManipulationCompleted="JPGImage_ManipulationCompleted"/>
</Grid>
C#:
private void Image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.DeltaManipulation.Translation.X + " " + e.DeltaManipulation.Translation.Y);
if (e.Manipulators.Count() > 1)
{
if (scale.ScaleX > 1.6 || scale.ScaleX < 0.5)
{
scale.ScaleX = 1;
scale.ScaleY = 1;
translation.X = 0;
translation.Y = 0;
this.JPGImage.RenderTransform = transformGroup;
}
else
{
if (isScale)
{
scale.ScaleX = previousCumlativeScale * e.DeltaManipulation.Scale.X;
scale.ScaleY = previousCumlativeScale * e.DeltaManipulation.Scale.Y;
var x = (e.ManipulationOrigin.X - previousXPosition) * (scale.ScaleX - 1);
var y = (e.ManipulationOrigin.Y - previousYPosition) * (scale.ScaleY - 1);
translation.X += x;
translation.Y += y;
}
else
{
scale.ScaleX *= e.DeltaManipulation.Scale.X;
scale.ScaleY *= e.DeltaManipulation.Scale.Y;
translation.X += e.DeltaManipulation.Translation.X;
translation.Y += e.DeltaManipulation.Translation.Y;
}
scale.CenterX = e.ManipulationOrigin.X;
scale.CenterY = e.ManipulationOrigin.Y;
this.JPGImage.RenderTransform = transformGroup;
}
previousCumlativeScale = scale.ScaleX;
previousTranslateX = translation.X;
previousTranslateY = translation.Y;
previousXPosition = scale.CenterX;
previousYPosition = scale.CenterY;
}
else
{
translation.X += e.DeltaManipulation.Translation.X;
translation.Y += e.DeltaManipulation.Translation.Y;
}
}
My problems are
If i try to Zoomout the image using pinch, then it get disappeared when its scale value becomes less than 1
Zooming is also not smooth
Also i have reset the zoom after certain level of scale (mentioned below) then the image is not get reset properly.
C#
if (scale.ScaleX > 1.6 || scale.ScaleX < 0.5)
{
scale.ScaleX = 1;
scale.ScaleY = 1;
translation.X = 0;
translation.Y = 0;
this.JPGImage.RenderTransform = transformGroup;
}
Please get the sample from the below link
WPFZooming
I have found the below issue only related to manipulation events in github
https://github.com/Microsoft/dotnet/issues/575
Could you please help me to resolve the problems?.
Thanks in advance
Vignesh.
Not sure why exactly your code seems so complicated. The following also works, where the important point is to handle the ManipulationDelta on the parent element of the Image element:
<Canvas IsManipulationEnabled="True"
ManipulationDelta="OnManipulationDelta">
<Image Source="...">
<Image.RenderTransform>
<MatrixTransform x:Name="imageTransform"/>
</Image.RenderTransform>
</Image>
</Canvas>
with this event handler:
private void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
var origin = e.ManipulationOrigin;
var delta = e.DeltaManipulation;
var scale = (delta.Scale.X + delta.Scale.Y) / 2; // mean value
var matrix = imageTransform.Matrix; // current transform matrix
matrix.ScaleAt(scale, scale, origin.X, origin.Y);
matrix.Translate(delta.Translation.X, delta.Translation.Y);
imageTransform.Matrix = matrix; // new transform matrix
}
I am doing a simple application in windows phone. Having two transparent frames, One on top and other on Bootom. Now i set two different images one in the Top frames and other in second one. Now i use Pinch Zoom in and Zoom out but my images overlap each other i want to prevent them from overlapping. How can i Do that Please Suggest? Here is My Pinch Zoom and Image drag Code
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
if (InitialScale * e.DistanceRatio > 2 || (InitialScale != 1 && e.DistanceRatio == 1) || InitialScale * e.DistanceRatio < 1)
return;
if (e.DistanceRatio < 0.05)
{
ImageTransformation.CenterX = 0;
ImageTransformation.CenterY = 0;
ImageTransformation.TranslateX = 0;
ImageTransformation.TranslateY = 0;
}
ImageTransformation.CenterX = Center.X;
ImageTransformation.CenterY = Center.Y;
if (this.Orientation == PageOrientation.Landscape)
{
ImageTransformation.ScaleX = InitialScale * (1 + (e.DistanceRatio - 1) * 1);
}
else
{
ImageTransformation.ScaleX = InitialScale * e.DistanceRatio;
}
ImageTransformation.ScaleY = ImageTransformation.ScaleX;
ImageTransformation.Rotation = Angle + e.TotalAngleDelta;
}
private void GestureListener_PinchStarted(object sender, PinchStartedGestureEventArgs e)
{
InitialScale = ImageTransformation.ScaleX;
Angle = ImageTransformation.Rotation; //to rotate image
// Calculate the center for the zooming
Point firstTouch = e.GetPosition(Myimage, 0);
Point secondTouch = e.GetPosition(Myimage, 1);
Center = new Point(firstTouch.X + (secondTouch.X - firstTouch.X) / 2.0, firstTouch.Y + (secondTouch.Y - firstTouch.Y) / 2.0);
}
private void Image_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
double centerX = ImageTransformation.CenterX;
double centerY = ImageTransformation.CenterY;
double translateX = ImageTransformation.TranslateX;
double translateY = ImageTransformation.TranslateY;
double scale = ImageTransformation.ScaleX;
double width = Myimage.ActualWidth;
double height = Myimage.ActualHeight;
// Verify limits to not allow the image to get out of area
if (centerX - scale * centerX + translateX + e.HorizontalChange < 120 && centerX + scale * (width - centerX) + translateX + e.HorizontalChange > 120)
{
ImageTransformation.TranslateX += e.HorizontalChange;
}
if (centerY - scale * centerY + translateY + e.VerticalChange < 120 && centerY + scale * (height - centerY) + translateY + e.VerticalChange > 120)
{
ImageTransformation.TranslateY += e.VerticalChange;
}
return;
}
And This is my XAML code:
<Grid x:Name="LayoutRoot" ManipulationDelta="OnManipulationDelta" Height="728" VerticalAlignment="Top">
<Image x:Name="MyImage" HorizontalAlignment="Left" Height="814" VerticalAlignment="Top" Width="495" Stretch="Fill" />
<Canvas x:Name="PenguinCanvas"
RenderTransformOrigin="0.3,0.3" ManipulationDelta="PenguinCanvas_ManipulationDelta">
<Canvas.RenderTransform>
<ScaleTransform x:Name="PenguinTransform" />
</Canvas.RenderTransform>
<Image x:Name="Myimage" RenderTransformOrigin="0,0" Height="246" Width="342" HorizontalAlignment="Left" Stretch="Fill" Canvas.Top="-72" Canvas.Left="83" >
<Image.RenderTransform>
<CompositeTransform x:Name="ImageTransformation" ScaleX="1" ScaleY="1" />
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener PinchStarted="GestureListener_PinchStarted" PinchDelta="OnPinchDelta" DragDelta="Image_DragDelta" />
</toolkit:GestureService.GestureListener>
</Image>
<Image x:Name="Myimage1" RenderTransformOrigin="0,0" Height="259" Width="322" ManipulationDelta="MainPage_ManipulationDelta1" HorizontalAlignment="Left" Stretch="Fill" Canvas.Left="83" Canvas.Top="307" >
<Image.RenderTransform>
<CompositeTransform x:Name="ImageTransformation1" ScaleX="1" ScaleY="1" />
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener PinchStarted="GestureListener_PinchStarted1" PinchDelta="OnPinchDelta1" DragDelta="Image_DragDelta1" />
</toolkit:GestureService.GestureListener>
</Image>
</Canvas>
<Image x:Name="img" Source="/Assets/new collage/c10.png" Stretch="Fill"/>
<Image x:Name="img1" Source="/Assets/new collage/c10.png" Stretch="Fill"/>
are you looking for UIElement.ClipToBounds Property?
I need help to bound the path or canvas in a boundary. What I want is, when I click the mouse-left-button, holding it and move for panning. It should not move when mouse pointer reach some boundary as BORDER. I'll add code here please help me out
XAML code:
<Border x:Name="OutMoastBorder" Height="820" Width="820" ClipToBounds="True" BorderThickness="2" BorderBrush="Black" Block.IsHyphenationEnabled="True">
<Border x:Name="clipBorder" Height="810" Width="810" BorderThickness="2" BorderBrush="Black" ClipToBounds="True">
<Canvas x:Name="CanvasPanel" Height="800" Width="800" Background="Beige">
</Canvas>
</Border>
</Border>
<Grid>
<Button Content="Original Size" Height="23" Name="btn_Original" Width="75" Click="btn_Original_Click" Margin="4,4,921,973" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="4,59,0,0" Name="txtNoOfZones" VerticalAlignment="Top" Width="120" MaxLength="2" PreviewTextInput="txtNoOfZones_PreviewTextInput" />
<Label Content="Enter a number below for No. of Zones" Height="28" HorizontalAlignment="Left" Margin="4,33,0,0" Name="label1" VerticalAlignment="Top" Width="220" FontFamily="Vijaya" FontSize="15" FontWeight="Bold" FontStyle="Normal" />
<Button Content="Zones" Height="23" HorizontalAlignment="Left" Margin="130,58,0,0" Name="btnNoOfZones" VerticalAlignment="Top" Width="41" Click="btnNoOfZones_Click" />
</Grid>
</Grid>
Code behind for zooming and panning:
void Zoom_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point p = e.MouseDevice.GetPosition(((Path)sender));
Matrix m = CanvasPanel.RenderTransform.Value;
if (e.Delta > 0)
m.ScaleAtPrepend(1.1, 1.1, p.X, p.Y);
else
m.ScaleAtPrepend(1 / 1.1, 1 / 1.1, p.X, p.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
// CanvasPanel.RenderTransformOrigin = new Point(0.5, 0.5);
}
private Point origin;
private Point start;
void Pan_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (((Path)sender).IsMouseCaptured) return;
((Path)sender).CaptureMouse();
start = e.GetPosition(clipBorder);
origin.X = CanvasPanel.RenderTransform.Value.OffsetX;
origin.Y = CanvasPanel.RenderTransform.Value.OffsetY;
}
void Pan_MouseLeftBtnUp(object sender, MouseButtonEventArgs e)
{
((Path)sender).ReleaseMouseCapture();
}
void Pan_MouseMove(object sender, MouseEventArgs e)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
private const int NoOfSectors = 180;
private const int NoOfZones = 5;
void OnLoaded(object sender, RoutedEventArgs args)
{
const double PIES = 2 * Math.PI / NoOfSectors;
Point center = new Point(CanvasPanel.ActualWidth / 2, CanvasPanel.ActualHeight / 2); // center (x,y) Co-ordinates to get center of canvas
double radius = 0.1 * Math.Min(CanvasPanel.ActualWidth, CanvasPanel.ActualHeight);
for (int s = 0; s <= NoOfSectors; s++)
{
for (int z = 1; z <= NoOfZones; z++)
{
Path path = new Path();
PathGeometry pathGeo = new PathGeometry();
PathFigure pathFig = new PathFigure();
double radians = 2 * Math.PI * s / NoOfSectors;
double outerRadius = radius * z;
double innerRadius = radius * ((z - 1));
Size outerArcSize = new Size(outerRadius, outerRadius);
Size innerArcSize = new Size(innerRadius, innerRadius);
Point p1_1st_LineSegment; //------------------------------> Points variable, to store each iterate point in these.
Point p2_1st_ArcSegment;
Point p3_2nd_LineSegment;
Point p4_2nd_ArcSegment;
p1_1st_LineSegment = new Point(center.X + innerRadius * Math.Cos(radians - PIES), center.Y - innerRadius * Math.Sin(radians - PIES)); // point for LINE from Center
p2_1st_ArcSegment = new Point(center.X + innerRadius * Math.Cos(radians), center.Y - innerRadius * Math.Sin(radians)); // point for ARC after the 1st LINE formation
p3_2nd_LineSegment = new Point(center.X + outerRadius * Math.Cos(radians), center.Y - outerRadius * Math.Sin(radians)); // Point for 2nd LINE after forming both LINE abd ARC
p4_2nd_ArcSegment = new Point(center.X + outerRadius * Math.Cos(radians - PIES), center.Y - outerRadius * Math.Sin(radians - PIES)); // Point for 2nd ARC which is Counter-CLockwise that closes a path
pathFig.StartPoint = center;
pathFig.Segments.Add(new LineSegment(p1_1st_LineSegment, true));
pathFig.Segments.Add(new ArcSegment(p2_1st_ArcSegment, innerArcSize, 1, false, SweepDirection.Clockwise, true));
pathFig.Segments.Add(new LineSegment(p3_2nd_LineSegment, true));
pathFig.Segments.Add(new ArcSegment(p4_2nd_ArcSegment, outerArcSize, 1, false, SweepDirection.Counterclockwise, true));
pathFig.IsClosed = false; //false because, path has to be close with ARC, not with LINE
pathFig.IsFilled = true;
pathGeo.Figures.Add(pathFig); // binding data to a Geometry
pathGeo.FillRule = FillRule.Nonzero;
path.Data = pathGeo; // binding whole geometry data to a path
path.Stroke = Brushes.Black;
path.Fill = Brushes.Silver;
path.StrokeThickness = 0.1;
// CanvasPanel.RenderTransformOrigin = new Point(0.5, 0.5); //--------------------> this makes "Canvas" to be Zoom from center
CanvasPanel.Children.Add(path); // binding to a CanvasPanel as a children
path.MouseLeftButtonDown += MouseLeftButtonClick; // calling Mouse-click-event
path.MouseWheel += Zoom_MouseWheel;
path.MouseLeftButtonDown += Pan_MouseLeftButtonDown;
path.MouseLeftButtonUp += Pan_MouseLeftBtnUp;
path.MouseMove += Pan_MouseMove;
}
}
Please help me out.
Regards,
Viswanath.
PLz replace the MouseMove event with this following code in code behind.
void Pan_MouseMove(object sender, MouseEventArgs e)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
if (p.X > 0 && p.Y > 0 && p.X < clipBorder.ActualWidth && p.Y < clipBorder.ActualHeight)
{
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
}
I have tested, this will surely solve this.
regards,
Viswa
I can drag this pictures to right or left,up,down It passed over an screens.I had zoom in and out. I want limit about that. Using windows phone 8.1 app.
After the transformation, brings the image back if it is out of the boundary. You can detect if the image is out of boundary by comparing the values of TranslateX/TranslateY and the width/height of the boundary. The boundary is the parent of the image (it is a Grid?), you need to debug the code to determine the boundary for TranslateX and TranslateY.
XAML
<Grid>
<Grid Name="container">
<Image Name="img_container" Source="/papers.co-mb00-baloon-fly-sea-wallpaper-1920x1080.jpg"
ManipulationDelta="Image_ManipulationDelta"
ManipulationMode="Scale,TranslateX,TranslateY"
Stretch="Uniform"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</Grid>
</Grid>
C#
int mincale = 1;
private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
//zoom
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
//checking
if (ct.ScaleX < mincale)
ct.ScaleX = mincale;
if (ct.ScaleY < mincale)
ct.ScaleY = mincale;
//drag whitle zooming.
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
//checking drag not passed over a screen.that's fails.
if (ct.TranslateX < 10 - img.ActualWidth * ct.ScaleX)
ct.TranslateX = 10 - img.ActualWidth * ct.ScaleX;
if (ct.TranslateX > container.ActualWidth - 10)
ct.TranslateX = container.ActualWidth - 10;
if (ct.TranslateY < 10 - img.ActualHeight * ct.ScaleY)
ct.TranslateY = 10 - img.ActualHeight * ct.ScaleY;
if (ct.TranslateY > container.ActualHeight - 10)
ct.TranslateY = container.ActualHeight - 10;
}
you can check for which resolution is there , according to set Image height and width.
var scalfactor = App.Current.Host.Content.ScaleFactor;
switch (scalfactor)
{
case 150:
//write code for 720p or other screen Resolution
break;
case 160:
//write code for Wxga screen Resolution
break;
case 100:
//write code for Wvga screen Resolution
break;
default:
throw new InvalidOperationException("Unknown resolution type");
}
Plz refer this link for more info
http://msdn.microsoft.com/en-us/library/windows/apps/jj206974%28v=vs.105%29.aspx
I'm going to finish a application but I have a problem about scroll selection. I has zoom in and out that's ok.I has asked so many question but no one are not reply.Help me about scroll... This picture is zooming in:
<ListView Name="lst_intro">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding link}"
Stretch="Uniform"
RenderTransformOrigin="0.5,0.5"
ManipulationDelta="img_intro_ManipulationDelta"
ManipulationMode="Scale">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void img_intro_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < mincale) ct.ScaleX = mincale;
if (ct.ScaleY < mincale) ct.ScaleY = mincale;
ScaleTransform scale=new ScaleTransform();
}
You set ManipulationMode="Scale", meaning you cannot drag it left/right/down/up - that is call a translation, set it as ManipulationMode="Scale,TranslateX,TranslateY".
In the event handler, similar to what you did for the Scale transform, you do a Translate transform.
private void img_intro_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (ct == null) return;
//Scale transform
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
if (ct.ScaleX < mincale) ct.ScaleX = mincale;
if (ct.ScaleY < mincale) ct.ScaleY = mincale;
//Translate transform
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
//Confine boundary
BringIntoBounds();
}
After the transformation, brings the image back if it is out of the boundary. You can detect if the image is out of boundary by comparing the values of TranslateX/TranslateY and the width/height of the boundary. The boundary is the parent of the image (it is a Grid?), you need to debug the code to determine the boundary for TranslateX and TranslateY.
public void BringIntoBounds()
{
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (ct == null) return;
//out of screen, left edge
if (ct.TranslateX < 10 - img.ActualWidth * ct.ScaleX)
{
ct.TranslateX = 10 - img.ActualWidth * ct.ScaleX;
}
//out of screen, right edge
if (ct.TranslateX > Container.ActualWidth - 10 )
{
ct.TranslateX = Container.ActualWidth - 10;
}
...do the same for Y.
}
kennyzx gave a very good answer but the part where you test if the image is out of boundaries isn't working for me... that's my solution:
private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
ct.ScaleX *= e.Delta.Scale;
ct.ScaleY *= e.Delta.Scale;
ct.ScaleX = Math.Min(4, Math.Max(1, ct.ScaleX));
ct.ScaleY = Math.Min(4, Math.Max(1, ct.ScaleY));
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
var translateY = (img.ActualHeight * ct.ScaleY - img.ActualHeight) / 2;
ct.TranslateY = Math.Min(translateY, Math.Max(0 - translateY, ct.TranslateY));
var translateX = (img.ActualWidth * ct.ScaleX - img.ActualWidth) / 2;
ct.TranslateX = Math.Min(translateX, Math.Max(0 - translateX, ct.TranslateX));
}