WPF中对系统光标进行旋转平移操作

1、主要是实现对WPF中的光标进行旋转

2、代码如下

//https://stackoverflow.com/questions/18351872/how-to-convert-system-windows-input-cursor-to-imagesource
//https://wpf.2000things.com/2012/12/17/713-setting-the-cursor-to-an-image-of-an-uielement-while-dragging/
public class CursorHelper 
{
	private static class NativeMethods
	{
		public struct IconInfo
		{
			public bool fIcon;
			public int xHotspot;
			public int yHotspot;
			public IntPtr hbmMask;
			public IntPtr hbmColor;
		}

		[DllImport("user32.dll")]
		public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon);

		[DllImport("user32.dll")]
		public static extern bool DestroyIcon(IntPtr hIcon);

		[DllImport("user32.dll")]   
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);

		[DllImport("gdi32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool DeleteObject(IntPtr hObject);
	}

	[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
	private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
	{
		public SafeIconHandle()
			: base(true)
		{
		}

		override protected bool ReleaseHandle()
		{
			return NativeMethods.DestroyIcon(handle);
		}
	}

	public static Cursor BitmapToCursor(System.Drawing.Bitmap bmp)
	{
		var iconInfo = new NativeMethods.IconInfo();
		NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo);

		iconInfo.xHotspot = 0;
		iconInfo.yHotspot = 0;
		iconInfo.fIcon = false;

		SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
		return CursorInteropHelper.Create(cursorHandle);
	}

	public static Cursor CreateCursor(UIElement element)
	{
		element.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
		element.Arrange(new Rect(new System.Windows.Point(), element.DesiredSize));

		RenderTargetBitmap rtb =
		  new RenderTargetBitmap(
			(int)element.DesiredSize.Width,
			(int)element.DesiredSize.Height,
			96, 96, PixelFormats.Pbgra32);

		rtb.Render(element);

		var encoder = new PngBitmapEncoder();
		encoder.Frames.Add(BitmapFrame.Create(rtb));

		using (var ms = new MemoryStream())
		{
			encoder.Save(ms);
			using (var bmp = new System.Drawing.Bitmap(ms))
			{
				return BitmapToCursor(bmp);
			}
		}
	}

	/// <summary>
	/// Cursor转位图
	/// </summary>
	/// <param name="cur"></param>
	/// <returns></returns>
	public static Bitmap CursorToBitmap(System.Windows.Forms.Cursor cur)
	{
		//System.Drawing.Icon i = System.Drawing.Icon.ExtractAssociatedIcon(@"C:\Cursors\arrow.cur");
		//System.Drawing.Bitmap b = i.ToBitmap();

		var icon = System.Drawing.Icon.FromHandle(cur.Handle);
		System.Drawing.Bitmap bIcon = icon.ToBitmap();

		return bIcon;
	}

	/// <summary>
	/// Cursor转位图
	/// </summary>
	/// <param name="cur"></param>
	/// <returns></returns>
	public static Bitmap BitmapFromCursor(System.Windows.Forms.Cursor cur)
	{
		var iconInfo = new NativeMethods.IconInfo();
		NativeMethods.GetIconInfo(cur.Handle, ref iconInfo);

		Bitmap bmp = Bitmap.FromHbitmap(iconInfo.hbmColor);
		NativeMethods.DeleteObject(iconInfo.hbmColor);
		NativeMethods.DeleteObject(iconInfo.hbmMask);

		BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
		Bitmap dstBitmap = new Bitmap(bmData.Width, bmData.Height, bmData.Stride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, bmData.Scan0);
		bmp.UnlockBits(bmData);

		return new Bitmap(dstBitmap);
	}

	/// <summary>
	/// 旋转位图
	/// 使用GDI+
	/// </summary>
	/// <param name="bm"></param>
	/// <param name="angle"></param>
	/// <returns></returns>
	/// https://blog.csdn.net/lhtzbj12/article/details/54099572
	public static Bitmap RotateBitmap(Bitmap bm, float angle)
	{
		 https://docs.microsoft.com/zh-tw/dotnet/api/system.drawing.image.rotateflip?view=net-5.0
		// 不能任意角度旋转
		// bm.RotateFlip(RotateFlipType.Rotate180FlipY);
		// return bm;

		angle = angle % 360;
		//弧度转换
		double radian = angle * Math.PI / 180.0;
		double cos = Math.Cos(radian);
		double sin = Math.Sin(radian);
		//原图的宽和高
		int w = bm.Width;
		int h = bm.Height;
		int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin)));
		int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos)));

		//create a new empty bitmap to hold rotated image
		Bitmap returnBitmap = new Bitmap(W, H);
		//returnBitmap.SetResolution(bm.HorizontalResolution, bm.VerticalResolution);

		//make a graphics object from the empty bitmap
		Graphics g = Graphics.FromImage(returnBitmap);
		//计算偏移量
		System.Drawing.Point Offset = new System.Drawing.Point((W - w) / 2, (H - h) / 2);
		//构造图像显示区域:让图像的中心与窗口的中心点一致
		System.Drawing.Point center = new System.Drawing.Point(W / 2, H / 2);
		//g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
		g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
		//move rotation point to center of image
		g.TranslateTransform(center.X, center.Y);
		//rotate
		g.RotateTransform((float)angle);
		//move image back
		g.TranslateTransform(-center.X, -center.Y);
		//draw passed in image onto graphics object
		g.DrawImage(bm, new System.Drawing.Point(Offset.X, Offset.Y));
		g.Dispose();

		return returnBitmap;
	}

	/// <summary>
	/// 旋转位图
	/// </summary>
	/// <param name="bmp"></param>
	/// <param name="angle"></param>
	/// <returns></returns>
	/// https://stackoverflow.com/questions/12024406/how-can-i-rotate-an-image-by-any-degree
	public static Bitmap RotateImg(Bitmap bmp, float angle)
	{
		int w = bmp.Width;
		int h = bmp.Height;
		System.Drawing.Imaging.PixelFormat pf = bmp.PixelFormat;
		//System.Drawing.Color bkColor = System.Drawing.Color.Transparent;

		GraphicsPath path = new GraphicsPath();
		path.AddRectangle(new RectangleF(0f, 0f, w, h));
		System.Drawing.Drawing2D.Matrix mtrx = new System.Drawing.Drawing2D.Matrix();
		//Using System.Drawing.Drawing2D.Matrix class 
		mtrx.Rotate(angle);
		RectangleF rct = path.GetBounds(mtrx);
		Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
		Graphics g = Graphics.FromImage(newImg);
		g.Clear(System.Drawing.Color.LightBlue);
		g.TranslateTransform(-rct.X, -rct.Y);
		g.RotateTransform(angle);
		g.InterpolationMode = InterpolationMode.HighQualityBilinear;
		g.DrawImageUnscaled(bmp, 0, 0);
		g.Dispose();
		return newImg;
	}

	/// <summary>
	/// 旋转位图
	/// </summary>
	/// <param name="bm"></param>
	/// <param name="angle"></param>
	/// <returns></returns>
	/// http://csharphelper.com/blog/2016/03/rotate-images-in-c/
	public static Bitmap RotateBitmapByPath(Bitmap bm, float angle)
	{
		// Make a Matrix to represent rotation by this angle.
		System.Drawing.Drawing2D.Matrix rotate_at_origin = new System.Drawing.Drawing2D.Matrix();
		rotate_at_origin.Rotate(angle);

		// Rotate the image's corners to see how big
		// it will be after rotation.
		PointF[] points =
		{
			new PointF(0, 0),
			new PointF(bm.Width, 0),
			new PointF(bm.Width, bm.Height),
			new PointF(0, bm.Height),
		};
		rotate_at_origin.TransformPoints(points);
		float xmin, xmax, ymin, ymax;
		GetPointBounds(points, out xmin, out xmax, out ymin, out ymax);

		// Make a bitmap to hold the rotated result.
		int wid = (int)Math.Round(xmax - xmin);
		int hgt = (int)Math.Round(ymax - ymin);
		Bitmap result = new Bitmap(wid, hgt);

		// Create the real rotation transformation.
		System.Drawing.Drawing2D.Matrix rotate_at_center = new System.Drawing.Drawing2D.Matrix();
		rotate_at_center.RotateAt(angle,
			new PointF(wid / 2f, hgt / 2f));

		// Draw the image onto the new bitmap rotated.
		using (Graphics gr = Graphics.FromImage(result))
		{
			// Use smooth image interpolation.
			gr.InterpolationMode = InterpolationMode.High;

			// Clear with the color in the image's upper left corner.
			//gr.Clear(bm.GetPixel(0, 0));

			 For debugging. (Makes it easier to see the background.)
			// gr.Clear(System.Drawing.Color.LightBlue);

			// Set up the transformation to rotate.
			gr.Transform = rotate_at_center;

			// Draw the image centered on the bitmap.
			int x = (wid - bm.Width) / 2;
			int y = (hgt - bm.Height) / 2;
			gr.DrawImage(bm, x, y);
		}

		// Return the result bitmap.
		return result;
	}

	/// <summary>
	/// Find the bounding rectangle for an array of points.
	/// </summary>
	/// <param name="points"></param>
	/// <param name="xmin"></param>
	/// <param name="xmax"></param>
	/// <param name="ymin"></param>
	/// <param name="ymax"></param>
	private static void GetPointBounds(PointF[] points, out float xmin, out float xmax, out float ymin, out float ymax)
	{
		xmin = points[0].X;
		xmax = xmin;
		ymin = points[0].Y;
		ymax = ymin;
		foreach (PointF point in points)
		{
			if (xmin > point.X) xmin = point.X;
			if (xmax < point.X) xmax = point.X;
			if (ymin > point.Y) ymin = point.Y;
			if (ymax < point.Y) ymax = point.Y;
		}
	}

	/// <summary>
	/// 使用WPF变换位图
	/// </summary>
	/// <param name="bm"></param>
	/// <param name="angle"></param>
	/// <returns></returns>
	/// https://stackoverflow.com/questions/6084585/wpf-drawingvisual-on-a-background-thread
	/// https://social.msdn.microsoft.com/Forums/vstudio/en-US/b1a2c1f4-fa1f-440a-ba5b-ea9d2fe3a38f/background-image-and-color-setting-in-canvas?forum=wpf
	public static Bitmap TransformBitmap(Bitmap bm, float angle)
	{
		angle = angle % 360;
		//弧度转换
		double radian = angle * Math.PI / 180.0;
		double cos = Math.Cos(radian);
		double sin = Math.Sin(radian);
		//原图的宽和高
		int w = bm.Width;
		int h = bm.Height;
		int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin)));
		int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos)));

		// Create DrawingVisual and get its drawing context
		DrawingVisual dv = new DrawingVisual();
		DrawingContext dc = dv.RenderOpen();

		BitmapImage bitmap = new BitmapImage();
		using (MemoryStream ms = new MemoryStream())
		{
			// 注意需要使用ImageFormat.Png或ImageFormat.Jpeg
			// 如果使用Image.Bmp,则生成的位图背景为黑色
			bm.Save(ms, ImageFormat.Png);

			bitmap.BeginInit();
			bitmap.CacheOption = BitmapCacheOption.OnLoad;
			bitmap.StreamSource = ms;
			bitmap.EndInit();

			// 平移变换
			dc.PushTransform(new TranslateTransform((W - w) / 2, (H - h) / 2));
			// 旋转变换
			dc.PushTransform(new RotateTransform(angle, bm.Width / 2, bm.Height / 2));                
			dc.DrawImage(bitmap, new Rect(0, 0, bm.Width, bm.Height));
			dc.Pop();
			dc.Pop();
		}
        // 必须先关闭,如果在return resultBmp前一句位置处关闭
        // 则出现的是全黑的位图
		dc.Close();

		var renderBitmap = new RenderTargetBitmap(bitmap.PixelWidth, bitmap.PixelHeight, bitmap.DpiX, bitmap.DpiY, PixelFormats.Pbgra32);
		renderBitmap.Render(dv);
		System.Drawing.Bitmap resultBmp = null;
		using (MemoryStream outStream = new MemoryStream())
		{
			// 注意使用PngBitmapEncoder或JpegBitmapEncoder
			// 使用BmpBitmapEncoder生成的位图变成了黑色
			BitmapEncoder enc = new PngBitmapEncoder();
			enc.Frames.Add(BitmapFrame.Create(renderBitmap));
			enc.Save(outStream);
			resultBmp = new System.Drawing.Bitmap(outStream);
		}

		//using (FileStream fi = new FileStream("c:\\test.bmp", FileMode.Create))
		//{
		//    BitmapEncoder enc = new PngBitmapEncoder();
		//    enc.Frames.Add(BitmapFrame.Create(renderBitmap));
		//    enc.Save(fi);
		//}
		return resultBmp;
	}
}

3、调用如下:

RotateCursor(System.Windows.Forms.Cursors.SizeNS);
/// <summary>
/// 旋转光标
/// </summary>
/// <param name="cursor"></param>
/// <returns></returns>
private Cursor RotateCursor(System.Windows.Forms.Cursor cursor)
{
	var bm = CursorHelper.BitmapFromCursor(cursor);
	//bm = CursorHelper.RotateBitmapByPath(bm, (float)this.rotateAngle);
	bm = CursorHelper.TransformBitmap(bm, (float)this.rotateAngle);
	return CursorHelper.BitmapToCursor(bm);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LiveCharts控件提供了两种方法来实现缩放和平移: 1. 使用ZoomingOptions: 在XAML,可以通过设置ZoomingOptions属性来启用缩放和平移功能。例如,以下代码启用了鼠标滚轮缩放和拖动平移功能: ``` <lvc:CartesianChart ZoomingOptions="{x:Static lvc:ZoomingOptions.Xy}"> ... </lvc:CartesianChart> ``` ZoomingOptions属性有四个可选值: - None:禁用缩放和平移功能。 - X:启用水平缩放和平移功能。 - Y:启用垂直缩放和平移功能。 - Xy:启用水平和垂直缩放和平移功能。 2. 使用Zoom和Pan方法: 在代码,可以使用Zoom方法和Pan方法来实现缩放和平移。例如,以下代码实现了通过代码缩放和平移: ``` private void ZoomIn_Click(object sender, RoutedEventArgs e) { chart.Zoom(new Point(0, 0), ZoomDirection.ZoomIn); } private void ZoomOut_Click(object sender, RoutedEventArgs e) { chart.Zoom(new Point(0, 0), ZoomDirection.ZoomOut); } private void PanLeft_Click(object sender, RoutedEventArgs e) { chart.Pan(new Point(-10, 0)); } private void PanRight_Click(object sender, RoutedEventArgs e) { chart.Pan(new Point(10, 0)); } ``` 其,Zoom方法有两个参数:缩放心点和缩放方向。缩放心点是一个Point类型的值,表示缩放的心点。缩放方向是ZoomDirection枚举类型的值,表示缩放的方向,有ZoomIn和ZoomOut两个值。 Pan方法有一个参数:平移向量。平移向量是一个Point类型的值,表示平移的向量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值