静止画 キャプチャ

<B>
<font COLOR="blue" >
・---------------------------------------------------------------------------------------・<BR>
・端末を操作してもらっている時、その操作記録を取る必要があり作成しました。<BR>
・(WIN+Gによるキャプチャは使用不可)<BR>
・手持ちのフルスクリーンの3Dゲーム画面もキャプチャできました。<BR>
・---------------------------------------------------------------------------------------・</B>

### <font  color="6495ed">1.仕様</F>
* 実行すると直ちにキャプチャを開始します。<BR>
* 停止する場合は X で閉じるか、タスクバーで右ボタン → 「ウィンドウを閉じる」です。
* キャプチャ画像に変化が無い場合は無駄なので保存しないようにしてあります。
* 一見、画面に変化が無い様でもテキストボックス等にある点滅する縦棒のカーソルは、違う画像と認識し保存されてしまいます。
* タスクバーに時刻が表示されている場合も分が変わる度に1枚保存されます。
* マウスカーソルはキャプチャされません。(リモートデスクトップの画面は除く)
* 重複確認は<a href="https://takap-tech.com/entry/2021/10/08/001246">このサイト</A>を利用してます。
* System.Threading.Mutex 等を利用して二重起動できないように必要に応じて改修して下さい。
* 参照設定 System.Drawing

### <font  color="6495ed">2.再生方法</F>

* 事前にpngファイルのクリックで標準の「フォト」が起動できるようにしておきます。
* キャプチャが止まると保存フォルダが表示されます。(枚数が多いと時間かかります)
* 保存フォルダの連番の小さいファイルを選択。その後、カーソル右ボタン押したままにすると順次表示し、疑似アニメーションで操作が再現されます。


### <font  color="6495ed">3.WPF (C#)</F>

```c#
//////////////////////////////////////////
// ND-CAPTURE (WPF)
// (c)inf102 S.H 2022
//////////////////////////////////////////

using System;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;

namespace Bitmapdata {

    public partial class MainWindow : Window {

        //////////////////////////////////////////////////////////////////////////
        // 最大キャプチャ数 
        const int MAX=1000; 
        
        // キャプチャ間隔(mmSEC) Ex. 500=0.5Sec 3000=3Sec
        const int INTER=500;
        //////////////////////////////////////////////////////////////////////////
     
        static int cnt=1;   // 通し番号の初めの数字
        public string PATH;

        public  MainWindow() {

            InitializeComponent();
            
            this.WindowState = WindowState.Minimized;
            
            // Mydoc　ディレクトリパス取得
            string MyDocPATH= Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            // Mydoc ディレクトリに保存用ディレクトリ作成
            Directory.CreateDirectory (MyDocPATH+@"\ND-CAPTURE");
            PATH=MyDocPATH+@"\ND-CAPTURE\";
            
            Title = "ND-CAPTURE "+ INTER.ToString()+"mmSEC,MAX"+MAX.ToString() +"Cnt";

            // MAINLOOP
            CAPTURE2WRITE();
          
        }

        // CAPTURE -> Mydoc.
        public async void  CAPTURE2WRITE(){

            while (true){
                BitmapSource x=CopyScreen();
                
                DateTime dt = DateTime.Now;
                string da=dt.Year.ToString()+"-"+dt.Month.ToString()+"-"+dt.Day.ToString()+"-";
                                               
                using (Stream stream = new FileStream (PATH+da+cnt.ToString() +".png", FileMode.Create)){
                   
                    PngBitmapEncoder encoder = new PngBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(x));
                    encoder.Save(stream);
                  

                }

                if ( cnt != 1 ){
                    if ( ContentsEqual ( PATH+da+cnt.ToString() +".png", PATH+da+(cnt-1).ToString() +".png" ) )  {
                        File.Delete( PATH+da+(cnt).ToString() +".png");
                        cnt--;
                    }
                        
                }

                if ( cnt >=MAX ) {
                    MessageBox.Show("ND-CAPTURE 終了");
                    System.Diagnostics.Process.Start("EXPLORER.EXE", PATH);
                    Application.Current.Shutdown();
                }

                cnt++;
            
                await Task.Delay(INTER);
            }


        }

        private void Window_Closed(object sender, EventArgs e) {
            System.Diagnostics.Process.Start("EXPLORER.EXE", PATH);
        }

        // CAPTURE
        private static BitmapSource CopyScreen(){

            using (var screenBmp = new Bitmap((int)SystemParameters.PrimaryScreenWidth,(int)SystemParameters.PrimaryScreenHeight,System.Drawing.Imaging.PixelFormat.Format32bppArgb)){
                using (var bmpGraphics = Graphics.FromImage(screenBmp)){
                    bmpGraphics.CopyFromScreen(0, 0, 0, 0, screenBmp.Size);
                    return Imaging.CreateBitmapSourceFromHBitmap(screenBmp.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
                }

            }
        }

        // 重複CHK.
        public static bool ContentsEqual(string path1, string path2){
            //https://takap-tech.com/entry/2021/10/08/001246

           // MessageBox.Show(path1);

            if (path1 == path2){
                return true;
            }

            FileStream fs1 = null;
            FileStream fs2 = null;
      
            try{
                fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read, FileShare.Read);
                fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read, FileShare.Read);

                if (fs1.Length != fs2.Length){
                    return false;
                }

                int file1byte;
                int file2byte;

                do{
                    file1byte = fs1.ReadByte();
                    file2byte = fs2.ReadByte();
                }
                while ((file1byte == file2byte) && (file1byte != -1));

                return (file1byte - file2byte) == 0;
            }
            finally {
                using (fs1) { }
                using (fs2) { }
            }
        }
    }
}

```

### <font  color="6495ed">4.WPF (XAML)</F>
```xml
<Window x:Class="Bitmapdata.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Bitmapdata"
        mc:Ignorable="d"
        Title="ND-CAPTURE" Height="40" Width="425" ResizeMode="CanMinimize" Closed="Window_Closed">
    <Grid>
        
    </Grid>
</Window>
```

### <font  color="6495ed">5.リアルタイムモニタに改修方法</F>
* 保存ファイル名を決め打ちして共有フォルダに上書き保存させる。
* そのファイルの画像再表示(再読み込み)を自動的に行うようにすればリアルタイムで他端末の操作状況が確認できる。(表示しているファイルに対して排他が掛かり書込みできない場合等考慮する点はある)
* 複数端末の同時モニタも可能。
* VNCのインストールも不要。