Windows screen tools (screen capture, texture map/screen color picker/screenshot text, table recognition/screenshot translation, GIF screen recording, GIF compression)

background

Do you feel troublesome when you need to open WeChat or QQ screenshots every time you want to take screenshots? Do you often feel uncomfortable when you are not able to copy text similar to a certain degree library? Do you need to get a certain color on the screen and look for tools everywhere? Screenshot translation, word translation (need to apply for Baidu translation service), GIF screen recording, GIF compression and other functions
. And the source code is open source, and the installation program is provided, hoping to help friends who have the same trouble.

Features

Main interface

insert image description here

boot settings

After setting the boot, you don’t need to open it manually every time, and you can use it directly every time you need functions such as screenshots or text recognition.
insert image description here

shortcut key setting

Functions such as screenshots, textures, text recognition, and table recognition can be quickly invoked through shortcut key settings.
insert image description here

Baidu cloud information settings

Text recognition and translation are the interface of the Baidu cloud platform called, so those who want to use these functions need to register the corresponding Key on the Baidu cloud open platform, and set it in the software to use it normally. How to apply for the service, please refer to this article: https://luotengyuan.notion.site/OCR-APIKey-SecretKey-a4ae1949601f44d1a5ef67065f56eb11
insert image description here

Screenshot text recognition

By intercepting the text area in the screen, the text in the area is extracted, and automatically copied to the clipboard, so that it can be directly pasted to the desired place.
Screenshot text recognition

screenshot text translation

Recognize the text in the image and translate it into the specified language.
screenshot text translation

screen color picker

The screen color picker extracts RGB, HSB, HSL, HSV, CMYK and other color values ​​of a pixel.
screen color picker

GIF screen recording

Record screen operations as GIF animations, including functions such as full-screen recording, custom area recording, mouse capture, file saving or copying to the clipboard.
GIF screen recording

gif compression

Batch GIF compression is realized by encapsulating the function of gifscile.exe program, including default compression, compression by color, compression by ratio, lossy compression and compression by size, etc.
insert image description here

Code

PrScrn.dll screenshot library use

PrScrn.dll is a WeChat screenshot tool. We put this library in the program directory and call it directly to quickly realize the screenshot function.

        // 库方法导入
        [DllImport("PrScrn.dll", EntryPoint = "PrScrn")]
        public static extern int PrScrn();

		// 调用的地方直接使用就行
		PrScrn();

Realization of custom screenshots

Since the packaged method of PrScrn.dll can only be used for screenshots, it does not support special scenarios such as text recognition after screenshots, so a custom screenshot tool is implemented here.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 屏幕工具
{
    
    
    //定义委托
    public delegate void SetICS(bool isScreenShot);
    public partial class Form_catch : Form
    {
    
    
        //鼠标位置的枚举
        private enum MouseLocation
        {
    
    
            LeftUpPoint, LeftDownPoint, RightUpPoint, RightDownPoint, LeftLine, RightLine, UpLine, DownLine,
            InRectangle, OutOfRectangle
        }
        private MouseLocation mouseLocation;
        //定义该委托的事件
        public event SetICS SetICSEvent;
        //截屏原始图片
        private Bitmap originBmp;
        //鼠标左键按下的坐标
        private Point mouseDownPoint;
        //调节截图框时的固定不动点
        private Point fixedPoint;
        //是否允许绘制矩形截图状态
        private bool isDraw;
        //截图完成状态
        private bool isCatched;
        //是否允许调节矩形框
        private bool isAdjust;
        //绘制的截图矩形框
        private Rectangle rect;

        public Rectangle Rect
        {
    
    
            get {
    
     return rect; }
            set {
    
     rect = value; }
        }

        //缩放比
        private double scale;
        // 截图类型
        private CatchType mCatchType;
        // 默认的图片保持路径
        public string catchPicture = System.IO.Directory.GetCurrentDirectory() + "\\catch.jpg";
        public Form_catch(CatchType type)
        {
    
    
            InitializeComponent();
            mCatchType = type;
        }

        //将当前屏幕截图,显示到全屏无标题栏窗体上
        private void Form_catch_Load(object sender, EventArgs e)
        {
    
    
            //设置截图状态为开始
            SetICSEvent(true);
            //隐藏窗体,保证截屏图片为当前屏幕而不是被窗体覆盖
            this.Hide();
            //以当前窗口大小(窗口默认最大化,即全屏)创建截屏空白图片
            var g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
            int width = System32DllHelper.GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPHORZRES);
            int higth = System32DllHelper.GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
            scale = width * 1.0 / this.Width;
            //int width = 1920;
            //int higth = 1080;
            //int width = this.Width;
            //int higth = this.Height;
            //MessageBox.Show("Width: " + width + "  Height: " + higth);
            //this.originBmp = new Bitmap(this.Width, this.Height);
            this.originBmp = new Bitmap(width, higth);
            //以截屏图片作为画板
            using (Graphics gs = Graphics.FromImage(originBmp))
            {
    
    
                //复制当前屏幕到画板上,即将截屏图片的内容设置为当前屏幕
                //gs.CopyFromScreen(0, 0, 0, 0, this.Size);
                //gs.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(width, higth));
                gs.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(width, higth));
            }
            //将截屏图片设为窗体背景
            //this.Width = width;
            //this.Height = higth;
            this.BackgroundImage = new Bitmap(this.originBmp);
            //SaveFile(new Bitmap(this.originBmp));
            //添加截屏时的黑色遮罩,即在窗体背景上绘制全屏半透明黑色填充矩形
            using (Graphics blackgs = Graphics.FromImage(this.BackgroundImage))
            {
    
    
                using (SolidBrush backBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
    
    
                    blackgs.FillRectangle(backBrush, 0, 0, width, higth);
                }
            }
            //显示窗体
            this.Show();
            //激活当前窗体,使之具有焦点。主要针对win8 Metro界面的截图。
            this.Activate();
        }

        //右键点击动作
        private void Form_catch_MouseClick(object sender, MouseEventArgs e)
        {
    
    
            if (e.Button == MouseButtons.Right)
            {
    
    
                //开始绘制矩形框前,即初始状态,直接退出截图
                if (isCatched == false)
                {
    
    
                    this.Close();
                }
                //若矩形框已绘制,设定状态为初始状态,设定矩形各参数为0,
                //刷新窗体重绘,以清除已绘制的矩形,重新开始截图,即撤销功能。
                else
                {
    
    
                    this.isCatched = false;
                    this.isAdjust = false;
                    this.isDraw = false;
                    this.rect = new Rectangle(0, 0, 0, 0);
                    this.Refresh();
                    panel_menu.Visible = false;
                }
            }
        }

        //鼠标双击复制截图到剪贴板并存储
        private void Form_catch_MouseDoubleClick(object sender, MouseEventArgs e)
        {
    
    
            if (e.Button == MouseButtons.Left && isCatched == true)
            {
    
    
                Bitmap bitmap = getCatchPictureBitmap();
                if (bitmap != null)
                {
    
    
                    //复制到剪贴板
                    Clipboard.SetImage(bitmap);
                    //保持到默认路径
                    SaveFile(bitmap, true);
                    this.DialogResult = DialogResult.OK;
                    this.Close();
                }
            }
        }

        //鼠标左键按下开始截图
        private void Form_catch_MouseDown(object sender, MouseEventArgs e)
        {
    
    
            if (e.Button == MouseButtons.Left)
            {
    
    
                //未捕获时,设定状态为允许绘制矩形
                if (isCatched == false)
                {
    
    
                    this.isDraw = true;

                }
                else
                {
    
    
                    //捕获完成后在矩形框内按下左键,设置状态为调节矩形框位置和大小
                    //为方便使用,矩形框内外以及边和顶点的判定都为目标附近
                    if (MousePosition.X > rect.Left - 3 && MousePosition.X < rect.Right + 3
                        && MousePosition.Y > rect.Top - 3 && MousePosition.Y < rect.Bottom + 3)
                    {
    
    
                        this.isAdjust = true;
                    }
                }
                //记下鼠标左键按下的坐标,设置显示光标
                this.CursorLocation();
                this.mouseDownPoint = new Point(e.X, e.Y);
            }
        }

        private void Form_catch_MouseMove(object sender, MouseEventArgs e)
        {
    
    
            //移动鼠标绘制矩形
            if (this.isDraw == true)
            {
    
    
                //鼠标按下并移动设定状态为已捕获
                this.isCatched = true;
                panel_menu.Visible = true;
                if (mCatchType != CatchType.CATCH)
                {
    
    
                    btn_dowload.Visible = false;
                }
                //记录矩形左上角点的坐标
                Point leftUpPoint = new Point(this.mouseDownPoint.X, this.mouseDownPoint.Y);
                if (e.X < this.mouseDownPoint.X)
                    leftUpPoint.X = e.X;
                if (e.Y < this.mouseDownPoint.Y)
                    leftUpPoint.Y = e.Y;
                //获取矩形的长和宽
                int wideth = Math.Abs(this.mouseDownPoint.X - e.X);
                int height = Math.Abs(this.mouseDownPoint.Y - e.Y);
                //防止分辨率为0的截图区域
                if (wideth == 0)
                    ++wideth;
                if (height == 0)
                    ++height;
                //记录绘制的矩形
                this.rect = new Rectangle(leftUpPoint.X, leftUpPoint.Y, wideth, height);
                //刷新窗体,以触发OnPain事件重绘窗体
                this.Refresh();
            }
            //调节矩形框
            else
            {
    
    
                if (isCatched == true)
                {
    
    
                    //捕获完成,按下左键前显示当鼠标在矩形框上时的形状
                    if (isAdjust == false)
                    {
    
    
                        this.CursorLocation();
                    }
                    else
                    {
    
    
                        //计算调节矩形框的大小和位置
                        Point leftUpPoint = new Point(this.fixedPoint.X, this.fixedPoint.Y);
                        if (e.X < this.fixedPoint.X)
                            leftUpPoint.X = e.X;
                        if (e.Y < this.fixedPoint.Y)
                            leftUpPoint.Y = e.Y;
                        int wideth = Math.Abs(this.fixedPoint.X - e.X);
                        int height = Math.Abs(this.fixedPoint.Y - e.Y);
                        switch (mouseLocation)
                        {
    
    
                            //校正以上计算的矩形框位置以及大小
                            case MouseLocation.InRectangle:
                                leftUpPoint.X = this.fixedPoint.X + e.X - this.mouseDownPoint.X;
                                leftUpPoint.Y = this.fixedPoint.Y + e.Y - this.mouseDownPoint.Y;
                                wideth = this.rect.Width;
                                height = this.rect.Height;
                                //防止矩形框移出屏幕外
                                if (leftUpPoint.X < 0)
                                    leftUpPoint.X = 0;
                                if (leftUpPoint.Y < 0)
                                    leftUpPoint.Y = 0;
                                if (leftUpPoint.X + wideth >= this.Width)
                                    leftUpPoint.X = this.Width - wideth - 1;
                                if (leftUpPoint.Y + height >= this.Height)
                                    leftUpPoint.Y = this.Height - height - 1;
                                break;
                            case MouseLocation.LeftLine:
                            case MouseLocation.RightLine:
                                leftUpPoint.Y = this.rect.Y;
                                height = this.rect.Height;
                                break;
                            case MouseLocation.UpLine:
                            case MouseLocation.DownLine:
                                leftUpPoint.X = this.rect.X;
                                wideth = this.rect.Width;
                                break;
                        }
                        //防止分辨率为0的截图区域
                        if (wideth == 0)
                            ++wideth;
                        if (height == 0)
                            ++height;
                        //改变矩形框,刷新重绘
                        this.rect = new Rectangle(leftUpPoint.X, leftUpPoint.Y, wideth, height);
                        this.Refresh();
                    }
                }
            }
        }

        //放开鼠标左键,设置状态
        private void Form_catch_MouseUp(object sender, MouseEventArgs e)
        {
    
    
            if (e.Button == MouseButtons.Left)
            {
    
    
                //不允许绘制和调整
                this.isDraw = false;
                this.isAdjust = false;
            }
        }

        //按下ESC键退出截图
        private void Form_catch_KeyDown(object sender, KeyEventArgs e)
        {
    
    
            if (e.KeyValue == 27)
            {
    
    
                this.Close();
            }
        }

        //窗口关闭时设置主窗口的截图状态标记
        private void Form_catch_FormClosing(object sender, FormClosingEventArgs e)
        {
    
    
            SetICSEvent(false);
        }

        //重载OnPaint事件,窗体每次重绘所调用的函数
        protected override void OnPaint(PaintEventArgs e)
        {
    
    
            base.OnPaint(e);
            //防止窗体第一次显示时绘出分辨率显示
            if (this.rect.Width != 0)
            {
    
    
                int tempX = this.rect.X + this.rect.Width - panel_menu.Width;
                int tempY = this.rect.Y + this.rect.Height;
                if (this.Height - (this.rect.Y + this.rect.Height) < panel_menu.Height)
                {
    
    
                    tempY = this.rect.Y + this.rect.Height - panel_menu.Height;
                }
                panel_menu.Location = new Point(tempX, tempY);
                //向窗体添加画板,绘制矩形
                Graphics gs = e.Graphics;
                //绘制截屏图片上的矩形框选中部分到当前画板上的矩形框部分,以覆盖黑色遮罩
                Rectangle tempRect = new Rectangle(GetScaleInt(this.rect.X), GetScaleInt(this.rect.Y), GetScaleInt(this.rect.Width), GetScaleInt(this.rect.Height));
                gs.DrawImage(this.originBmp, this.rect, tempRect, GraphicsUnit.Pixel);
                //定义画笔
                using (Pen linePen = new Pen(Color.FromArgb(255, 0, 174, 255), 1))
                {
    
    
                    //绘制矩形
                    gs.DrawRectangle(linePen, this.rect);
                    //绘出线条上的点
                    using (SolidBrush pointBrush = new SolidBrush(Color.FromArgb(255, 0, 174, 255)))
                    {
    
    
                        //顶点
                        gs.FillRectangle(pointBrush, this.rect.X - 2, this.rect.Y - 2, 4, 4);
                        gs.FillRectangle(pointBrush, this.rect.Right - 2, this.rect.Y - 2, 4, 4);
                        gs.FillRectangle(pointBrush, this.rect.X - 2, this.rect.Bottom - 2, 4, 4);
                        gs.FillRectangle(pointBrush, this.rect.Right - 2, this.rect.Bottom - 2, 4, 4);
                        //中点
                        gs.FillRectangle(pointBrush, this.rect.X - 2, (this.rect.Y + this.rect.Bottom) / 2 - 2, 4, 4);
                        gs.FillRectangle(pointBrush, (this.rect.X + this.rect.Right) / 2 - 2, this.rect.Y - 2, 4, 4);
                        gs.FillRectangle(pointBrush, (this.rect.X + this.rect.Right) / 2 - 2, this.rect.Bottom - 2, 4, 4);
                        gs.FillRectangle(pointBrush, this.rect.Right - 2, (this.rect.Y + this.rect.Bottom) / 2 - 2, 4, 4);
                    }
                }
                //定义分辨率文字显示背景画刷,ARGB值。
                using (SolidBrush backBrush = new SolidBrush(Color.FromArgb(150, 0, 0, 0)))
                {
    
    
                    //绘制分辨率文字背景
                    //靠近屏幕上方和右边缘调整背景绘图位置,避免超出屏幕范围
                    if (this.rect.Y < 16)
                    {
    
    
                        if (this.rect.X + 70 > this.Width - 71)
                            gs.FillRectangle(backBrush, this.rect.X - 71, this.rect.Y, 70, 15);
                        else
                            gs.FillRectangle(backBrush, this.rect.X, this.rect.Y, 70, 15);
                    }
                    else
                    {
    
    
                        if (this.rect.X > this.Width - 71)
                            gs.FillRectangle(backBrush, this.rect.X - 71, this.rect.Y - 16, 70, 15);
                        else

                            gs.FillRectangle(backBrush, this.rect.X, this.rect.Y - 16, 70, 15);
                    }
                }
                //定义绘制文字字体
                using (Font drawFont = new Font("Arial", 9))
                {
    
    
                    //定义分辨率文字画刷
                    using (SolidBrush drawBrush = new SolidBrush(Color.White))
                    {
    
    
                        //获取分辨率文字
                        string ratio = this.rect.Width.ToString() + " x " + rect.Height.ToString();
                        //绘制分辨率文字
                        if (this.rect.Y < 16)
                        {
    
    
                            if (this.rect.X > this.Width - 71)
                                gs.DrawString(ratio, drawFont, drawBrush, new Point(this.rect.X - 71, this.rect.Y));
                            else
                                gs.DrawString(ratio, drawFont, drawBrush, new Point(this.rect.X, this.rect.Y));
                        }
                        else
                        {
    
    
                            if (this.rect.X > this.Width - 71)
                                gs.DrawString(ratio, drawFont, drawBrush, new Point(this.rect.X - 71, this.rect.Y - 16));
                            else
                                gs.DrawString(ratio, drawFont, drawBrush, new Point(this.rect.X, this.rect.Y - 16));
                        }
                    }
                }
            }
        }

        //储存图片
        private void SaveFile(Bitmap bmp, bool isDefaultFile)
        {
    
    
            if (isDefaultFile)
            {
    
    
                bmp.Save(catchPicture, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
            {
    
    
                //用当前时间作为文件名
                string time = DateTime.Now.ToString();
                //去除时间中的非法字符
                string filename = null;
                foreach (char symbol in time)
                {
    
    
                    if (symbol != '/' && symbol != ':' && symbol != ' ')
                        filename += symbol;
                }
                saveFileDialog1.FileName = "截图" + filename;
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
    
    
                    //存储为jpeg或者png格式
                    switch (saveFileDialog1.FilterIndex)
                    {
    
    
                        case 0:
                            bmp.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Png);
                            break;
                        case 1:
                            bmp.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                        default:
                            bmp.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
                            break;
                    }
                }
            }
        }

        //判定并记录鼠标与矩形框的位置关系,改变鼠标形状,并记录下矩形框上的一个标记点,
        //用作计算调节矩形框时矩形框的位置及大小     
        private void CursorLocation()
        {
    
    
            int mouseX = Control.MousePosition.X;
            int mouseY = Control.MousePosition.Y;
            //鼠标在矩形内
            if (mouseX > rect.Left + 2 && mouseX < rect.Right - 2 && mouseY > rect.Top + 2 && mouseY < rect.Bottom - 2)
            {
    
    
                Cursor.Current = Cursors.SizeAll;
                if (this.isAdjust == true)
                {
    
    
                    this.mouseLocation = MouseLocation.InRectangle;
                    this.fixedPoint = new Point(this.rect.Left, this.rect.Top);
                }
            }
            //鼠标在矩形外
            else if (mouseX < rect.Left - 2 || mouseX > rect.Right + 2 || mouseY < rect.Top - 2 || mouseY > rect.Bottom + 2)
            {
    
    
                Cursor.Current = Cursors.Default;
                this.mouseLocation = MouseLocation.OutOfRectangle;
            }
            //鼠标在矩形上
            else
            {
    
    
                //鼠标在矩形的左边宽以及顶点上
                if (mouseX > rect.Left - 3 && mouseX < rect.Left + 3)
                {
    
    
                    if (mouseY > rect.Top - 3 && mouseY < rect.Top + 3)
                    {
    
    
                        Cursor.Current = Cursors.SizeNWSE;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.LeftUpPoint;
                            this.fixedPoint = new Point(this.rect.Right, this.rect.Bottom);
                        }
                    }
                    else if (mouseY > rect.Bottom - 3 && mouseY < rect.Bottom + 3)
                    {
    
    
                        Cursor.Current = Cursors.SizeNESW;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.LeftDownPoint;
                            this.fixedPoint = new Point(this.rect.Right, this.rect.Top);
                        }
                    }
                    else
                    {
    
    
                        Cursor.Current = Cursors.SizeWE;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.LeftLine;
                            this.fixedPoint = new Point(this.rect.Right, this.rect.Top);
                        }
                    }
                }
                //鼠标在矩形的右边宽以及顶点上
                else if (mouseX > rect.Right - 3 && mouseX < rect.Right + 3)
                {
    
    
                    if (mouseY == rect.Top)
                    {
    
    
                        Cursor.Current = Cursors.SizeNESW;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.RightUpPoint;
                            this.fixedPoint = new Point(this.rect.Left, this.rect.Bottom);
                        }
                    }
                    else if (mouseY > rect.Bottom - 3 && mouseY < rect.Bottom + 3)
                    {
    
    
                        Cursor.Current = Cursors.SizeNWSE;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.RightDownPoint;
                            this.fixedPoint = new Point(this.rect.Left, this.rect.Top);
                        }
                    }
                    else
                    {
    
    
                        Cursor.Current = Cursors.SizeWE;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.RightLine;
                            this.fixedPoint = new Point(this.rect.Left, this.rect.Top);
                        }

                    }
                }
                //鼠标在矩形的长上
                else
                {
    
    
                    if (mouseY > rect.Top - 3 && mouseY < rect.Top + 3)
                    {
    
    
                        Cursor.Current = Cursors.SizeNS;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.UpLine;
                            this.fixedPoint = new Point(this.rect.Left, this.rect.Bottom);
                        }
                    }
                    else
                    {
    
    
                        Cursor.Current = Cursors.SizeNS;
                        if (this.isAdjust == true)
                        {
    
    
                            this.mouseLocation = MouseLocation.DownLine;
                            this.fixedPoint = new Point(this.rect.Left, this.rect.Top);
                        }
                    }
                }
            }
        }

        private int GetScaleInt(int val)
        {
    
    
            return (int) (val * scale);
        }

        private void btn_confirm_Click(object sender, EventArgs e)
        {
    
    
            Bitmap bitmap = getCatchPictureBitmap();
            if (bitmap != null)
            {
    
    
                //复制到剪贴板
                Clipboard.SetImage(bitmap);
                //保持到默认路径
                SaveFile(bitmap, true);
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }

        private void btn_cancel_Click(object sender, EventArgs e)
        {
    
    
            this.Close();
        }

        private void btn_dowload_Click(object sender, EventArgs e)
        {
    
    
            Bitmap bitmap = getCatchPictureBitmap();
            if (bitmap != null)
            {
    
    
                //选择文件路径保存文件
                SaveFile(bitmap, false);
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }

        private Bitmap getCatchPictureBitmap()
        {
    
    
            if (isCatched == false)
            {
    
    
                return null;
            }
            //新建矩形大小的图片,并作为画板
            Bitmap bmp = new Bitmap(rect.Width, rect.Height);
            using (Graphics gs = Graphics.FromImage(bmp))
            {
    
    
                //从原始截屏图片originBmp上截取指定的矩形部分rect到图片画板bmp的指定部分,单位为像素。
                Rectangle tempRect = new Rectangle(GetScaleInt(this.rect.X), GetScaleInt(this.rect.Y), GetScaleInt(this.rect.Width), GetScaleInt(this.rect.Height));
                gs.DrawImage(this.originBmp, new Rectangle(0, 0, this.rect.Width, this.rect.Height), tempRect, GraphicsUnit.Pixel);
            }
            return bmp;
        }
    }
}

color conversion

    class ColorConversionUtils
    {
    
    

        public static void RGB2HSB(int red, int green, int blue, out double hue, out double sat, out double bri)
        {
    
    
            double r = ((double)red / 255.0);
            double g = ((double)green / 255.0);
            double b = ((double)blue / 255.0);

            double max = Math.Max(r, Math.Max(g, b));
            double min = Math.Min(r, Math.Min(g, b));

            hue = 0.0;
            if (max == r && g >= b)
            {
    
    
                if (max - min == 0) hue = 0.0;
                else hue = 60 * (g - b) / (max - min);
            }
            else if (max == r && g < b)
            {
    
    
                hue = 60 * (g - b) / (max - min) + 360;
            }
            else if (max == g)
            {
    
    
                hue = 60 * (b - r) / (max - min) + 120;
            }
            else if (max == b)
            {
    
    
                hue = 60 * (r - g) / (max - min) + 240;
            }

            sat = (max == 0) ? 0.0 : (1.0 - ((double)min / (double)max));
            bri = max;
        }

        public static void HSB2RGB(double hue, double sat, double bri, out int red, out int green, out int blue)
        {
    
    
            double r = 0;
            double g = 0;
            double b = 0;

            if (sat == 0)
            {
    
    
                r = g = b = bri;
            }
            else
            {
    
    
                // the color wheel consists of 6 sectors. Figure out which sector you're in.
                double sectorPos = hue / 60.0;
                int sectorNumber = (int)(Math.Floor(sectorPos));
                // get the fractional part of the sector
                double fractionalSector = sectorPos - sectorNumber;

                // calculate values for the three axes of the color. 
                double p = bri * (1.0 - sat);
                double q = bri * (1.0 - (sat * fractionalSector));
                double t = bri * (1.0 - (sat * (1 - fractionalSector)));

                // assign the fractional colors to r, g, and b based on the sector the angle is in.
                switch (sectorNumber)
                {
    
    
                    case 0:
                        r = bri;
                        g = t;
                        b = p;
                        break;
                    case 1:
                        r = q;
                        g = bri;
                        b = p;
                        break;
                    case 2:
                        r = p;
                        g = bri;
                        b = t;
                        break;
                    case 3:
                        r = p;
                        g = q;
                        b = bri;
                        break;
                    case 4:
                        r = t;
                        g = p;
                        b = bri;
                        break;
                    case 5:
                        r = bri;
                        g = p;
                        b = q;
                        break;
                }
            }
            red = Convert.ToInt32(r * 255);
            green = Convert.ToInt32(g * 255);
            blue = Convert.ToInt32(b * 255); ;
        }

        /// <summary>
        /// RGB转换HSL
        /// </summary>
        /// <param name="rgb"></param>
        /// <returns></returns>
        public static void RGB2HSL(int r, int g, int b, out double h, out double s, out double l)
        {
    
    
            float min, max, tmp, H, S, L;
            float R = r * 1.0f / 255, G = g * 1.0f / 255, B = b * 1.0f / 255;
            tmp = Math.Min(R, G);
            min = Math.Min(tmp, B);
            tmp = Math.Max(R, G);
            max = Math.Max(tmp, B);
            // H
            H = 0;
            if (max == min)
            {
    
    
                H = 0;  // 此时H应为未定义,通常写为0
            }
            else if (max == R && G > B)
            {
    
    
                H = 60 * (G - B) * 1.0f / (max - min) + 0;
            }
            else if (max == R && G < B)
            {
    
    
                H = 60 * (G - B) * 1.0f / (max - min) + 360;
            }
            else if (max == G)
            {
    
    
                H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
            }
            else if (max == B)
            {
    
    
                H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
            }
            // L 
            L = 0.5f * (max + min);
            // S
            S = 0;
            if (L == 0 || max == min)
            {
    
    
                S = 0;
            }
            else if (0 < L && L < 0.5)
            {
    
    
                S = (max - min) / (L * 2);
            }
            else if (L > 0.5)
            {
    
    
                S = (max - min) / (2 - 2 * L);
            }
            h = H;
            s = S;
            l = L;
        }

        /// <summary>
        /// HSL转换RGB
        /// </summary>
        /// <param name="hsl"></param>
        /// <returns></returns>
        public static void HSL2RGB(double h, double s, double l, out int r, out int g, out int b)
        {
    
    
            float R = 0f, G = 0f, B = 0f;
            float S = (float)s, L = (float)l;
            float temp1, temp2, temp3;
            if (S == 0f) // 灰色
            {
    
    
                R = L;
                G = L;
                B = L;
            }
            else
            {
    
    
                if (L < 0.5f)
                {
    
    
                    temp2 = L * (1.0f + S);
                }
                else
                {
    
    
                    temp2 = L + S - L * S;
                }
                temp1 = 2.0f * L - temp2;
                float H = (float)h * 1.0f / 360;
                // R
                temp3 = H + 1.0f / 3.0f;
                if (temp3 < 0) temp3 += 1.0f;
                if (temp3 > 1) temp3 -= 1.0f;
                R = temp3;
                // G
                temp3 = H;
                if (temp3 < 0) temp3 += 1.0f;
                if (temp3 > 1) temp3 -= 1.0f;
                G = temp3;
                // B
                temp3 = H - 1.0f / 3.0f;
                if (temp3 < 0) temp3 += 1.0f;
                if (temp3 > 1) temp3 -= 1.0f;
                B = temp3;
            }
            R = R * 255;
            G = G * 255;
            B = B * 255;
            r = (int)R;
            g = (int)G;
            b = (int)B;
        }
      
        /// <summary>
        /// RGB转换HSV
        /// </summary>
        /// <param name="rgb"></param>
        /// <returns></returns>
        public static void RGB2HSV(int r, int g, int b, out double h, out double s, out double v)
        {
    
    
            float min, max, tmp, H, S, V;
            float R = r * 1.0f / 255, G = g * 1.0f / 255, B = b * 1.0f / 255;
            tmp = Math.Min(R, G);
            min = Math.Min(tmp, B);
            tmp = Math.Max(R, G);
            max = Math.Max(tmp, B);
            // H
            H = 0;
            if (max == min)
            {
    
    
                H = 0;
            }
            else if (max == R && G > B)
            {
    
    
                H = 60 * (G - B) * 1.0f / (max - min) + 0;
            }
            else if (max == R && G < B)
            {
    
    
                H = 60 * (G - B) * 1.0f / (max - min) + 360;
            }
            else if (max == G)
            {
    
    
                H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
            }
            else if (max == B)
            {
    
    
                H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
            }
            // S
            if (max == 0)
            {
    
    
                S = 0;
            }
            else
            {
    
    
                S = (max - min) * 1.0f / max;
            }
            // V
            V = max;
            h = H;
            s = S;
            v = V;
        }
 
        /// <summary>
        /// HSV转换RGB
        /// </summary>
        /// <param name="hsv"></param>
        /// <returns></returns>
        public static void HSV2RGB(double h, double s, double v, out int r, out int g, out int b)
        {
    
    
            if (h == 360) h = 359; // 360为全黑,原因不明
            float R = 0f, G = 0f, B = 0f;
            if (s == 0)
            {
    
    
                r = (int)(v * 255);
                g = (int)(v * 255);
                b = (int)(v * 255);
                return;
            }
            float S = (float)s, V = (float)v;
            int H1 = (int)(h * 1.0f / 60), H = (int)h;
            float F = H * 1.0f / 60 - H1;
            float P = V * (1.0f - S);
            float Q = V * (1.0f - F * S);
            float T = V * (1.0f - (1.0f - F) * S);
            switch (H1)
            {
    
    
                case 0: R = V; G = T; B = P; break;
                case 1: R = Q; G = V; B = P; break;
                case 2: R = P; G = V; B = T; break;
                case 3: R = P; G = Q; B = V; break;
                case 4: R = T; G = P; B = V; break;
                case 5: R = V; G = P; B = Q; break;
            }
            R = R * 255;
            G = G * 255;
            B = B * 255;
            while (R > 255) R -= 255;
            while (R < 0) R += 255;
            while (G > 255) G -= 255;
            while (G < 0) G += 255;
            while (B > 255) B -= 255;
            while (B < 0) B += 255;
            r = (int)R;
            g = (int)G;
            b = (int)B;
        }

        public static void RGB2CMYK(int red, int green, int blue, out double c, out double m, out double y, out double k)
        {
    
    
            c = (double)(255 - red) / 255;
            m = (double)(255 - green) / 255;
            y = (double)(255 - blue) / 255;

            k = (double)Math.Min(c, Math.Min(m, y));
            if (k == 1.0)
            {
    
    
                c = m = y = 0;
            }
            else
            {
    
    
                c = (c - k) / (1 - k);
                m = (m - k) / (1 - k);
                y = (y - k) / (1 - k);
            }
        }
        public static void CMYK2RGB(double c, double m, double y, double k, out int r, out int g, out int b)
        {
    
    
            r = Convert.ToInt32((1.0 - c) * (1.0 - k) * 255.0);
            g = Convert.ToInt32((1.0 - m) * (1.0 - k) * 255.0);
            b = Convert.ToInt32((1.0 - y) * (1.0 - k) * 255.0);
        }

        public static string RGB2Hex(int r, int g, int b)
        {
    
    
            return String.Format("#{0:x2}{1:x2}{2:x2}", (int)r, (int)g, (int)b);
        }
        public static Color Hex2Color(string hexColor)
        {
    
    
            string r, g, b;

            if (hexColor != String.Empty)
            {
    
    
                hexColor = hexColor.Trim();
                if (hexColor[0] == '#') hexColor = hexColor.Substring(1, hexColor.Length - 1);

                r = hexColor.Substring(0, 2);
                g = hexColor.Substring(2, 2);
                b = hexColor.Substring(4, 2);

                r = Convert.ToString(16 * GetIntFromHex(r.Substring(0, 1)) + GetIntFromHex(r.Substring(1, 1)));
                g = Convert.ToString(16 * GetIntFromHex(g.Substring(0, 1)) + GetIntFromHex(g.Substring(1, 1)));
                b = Convert.ToString(16 * GetIntFromHex(b.Substring(0, 1)) + GetIntFromHex(b.Substring(1, 1)));

                return Color.FromArgb(Convert.ToInt32(r), Convert.ToInt32(g), Convert.ToInt32(b));
            }

            return Color.Empty;
        }
        private static int GetIntFromHex(string strHex)
        {
    
    
            switch (strHex)
            {
    
    
                case ("A"):
                    {
    
    
                        return 10;
                    }
                case ("B"):
                    {
    
    
                        return 11;
                    }
                case ("C"):
                    {
    
    
                        return 12;
                    }
                case ("D"):
                    {
    
    
                        return 13;
                    }
                case ("E"):
                    {
    
    
                        return 14;
                    }
                case ("F"):
                    {
    
    
                        return 15;
                    }
                default:
                    {
    
    
                        return int.Parse(strHex);
                    }
            }
        }
    }

GIF generation

Call the GifEncoder class to convert the recorded pictures into gif pictures code:

        /// <summary>
        /// 保存GIF到图片
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private bool SaveGifToFile(string path)
        {
    
    
            panel_progress.Visible = true;
            using (var stream = new MemoryStream())
            {
    
    
                using (var encoderNet = new GifEncoder(stream, null, null, 0))
                {
    
    
                	// _listFrames 是每一帧图像在磁盘中保存的路径
                    int count = _listFrames.Count;
                    pb_save.Maximum = count;
                    pb_save.Value = 0;
                    for (int i = 0; i < count; i++)
                    {
    
    
                        var bitmapAux = new Bitmap(_listFrames[i]);
                        encoderNet.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(1000 / gif_fps));
                        bitmapAux.Dispose();
                        pb_save.Value = i + 1;
                    }
                }

                stream.Position = 0;

                try
                {
    
    
                    using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 0x2000, false))
                    {
    
    
                        stream.WriteTo(fileStream);
                    }
                    panel_progress.Visible = false;
                    return true;
                }
                catch (Exception ex)
                {
    
    
                    //LogWriter.Log(ex, "Error while writing to disk.");
                }
            }
            panel_progress.Visible = false;
            return false;
        }

GifEncoder tool class:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace ScreenToGif.Encoding
{
    
    
    /// <summary>
    /// Encodes multiple images as an animated gif to a stream. <br />
    /// ALWAYS wire this up in a "using" block <br />
    /// Disposing the encoder will complete the file. <br />
    /// Uses default .net GIF encoding and adds animation headers.
    /// </summary>
    public sealed class GifEncoder : IDisposable
    {
    
    
        #region Header Constants

        private const string FileType = "GIF";

        private const string FileVersion = "89a";

        private const byte FileTrailer = 0x3b;

        private const int ApplicationExtensionBlockIdentifier = 0xff21;

        private const byte ApplicationBlockSize = 0x0b;

        private const string ApplicationIdentification = "NETSCAPE2.0";

        private const int GraphicControlExtensionBlockIdentifier = 0xf921;

        private const byte GraphicControlExtensionBlockSize = 0x04;

        private const long SourceGlobalColorInfoPosition = 10;

        private const long SourceGraphicControlExtensionPosition = 781;

        private const long SourceGraphicControlExtensionLength = 8;

        private const long SourceImageBlockPosition = 789;

        private const long SourceImageBlockHeaderLength = 11;

        private const long SourceColorBlockPosition = 13;

        private const long SourceColorBlockLength = 768;

        #endregion

        private bool _isFirstImage = true;

        private int? _width;

        private int? _height;

        private int? _repeatCount;

        private readonly Stream _stream;

        /// <summary>
        /// Frame delay for the frame.
        /// </summary>
        public TimeSpan FrameDelay {
    
     get; set; }

        /// <summary>
        /// Encodes multiple images as an animated gif to a stream. <br />
        /// ALWAYS wire this in a using block <br />
        /// Disposing the encoder will complete the file. <br />
        /// Uses default .net GIF encoding and adds animation headers.
        /// </summary>
        /// <param name="stream">The stream that will be written to.</param>
        /// <param name="width">Sets the width for this gif or null to use the first frame's width.</param>
        /// <param name="height">Sets the height for this gif or null to use the first frame's height.</param>
        /// <param name="repeatCount">The repeat count of the animation</param>
        public GifEncoder(Stream stream, int? width = null, int? height = null, int? repeatCount = null)
        {
    
    
            _stream = stream;
            _width = width;
            _height = height;
            _repeatCount = repeatCount;
        }

        /// <summary>
        /// Adds a frame to this animation.
        /// </summary>
        /// <param name="img">The image to add</param>
        /// <param name="x">The positioning x offset this image should be displayed at.</param>
        /// <param name="y">The positioning y offset this image should be displayed at.</param>
        /// <param name="frameDelay">The delay of the redraw of the next frame.</param>
        public void AddFrame(Image img, int x = 0, int y = 0, TimeSpan? frameDelay = null)
        {
    
    
            using (var gifStream = new MemoryStream())
            {
    
    
                img.Save(gifStream, ImageFormat.Gif);
                if (_isFirstImage) // Steal the global color table info
                {
    
    
                    InitHeader(gifStream, img.Width, img.Height);
                }
                WriteGraphicControlBlock(gifStream, frameDelay.GetValueOrDefault(FrameDelay));
                WriteImageBlock(gifStream, !_isFirstImage, x, y, img.Width, img.Height);
            }
            _isFirstImage = false;
        }

        private void InitHeader(Stream sourceGif, int w, int h)
        {
    
    
            // File Header
            WriteString(FileType);
            WriteString(FileVersion);
            WriteShort(_width.GetValueOrDefault(w)); // Initial Logical Width
            WriteShort(_height.GetValueOrDefault(h)); // Initial Logical Height
            sourceGif.Position = SourceGlobalColorInfoPosition;
            WriteByte(sourceGif.ReadByte()); // Global Color Table Info
            WriteByte(0); // Background Color Index
            WriteByte(0); // Pixel aspect ratio
            WriteColorTable(sourceGif);

            // App Extension Header
            WriteShort(ApplicationExtensionBlockIdentifier);
            WriteByte(ApplicationBlockSize);
            WriteString(ApplicationIdentification);
            WriteByte(3); // Application block length
            WriteByte(1);
            WriteShort(_repeatCount.GetValueOrDefault(0)); // Repeat count for images.
            WriteByte(0); // terminator
        }

        private void WriteColorTable(Stream sourceGif)
        {
    
    
            sourceGif.Position = SourceColorBlockPosition; // Locating the image color table
            var colorTable = new byte[SourceColorBlockLength];
            sourceGif.Read(colorTable, 0, colorTable.Length);
            _stream.Write(colorTable, 0, colorTable.Length);
        }

        private void WriteGraphicControlBlock(Stream sourceGif, TimeSpan frameDelay)
        {
    
    
            sourceGif.Position = SourceGraphicControlExtensionPosition; // Locating the source GCE
            var blockhead = new byte[SourceGraphicControlExtensionLength];
            sourceGif.Read(blockhead, 0, blockhead.Length); // Reading source GCE

            WriteShort(GraphicControlExtensionBlockIdentifier); // Identifier
            WriteByte(GraphicControlExtensionBlockSize); // Block Size
            WriteByte(blockhead[3] & 0xf7 | 0x08); // Setting disposal flag
            WriteShort(Convert.ToInt32(frameDelay.TotalMilliseconds / 10)); // Setting frame delay
            WriteByte(blockhead[6]); // Transparent color index
            WriteByte(0); // Terminator
        }

        private void WriteImageBlock(Stream sourceGif, bool includeColorTable, int x, int y, int h, int w)
        {
    
    
            sourceGif.Position = SourceImageBlockPosition; // Locating the image block
            var header = new byte[SourceImageBlockHeaderLength];
            sourceGif.Read(header, 0, header.Length);
            WriteByte(header[0]); // Separator
            WriteShort(x); // Position X
            WriteShort(y); // Position Y
            WriteShort(h); // Height
            WriteShort(w); // Width

            if (includeColorTable) // If first frame, use global color table - else use local
            {
    
    
                sourceGif.Position = SourceGlobalColorInfoPosition;
                WriteByte(sourceGif.ReadByte() & 0x3f | 0x80); // Enabling local color table
                WriteColorTable(sourceGif);
            }
            else
            {
    
    
                WriteByte(header[9] & 0x07 | 0x07); // Disabling local color table
            }

            WriteByte(header[10]); // LZW Min Code Size

            // Read/Write image data
            sourceGif.Position = SourceImageBlockPosition + SourceImageBlockHeaderLength;

            var dataLength = sourceGif.ReadByte();
            while (dataLength > 0)
            {
    
    
                var imgData = new byte[dataLength];
                sourceGif.Read(imgData, 0, dataLength);

                _stream.WriteByte(Convert.ToByte(dataLength));
                _stream.Write(imgData, 0, dataLength);
                dataLength = sourceGif.ReadByte();
            }

            _stream.WriteByte(0); // Terminator
        }

        private void WriteByte(int value)
        {
    
    
            _stream.WriteByte(Convert.ToByte(value));
        }

        private void WriteShort(int value)
        {
    
    
            _stream.WriteByte(Convert.ToByte(value & 0xff));
            _stream.WriteByte(Convert.ToByte((value >> 8) & 0xff));
        }

        private void WriteString(string value)
        {
    
    
            _stream.Write(value.ToArray().Select(c => (byte)c).ToArray(), 0, value.Length);
        }

        public void Dispose()
        {
    
    
            // Complete Application Block
            //WriteByte(0);
            // Complete File
            WriteByte(FileTrailer);
            // Pushing data
            _stream.Flush();
        }
    }
}

GIF generation

The core code of GIF compression is as follows:

// 通过CMD命令行调用gifscile.exe程序执行压缩操作
CMD("gifsicle.exe --colors 256 --scale 0.80 --lossy=35 --resize 600x500 \"C:\Users\Administrator\Desktop\GIF 2022-10-12 16-57-46.gif\" -o \"C:\Users\Administrator\Desktop\Modif_GIF 2022-10-12 16-57-46.gif\"");

/// <summary>
/// 执行cmd命令方法
/// </summary>
/// <param name="mingLing"></param>
/// <returns></returns>
string CMD(string mingLing)
{
    
    
	System.Diagnostics.Process p = new System.Diagnostics.Process();
	p.StartInfo.FileName = "cmd.exe";
	p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
	p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
	p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
	p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
	p.StartInfo.CreateNoWindow = true;//不显示程序窗口
	p.Start();//启动程序
	
	//向cmd窗口发送输入信息
	p.StandardInput.WriteLine(mingLing + "&exit");
	
	p.StandardInput.AutoFlush = true;
	//p.StandardInput.WriteLine("exit");
	//向标准输入写入要执行的命令。这里使用&是批处理命令的符号,表示前面一个命令不管是否执行成功都执行后面(exit)命令,如果不执行exit命令,后面调用ReadToEnd()方法会假死
	//同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令,后者表示必须前一个命令执行失败才会执行后面的命令
	
	//获取cmd窗口的输出信息
	string output = p.StandardOutput.ReadToEnd();
	
	//StreamReader reader = p.StandardOutput;
	//string line=reader.ReadLine();
	//while (!reader.EndOfStream)
	//{
    
    
	//    str += line + "  ";
	//    line = reader.ReadLine();
	//}
	
	p.WaitForExit();//等待程序执行完退出进程
	p.Close();
	
	//Console.WriteLine(output);
	return output;
}

Guess you like

Origin blog.csdn.net/loutengyuan/article/details/125669369