在上一篇文章中,提到了以鼠标控制变换图片的方法。

这种方法在某种情况下可以,例如,直接在windows窗体上。但我发现,当把它封装到一个控件中的时候,它就不行了。

经过不断的尝试,我找到了一种更简单的方法,而且,封装到控件中也工作正常。

这里就要介绍WPF中另外一种变换:矩阵变换(MatrixTransform)。它就是通过对矩阵进行计算以改变图片的坐标系。

实际上,WPF中的所有变换,都是矩阵变换的特例。例如ScaleTransform、TranslateTransform等,都是通过MatrixTransform来实现的。而TransformGroup就是将ScaleTransform、TranslateTransform、

RotateTransform、SkewTransform等四种变换融合到MatrixTransform中进行计算。

因此,如果要控制图片的变形,可以直接使用MatrixTransform。而且,对于多种组合变换,它更简单。

这里还需要强调一个重点:

  // 这条代码在Mouse事件中

  // img为Iamge控件。而实际上可以是任何UIElement的实例

  Point start = e.GetPosition(img);

这条语句,获取到的点,其实是相对于img控件的原始坐标系的。不管img元素如何变换,获取到的点,只要鼠标的点不变,获取到的值永远不变。因此,如果想要以鼠标为中心点旋转、缩放,就需要将start点变换到控件现状的坐标系下(也就是鼠标在屏幕中的实际位置)。

直接上代码吧,其他的不解释了。

Xaml代码:

<Style TargetType="{x:Type rayCtl:ImgViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type rayCtl:ImgViewer}"> <Grid ClipToBounds="{TemplateBinding ClipToBounds}"> <Image Name="Part_Image" RenderOptions.BitmapScalingMode="NearestNeighbor" Source="{TemplateBinding Source}"/>

              <!-- 以下是控件按钮,以执行某些命令。如果不需要,可以删除 -->
<StackPanel Name="toolBar" Orientation="Horizontal" Opacity="0"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="0,0,15,0" > <StackPanel.Background>
<LinearGradientBrush>
<GradientStop Color="#EAE5C9" Offset="0"/>
<GradientStop Color="#6CC6CB" Offset="1"/>
</LinearGradientBrush>
</StackPanel.Background> <StackPanel.Resources> <ControlTemplate TargetType="Separator" x:Key="simpleSeparator">
<Border SnapsToDevicePixels="True"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" >
</Border>
</ControlTemplate> <Style TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Margin" Value="3"/>
</Style> <Style TargetType="Path">
<Setter Property="Fill" Value="White"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Stretch" Value="Uniform"/>
</Style> </StackPanel.Resources> <Button Command="rayCtl:TransformCommands.MoveLeft">
<Path Data="M896 544H250.4l242.4 242.4L448 832 173.6 557.6 128 512l45.6-45.6L448 192l45.6 45.6L250.4 480H896v64z" />
</Button> <Button Command="rayCtl:TransformCommands.MoveRight">
<Path Data="M128 480h645.6L530.4 237.6 576 192l274.4 274.4L896 512l-45.6 45.6L576 832l-45.6-45.6L773.6 544H128v-64z"/>
</Button> <Button Command="rayCtl:TransformCommands.MoveUp">
<Path Data="M480 896V250.4L237.6 493.6 192 448l274.4-274.4L512 128l45.6 45.6L832 448l-45.6 45.6L544 250.4V896h-64z"/>
</Button> <Button Command="rayCtl:TransformCommands.MoveDown">
<Path Data="M544 128v645.6l242.4-242.4L832 576l-274.4 274.4L512 896l-45.6-45.6L192 576l45.6-45.6L480 773.6V128h64z" />
</Button> <Separator Width="1" Template="{StaticResource simpleSeparator}"/> <Button Command="rayCtl:TransformCommands.RotateLeft">
<Path Data="M64 536.6c0.6-19.4 2.5-38.8 5.5-58l143 17.6c-1 13.5-1.2 27-0.5 40.4H64zM81.7 423.2c10.3-36.3 25.1-71.3 43.7-103.8l117.3 62.1c-11.4 24.2-19.7 49.6-24.9 75.5L81.7 423.2zM156.1 272.6c22.3-29.9 48.1-56.9 76.6-80.4l80.4 91c-19.6 19-36.7 40.2-51 63l-106-73.6zM277.4 159.7c31-19.8 64.3-35.8 98.9-47.6L415.2 215a336.57 336.57 0 0 0-71.1 41.5l-66.7-96.8zM429.1 97.8c35.6-7.4 71.9-10.4 107.8-9.1v98.6c-28.1 1.3-55.9 5.8-82.5 13.6L429.1 97.8zM590.5 93.8c35.5 5.5 70.2 15.4 103 29.2l-31 81.6c-27.1-8.9-55.2-14.5-83.4-16.6l11.4-94.2zM741.3 146.6c30.8 17.6 59.3 38.9 84.7 63.1l-50.3 56.8c-22.6-18.3-47.2-33.8-73.2-46l38.8-73.9zM861.8 248.2c22.3 27 41.2 56.5 56.2 87.8l-57 30c-14.9-25.5-32.8-49-53.1-70l53.9-47.8zM937.7 384c11.1 32.7 18.2 66.7 21 100.8l-52.8 6.4c-4.9-29.6-13.3-58.4-25-85.6l56.8-21.6zM960 535.9c-1.2 34-6.5 67.8-15.7 100.3l-40.6-9.9c6-29.8 8.2-60.2 6.9-90.3l49.4-0.1zM927.6 684c-13 31-29.8 60.3-49.7 87l-25.1-17.2c16.4-26.1 29.6-54.1 39.2-83.1l35.6 13.3zM845.7 809c-22.9 24-48.5 45.2-76.2 62.9l-10.9-15.6c25-18.9 47.5-40.8 67.1-64.9l20 17.6zM726.6 895.9c-29.5 14.2-60.5 24.7-92.3 31.3l-1.9-7.4c30.5-8.9 59.8-21.5 87-37.4l7.2 13.5zM586.1 934.2c-16.5 1.4-33 1.7-49.5 1.1 16.4-0.6 32.8-2.3 49-4.9l0.5 3.8z"/>
</Button> <TextBlock /> <Button Command="rayCtl:TransformCommands.RotateRight">
<Path Data="M158.6,104.8c0.1-2.6,0.1-5.3-0.1-7.9l27.9-3.4c0.6,3.8,1,7.5,1.1,11.3H158.6z M157.5,89.3c-1-5.1-2.6-10-4.9-14.7 l22.9-12.1c3.6,6.3,6.5,13.2,8.5,20.3L157.5,89.3z M148.8,67.6c-2.8-4.5-6.1-8.6-10-12.3l15.7-17.8c5.6,4.6,10.6,9.9,15,15.7 L148.8,67.6z M132.8,50.1c-4.3-3.3-8.9-6-13.9-8.1l7.6-20.1c6.8,2.3,13.3,5.4,19.3,9.3C145.8,31.2,132.8,50.1,132.8,50.1z M111.3,39.2c-5.2-1.5-10.6-2.4-16.1-2.7V17.3c7-0.3,14.1,0.3,21.1,1.8L111.3,39.2z M86.9,36.7c-5.5,0.4-11,1.5-16.3,3.2L64.6,24 c6.4-2.7,13.2-4.6,20.1-5.7L86.9,36.7z M62.8,43.1c-5.1,2.4-9.9,5.4-14.3,9L38.7,41c5-4.7,10.5-8.9,16.5-12.3L62.8,43.1z M31.7,48.5 l10.5,9.3c-4,4.1-7.5,8.7-10.4,13.7l-11.1-5.9C23.6,59.5,27.3,53.8,31.7,48.5L31.7,48.5z M27.9,79.2c-2.3,5.3-3.9,10.9-4.9,16.7 l-10.3-1.3c0.5-6.7,1.9-13.3,4.1-19.7C16.9,75,27.9,79.2,27.9,79.2z M12.5,104.7l9.6,0c-0.3,5.9,0.2,11.8,1.3,17.6l-7.9,1.9 C13.8,117.9,12.7,111.3,12.5,104.7L12.5,104.7z M25.8,131c1.9,5.7,4.5,11.1,7.7,16.2l-4.9,3.4c-3.9-5.2-7.2-10.9-9.7-17L25.8,131z M34.8,158l3.9-3.4c3.8,4.7,8.2,9,13.1,12.7l-2.1,3C44.3,166.8,39.3,162.7,34.8,158L34.8,158z M58.1,175l1.4-2.6 c5.3,3.1,11,5.6,17,7.3l-0.4,1.4C69.9,179.8,63.8,177.8,58.1,175L58.1,175z M85.5,182.5l0.1-0.7c3.2,0.5,6.4,0.8,9.6,1 C92,182.8,88.8,182.7,85.5,182.5L85.5,182.5z"/>
</Button> <Separator Width="1" Template="{StaticResource simpleSeparator}"/> <Button Command="rayCtl:TransformCommands.Enlarge">
<Path>
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M763.221333 702.848L981.333333 921.002667 921.002667 981.333333l-218.154667-218.112A403.626667 403.626667 0 0 1 448 853.333333a405.333333 405.333333 0 1 1 405.333333-405.333333 403.626667 403.626667 0 0 1-90.112 254.848zM448 768a320 320 0 1 0 0-640 320 320 0 0 0 0 640z"/>
<PathGeometry Figures="M490.666667 405.333333h128v85.333334h-128v128h-85.333334v-128h-128v-85.333334h128v-128h85.333334z"/>
</GeometryGroup>
</Path.Data>
</Path>
</Button> <TextBlock /> <Button Command="rayCtl:TransformCommands.Reduce">
<Path>
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M763.221333 702.848L981.333333 921.002667 921.002667 981.333333l-218.154667-218.112A403.626667 403.626667 0 0 1 448 853.333333a405.333333 405.333333 0 1 1 405.333333-405.333333 403.626667 403.626667 0 0 1-90.112 254.848zM448 768a320 320 0 1 0 0-640 320 320 0 0 0 0 640z"/>
<PathGeometry Figures="M277.333333 512v-85.333333h341.333334v85.333333z"/>
</GeometryGroup>
</Path.Data>
</Path>
</Button> <Separator Width="1" Template="{StaticResource simpleSeparator}"/> <Button Command="rayCtl:TransformCommands.FlipX">
<Path Data="M507.164444 913.92h398.222223l-397.653334-796.444444v796.444444M450.275556 913.92h-398.222223l398.222223-796.444444v796.444444m-42.382223-56.888889v-568.888889l-284.444444 568.888889h284.444444"/>
</Button> <Button Command="rayCtl:TransformCommands.FlipY">
<Path Data="M724.48 202.808889l-224.142222 206.791111L275.911111 202.808889h448.568889m145.635556-56.888889h-739.555556l369.777778 341.333333 369.777778-341.333333zM500.337778 544.142222l-369.777778 341.333334h739.555556l-369.777778-341.333334z" />
</Button> <Separator Width="1" Template="{StaticResource simpleSeparator}"/> <Button Command="rayCtl:TransformCommands.Reset">
<Path Data="M750.72 170.666667h-111.061333V85.333333h256.170666v256.256h-85.290666V231.424l-196.010667 195.157333-60.16-60.458666 196.352-195.498667z m-0.64 640l-195.712-195.84 60.330667-60.288L810.666667 750.677333v-110.848H896V896h-256.341333v-85.333333h110.421333zM170.666667 750.677333l195.413333-196.096 60.416 60.245334L231.168 810.666667h110.506667V896H85.333333v-256.170667h85.290667v110.805334zM170.666667 230.613333v111.061334H85.333333V85.333333h254.506667v85.333334H231.424L426.666667 366.421333 366.250667 426.666667z"/>
</Button> </StackPanel>
</Grid>

            <!-- 触发器只是为了让按钮显示,如果没有按钮,可以删除 -->
<ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="toolBar" Property="Opacity" Value="1" />
</Trigger>
</ControlTemplate.Triggers> </ControlTemplate>
</Setter.Value>
</Setter>
</Style>

后台代码:

namespace RaymondLib.Controls
{
[TemplatePart(Name = elementName, Type =typeof(Image))]
public class ImgViewer : Control
{
const string elementName = "Part_Image";
Image? img;
MatrixTransform tranformer; // 变形器 Point geometryCenter; // img的几何中心
Point moveStart;
Point rotateStart;
bool mouseDown;
bool executable; // 命令是否能执 #region 依赖属性 internal static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source", typeof(BitmapSource), typeof(ImgViewer), new PropertyMetadata(null)); /// <summary>
/// 图片的源
/// </summary>
public BitmapSource Source
{
get => (BitmapSource)GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
#endregion static ImgViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ImgViewer), new FrameworkPropertyMetadata(typeof(ImgViewer)));
} public ImgViewer()
{
// 注册命令
CommandBindings.Add(new CommandBinding(TransformCommands.MoveUp, OnMoveUp));
CommandBindings.Add(new CommandBinding(TransformCommands.MoveDown, OnMoveDown));
CommandBindings.Add(new CommandBinding(TransformCommands.MoveLeft, OnMoveLeft));
CommandBindings.Add(new CommandBinding(TransformCommands.MoveRight, OnMoveRight));
CommandBindings.Add(new CommandBinding(TransformCommands.RotateLeft, OnRotateLeft));
CommandBindings.Add(new CommandBinding(TransformCommands.RotateRight, OnRotateRight));
CommandBindings.Add(new CommandBinding(TransformCommands.Enlarge, OnEnlarge));
CommandBindings.Add(new CommandBinding(TransformCommands.Reduce, OnReduce));
CommandBindings.Add(new CommandBinding(TransformCommands.FlipX, OnFlipX));
CommandBindings.Add(new CommandBinding(TransformCommands.FlipY, OnFlipY));
CommandBindings.Add(new CommandBinding(TransformCommands.Reset, OnReset));
}
#region 命令:对基础方法的调用 // 向上移动20
private void OnMoveUp(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoMove(0, -20);
} // 向下移动20
private void OnMoveDown(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoMove(0, 20);
} // 向左移动20
private void OnMoveLeft(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoMove(-20, 0);
} // 向右移动20
private void OnMoveRight(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoMove(20, 0);
} // 向左旋转90°
private void OnRotateLeft(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoRotate(-90);
} // 向右旋转90°
private void OnRotateRight(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoRotate(90);
} // 放大0.2倍
private void OnEnlarge(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoScale(true);
} // 缩小0.2倍
private void OnReduce(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoScale(false);
} // 垂直翻转命令
private void OnFlipY(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoVerFlip();
} // 水平翻转命令
private void OnFlipX(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoHorFlip();
} // 重置
private void OnReset(object sender, ExecutedRoutedEventArgs e)
{
if (executable) DoReset();
} #endregion #region 基础方法:平移、缩放、旋转 /// <summary>
/// 移动图片
/// </summary>
/// <param name="deltaX">水平方向增量</param>
/// <param name="deltaY">垂直方向增量</param>
private void DoMove(double deltaX,double deltaY)
{
Vector v = new Vector(deltaX, deltaY);
DoMove(v);
} /// <summary>
/// 移动图片
/// </summary>
/// <param name="vector">移动的向量</param>
private void DoMove(Vector vector)
{
Matrix temp = tranformer.Matrix;
Vector moveReal = temp.Transform(vector); // 将相对于图片原始坐标的向量,变换为经过变换的向量,其实就是考虑到了旋转、翻转的情况
temp.Translate(moveReal.X, moveReal.Y);
tranformer.Matrix = temp;
} /// <summary>
/// 缩放元素:以几何中心点为缩放中心点。
/// 最小缩放0.2倍,最大30倍
/// </summary>
/// <param name="delta">缩放倍率的增量</param>
private void DoScale(bool enlarge)
{
DoScale(enlarge, geometryCenter);
} /// <summary>
/// 缩放元素
/// </summary>
/// <param name="delta">缩放倍率</param>
/// <param name="center">缩放的中心点。这个中心点就是e.GetPosition(img)获取到的点</param>
private void DoScale(bool enlarge,Point center)
{
Matrix temp = tranformer.Matrix;
Point centerReal = temp.Transform(center);    // 将相对于img原始坐标的点,变换成现状坐标系的点(鼠标在屏幕中的位置) // 缩放倍率分为三段:
// 小于0.2时,只允许放大
// 0.2-50之间,可以放大、缩小
// 大于50,只允许缩小 if(Math.Abs(temp.M11) < 0.2)
{
if (enlarge)
{
            // 这里需要注意:ScaleAt()方法内部将创建一个缩放倍数的矩阵与现有矩阵相乘。因此但给定一个小于1的缩放倍数,则实际将缩小图片
temp.ScaleAt(1.1, 1.1, centerReal.X, centerReal.Y);
}
}
else if (Math.Abs(temp.M11) > 50)
{
if(!enlarge)
{
temp.ScaleAt(0.9, 0.9, centerReal.X, centerReal.Y);
}0
}
else
{
if (enlarge)
{
temp.ScaleAt(1.1, 1.1, centerReal.X, centerReal.Y);
}
else
{
temp.ScaleAt(0.9, 0.9, centerReal.X, centerReal.Y);
}
}
tranformer.Matrix = temp;
} /// <summary>
/// 旋转元素:以几何中心点为旋转中心点
/// </summary>
/// <param name="angle">旋转的角度增量</param>
private void DoRotate(double angle)
{
DoRotate(angle, geometryCenter);
} /// <summary>
/// 旋转元素
/// </summary>
/// <param name="angle">旋转的角度增量</param>
/// <param name="center">旋转的中心点</param>
private void DoRotate(double angle,Point center)
{
Matrix temp = tranformer.Matrix;
Point centerReal = temp.Transform(center);
temp.RotateAt(angle, centerReal.X, centerReal.Y);
tranformer.Matrix = temp;
} /// <summary>
/// 水平翻转:以元素的几何中心为中心点水平翻转
/// </summary>
private void DoHorFlip()
{
Matrix temp = tranformer.Matrix;
temp.M11 *= -1;
temp.M21 *= -1;
temp.OffsetX = img.ActualWidth - temp.OffsetX;  // 以几何中心为原点,沿Y轴翻转
tranformer.Matrix = temp;
} /// <summary>
/// 垂直翻转:以元素的几何中心为中心点垂直翻转
/// </summary>
private void DoVerFlip()
{
Matrix temp = tranformer.Matrix;
temp.M12 *= -1;
temp.M22 *= -1;
temp.OffsetY = img.ActualHeight - temp.OffsetY;    // 以几何中心为原点,沿X轴翻转
tranformer.Matrix = temp;
} /// <summary>
/// 重置
/// </summary>
private void DoReset()
{
tranformer.Matrix = new Matrix();
} #endregion // 设置模板
public override void OnApplyTemplate()
{
executable = false;
if (img != null)
{
tranformer = null;
} img = GetTemplateChild(elementName) as Image;
if (img != null)
{
tranformer = new MatrixTransform();
img.RenderTransform = tranformer;
executable = true; // 命令是否能执行 // 鼠标事件
img.MouseLeftButtonDown += Element_MouseLeftButtonDown;
img.MouseRightButtonDown += Element_MouseRightButtonDown;
img.MouseMove += Element_MouseMove;
img.MouseUp += Element_MouseUp;
img.MouseWheel += Element_MouseWheel;
img.SizeChanged += Element_SizeChanged;
}
} // 尺寸发生改变时:中心发生变化
private void Element_SizeChanged(object sender, SizeChangedEventArgs e)
{
        // 这里应该使用img的ActualXX属性,因为img有可能控件在布局的时候,有可能缩放。
this.geometryCenter = new Point(img.ActualWidth / 2, img.ActualHeight / 2);
} // 按下鼠标左键
private void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
img.CaptureMouse();
mouseDown = true;
moveStart = e.GetPosition(img);
} private void Element_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
img.CaptureMouse();
mouseDown = true;
rotateStart = e.GetPosition(img);
} // 鼠标移动
private void Element_MouseMove(object sender, MouseEventArgs e)
{
if (!mouseDown) return;
Point mouseEnd = e.GetPosition(img);
if (e.LeftButton == MouseButtonState.Pressed)
{
var delta = mouseEnd - moveStart;
DoMove(delta.X, delta.Y);
//moveStart = mouseEnd;
}
else if(e.RightButton == MouseButtonState.Pressed)
{
// 按下鼠标右键,旋转图片
double angle = (mouseEnd.Y - rotateStart.Y) * 0.2;
DoRotate(angle,rotateStart);
resetRotater = true;
}
} // 释放鼠标
private void Element_MouseUp(object sender, MouseButtonEventArgs e)
{
img.ReleaseMouseCapture();
mouseDown = false;
} // 滚动鼠标滚轮
private void Element_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point scaleCenter = e.GetPosition(img);
bool enlarge = e.Delta > 0;
DoScale(enlarge, scaleCenter);
} }

   // 以下为该控件支持的命令
public static class TransformCommands
{
/// <summary>
/// 向上移动
/// </summary>
public static RoutedCommand MoveUp { get; } = new(nameof(MoveUp), typeof(TransformCommands)); /// <summary>
/// 向下移动
/// </summary>
public static RoutedCommand MoveDown { get; } = new(nameof(MoveDown), typeof(TransformCommands)); /// <summary>
/// 向左移动
/// </summary>
public static RoutedCommand MoveLeft { get; } = new(nameof(MoveLeft), typeof(TransformCommands)); /// <summary>
/// 向右移动
/// </summary>
public static RoutedCommand MoveRight { get; } = new(nameof(MoveRight), typeof(TransformCommands)); /// <summary>
/// 向左旋转
/// </summary>
public static RoutedCommand RotateLeft { get; } = new(nameof(RotateLeft), typeof(TransformCommands)); /// <summary>
/// 向右旋转
/// </summary>
public static RoutedCommand RotateRight { get; } = new(nameof(RotateRight), typeof(TransformCommands)); /// <summary>
/// 放大
/// </summary>
public static RoutedCommand Enlarge { get; } = new(nameof(Enlarge), typeof(TransformCommands)); /// <summary>
/// 缩小
/// </summary>
public static RoutedCommand Reduce { get; } = new(nameof(Reduce), typeof(TransformCommands)); /// <summary>
/// 水平翻转
/// </summary>
public static RoutedCommand FlipX { get; } = new(nameof(FlipX), typeof(TransformCommands)); /// <summary>
/// 垂直翻转
/// </summary>
public static RoutedCommand FlipY { get; } = new(nameof(FlipY), typeof(TransformCommands)); /// <summary>
/// 重置
/// </summary>
public static RoutedCommand Reset { get; } = new(nameof(Reset), typeof(TransformCommands));
}
}

以上为个人自己摸索所得。如有错误,还请高手指点。

WPF学习 - 用鼠标移动、缩放、旋转图片(2)- 使用MatrixTransform的更多相关文章

  1. Magnifier.js - 支持鼠标滚轮缩放的图片放大镜效果

    Magnifier.js 是一个 JavaScript 库,能够帮助你在图像上实现放大镜效果,支持使用鼠标滚轮放大/缩小功能.放大的图像可以显示在镜头本身或它的外部容器中.Magnifier.js 使 ...

  2. WPF通过鼠标滑轮缩放显示图片

    如果你使用WinForm比较难实现通过滚动鼠标滑轮来对图片进行缩放显示,那么,你应该考虑一下使用WPF,既然是下一代Windows客户端开发平台,明显是有一定优势的,不然,MS是吃饱了撑着.   首先 ...

  3. WPF学习笔记——为BUTTON添加背景图片

    首先要肯定,代码: <Style x:Key="UserItemButton" TargetType="Button"> <Setter Pr ...

  4. 在WPF里面实现以鼠标位置为中心缩放移动图片

    原文:在WPF里面实现以鼠标位置为中心缩放移动图片 在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片, ...

  5. WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示

    原文:WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示 为方便描述, 这里仅以正方形来做演示, 其他图形从略. 运行时效果图:XAML代码:// Transform.XAML< ...

  6. 【Thumbnailator】java 使用Thumbnailator实现等比例缩放图片,旋转图片等【转载】

    Thumbnailator概述:     Thumbnailator是与Java界面流畅的缩略图生成库.它简化了通过提供一个API允许精细的缩略图生成调整生产从现有的图像文件的缩略图和图像对象的过程, ...

  7. Java图片缩略图裁剪水印缩放旋转压缩转格式-Thumbnailator图像处理

    前言 java开发中经常遇到对图片的处理,JDK中也提供了对应的工具类,不过处理起来很麻烦,Thumbnailator是一个优秀的图片处理的开源Java类库,处理效果远比Java API的好,从API ...

  8. 【WPF学习】第五十三章 动画类型回顾

    创建动画面临的第一个挑战是为动画选择正确的属性.期望的结果(例如,在窗口中移动元素)与需要使用的属性(在这种情况下是Canvas.Left和Canvas.Top属性)之间的关系并不总是很直观.下面是一 ...

  9. WPF学习之路初识

    WPF学习之路初识   WPF 介绍 .NET Framework 4 .NET Framework 3.5 .NET Framework 3.0 Windows Presentation Found ...

  10. 在WPF设计工具Blend2中制作立方体图片效果

    原文:在WPF设计工具Blend2中制作立方体图片效果 ------------------------------------------------------------------------ ...

随机推荐

  1. 手机app抓包个人简述

    1.将在网上下载的手机软件放入apps 2.启动 3.查看结果 urls里是网址

  2. 探索JS中this的最终指向

    js 中的this 指向 一直是前端开发人员的一个痛点难点,项目中有很多bug往往是因为this指向不明确(this指向在函数定义时无法确定,只有在函数被调用时,才确定该this的指向为最终调用它的对 ...

  3. 代码随想录算法训练营Day17二叉树|110.平衡二叉树  257. 二叉树的所有路径 404.左叶子之和

    优先掌握递归 110.平衡二叉树 题目链接:110.平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树_每个节点_ 的左右两个子树的高度差的绝对 ...

  4. K8S 证书详解(认证)

    K8S 证书介绍 在 Kube-apiserver 中提供了很多认证方式,其中最常用的就是 TLS 认证,当然也有 BootstrapToken,BasicAuth 认证等,只要有一个认证通过,那么 ...

  5. nordic——NCS下的DFU升级(基于NCS)

    一.简介 在NCS中有多种的DFU选择,强烈推荐使用MCUboot,当然如果你需要选择传统的nrf_DFU也是可以的,但是要用到官方修改的源文件. 关于mcuboot,原理性的东西在官网和官方博客中有 ...

  6. STM32低功耗配置

    一.相关介绍 1.1 STM32下的电源管理 电源框图 电源标号说明 电压调节器 复位后调节器总是使能.以3种不同的模式工作. 运转模式:调节器以正常功耗模式提供1.8V电源(内核,内存和外设). 停 ...

  7. C++面试八股文:override和finial关键字有什么作用?

    某日二师兄参加XXX科技公司的C++工程师开发岗位第22面: (二师兄好苦逼,节假日还在面试...) 面试官:C++的继承了解吗? 二师兄:(不好意思,你面到我的强项了..)了解一些. 面试官:什么是 ...

  8. 如何通过AWS的云安全服务保护企业数据

    目录 随着企业数字化程度的不断加深,数据安全和隐私保护成为了企业面临的新的挑战.在数字化转型的过程中,企业需要处理大量的数据,这些数据的安全性和隐私保护的重要性不言而喻. AWS 云安全服务是Amaz ...

  9. PostgreSQL 12 文档: 部分 III. 服务器管理

    部分 III. 服务器管理 这部份覆盖了PostgreSQL数据库管理员感兴趣的主题.包括软件安装.搭建和配置一个服务器.管理用户和数据库以及维护任务.任何想要运行一个PostgreSQL服务器的人( ...

  10. 数据挖掘18大算法实现以及其他相关经典DM算法:决策分类,聚类,链接挖掘,关联挖掘,模式挖掘。图算法,搜索算法等

    数据挖掘18大算法实现以及其他相关经典DM算法:决策分类,聚类,链接挖掘,关联挖掘,模式挖掘.图算法,搜索算法等 算法码源见文末 1.算法目录 18大DM算法 包名 目录名 算法名 Associati ...