【问题标题】:How to Write a Screen Recorder in .NET?如何在 .NET 中编写屏幕录像机?
【发布时间】:2009-09-29 02:50:43
【问题描述】:

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

【问题讨论】:

  • 我敢打赌,你可以像 VB.NET 屏幕录像机一样做到这一点。
  • @John Saunders - 您对如何完成此操作或教程链接等有什么想法吗?
  • 是的。就像 VB.NET 或任何其他 .NET 语言一样 - 它与 C# 无关。你可能实际上知道这一点,但你听起来好像不知道。如果你不是真的那么无知,那么我道歉。
  • 我认为您不需要在标签中使用“屏幕抓取”。屏幕抓取通常是指从另一个应用程序的一个或多个控件或屏幕中提取文本。
  • @John Saunders - 我知道它适用于任何 .NET 语言。

标签: c# .net screen capture


【解决方案1】:

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

【讨论】:

  • 问题是引号中的正斜杠。我不知道一个不会混淆编辑器的 VB.NET 等价物,所以我把它留给你。
  • 几年前我用 C# 写了一些非常相似的东西。表演很糟糕。我会对它的表现感兴趣。
  • 我想我已经没有代码了。大约 6 年前,我为一位雇主写了这篇文章。我确信它仍然存在于他们的 CVS 存储库中,但这些位可能早就从我的任何驱动器中消失了。对不起。它确实遵循相同的基本概念:定期屏幕截图保存到磁盘。我记得尝试了几种不同的方法来优化它,但不记得细节。从那时到现在编写的代码太多。
  • 好的,我将使用它,将其转换为 C#(我更喜欢 C# 而不是 VB)。希望一切顺利。谢谢。
  • 也许您可以在 CodePlex 上发布 C# 版本以供将来使用。祝你好运!
【解决方案2】:

我从 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();
        }
    }
}

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

【讨论】:

  • 如果有人喜欢使用代码检查我的答案以更快地获得工作解决方案here
【解决方案3】:

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

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

并将标志作为静态私有布尔(全局)并将其而不是真正的值放在while循环中:

while(flag)

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

问候, 法瓦兹

【讨论】:

    【解决方案4】:

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

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

    长时间录制可能会导致Counter 溢出和覆盖从录制的第一秒获取的 PNG 以及可能的其他问题,但我认为最好将其附加到线程中以供其他人使用:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多