星期二, 6月 21, 2022

[C#] 螢幕截圖含滑鼠指標

系統發生 Exception 時除了根據需求紀錄 Exception 外,在 WinForm 領域內常見會把螢幕截圖保留下來方便事後 debug,該篇紀錄螢幕截圖,還包含截圖當下的滑鼠指標並把滑鼠指標放大

範例應用重點內容

螢幕截圖範例

該範例預設應用程式為最大化,有三種截圖方式,分別為
  • 根據主螢幕
  • 根據應用程式所在螢幕
  • 多螢幕截圖
個人環境是筆電外接一個螢幕,有兩個螢幕可以進行螢幕截圖測試喔
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;

namespace CaptureScreenSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // 預設應用程式是最大化的
            WindowState = FormWindowState.Maximized;
        }

        #region 螢幕截圖

        private void btnPrimaryScreenCapture_Click(object sender, EventArgs e)
        {
            if (IsAppInPrimaryScreen() == false)
            {
                MessageBox.Show("應用程式不在主螢幕上,無法使用該功能進行截圖", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Rectangle screenRectangle = Screen.PrimaryScreen.Bounds;
            Point cursorPoint = Cursor.Position;
            string screenCatureFullName = @"D:\ScreenCapture\PrimaryScreenCapture.png";
            ScreenCaptureWorkFlow(screenRectangle, cursorPoint, screenCatureFullName);
        }

        private void btnAppScreenCapture_Click(object sender, EventArgs e)
        {
            Rectangle screenRectangle = GetAppInScreen().Bounds;
            // 要以應用程式 Form 位置為計算基準
            Point cursorPoint = PointToClient(Cursor.Position);
            string screenCatureFullName = @"D:\ScreenCapture\AppScreenCapture.png";
            ScreenCaptureWorkFlow(screenRectangle, cursorPoint, screenCatureFullName);
        }

        private void btnAllScreenCature_Click(object sender, EventArgs e)
        {
            Rectangle allScreenRectangle = GetAllScreenRectangle();
            Point cursorPoint = Cursor.Position;
            string screenCatureFullName = @"D:\ScreenCapture\AllScreenCapture.png";
            ScreenCaptureWorkFlow(allScreenRectangle, cursorPoint, screenCatureFullName);
        }

        private void ScreenCaptureWorkFlow(Rectangle screenRectangle, Point cursorPoint, string screenCatureFullName)
        {
            try
            {
                Image image = CaptureScreenIncludeCursor(screenRectangle, cursorPoint);
                PutImage(image, screenCatureFullName);
                image.Dispose();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private bool IsAppInPrimaryScreen()
        {
            return GetAppInScreen().Primary;
        }

        private Screen GetAppInScreen()
        {
            return Screen.FromControl(this);
        }

        private Rectangle GetAllScreenRectangle()
        {
            return Screen.AllScreens.Aggregate(
                new Rectangle(),
                (current, screen) => Rectangle.Union(current, screen.Bounds));
        }

        private Image CaptureScreenIncludeCursor(Rectangle screenRectangle, Point cursorPoint)
        {
            // 產生畫布
            Size screenSize = new Size(screenRectangle.Width, screenRectangle.Height);
            Bitmap image = new Bitmap(screenSize.Width, screenSize.Height);

            using (Graphics g = Graphics.FromImage(image))
            {
                // 螢幕截圖
                Point upperLeftSource = screenRectangle.Location;
                Point upperLeftDestination = Point.Empty; // Point.Empty 即為 Point(0, 0)
                g.CopyFromScreen(upperLeftSource, upperLeftDestination, screenSize);

                // 繪製滑鼠
                Rectangle cursorRectangle = GetCursorRectangle(cursorPoint);
                if (cursorRectangle != Rectangle.Empty)
                    Cursor.DrawStretched(g, cursorRectangle);
            }

            return image;
        }

        private Rectangle GetCursorRectangle(Point cursorPoint)
        {
            if (Cursor == Cursors.Hand ||
                Cursor.Current != Cursors.Default)
                return Rectangle.Empty;

            // 把滑鼠放大兩倍
            int rate = 2;
            int cursorWidth = Cursor.Size.Width * rate;
            int cursorHeight = Cursor.Size.Height * rate;
            Size cursorSize = new Size(cursorWidth, cursorHeight);

            return new Rectangle(cursorPoint, cursorSize);
        }

        private void PutImage(Image image, string imageFullName)
        {
            image.Save(imageFullName, ImageFormat.Png);
        }
        #endregion
    }
}

螢幕截圖成果

原本想說要把下面工具列裁掉,後來發現剛好可以用在是別主螢幕還是延伸螢幕,不過為了閱讀方便,還是有把多餘空間裁掉

主螢幕截圖,可以看到那兩倍大滑鼠指標在那

[C#] 螢幕截圖含滑鼠指標-1

延伸螢幕截圖,滑鼠指標也正確繪製在 Button 上

[C#] 螢幕截圖含滑鼠指標-2

延伸螢幕上使用主螢幕截圖,就被防呆下來,記錄如何識別主螢幕語法

[C#] 螢幕截圖含滑鼠指標-3

多螢幕截圖

[C#] 螢幕截圖含滑鼠指標-4


沒有留言:

張貼留言