C# wpf implements desktop magnifying glass


Preface

When doing the desktop screenshot function, you need a magnifying glass to display the enlarged image of the mouse position. You can use Bursh's ViewBox property in WPF to achieve image magnification. You need to take a screenshot of the desktop screen. Generally speaking, it is relatively easy to implement.


1. How to achieve it?

1. Create a borderless window

It is recommended to use WindowChrome

<Window Background="{x:Null}" ResizeMode="NoResize"  WindowStyle="None">

WindowChrome is placed in the Window tag

<WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
</WindowChrome.WindowChrome>

2. Viewbox enlargement

Define an Ellipse control as a magnifying glass. The Viewbox defaults to relative units, that is, the range is 0-1. The smaller the value, the greater the magnification ratio.

<Ellipse Stroke="LightBlue">
   <Ellipse.Fill>
       <ImageBrush x:Name="ib" Viewbox="0,0,0.5,0.5" />
   </Ellipse.Fill>
</Ellipse>

3. Screenshot display

(1), screenshot

Refer to the simple screenshot in "C# wpf uses GDI+ to take screenshots" and you're done. The data type obtained is Bitmap.

(2), transfer to BitmapSource

Refer to "Method of Converting C# wpf Bitmap to WriteableBitmap (BitmapSource)" to convert the Bitmap into a wpf object.

(3), display

Just get the BitmapSource and assign a value to the control.

//显示到界面
ib.ImageSource = wb;

4. Scheduled screenshots

Displaying the desktop must require real-time images, so regular screenshots are required.

//启动定时器,截屏
var dispatcherTimer = new DispatcherTimer() {
    
     Interval = TimeSpan.FromMilliseconds(33), };
dispatcherTimer.Tick += (s, e) =>
{
    
    
   //截屏并显示
};
dispatcherTimer.Start();

2. Complete code

The complete code relies on System.Drawing. To add a reference method, please refer to "C# wpf uses GDI+ to implement screenshots" .

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);
        }
    }
}

3. Effect preview

What is displayed is the picture on the left side of the window (magnifying glass)
Insert image description here


Summarize

The above is what I will talk about today. This article only briefly introduces the method of implementing a desktop magnifying glass. The key is to use Viewbox. The screenshot function is relatively simple because it is ready. Of course, the method in this article is simple to implement, but it can still be optimized, especially Bitmap objects can be reused in screenshots. In general, it is relatively easy to implement a desktop magnifying glass in WPF, and the effect is very good.

Guess you like

Origin blog.csdn.net/u013113678/article/details/132743195