自己编写的一个截图工具

Posted crystal_lz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己编写的一个截图工具相关的知识,希望对你有一定的参考价值。

http://blog.csdn.net/crystal_lz/article/details/9200859

上面是以前写的 不过现在重写了 增加了一些功能

源代码下载地址:http://download.csdn.net/detail/crystal_lz/9556929


第一次运行 会弹出此窗口进行快捷键的设置

因为需要修改注册表开机启动 所以需要使用管理员权限运行

启动截图的时候 [W,A,S,D] 微距移动鼠标

按下 V -> 自动框选的时候是否 只获取可见窗体

按下 T -> 是否获取透明窗体

按下 H -> 是否对webbrowser进行spy

 

在自动框选的时候 按下ctrl 的同时点击左键 弹出SpyTool

在自动框选的时候 按下 alt 的同时点击左键 将目标窗体设置为GIF截图窗体


这些快捷键都可以自己试一下


上面是对webbrowser进行spy的效果 是酷狗播放器


比起以前增加了 多显示器截图 其实要多显示器 很简单

/// <summary>
/// 获取整个屏幕的矩形区域
/// </summary>
/// <returns>矩形区域</returns>
public static Rectangle GetDesktopRect() {
    Rectangle rect = new Rectangle();
    rect.X = Win32.GetSystemMetrics(Win32.SM_XVIRTUALSCREEN);
    rect.Y = Win32.GetSystemMetrics(Win32.SM_YVIRTUALSCREEN);
    rect.Width = Win32.GetSystemMetrics(Win32.SM_CXVIRTUALSCREEN);
    rect.Height = Win32.GetSystemMetrics(Win32.SM_CYVIRTUALSCREEN);
    return rect;
}

但是需要注意的是 截图窗体是全屏运行的 正常情况下鼠标在窗体上的坐标就是 鼠标的屏幕坐标 但是 多显示器上不一定 

假设我现在是两个显示器 左边一个 右边一个分辨率都是 1920 * 1080 如果说 我右边的显示器是主显示器 那么 左边显示器的坐标是(-1920,0)开始的 所以在写代码的时候 窗体坐标到屏幕坐标的时候 需要注意

这次 程序增加了插件功能


插件可以自己编写 不过我想一般也没有去搞

namespace IPlugins
{
    public interface IFilter
    {
        /// <summary>
        /// 获取插件显示的名字
        /// </summary>
        /// <returns>插件名字</returns>
        string GetPluginName();
        /// <summary>
        /// 获取插件在菜单上显示的图标 若不需要显示则返回null
        /// </summary>
        /// <returns>图标 否则 null</returns>
        Image GetPluginIcon();
        /// <summary>
        /// 用于加载插件时候初始化调用
        /// </summary>
        /// <param name="strStarPath">主程序启动路径</param>
        void InitPlugin(string strStarPath);

        ResultInfo ExecFilter(Image imgSrc);
    }
}

接口很简单 新建一个dll工程 然后引入我的IPlugins.dll文件继承实现 IFilter接口即可

一个Dll里面可以编写多个插件 不过到时候加载到右键菜单上面 会以dll名字作为分组 否则只有一个插件的话就没有子菜单

比如我上面演示的插件 工程是这样的


Gray中写了两个插件 那么到时候右键菜单中就会用Gray(Gray.dll)的名字作为分组 而如果dll中只有一个插件 那么就不用进行分组了

插件返回类型(悲剧的解决方案中忘了给这个类写注释了)

namespace IPlugins
{
    public class ResultInfo : IDisposable
    {
        private Image _ResultImage;
        /// <summary>
        /// 获取插件处理后的图像
        /// </summary>
        public Image ResultImage {
            get { return _ResultImage; }
        }

        private bool _IsModified;
        /// <summary>
        /// 告知程序图片是否被编辑 如果false 则忽略插件操作 如果true 则取出ResultImage作为结果
        /// </summary>
        public bool IsModified {
            get { return _IsModified; }
        }

        private bool _IsClose;
        /// <summary>
        /// 如果true则截图窗体关闭 比如编写一个图片编辑器插件
        /// 插件得到图片后想独占编辑 则可以在插件中Show一个窗体出来 然后返回一个ResultInfo
        /// 并将IsClose设置为true则 截图窗体就关闭了 剩下的操作就可以在自己编写的编辑器中进行
        /// </summary>
        public bool IsClose {
            get { return _IsClose; }
        }

        public ResultInfo(Image imgResult, bool bModified, bool bClose) {
            this._ResultImage = imgResult;
            this._IsModified = bModified;
            this._IsClose = bClose;
        }

        public void Dispose() {
            if (this._ResultImage != null) this._ResultImage.Dispose();
        }
    }
}

//调用插件
private void item_Click(object sender, EventArgs e) {
    try {
        var result = ((sender as ToolStripMenuItem).Tag as IPlugins.IFilter).ExecFilter(m_imgLastLayer.Clone() as Bitmap);
        if (result.IsClose) this.Close();//如果插件需要关闭窗体(则插件里面可以自己show一个窗体出来 而不是ShowDialog)
        if (!result.IsModified) return;//如果图片没有被编辑 则忽略操作
        m_imgCurrentLayer = result.ResultImage;
        imageCroppingBox1.Invalidate(imageCroppingBox1.SelectedRectangle);
        this.SetHistoryLayer();
        imageCroppingBox1.IsLockSelected = true;
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

可以自己整理一下逻辑


这是上面二值化插件弹出来的窗体 反正插件要怎么写 随便自己 可以不用弹出 比如上面的  黑白处理 和 反色处理 就不需要弹出窗体来进行一些参数设置

这个是上面插件的代码:

namespace Gray
{
    public class PluginBinary : IFilter
    {
        public string GetPluginName() {
            return "二值化";
        }

        public System.Drawing.Image GetPluginIcon() {
            return Properties.Resources.icon_binary;
        }

        public void InitPlugin(string strStarPath) {

        }

        public ResultInfo ExecFilter(System.Drawing.Image imgSrc) {
            Form1 frm = new Form1(imgSrc);
            if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                return new ResultInfo(frm.ResultImage, true, false);
            }
            return new ResultInfo(null, false, false);
        }
    }
}

是不是感觉很简单

IPlugins.Dll里面有些自己写的控件 可以用 不过里面只写了我需要用到的控件 没几个


还有就是 由于平时经常用到打码 所以直接截图也内置了


选择 填充 和 马赛克 模式 反正就是自己尝试

如果不勾选马赛克 那么就是普通按照选择的颜色进行填充

不过这里注意 如果选择的是 绘制 和 马赛克 模式 你可能会感觉到绘制没有效果 这不是bug而是设定上就是这样的

只要勾选马赛克模式 无论画刷还是画笔都是以马赛克方式呈现的

如果画笔大小放大一点就能看到是什么效果了


GIF录制也经常用到 所以也内置了这个功能

GIF录制有两种模式 一种是窗体录制 一种是选择区域录制

选择区域录制就是上面截图看到的 选择一个区域右键菜单 -> 设置为GIF录制区域 这个很好理解

窗体录制是 只启动截图在自动框选的时候还没有确定区域的时候 按住ALT键然后点击鼠标左键 则会把自动框出来的窗体作为录制目标 和区域录制唯一的不同是

区域录制只会录制指定区域 而窗体录制则会跟踪窗体位置 比如窗体从屏幕左边移动到了右边依然会录制该窗体 而区域录制则办不到

GIF录制的时候 托盘图标右下角会变成绿色暂停录制是红色 否则显示正常图标

启动了录制gif切记 你正则录制 不然你忘了就悲剧了 就等着内存被沾满 然后蹦了吧


上面是录制的效果 可以选择高质量和低质量 可以点击复制 能直接将图片粘贴到QQ聊天窗体中去 为此我还分析了一下QQ的剪切板数据

{string[10]}
    [0]: "QQ_Unicode_RichEdit_Format" //MemoryStream 是一段xml
    [1]: "QQ_RichEdit_Format"         //MemoryStream 同上(和上面的可以粘贴到聊天窗口)
    [2]: "DeviceIndependentBitmap"    //直接使用Image类型即可(进行普通粘贴)
    [3]: "FileDrop"                   //string[] 文件路径(复制文件)
    [4]: "FileNameW"                  //string[] 同上
    [5]: "FileName"                   //同上
    [6]: "html Format"
    [7]: "System.String"
    [8]: "UnicodeText"
    [9]: "Text"
这是我的代码

private void btn_copy_Click(object sender, EventArgs e) {
    if (!System.IO.Directory.Exists("./temp")) System.IO.Directory.CreateDirectory("./temp");
    string strTempFile = "./temp/DevCap_"/*Developer Capture*/ + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".gif";
    strTempFile = System.IO.Path.GetFullPath(strTempFile);
    pictureBox1.Image.Save(strTempFile);
    var i = new DataObject();
    byte[] byData = Encoding.UTF8.GetBytes("<QQRichEditFormat><Info version=\\"1001\\"></Info><EditElement type=\\"1\\" filepath=\\"" + strTempFile + "\\" shortcut=\\"\\"></EditElement><EditElement type=\\"0\\"><![CDATA[]]></EditElement></QQRichEditFormat>");
    i.SetData("QQ_Unicode_RichEdit_Format", new System.IO.MemoryStream(byData));
    i.SetData("QQ_RichEdit_Format", new System.IO.MemoryStream(byData));
    i.SetData("FileDrop", new string[] { strTempFile });
    i.SetData("FileNameW", new string[] { strTempFile });
    i.SetData("FileName", new string[] { strTempFile });
    i.SetData("DeviceIndependentBitmap", pictureBox1.Image);
    Clipboard.SetDataObject(i, true);
}

其他的还是自己看代码吧 关键注释已经很详细了

最后说明一下 虽然源代码开放 但是我实在是不希望看到那种 只改一个标题然后就重新发布说是自己写的那种情况 不是说不让用我的代码

只是说如果仅仅是使用或者在这个基础上修改代码 请保留代码一些原有的信息 比如我的ID:Crystal_lz (本想在每个类开头写个注释头的 估计写了也没用)

开放代码的目的是希望大家一起交流学习 顺便装个逼 而不是把东西送给你 对于我写的代码我完全可以选择开放或者不开放代码 但是既然我开放出来了 就希望别 “据为己有” 随便改改就说是你自己写的 即使你要这样做 请保留我的ID也好让我能继续装逼


如果有BUG请记得反馈

以上是关于自己编写的一个截图工具的主要内容,如果未能解决你的问题,请参考以下文章

自己编写的一个截图工具

网页版截图工具上线啦

小程序开发,远离bug

漫画 | 有人向我反馈了一个bug…

ipa上传反馈请修改应用程序info.plist文件中相关用途字符串问题

开源的截图工具