7

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

4

4 回答 4

3

看看这个 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
于 2009-09-29T03:05:36.153 回答
3

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

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

在此处输入图像描述

于 2011-06-20T17:31:51.167 回答
1

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

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

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

while(flag)

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

问候,法瓦兹

于 2012-12-10T19:12:28.927 回答
0

我采用了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;
    }
}
于 2020-04-19T14:23:14.000 回答