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

这种方法在某种情况下可以,例如,直接在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. JAVA 23种设计模式(小白进阶必经之路)

    如今几乎所有程序都遵循万物皆对象的开发理念,然在写程序中我们用的最多的应该是封装(encapsulation).继承(inheritance).多态(Polymorphism)开发模式:而更高一个境界 ...

  2. qq飞车端游最全按键指法教学

    目录 起步篇 超级起步 弹射起步 段位起步 基础篇 点飘 撞墙漂移 撞墙点喷 进阶篇 双喷 叠喷 断位漂移 段位双喷 侧身漂移 快速出弯 CW WCW CWW 牵引 甩尾点飘 甩尾漂移 右侧卡 左侧卡 ...

  3. springboot接入influxdb

    转载请注明出处: 1.添加maven依赖 <dependency> <groupId>org.springframework.boot</groupId> < ...

  4. 海量数据运维要给力,GaussDB(for Cassandra)来助力

    摘要:应用运维管理平台(AOM)和Cassandra是两个不可分割的组成部分,它们共同构成了一个高效的解决方案,可以帮助企业在应用运维业务上取得巨大的优势.在这篇文章中,我们将介绍AOM和Cassan ...

  5. 【Netty】Netty部分源码分析(启动流程,EventLoop,accept流程,read流程)

    源码分析 Netty源码中调用链特别长,且涉及到线程切换等步骤,令人头大:) 1 启动剖析 我们就来看看 netty 中对下面的代码是怎样进行处理的 //1 netty 中使用 NioEventLoo ...

  6. 国产MCU兆易GD32实现矩阵按键扫描

    一.矩阵键盘     为了减少I/O口的占用,通常将按键排列成矩阵形式.在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接.使用8个io口来进行16个按键的控制读取,可以减 ...

  7. 6个常见的IB网络不通问题

    摘要:如果遇到IB网络不通,可以试着从高层往底层逐步分析看看. 本文分享自华为云社区<常见IB网络不通问题记录>,作者: tsjsdbd . 如果遇到IB网络不通,可以试着从高层往底层逐步 ...

  8. 深度解读AIGC存储解决方案

    5月26日,2023数据基础设施技术峰会在苏州举办,腾讯云首席存储技术专家温涛受邀出席并分享了腾讯云领先的存储技术在AIGC场景中的应用,通过对AIGC业务流程和场景的提炼,从内容生成.内容审核和内容 ...

  9. 根据模板动态生成word(三)使用poi-tl生成word

    @ 目录 一.前言 1.什么是poi-tl 2.官方信息 2.1 源码仓库 2.2 中文文档 2.3 开源协议 3.poi-tl的优势 3.1 poi-tl和其他模板引擎的对比 3.2 poi-tl ...

  10. Federated Learning002

    联邦学习笔记--002 2022.11.26周六 今天学习了联邦学习中又一篇很经典的论文--Federated Machine Learning: Concept and Applications(联 ...