在以往几篇文章里面,大家都可以看到各种录制的GIF效果图,把gif放在文章开始,不仅可以减少很多冗余的解释白话文,更可以让读者一览无余看到文章大概要义。

以往都是使用“LicEcap”来录制的,那么我们是否能自己实现一个这样的工具呢?一方面国庆假期结束,练练代码手感,另一方面可以根据自己需求扩展需要的功能。

01介绍软件UI及操作

操作比较简单,以下是运行界面:

  1. 选择录制区域,绘制需要录制的ROI区域

  2. 点击开始录制

  3. 录制结束后,停止录制即可.弹出保存路径保存gif

02效果图

  1. 整个运行作业图

  2. 实际录屏的ROI区域效果GIF

03源码介绍

private void InitializeComponents()
{
    this.Text = "GIF录制工具";
    this.Size = new Size(400, 200);
    this.StartPosition = FormStartPosition.CenterScreen;

    // 选择区域按钮
    Button btnSelectArea = new Button();
    btnSelectArea.Text = "选择录制区域";
    btnSelectArea.Size = new Size(120, 30);
    btnSelectArea.Location = new Point(20, 20);
    btnSelectArea.Click += BtnSelectArea_Click;
    this.Controls.Add(btnSelectArea);

    // 开始录制按钮
    Button btnStart = new Button();
    btnStart.Text = "开始录制";
    btnStart.Size = new Size(120, 30);
    btnStart.Location = new Point(20, 60);
    btnStart.Click += BtnStart_Click;
    this.Controls.Add(btnStart);

    // 停止录制按钮
    Button btnStop = new Button();
    btnStop.Text = "停止录制";
    btnStop.Size = new Size(120, 30);
    btnStop.Location = new Point(20, 100);
    btnStop.Click += BtnStop_Click;
    this.Controls.Add(btnStop);

    // 帧率选择
    Label lblFrameRate = new Label();
    lblFrameRate.Text = "帧率:";
    lblFrameRate.Location = new Point(160, 65);
    lblFrameRate.Size = new Size(50, 20);
    this.Controls.Add(lblFrameRate);

    NumericUpDown numFrameRate = new NumericUpDown();
    numFrameRate.Value = frameRate;
    numFrameRate.Minimum = 1;
    numFrameRate.Maximum = 30;
    numFrameRate.Location = new Point(210, 65);
    numFrameRate.Size = new Size(60, 20);
    numFrameRate.ValueChanged += (s, e) => { frameRate = (int)numFrameRate.Value; };
    this.Controls.Add(numFrameRate);

    // 状态标签
    Label lblStatus = new Label();
    lblStatus.Text = "状态: 就绪";
    lblStatus.Location = new Point(160, 25);
    lblStatus.Size = new Size(200, 20);
    lblStatus.Name = "lblStatus";
    this.Controls.Add(lblStatus);

    // 录制计时器
    captureTimer = new System.Windows.Forms.Timer();
    captureTimer.Tick += CaptureTimer_Tick;
}

选择ROI录屏区域

private void StartAreaSelection()
{
    this.Hide();
    Thread.Sleep(500); // 等待窗体隐藏

    isSelectingArea = true;
    Cursor = Cursors.Cross;

    // 创建全屏透明窗体用于区域选择
    Form selectionForm = new Form();
    selectionForm.WindowState = FormWindowState.Maximized;
    selectionForm.FormBorderStyle = FormBorderStyle.None;
    selectionForm.BackColor = Color.Black;
    selectionForm.Opacity = 0.3;
    selectionForm.TopMost = true;
    selectionForm.Cursor = Cursors.Cross;

    Rectangle selectedArea = Rectangle.Empty;
    bool isDragging = false;
    Point dragStart = Point.Empty;

    selectionForm.MouseDown += (s, e) =>
    {
        if (e.Button == MouseButtons.Left)
        {
            isDragging = true;
            dragStart = e.Location;
        }
    };

    selectionForm.MouseMove += (s, e) =>
    {
        if (isDragging)
        {
            int x = Math.Min(dragStart.X, e.X);
            int y = Math.Min(dragStart.Y, e.Y);
            int width = Math.Abs(e.X - dragStart.X);
            int height = Math.Abs(e.Y - dragStart.Y);

            selectedArea = new Rectangle(x, y, width, height);
            selectionForm.Invalidate();
        }
    };

    selectionForm.MouseUp += (s, e) =>
    {
        if (e.Button == MouseButtons.Left && isDragging)
        {
            isDragging = false;
            if (selectedArea.Width > 10 && selectedArea.Height > 10)
            {
                recordingArea = selectedArea;
                UpdateStatus($"已选择区域: {recordingArea}");
            }
            selectionForm.Close();
        }
    };

    selectionForm.Paint += (s, e) =>
    {
        if (isDragging && !selectedArea.IsEmpty)
        {
            using (Pen pen = new Pen(Color.Red, 2))
            {
                e.Graphics.DrawRectangle(pen, selectedArea);
            }

            string sizeText = $"{selectedArea.Width} x {selectedArea.Height}";
            using (Font font = new Font("Arial", 12))
            using (Brush brush = new SolidBrush(Color.Red))
            {
                e.Graphics.DrawString(sizeText, font, brush, selectedArea.X, selectedArea.Y - 20);
            }
        }
    };

    selectionForm.KeyDown += (s, e) =>
    {
        if (e.KeyCode == Keys.Escape)
        {
            selectionForm.Close();
        }
    };

    selectionForm.FormClosed += (s, e) =>
    {
        isSelectingArea = false;
        Cursor = Cursors.Default;
        this.Show();
        this.BringToFront();
    };

    selectionForm.ShowDialog();
}

录制结束,保存GIF

private void SaveGif()
 {
     if (frames.Count == 0)
     {
         MessageBox.Show("没有可保存的帧!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
         return;
     }

     using (SaveFileDialog saveDialog = new SaveFileDialog())
     {
         saveDialog.Filter = "GIF 文件|*.gif";
         saveDialog.Title = "保存GIF文件";
         saveDialog.DefaultExt = "gif";

         if (saveDialog.ShowDialog() == DialogResult.OK)
         {
             try
             {
                 // 使用GifBitmapEncoder替代方案
                 SaveFramesAsGif(frames, saveDialog.FileName, frameRate);
                 MessageBox.Show($"GIF保存成功!\n文件: {saveDialog.FileName}\n帧数: {frames.Count}", "成功",
                     MessageBoxButtons.OK, MessageBoxIcon.Information);
             }
             catch (Exception ex)
             {
                 MessageBox.Show($"保存GIF时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
             }
         }
     }

     // 清理资源
     foreach (var frame in frames)
     {
         frame.Dispose();
     }
     frames.Clear();
 }
private void SaveFramesAsGif(List<Bitmap> frames, string filePath, int frameRate)
 {
     using (var collection = new MagickImageCollection())
     {
         foreach (var frame in frames)
         {
             using (var memoryStream = new MemoryStream())
             {
                 frame.Save(memoryStream, ImageFormat.Bmp);
                 memoryStream.Position = 0;

                 var image = new MagickImage(memoryStream);
                 image.AnimationDelay =Convert.ToUInt32( 100 / frameRate); // 设置帧延迟
                 collection.Add(image);
             }
         }

         // 优化GIF
         collection.Optimize();
         collection.Write(filePath);
     }
 }

主要用到第三方nuget包

  1. AnimatedGif

  2. Magick.NET-Q16-AnyCPU

结束语

感谢各位耐心查阅!  如果您有更好的想法欢迎一起交流,有不懂的也可以微信公众号联系博主,作者公众号会经常发一些实用的小工具和demo源码,需要的可以去看看!另外,如果觉得本篇博文对您或者身边朋友有帮助的,麻烦点个关注!赠人玫瑰,手留余香,您的支持就是我写作最大的动力,感谢您的关注,期待和您一起探讨!再会!

c#造个轮子--GIF录制工具的更多相关文章

  1. LICEcap – 灵活好用,GIF 屏幕录制工具

    LICEcap – 灵活好用,GIF 屏幕录制工具 http://www.appinn.com/licecap/

  2. LICEcap GIF 屏幕录制工具

    LICEcap 是一款屏幕录制工具,支持导出git动画图片格式,简单好用.大小只有几百KB   运行之后,可以随意调整大小,右下角有开始/停止按钮.      压缩包:http://files.cnb ...

  3. 免费Gif图片录制工具

    /************************************************************************* * 免费Gif图片录制工具 * 说明: * 最近在 ...

  4. gif录制工具

    gif录制工具 This tool allows you to record a selected area of your screen and save it as a Gif. http://s ...

  5. 自己开发的轻量级gif动画录制工具

    虽然网上已经有LICEcap.GifCam等gif录制工具,但我仍然觉得对于我个人使用还是不够方面,所以自己又写了一个,功能相对简洁一些.    Gif Recorder 支持全屏录制和区域录制,可自 ...

  6. 【录教程必备】推荐几款屏幕录制工具(可录制GIF)

    我们经常会遇到一些场景,需要你向别人展示一些操作或是效果——例如告诉别人某某软件的配置步骤啊.刚设计出来网站的动画效果怎么样啊.某某电影里面的一个镜头多么经典啊.打得大快人心的NBA绝杀瞬间是怎么回事 ...

  7. 「造个轮子」——cicada 设计一个配置模块

    前言 在前两次的 cicada 版本中其实还不支持读取配置文件,比如对端口.路由的配置. 因此我按照自己的想法创建了一个 issue ,也收集到了一些很不错的建议. 最终其实还是按照我之前的想法来做了 ...

  8. 「造个轮子」——cicada 源码分析

    前言 两天前写了文章<「造个轮子」--cicada(轻量级 WEB 框架)> 向大家介绍了 cicada 之后收到很多反馈,也有许多不错的建议. 同时在 GitHub 也收获了 80 几颗 ...

  9. Ubuntu18.04 下的Gif录制工具

    正文: 开源地址:https://github.com/phw/peek Linux包相关的知识如果不知道可以看以前讲的:https://www.cnblogs.com/dunitian/p/9095 ...

  10. Gource 方便的软件版本可视化录制工具

    Gource 是一个特别棒的软件变更可视化录制工具,我们可以使用此工具,方便的将软件的版本变动,录制 为视频 安装 brew install gource brew install ffmpeg   ...

随机推荐

  1. 洛谷 U388010 题解

    洛谷 U388010 题解 link:https://www.luogu.com.cn/problem/U388010 Sol 首先,我们看到这一条件: 对于每一个 \(1 \le i \le n\) ...

  2. iPaaS混合集成平台,打造数字化生态

    如今企业分工越来越细,上下游合作越来越紧密.各企业之间的业务系统需要相互协作完成业务.外部API依赖越来越多.同时企业系统运行在多个混合云环境及SaaS中,私有端大量业务系统与云端系统形成了错综复杂的 ...

  3. AppLink让你的电商运营财务管理自动化

    电商运营财务管理的现状 在我们做电商运营管理的时候,财务管理是一个很繁琐并且对精度要求比较高的工作.通常需要花费财务管理人员很长的时间和经理进行核对.企业电商金额大,商品多.个体电商人员少,精力更多在 ...

  4. 数学: R连续性+Q稠密性与数系的完善历史

    R实数集合最重要的基本性质: 连续性(完备性: Q有理数+IR.无理数即无限不循环小数) 数系的扩充历史 自然数集合N: 关于 +加法 与 *乘法 运算是封闭的,但是 N 关于 -减法 运算并不封闭. ...

  5. Failed to start LVS and VRRP High Availability Monitor.-keepalived--九五小庞

    Keepalive启动报错,Fail to start LVS and VRRP High Availability Monitor. 输入:systemctl status keepalived,显 ...

  6. 雨林木风Win11纯净版无法进入系统的问题

    近期就有雨林木风官网用户在win11纯净版系统开机时电脑一直处于欢迎界面无法进入系统,那么有没有什么方法可以恢复呢?有遇到同样问题的朋友们可以试试下面雨林木风小编带来的解决方法,希望可以帮到你. 以下 ...

  7. Linux PAM认证模块框架

    Linux PAM(Pluggable Authentication Modules,可插拔认证模块)是Linux系统中一种​​模块化.动态可配置的用户级认证框架​​,用于统一管理各类服务的身份验证. ...

  8. webdriver中的三种等待

    1.强制等待:sleep()设置固定休眠时间,单位为秒.由Python的time包提供, 导入time包后就可以使用. 缺点:不智能,使用太多的sleep会影响脚本运行速度. 2.隐式等待:impli ...

  9. 文件服务(SMB)共享详解

    三种共享类型: 微软的CIFS文件共享协议,可以让windows机器在网上邻居之间共享文件,也即是windows-windows之间的文件共享: NFS文件共享协议,可以让远程共享的共享目录挂载在本地 ...

  10. Flutter SizeTransition:让你的UI动画更加丝滑

    在Flutter开发中,动画是提升用户体验的重要手段.今天我们来深入探讨一个强大而优雅的动画组件--SizeTransition,它能让你的UI元素在尺寸变化时呈现出流畅的过渡效果. SizeTran ...