前言
做桌面截屏功能时需要放大镜,显示鼠标所在位置的放大图像,在wpf中使用Bursh的ViewBox属性可以实现图像放大,桌面的画面则需要截屏了,总的来说还是比较容易实现的。
一、如何实现?
1、制作无边框窗口
推荐使用WindowChrome
<Window Background="{x:Null}" ResizeMode="NoResize" WindowStyle="None">
WindowChrome放在Window 标签内
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" CaptionHeight="0" />
</WindowChrome.WindowChrome>
2、Viewbox放大
定义一个Ellipse 控件作为放大镜,Viewbox默认为相对单位,即范围时0-1,值越小放大越大
<Ellipse Stroke="LightBlue">
<Ellipse.Fill>
<ImageBrush x:Name="ib" Viewbox="0,0,0.5,0.5" />
</Ellipse.Fill>
/Ellipse>
3、截屏显示
(1)、截屏
参考《C# wpf 使用GDI+实现截屏》里的简单截屏即完成。获取的数据类型为Bitmap。
(2)、转BitmapSource
参考《C# wpf Bitmap转换成WriteableBitmap(BitmapSource)的方法》将Bitmap转换为转换成wpf对象。
(3)、显示
获取到BitmapSource给控件赋值即可。
//显示到界面
ib.ImageSource = wb;
4、定时截屏
显示桌面必然需要实时的画面,所以需要定时截屏。
//启动定时器,截屏
var dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(33), };
dispatcherTimer.Tick += (s, e) =>
{
//截屏并显示
};
dispatcherTimer.Start();
二、完整代码
完整代码依赖System.Drawing,添加引用方法可以参考《C# wpf 使用GDI+实现截屏》。
MainWindow.xaml
<Window x:Class="WpfMagnifier.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfMagnifier"
mc:Ignorable="d"
Background="{x:Null}"
ResizeMode="NoResize"
WindowStyle="None"
ShowInTaskbar="False"
Topmost="True"
Title="MainWindow" Height="200" Width="200"
MouseLeftButtonDown="Window_MouseDown">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" CaptionHeight="0" />
</WindowChrome.WindowChrome>
<Ellipse Stroke="LightBlue">
<Ellipse.Fill>
<ImageBrush x:Name="ib" Viewbox="0,0,0.5,0.5" />
</Ellipse.Fill>
</Ellipse>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfMagnifier
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//启动定时器,截屏
var dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(33), };
dispatcherTimer.Tick += (s, e) =>
{
//gdi+截屏,截取窗口左边的区域(可根据具体使用场景调整截屏位置),使用PointToScreen消除dpi影响
var leftTop = PointToScreen(new Point(-Width, 0));
var rightBottom = PointToScreen(new Point(0, Height));
var bm = Snapshot((int)leftTop.X, (int)leftTop.Y, (int)(rightBottom.X - leftTop.X), (int)(rightBottom.Y - leftTop.Y));
var wb = BitmapToWriteableBitmap(bm);
//显示到界面
ib.ImageSource = wb;
};
dispatcherTimer.Start();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
/// <summary>
/// 截取一帧图片
/// </summary>
/// <param name="x">x坐标</param>
/// <param name="y">y坐标</param>
/// <param name="width">宽</param>
/// <param name="height">高</param>
/// <returns>截屏后的位图对象,需要调用Dispose手动释放资源。</returns>
public static System.Drawing.Bitmap Snapshot(int x, int y, int width, int height)
{
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), System.Drawing.CopyPixelOperation.SourceCopy);
}
return bitmap;
}
//将Bitmap 转换成WriteableBitmap
public static WriteableBitmap BitmapToWriteableBitmap(System.Drawing.Bitmap src)
{
var wb = CreateCompatibleWriteableBitmap(src);
System.Drawing.Imaging.PixelFormat format = src.PixelFormat;
if (wb == null)
{
wb = new WriteableBitmap(src.Width, src.Height, 0, 0, System.Windows.Media.PixelFormats.Bgra32, null);
format = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
}
BitmapCopyToWriteableBitmap(src, wb, new System.Drawing.Rectangle(0, 0, src.Width, src.Height), 0, 0, format);
return wb;
}
//创建尺寸和格式与Bitmap兼容的WriteableBitmap
public static WriteableBitmap CreateCompatibleWriteableBitmap(System.Drawing.Bitmap src)
{
System.Windows.Media.PixelFormat format;
switch (src.PixelFormat)
{
case System.Drawing.Imaging.PixelFormat.Format16bppRgb555:
format = System.Windows.Media.PixelFormats.Bgr555;
break;
case System.Drawing.Imaging.PixelFormat.Format16bppRgb565:
format = System.Windows.Media.PixelFormats.Bgr565;
break;
case System.Drawing.Imaging.PixelFormat.Format24bppRgb:
format = System.Windows.Media.PixelFormats.Bgr24;
break;
case System.Drawing.Imaging.PixelFormat.Format32bppRgb:
format = System.Windows.Media.PixelFormats.Bgr32;
break;
case System.Drawing.Imaging.PixelFormat.Format32bppPArgb:
format = System.Windows.Media.PixelFormats.Pbgra32;
break;
case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
format = System.Windows.Media.PixelFormats.Bgra32;
break;
default:
return null;
}
return new WriteableBitmap(src.Width, src.Height, 0, 0, format, null);
}
//将Bitmap数据写入WriteableBitmap中
public static void BitmapCopyToWriteableBitmap(System.Drawing.Bitmap src, WriteableBitmap dst, System.Drawing.Rectangle srcRect, int destinationX, int destinationY, System.Drawing.Imaging.PixelFormat srcPixelFormat)
{
var data = src.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), src.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, srcPixelFormat);
dst.WritePixels(new Int32Rect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height), data.Scan0, data.Height * data.Stride, data.Stride, destinationX, destinationY);
src.UnlockBits(data);
}
}
}
三、效果预览
显示的是窗口(放大镜)左边的画面
总结
以上就是今天要讲的内容,本文仅仅简单介绍了实现桌面放大镜的方法,关键在于使用Viewbox,截屏的功能因为有现成的所以比较简单,当然本文的方法是简单实现,其实还是可以优化的,尤其是截屏是可以复用Bitmap对象的。总的来说,wpf实现桌面放大镜还是比较容易的,而且效果也很不错。