【WPF】 スクリーンショットを撮り続けて動画に保存する
タイトルにあるようにスクリーンショットを撮り続けて動画に保存する方法のメモをします。 まずはスクリーンショットを撮る部分ですが、スクリーンショットをそのまま動画にすると容量がすごいことになるので、スクリーンショットを撮る⇒縮小するまでを作成します。
// Bitmapクラスを使うため参照の追加が必要 using System.Drawing; private Bitmap GetScreenShot(int width, int height) { var resizedBmp = new Bitmap(width, height); using (var bmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight)) using (Graphics g = Graphics.FromImage(bmp)) using (Graphics resizedG = Graphics.FromImage(resizedBmp)) { // スクリーンショットを撮る g.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), bmp.Size); // 動画サイズを減らすためリサイズする resizedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; resizedG.DrawImage(bmp, 0, 0, width, height); } return resizedBmp; }
一定時間ごとに上記メソッドを呼び出す必要があるので、DispatcherTimerクラスを利用します。動画保存はAccord.Video.VFWのAVIWriterクラスを利用します。Accord.Video.VFWはNuGETを使ってインストールします。
using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows; using Accord.Video.VFW; using System.Drawing; using System.Windows.Threading; namespace CSMovie { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { private readonly DispatcherTimer _timer = new DispatcherTimer(); private readonly AVIWriter _aviWriter = new AVIWriter(); // フレームレート private readonly int _frameRate = 15; // 動画の横サイズ private readonly int _videoWidth = 640; // 動画の縦サイズ private readonly int _videoHeight = 480; private readonly List<Task> _tasks = new List<Task>(); public MainWindow() { InitializeComponent(); InitializeDispatcherTimer(); InitializeVideo(); } private void InitializeDispatcherTimer() { // フレームレートに合わせて起動時間を設定する int interval_msec = 1000 / _frameRate; _timer.Interval = new TimeSpan(0, 0, 0, 0, interval_msec); _timer.Tick += dispatcherTimer_Tick; } private void dispatcherTimer_Tick(object sender, EventArgs e) { // 時間がかかる処理なのでバックグラウンドで実行する _tasks.Add( Task.Run(() => { // スクリーンショットを撮る using (Bitmap bmp = GetScreenShot(_videoWidth, _videoHeight)) { // フレームに追加する _aviWriter.AddFrame(bmp); } })); } private void InitializeVideo() { _aviWriter.FrameRate = _frameRate; _aviWriter.Open("video.avi", _videoWidth, _videoHeight); } private void Window_ContentRendered(object sender, EventArgs e) { _timer.Start(); } private Bitmap GetScreenShot(int width, int height) { var resizedBmp = new Bitmap(width, height); using (var bmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight)) using (Graphics g = Graphics.FromImage(bmp)) using (Graphics resizedG = Graphics.FromImage(resizedBmp)) { // スクリーンショットを撮る g.CopyFromScreen(new System.Drawing.Point(0, 0), new System.Drawing.Point(0, 0), bmp.Size); // 動画サイズを減らすためリサイズする resizedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; resizedG.DrawImage(bmp, 0, 0, width, height); } return resizedBmp; } private void Window_Closed(object sender, EventArgs e) { // タイマーを止める _timer.Stop(); // 動作中のタスクがあれば待つ foreach (var task in _tasks) { task.Wait(); } if (_aviWriter != null) { _aviWriter.Close(); _aviWriter.Dispose(); } } } }
ちなみにスクリーンショットを撮る部分はここを参考にしました。