如何在.NET 中编写屏幕录像机?

发布于 2024-08-06 06:06:51 字数 55 浏览 2 评论 0原文

有没有办法用C#制作屏幕录像机?如果是这样,有人知道我可以使用任何教程或有关该主题的任何信息吗?

Is there a way to make a screen recorder in C#? If so, does anybody know of any tutorials I could use or any information on the subject?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡墨 2024-08-13 06:06:51

看一下这段 VB.NET 代码。

Public Class ScreenRecorder

Private Shared tempDir As String = My.Computer.FileSystem.SpecialDirectories.Temp & "snapshot"
Private Shared snap As New System.Threading.Thread(AddressOf Snapshot)
Private Shared _Bounds As System.Drawing.Rectangle = System.Windows.Forms.Screen.PrimaryScreen.Bounds

Public Shared Property Bounds() As System.Drawing.Rectangle
    Get
        Return _Bounds
    End Get
    Set(ByVal value As System.Drawing.Rectangle)
        _Bounds = value
    End Set
End Property

Private Shared Sub Snapshot()
    If Not My.Computer.FileSystem.DirectoryExists(tempDir) Then _
        My.Computer.FileSystem.CreateDirectory(tempDir)
    Dim Co As Integer = 0
    Do
        Co += 1
        System.Threading.Thread.Sleep(50)
        Dim X As New System.Drawing.Bitmap(_Bounds.Width, _Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Using G = System.Drawing.Graphics.FromImage(X)
            G.CopyFromScreen(_Bounds.Location, New System.Drawing.Point(), _Bounds.Size)
            Dim CurBounds As New System.Drawing.Rectangle(System.Windows.Forms.Cursor.Position - Bounds.Location, System.Windows.Forms.Cursor.Current.Size)
            Forms.Cursors.Default.Draw(G, CurBounds)
        End Using
        Dim FS As New IO.FileStream(tempDir & FormatString(Co.ToString, 5, "0"c) & ".png", IO.FileMode.OpenOrCreate)
        X.Save(FS, System.Drawing.Imaging.ImageFormat.Png)
        X.Dispose()
        FS.Close()
    Loop
End Sub

Public Shared Sub ClearRecording()
    If My.Computer.FileSystem.DirectoryExists(tempDir) Then _
    My.Computer.FileSystem.DeleteDirectory(tempDir, FileIO.DeleteDirectoryOption.DeleteAllContents)
    My.Computer.FileSystem.CreateDirectory(tempDir)
End Sub

Public Shared Sub Save(ByVal Output As String)
    Dim G As New Windows.Media.Imaging.GifBitmapEncoder

    Dim X As New List(Of IO.FileStream)
    For Each Fi As String In My.Computer.FileSystem.GetFiles(tempDir, FileIO.SearchOption.SearchTopLevelOnly, "*.png")
        Dim TempStream As New IO.FileStream(Fi, IO.FileMode.Open)
        Dim Frame = Imaging.BitmapFrame.Create(TempStream)
        X.Add(TempStream)
        G.Frames.Add(Frame)
    Next
    Dim FS As New IO.FileStream(Output, IO.FileMode.OpenOrCreate)
    G.Save(FS)
    FS.Close()

    For Each St As IO.FileStream In X
        St.Close()

    Next

End Sub

Public Shared Sub Start()
    snap = New System.Threading.Thread(AddressOf Snapshot)
    snap.Start()
End Sub

Public Shared Sub [Stop]()
    snap.Abort()
End Sub

Private Shared Function FormatString(ByVal S As String, ByVal places As Integer, ByVal character As Char) As String
    If S.Length >= places Then Return S
    For X As Integer = S.Length To places
        S = character & S
    Next
    Return S
End Function

End Class

Take a look at this VB.NET code.

Public Class ScreenRecorder

Private Shared tempDir As String = My.Computer.FileSystem.SpecialDirectories.Temp & "snapshot"
Private Shared snap As New System.Threading.Thread(AddressOf Snapshot)
Private Shared _Bounds As System.Drawing.Rectangle = System.Windows.Forms.Screen.PrimaryScreen.Bounds

Public Shared Property Bounds() As System.Drawing.Rectangle
    Get
        Return _Bounds
    End Get
    Set(ByVal value As System.Drawing.Rectangle)
        _Bounds = value
    End Set
End Property

Private Shared Sub Snapshot()
    If Not My.Computer.FileSystem.DirectoryExists(tempDir) Then _
        My.Computer.FileSystem.CreateDirectory(tempDir)
    Dim Co As Integer = 0
    Do
        Co += 1
        System.Threading.Thread.Sleep(50)
        Dim X As New System.Drawing.Bitmap(_Bounds.Width, _Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Using G = System.Drawing.Graphics.FromImage(X)
            G.CopyFromScreen(_Bounds.Location, New System.Drawing.Point(), _Bounds.Size)
            Dim CurBounds As New System.Drawing.Rectangle(System.Windows.Forms.Cursor.Position - Bounds.Location, System.Windows.Forms.Cursor.Current.Size)
            Forms.Cursors.Default.Draw(G, CurBounds)
        End Using
        Dim FS As New IO.FileStream(tempDir & FormatString(Co.ToString, 5, "0"c) & ".png", IO.FileMode.OpenOrCreate)
        X.Save(FS, System.Drawing.Imaging.ImageFormat.Png)
        X.Dispose()
        FS.Close()
    Loop
End Sub

Public Shared Sub ClearRecording()
    If My.Computer.FileSystem.DirectoryExists(tempDir) Then _
    My.Computer.FileSystem.DeleteDirectory(tempDir, FileIO.DeleteDirectoryOption.DeleteAllContents)
    My.Computer.FileSystem.CreateDirectory(tempDir)
End Sub

Public Shared Sub Save(ByVal Output As String)
    Dim G As New Windows.Media.Imaging.GifBitmapEncoder

    Dim X As New List(Of IO.FileStream)
    For Each Fi As String In My.Computer.FileSystem.GetFiles(tempDir, FileIO.SearchOption.SearchTopLevelOnly, "*.png")
        Dim TempStream As New IO.FileStream(Fi, IO.FileMode.Open)
        Dim Frame = Imaging.BitmapFrame.Create(TempStream)
        X.Add(TempStream)
        G.Frames.Add(Frame)
    Next
    Dim FS As New IO.FileStream(Output, IO.FileMode.OpenOrCreate)
    G.Save(FS)
    FS.Close()

    For Each St As IO.FileStream In X
        St.Close()

    Next

End Sub

Public Shared Sub Start()
    snap = New System.Threading.Thread(AddressOf Snapshot)
    snap.Start()
End Sub

Public Shared Sub [Stop]()
    snap.Abort()
End Sub

Private Shared Function FormatString(ByVal S As String, ByVal places As Integer, ByVal character As Char) As String
    If S.Length >= places Then Return S
    For X As Integer = S.Length To places
        S = character & S
    Next
    Return S
End Function

End Class
嗫嚅 2024-08-13 06:06:51

我从 Lucas McCoy 获取了 VB.net 代码并将其转换为 C#。
录制 5 秒并将 gif 保存到桌面。 PS:有时当最后一个屏幕截图仍然通过线程中止,然后流尝试读取它时,我会收到错误。

代码非常慢。

using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;


namespace ConsoleApplication1
{

    public class ScreenRecorder
    {

        private static string tempDir = Path.GetTempPath() + "/snapshot/";
        private static System.Threading.Thread snap = new System.Threading.Thread(Snapshot);

        private static System.Drawing.Rectangle _Bounds = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
        public static System.Drawing.Rectangle Bounds
        {
            get { return _Bounds; }
            set { _Bounds = value; }
        }

        private static void Snapshot()
        {
            if (!Directory.Exists(tempDir))
                Directory.CreateDirectory(tempDir);
            int Co = 0;
            do
            {
                Co += 1;
                System.Threading.Thread.Sleep(50);
                System.Drawing.Bitmap X = new System.Drawing.Bitmap(_Bounds.Width, _Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using(System.Drawing.Graphics G = System.Drawing.Graphics.FromImage(X)) {
                    G.CopyFromScreen(_Bounds.Location, new System.Drawing.Point(), _Bounds.Size);
                    System.Drawing.Rectangle CurBounds = new System.Drawing.Rectangle(System.Drawing.Point.Subtract(System.Windows.Forms.Cursor.Position,Bounds.Size), System.Windows.Forms.Cursor.Current.Size);
                    System.Windows.Forms.Cursors.Default.Draw(G, CurBounds);
               }
                System.IO.FileStream FS = new System.IO.FileStream(tempDir + FormatString(Co.ToString(), 5, '0') + ".png", System.IO.FileMode.OpenOrCreate);
                X.Save(FS, System.Drawing.Imaging.ImageFormat.Png);
                X.Dispose();
                FS.Close();
            } while (true);
        }

        public static void ClearRecording()
        {
            if (Directory.Exists(tempDir))
                Directory.Delete(tempDir, true);
                Directory.CreateDirectory(tempDir);
        }

        public static void Save(string Output)
        {
            System.Windows.Media.Imaging.GifBitmapEncoder G = new System.Windows.Media.Imaging.GifBitmapEncoder();

            List<System.IO.FileStream> X = new List<System.IO.FileStream>();
            foreach (string Fi in Directory.GetFiles(tempDir, "*.png", SearchOption.TopDirectoryOnly))
            {
                System.IO.FileStream TempStream = new System.IO.FileStream(Fi, System.IO.FileMode.Open);
                System.Windows.Media.Imaging.BitmapFrame Frame = System.Windows.Media.Imaging.BitmapFrame.Create(TempStream);
                X.Add(TempStream);
                G.Frames.Add(Frame);
            }
            System.IO.FileStream FS = new System.IO.FileStream(Output, System.IO.FileMode.OpenOrCreate);
            G.Save(FS);
            FS.Close();

            foreach (System.IO.FileStream St in X)
            {
                St.Close();

            }

        }

        public static void Start()
        {
            snap = new System.Threading.Thread(Snapshot);
            snap.Start();
        }

        public static void Stop()
        {
            snap.Abort();
        }

        private static string FormatString(string S, int places, char character)
        {
            if (S.Length >= places)
                return S;
            for (int X = S.Length; X <= places; X++)
            {
                S = character + S;
            }
            return S;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            ScreenRecorder.Start();
            System.Threading.Thread.Sleep(5000);
            ScreenRecorder.Stop();
            ScreenRecorder.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\video.gif");
            ScreenRecorder.ClearRecording();
        }
    }
}

这些是我必须添加的参考:

在此处输入图像描述

I took the VB.net code from Lucas McCoy and turned it into C#.
This records for 5 seconds and saved the gif to desktop. PS: I get an error sometimes when the last screenshot is still aborting via the thread and then the stream tries to read it.

Very slow code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;


namespace ConsoleApplication1
{

    public class ScreenRecorder
    {

        private static string tempDir = Path.GetTempPath() + "/snapshot/";
        private static System.Threading.Thread snap = new System.Threading.Thread(Snapshot);

        private static System.Drawing.Rectangle _Bounds = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
        public static System.Drawing.Rectangle Bounds
        {
            get { return _Bounds; }
            set { _Bounds = value; }
        }

        private static void Snapshot()
        {
            if (!Directory.Exists(tempDir))
                Directory.CreateDirectory(tempDir);
            int Co = 0;
            do
            {
                Co += 1;
                System.Threading.Thread.Sleep(50);
                System.Drawing.Bitmap X = new System.Drawing.Bitmap(_Bounds.Width, _Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using(System.Drawing.Graphics G = System.Drawing.Graphics.FromImage(X)) {
                    G.CopyFromScreen(_Bounds.Location, new System.Drawing.Point(), _Bounds.Size);
                    System.Drawing.Rectangle CurBounds = new System.Drawing.Rectangle(System.Drawing.Point.Subtract(System.Windows.Forms.Cursor.Position,Bounds.Size), System.Windows.Forms.Cursor.Current.Size);
                    System.Windows.Forms.Cursors.Default.Draw(G, CurBounds);
               }
                System.IO.FileStream FS = new System.IO.FileStream(tempDir + FormatString(Co.ToString(), 5, '0') + ".png", System.IO.FileMode.OpenOrCreate);
                X.Save(FS, System.Drawing.Imaging.ImageFormat.Png);
                X.Dispose();
                FS.Close();
            } while (true);
        }

        public static void ClearRecording()
        {
            if (Directory.Exists(tempDir))
                Directory.Delete(tempDir, true);
                Directory.CreateDirectory(tempDir);
        }

        public static void Save(string Output)
        {
            System.Windows.Media.Imaging.GifBitmapEncoder G = new System.Windows.Media.Imaging.GifBitmapEncoder();

            List<System.IO.FileStream> X = new List<System.IO.FileStream>();
            foreach (string Fi in Directory.GetFiles(tempDir, "*.png", SearchOption.TopDirectoryOnly))
            {
                System.IO.FileStream TempStream = new System.IO.FileStream(Fi, System.IO.FileMode.Open);
                System.Windows.Media.Imaging.BitmapFrame Frame = System.Windows.Media.Imaging.BitmapFrame.Create(TempStream);
                X.Add(TempStream);
                G.Frames.Add(Frame);
            }
            System.IO.FileStream FS = new System.IO.FileStream(Output, System.IO.FileMode.OpenOrCreate);
            G.Save(FS);
            FS.Close();

            foreach (System.IO.FileStream St in X)
            {
                St.Close();

            }

        }

        public static void Start()
        {
            snap = new System.Threading.Thread(Snapshot);
            snap.Start();
        }

        public static void Stop()
        {
            snap.Abort();
        }

        private static string FormatString(string S, int places, char character)
        {
            if (S.Length >= places)
                return S;
            for (int X = S.Length; X <= places; X++)
            {
                S = character + S;
            }
            return S;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            ScreenRecorder.Start();
            System.Threading.Thread.Sleep(5000);
            ScreenRecorder.Stop();
            ScreenRecorder.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\video.gif");
            ScreenRecorder.ClearRecording();
        }
    }
}

These are references I had to add:

enter image description here

嘦怹 2024-08-13 06:06:51

对于线程异常,您可以使用此代码来避免这种情况

    public static void Stop()
    {
        flag = false;
        snap.Join();
    }

,并将标志设置为 static private bool (全局),并将其代替 while 循环中的 true 值:

while(flag)

这就是如何避免资源上的线程重叠。我知道这不是主题,但我想分享这条信息,因为线程总是使调试变得令人讨厌。

问候,
法瓦兹

For the Thread Exception, you can avoid that with this code

    public static void Stop()
    {
        flag = false;
        snap.Join();
    }

and put the flag as static private bool (global) and put it instead of the true value in the while loop:

while(flag)

that how you can avoid threading overlap on resource. I know that is not the subject but I want to share this piece of info because threads always make the debugging nasty.

Regards,
Fawaz

栀梦 2024-08-13 06:06:51

我采用了 Parox 代码并对其进行了修复,以减少错误并更适合 C# 语言编译器。

作为一名 C# 程序员,我可以说代码抛出错误并不奇怪。某些部分甚至可能导致堆栈溢出或终止应用程序异常 - 但这就是我们在此问答中所处的领域;)

长时间录制可能会导致 Counter 溢出并覆盖从录制的第一秒和可能的其他问题,但在我看来,最好将其附加到其他人的线程中:

public class ScreenRecorder
{
    // C:\Users\sebas.000\AppData\Local\Temp\snapshot
    private static string tempSnapshotDir = Path.GetTempPath() + "snapshot\\";
    private static Thread snapThread = new Thread(Snapshot);
    private static bool flag = false;

    private static Rectangle _Bounds = Screen.PrimaryScreen.Bounds;

    public static Rectangle Bounds
    {
        get { return _Bounds; }
        set { _Bounds = value; }
    }

    private static void Snapshot()
    {
        ClearRecording();

        using (var memoryBitmap = new Bitmap(_Bounds.Width, _Bounds.Height, Imaging.PixelFormat.Format32bppArgb))
        using (var graphSurface = Graphics.FromImage(memoryBitmap))
        {
            //var currentBounds = new Rectangle();
            var Counter = (UInt64)0;                
            var freshPoint = new System.Drawing.Point();

            flag = true;
            do
            {                    
                Thread.Sleep(100);
                graphSurface.CopyFromScreen(_Bounds.Location, freshPoint, _Bounds.Size);

                // add cursor
                //currentBounds.Size = Cursor.Current.Size;
                //currentBounds.Location = System.Drawing.Point.Subtract(Cursor.Position, Bounds.Size);
                //Cursors.Default.Draw(graphSurface, currentBounds);

                Counter++;

                var fileName = FormatFileName(Counter.ToString(), 6, '0', ".png");
                using (var FS = new FileStream(string.Concat(tempSnapshotDir, fileName), FileMode.Create, FileAccess.Write))
                {
                    memoryBitmap.Save(FS, ImageFormat.Png);
                }

            } while (flag);
        }
    }

    private static void ClearRecording()
    {
        if (Directory.Exists(tempSnapshotDir))
            Directory.Delete(tempSnapshotDir, true);

        Directory.CreateDirectory(tempSnapshotDir);
    }

    public static void StartRecording()
    {
        //snapThread = new Thread(Snapshot);
        snapThread.Start();
    }

    public static void StopRecording()
    {
        flag = false;
        snapThread.Join();
    }

    public static void Save(string outpuFinlename)
    {
        var gifBitmapEncoder = new GifBitmapEncoder();
        var fileStreamList = new List<FileStream>();

        // encode GIF from PNGs
        foreach (string pngFile in Directory.GetFiles(tempSnapshotDir, "*.png", SearchOption.TopDirectoryOnly)) // efficiency !!! create list like Counter !!!
        {
            var tempStream = new FileStream(pngFile, FileMode.Open);            
            var bitmapFrame = BitmapFrame.Create(tempStream);
            fileStreamList.Add(tempStream);
            gifBitmapEncoder.Frames.Add(bitmapFrame);                
        }

        // save GIF to disk
        using (var fileStream = new FileStream(outpuFinlename, FileMode.Create, FileAccess.Write))
        {                
            gifBitmapEncoder.Save(fileStream);
        }

        fileStreamList.Clear();
        ClearRecording();
    }

    private static string FormatFileName(string S, int places, char character, string extension)
    {
        if (S.Length >= places)
            return S;

        return S.PadLeft(places, '0') + extension;
    }
}

I took Parox code and repair it to be less buggy and more proper for C# language compilers.

What I can say as a C# programmer there is no surprise that the code throws errors. Some parts could even lead to stack overflows or killing the app exceptions - but that's the domain where we are at this Q&A ;)

Still long time recording can lead to Counter overflow and overriding PNGs taken from the first seconds of recording and probably other issues but in my opinion enough better to be attached in the thread for others:

public class ScreenRecorder
{
    // C:\Users\sebas.000\AppData\Local\Temp\snapshot
    private static string tempSnapshotDir = Path.GetTempPath() + "snapshot\\";
    private static Thread snapThread = new Thread(Snapshot);
    private static bool flag = false;

    private static Rectangle _Bounds = Screen.PrimaryScreen.Bounds;

    public static Rectangle Bounds
    {
        get { return _Bounds; }
        set { _Bounds = value; }
    }

    private static void Snapshot()
    {
        ClearRecording();

        using (var memoryBitmap = new Bitmap(_Bounds.Width, _Bounds.Height, Imaging.PixelFormat.Format32bppArgb))
        using (var graphSurface = Graphics.FromImage(memoryBitmap))
        {
            //var currentBounds = new Rectangle();
            var Counter = (UInt64)0;                
            var freshPoint = new System.Drawing.Point();

            flag = true;
            do
            {                    
                Thread.Sleep(100);
                graphSurface.CopyFromScreen(_Bounds.Location, freshPoint, _Bounds.Size);

                // add cursor
                //currentBounds.Size = Cursor.Current.Size;
                //currentBounds.Location = System.Drawing.Point.Subtract(Cursor.Position, Bounds.Size);
                //Cursors.Default.Draw(graphSurface, currentBounds);

                Counter++;

                var fileName = FormatFileName(Counter.ToString(), 6, '0', ".png");
                using (var FS = new FileStream(string.Concat(tempSnapshotDir, fileName), FileMode.Create, FileAccess.Write))
                {
                    memoryBitmap.Save(FS, ImageFormat.Png);
                }

            } while (flag);
        }
    }

    private static void ClearRecording()
    {
        if (Directory.Exists(tempSnapshotDir))
            Directory.Delete(tempSnapshotDir, true);

        Directory.CreateDirectory(tempSnapshotDir);
    }

    public static void StartRecording()
    {
        //snapThread = new Thread(Snapshot);
        snapThread.Start();
    }

    public static void StopRecording()
    {
        flag = false;
        snapThread.Join();
    }

    public static void Save(string outpuFinlename)
    {
        var gifBitmapEncoder = new GifBitmapEncoder();
        var fileStreamList = new List<FileStream>();

        // encode GIF from PNGs
        foreach (string pngFile in Directory.GetFiles(tempSnapshotDir, "*.png", SearchOption.TopDirectoryOnly)) // efficiency !!! create list like Counter !!!
        {
            var tempStream = new FileStream(pngFile, FileMode.Open);            
            var bitmapFrame = BitmapFrame.Create(tempStream);
            fileStreamList.Add(tempStream);
            gifBitmapEncoder.Frames.Add(bitmapFrame);                
        }

        // save GIF to disk
        using (var fileStream = new FileStream(outpuFinlename, FileMode.Create, FileAccess.Write))
        {                
            gifBitmapEncoder.Save(fileStream);
        }

        fileStreamList.Clear();
        ClearRecording();
    }

    private static string FormatFileName(string S, int places, char character, string extension)
    {
        if (S.Length >= places)
            return S;

        return S.PadLeft(places, '0') + extension;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文