Automatically save image that comes from 'print screen' key to specified folder.
C#Winform+WindowsAPI做个剪贴板无缝自动保存器(视频截图利器)
利用C#和Window API做了个自动保存剪贴板内的图片的工具,用在给视频截图上是最好不过的了。共享之。
点击Start按钮,就会在剪贴板内容发生变化时自动把保存到指定位置(保存为jpg格式的图片),并且以指定的字符串作为文件的前缀,后面跟上序号。所以这个工具是和PrtSc截屏键紧密结合使用的,按一次PrtSc,就保存一张图片。就算一直按着不放,也能把每个截屏命令都执行到。
另外,Distinct按钮可以把Path文件夹所在的所有文件检查一遍,自动删掉内容完全一样的文件。这个很实用吧。
源码在此:http://files.cnblogs.com/bitzhuwei/bitzhuwei.Clipboard.Winform.zip
release版程序在此:http://files.cnblogs.com/bitzhuwei/bitzhuwei.Clipboard.Winform-release.zip
代码如下。
1: void SaveClipboardImage()
2: {
3: var data = System.Windows.Forms.Clipboard.GetDataObject();
4: var bmap = (Image)(data.GetData(typeof(System.Drawing.Bitmap)));
5: if (bmap != null)
6: {
7: bmap.Save("bitzhuwei.cnblogs.com.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
8: bmap.Dispose();
9: }
10: }
override掉主窗体的WndProc事件,这样就能够实现当且仅当剪贴板内容发生变化时执行一次保存动作了。
override掉在主窗口的WindProc事件 const int WM_DRAWCLIPBOARD = 0x308; const int WM_CHANGECBCHAIN = 0x030D; protected override void WndProc(ref Message m) { if (nextClipboardViewer == null) nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle); switch (m.Msg) { case WM_CHANGECBCHAIN: if (m.WParam == nextClipboardViewer) { nextClipboardViewer = m.LParam; } else { SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam); } break; case WM_DRAWCLIPBOARD: SaveClipboardImage(); //将WM_DRAWCLIPBOARD 消息传递到下一个观察链中的窗口 SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam); //将WM_DRAWCLIPBOARD 消息传递到下一个观察链中的窗口 break; default: base.WndProc(ref m); break; } }
用文件流一个字节一个字节的判断即可。大部分不同的文件,判断不了多少次就会出现字节不一样了,所以我对这个方法的效率还是有信心的。自己也试验过,对视频截图得到的1000多张图片(全屏的截图1280*800的图片),2分钟就把重复的文件都删掉了。
删掉指定文件夹下所有内容相同的冗余文件 private void DeleteRedundancyFiles(string directory) { var files = (new DirectoryInfo(directory)).GetFiles("*.jpg"); for (int i = 0; i < files.Length; i++) { for (int j = i + 1; j < files.Length; j++) { if (File.Exists(files[i].FullName) && File.Exists(files[j].FullName)) { bool removeJ = IsSameContent(files, i, j); if (removeJ) { try { File.Delete(files[j].FullName); } catch (Exception) { } } } } } }<span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">bool</span> IsSameContent(FileInfo[] files, <span style="color: #0000ff;">int</span> i, <span style="color: #0000ff;">int</span> j) { var result = <span style="color: #0000ff;">true</span>; <span style="color: #0000ff;">using</span> (FileStream fsi = <span style="color: #0000ff;">new</span> FileStream(files[i].FullName, FileMode.Open)) { <span style="color: #0000ff;">using</span> (FileStream fsj = <span style="color: #0000ff;">new</span> FileStream(files[j].FullName, FileMode.Open)) { var counti = 0; var countj = 0; <span style="color: #0000ff;">do</span> { <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> length = 100; var bytesi = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[length]; var bytesj = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">byte</span>[length]; counti = fsi.Read(bytesi, 0, length); countj = fsj.Read(bytesj, 0, length); <span style="color: #0000ff;">if</span> (counti != countj) { result = <span style="color: #0000ff;">false</span>; } <span style="color: #0000ff;">else</span> { <span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> k = 0; k < counti; k++) { <span style="color: #0000ff;">if</span> (bytesi[k] != bytesj[k]) { result = <span style="color: #0000ff;">false</span>; <span style="color: #0000ff;">break</span>; } } } } <span style="color: #0000ff;">while</span> (result && counti > 0 && countj > 0); } } <span style="color: #0000ff;">return</span> result; }