c# 实现gif转化,视频合成,提取视频帧等

主代码

c 复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TextDancing
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 区域大小
        int maskSize = 2;
        // 字体
        Font font = new Font("仿宋", 20);
        // 字母c的间隔
        int unit_w = 20;


        //1.提取gif
        private void btnGIF_Click(object sender, EventArgs e)
        {
            // 路径
            string gifPath = "1.gif";

            // 载入gif图片
            using (Image gifImg = Image.FromFile(gifPath))
            {
                // 每一帧的维度(宽高)
                FrameDimension dimension = new FrameDimension(gifImg.FrameDimensionsList[0]);

                // 获取帧数
                int frameCount = gifImg.GetFrameCount(dimension);

                for (int i = 0; i < frameCount; i++)
                {
                    // 选择当前帧
                    gifImg.SelectActiveFrame(dimension, i);

                    // 每一张图片
                    // frame 原始gif 的每一张图片
                    using (Bitmap frame = new Bitmap(gifImg))
                    {
                        // bmp:准备转换的图片
                        Bitmap bmp = new Bitmap(frame.Width * 10, frame.Height * 10);

                        Graphics g = Graphics.FromImage(bmp);

                        // 纯黑的背景
                        g.Clear(Color.Black);

                        // 抗锯齿
                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                        g.SmoothingMode = SmoothingMode.AntiAlias;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

                        int idxI = 0;
                        int idxJ = 0;

                        for (int m = 0; m < frame.Width; m+=maskSize)
                        {
                            idxJ = 0;

                            for (int n = 0; n < frame.Height; n+=maskSize)
                            {
                                Color c = frame.GetPixel(m, n);
                                int gray = (c.R + c.G + c.B) / 3;
                                ///
                                bool draw = true;
                                String s = "蔡";

                                if (draw == true)
                                {
                                    g.DrawString("c", font,
                                        new SolidBrush(Color.FromArgb(gray, gray, gray)),
                                        idxI * unit_w, idxJ * unit_w);
                                }
                                idxJ++;
                            }
                            idxI++;
                        }
                        bmp.Save("cool//" + i.ToString() + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }
            }
        }


        //2.合成视频
        private void btnAVI_Click(object sender, EventArgs e)
        {
            SynthesisVideo("processedFrameMP4", 24);
        }
        
        //3.提取视频帧
        private void btnMP4_Click(object sender, EventArgs e)
        {
            ExtractFrames("2.mp4", "frameMP4");
        }

        // 合成视频
        public void SynthesisVideo(string path, int frame_rate = 30)
        {
            AVIWriter aviWriter = new AVIWriter();

            // 获取指定文件夹中所有的 .jpg 文件
            string[] imageFiles = Directory.GetFiles(path, "*.jpg");

            Bitmap bmp1 = new Bitmap(imageFiles[0]);

            //:avi中所有图像皆不能小于width及height
            Bitmap avi_frame = aviWriter.Create(System.DateTime.Now.Hour.ToString() + "_"
                + System.DateTime.Now.Minute.ToString() + "_" +
                System.DateTime.Now.Second.ToString() + ".avi", (uint)frame_rate, bmp1.Width, bmp1.Height);

            //由于转化为avi后呈现相反,所以翻转
            for (int i = 0; i < imageFiles.Length; i++)
            {
                Bitmap bmpKun = new Bitmap(imageFiles[i]);
                bmpKun.RotateFlip(RotateFlipType.Rotate180FlipX);

                //载入图像
                aviWriter.LoadFrame(bmpKun);
                aviWriter.AddFrame();
            }


            //释放资源
            aviWriter.Close();
            avi_frame.Dispose();

            MessageBox.Show("转换完毕");
        }

        // 提取视频帧
        public void ExtractFrames(string videoFilePath, string outputFolderPath, int frameRate = 1)
        {
            var ffmpegPath = "ffmpeg.exe"; // 或者如果 FFmpeg 在你的环境变量路径中,直接使用 "ffmpeg"
            var arguments = $"-i \"{videoFilePath}\" -q:v 1 -sws_flags lanczos \"{outputFolderPath}/frame_%04d.jpg\"";

            using (var process = new Process())
            {
                process.StartInfo = new ProcessStartInfo
                {
                    FileName = ffmpegPath,
                    Arguments = arguments,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true // FFmpeg 喜欢通过 StdErr 输出日志
                };

                process.Start();
                process.WaitForExit(); // 等待 FFmpeg 进程结束
            }
        }

        // 处理图片
        int videoMaskSize2 = 15;
        public void ProcessImagesInFolder2(String folderPath, String process_path)
        {
            // 获取指定文件夹中所有的.jpg文件
            string[] imageFiles = Directory.GetFiles(folderPath, "*.jpg");

            // 循环处理所有的图片
            foreach (string imageFile in imageFiles)
            {
                // 使用文件路径加载每个图片为Bitmap对象
                using (Bitmap frame = new Bitmap(imageFile))
                {
                    Bitmap bmp = new Bitmap(frame.Width, frame.Height);
                    Graphics graphics = Graphics.FromImage(bmp);
                    graphics.Clear(Color.Black);

                    int idxI = 0;
                    int idxJ = 0;

                    for (int m = 0; m < frame.Width; m += videoMaskSize2)
                    {
                        idxJ = 0;

                        int r = 0;
                        int g = 0;
                        int b = 0;

                        for (int n = 0; n < frame.Height; n += videoMaskSize2)
                        {
                            // 块内求和
                            for (int x = 0; x < videoMaskSize2; x++)
                            {
                                for (int y = 0; y < videoMaskSize2; y++)
                                {
                                    Color c1;
                                    if (m + x >= frame.Width || n + y >= frame.Height)
                                    {
                                        c1 = Color.FromArgb(0, 0, 0);
                                    } else
                                    {
                                        c1 = frame.GetPixel(m + x, n + y);
                                    }

                                    r += c1.R;
                                    g += c1.G;
                                    b += c1.B;
                                }
                            }

                            // 求平均
                            r /= (videoMaskSize2 * videoMaskSize2);
                            g /= (videoMaskSize2 * videoMaskSize2);
                            b /= (videoMaskSize2 * videoMaskSize2);

                            // 画圈圈
                            graphics.FillEllipse(new SolidBrush(Color.FromArgb(r, g, b)),
                                idxI * videoMaskSize2, idxJ * videoMaskSize2, videoMaskSize2, videoMaskSize2);

                            idxJ++;
                        }
                        idxI++;
                    }

                    // 保存图片
                    string processedImagePath = Path.Combine(process_path, "processed_" + Path.GetFileName(imageFile));
                    bmp.Save(processedImagePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                }
            }
        }

        private void btnCircle_Click(object sender, EventArgs e)
        {
            ProcessImagesInFolder2("frameMP4", "processedFrameMP4");
        }
    }
}

AVL writer类

c 复制代码
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TextDancing
{
    public class AVIWriter
    {
        const string AVIFILE32 = "AVIFIL32";
        private int _pfile = 0;
        private IntPtr _ps = new IntPtr(0);
        private IntPtr _psCompressed = new IntPtr(0);
        private UInt32 _frameRate = 0;
        private int _count = 0;
        private UInt32 _width = 0;
        private UInt32 _stride = 0;
        private UInt32 _height = 0;
        //avi标识
        private UInt32 _fccType = 1935960438; // vids
        private UInt32 _fccHandler = 808810089;// IV50

        private Bitmap _bmp;

        [DllImport(AVIFILE32)]
        private static extern void AVIFileInit();

        [DllImport(AVIFILE32)]
        private static extern int AVIFileOpenW(ref int ptr_pfile, [MarshalAs(UnmanagedType.LPWStr)] string fileName, int flags, int dummy);

        [DllImport(AVIFILE32)]
        private static extern int AVIFileCreateStream(int ptr_pfile, out IntPtr ptr_ptr_avi, ref AVISTREAMINFOW ptr_streaminfo);
        [DllImport(AVIFILE32)]
        private static extern int AVIMakeCompressedStream(out IntPtr ppsCompressed, IntPtr aviStream, ref AVICOMPRESSOPTIONS ao, int dummy);

        [DllImport(AVIFILE32)]
        private static extern int AVIStreamSetFormat(IntPtr aviStream, Int32 lPos, ref BITMAPINFOHEADER lpFormat, Int32 cbFormat);

        [DllImport(AVIFILE32)]
        unsafe private static extern int AVISaveOptions(int hwnd, UInt32 flags, int nStreams, IntPtr* ptr_ptr_avi, AVICOMPRESSOPTIONS** ao);

        [DllImport(AVIFILE32)]
        private static extern int AVIStreamWrite(IntPtr aviStream, Int32 lStart, Int32 lSamples, IntPtr lpBuffer, Int32 cbBuffer, Int32 dwFlags, Int32 dummy1, Int32 dummy2);

        [DllImport(AVIFILE32)]
        private static extern int AVIStreamRelease(IntPtr aviStream);

        [DllImport(AVIFILE32)]
        private static extern int AVIFileRelease(int pfile);

        [DllImport(AVIFILE32)]
        private static extern void AVIFileExit();

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct AVISTREAMINFOW
        {
            public UInt32 fccType;
            public UInt32 fccHandler;
            public UInt32 dwFlags;
            public UInt32 dwCaps;
            public UInt16 wPriority;
            public UInt16 wLanguage;
            public UInt32 dwScale;
            public UInt32 dwRate;
            public UInt32 dwStart;
            public UInt32 dwLength;
            public UInt32 dwInitialFrames;
            public UInt32 dwSuggestedBufferSize;
            public UInt32 dwQuality;
            public UInt32 dwSampleSize;
            public UInt32 rect_left;
            public UInt32 rect_top;
            public UInt32 rect_right;
            public UInt32 rect_bottom;
            public UInt32 dwEditCount;
            public UInt32 dwFormatChangeCount;
            public UInt16 szName0;
            public UInt16 szName1;
            public UInt16 szName2;
            public UInt16 szName3;
            public UInt16 szName4;
            public UInt16 szName5;
            public UInt16 szName6;
            public UInt16 szName7;
            public UInt16 szName8;
            public UInt16 szName9;
            public UInt16 szName10;
            public UInt16 szName11;
            public UInt16 szName12;
            public UInt16 szName13;
            public UInt16 szName14;
            public UInt16 szName15;
            public UInt16 szName16;
            public UInt16 szName17;
            public UInt16 szName18;
            public UInt16 szName19;
            public UInt16 szName20;
            public UInt16 szName21;
            public UInt16 szName22;
            public UInt16 szName23;
            public UInt16 szName24;
            public UInt16 szName25;
            public UInt16 szName26;
            public UInt16 szName27;
            public UInt16 szName28;
            public UInt16 szName29;
            public UInt16 szName30;
            public UInt16 szName31;
            public UInt16 szName32;
            public UInt16 szName33;
            public UInt16 szName34;
            public UInt16 szName35;
            public UInt16 szName36;
            public UInt16 szName37;
            public UInt16 szName38;
            public UInt16 szName39;
            public UInt16 szName40;
            public UInt16 szName41;
            public UInt16 szName42;
            public UInt16 szName43;
            public UInt16 szName44;
            public UInt16 szName45;
            public UInt16 szName46;
            public UInt16 szName47;
            public UInt16 szName48;
            public UInt16 szName49;
            public UInt16 szName50;
            public UInt16 szName51;
            public UInt16 szName52;
            public UInt16 szName53;
            public UInt16 szName54;
            public UInt16 szName55;
            public UInt16 szName56;
            public UInt16 szName57;
            public UInt16 szName58;
            public UInt16 szName59;
            public UInt16 szName60;
            public UInt16 szName61;
            public UInt16 szName62;
            public UInt16 szName63;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct AVICOMPRESSOPTIONS
        {
            public UInt32 fccType;
            public UInt32 fccHandler;
            public UInt32 dwKeyFrameEvery;

            public UInt32 dwQuality;
            public UInt32 dwBytesPerSecond;

            public UInt32 dwFlags;
            public IntPtr lpFormat;
            public UInt32 cbFormat;
            public IntPtr lpParms;
            public UInt32 cbParms;
            public UInt32 dwInterleaveEvery;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct BITMAPINFOHEADER
        {
            public UInt32 biSize;
            public Int32 biWidth;
            public Int32 biHeight;
            public Int16 biPlanes;
            public Int16 biBitCount;
            public UInt32 biCompression;
            public UInt32 biSizeImage;
            public Int32 biXPelsPerMeter;
            public Int32 biYPelsPerMeter;
            public UInt32 biClrUsed;
            public UInt32 biClrImportant;
        }

        public class AviException : ApplicationException
        {
            public AviException(string s) : base(s) { }
            public AviException(string s, Int32 hr)
                : base(s)
            {

                if (hr == AVIERR_BADPARAM)
                {
                    err_msg = "AVIERR_BADPARAM";
                }
                else
                {
                    err_msg = "unknown";
                }
            }

            public string ErrMsg()
            {
                return err_msg;
            }
            private const Int32 AVIERR_BADPARAM = -2147205018;
            private string err_msg;
        }

        public Bitmap Create(string fileName, UInt32 frameRate, int width, int
            height)
        {
            _frameRate = frameRate;
            _width = (UInt32)width;
            _height = (UInt32)height;
            _bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            //锁定为24位位图
            BitmapData bmpDat = _bmp.LockBits(new Rectangle(0, 0, width,
                height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            _stride = (UInt32)bmpDat.Stride;
            _bmp.UnlockBits(bmpDat);
            AVIFileInit();
            int hr = AVIFileOpenW(ref _pfile, fileName, 4097, 0);
            if (hr != 0)
            {
                throw new AviException("Create错误!");
            }

            CreateStream();
            SetOptions();

            return _bmp;
        }

        public void AddFrame()
        {

            BitmapData bmpDat = _bmp.LockBits(
                new Rectangle(0, 0, (int)_width, (int)_height),
                ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int hr = AVIStreamWrite(_psCompressed, _count, 1,
                bmpDat.Scan0,
                (Int32)(_stride * _height),
                0,
                0,
                0);

            if (hr != 0)
            {
                throw new AviException("AVIStreamWrite");
            }

            _bmp.UnlockBits(bmpDat);

            _count++;
        }

        public void LoadFrame(Bitmap nextframe)
        {

            _bmp = new Bitmap(nextframe);
        }

        public void Close()
        {
            AVIStreamRelease(_ps);
            AVIStreamRelease(_psCompressed);

            AVIFileRelease(_pfile);
            AVIFileExit();
        }

        /// <summary>
        /// 创建流文件
        /// </summary>
        private void CreateStream()
        {
            AVISTREAMINFOW strhdr = new AVISTREAMINFOW();
            strhdr.fccType = _fccType;
            strhdr.fccHandler = _fccHandler;
            strhdr.dwFlags = 0;
            strhdr.dwCaps = 0;
            strhdr.wPriority = 0;
            strhdr.wLanguage = 0;
            strhdr.dwScale = 1;
            strhdr.dwRate = _frameRate;
            strhdr.dwStart = 0;
            strhdr.dwLength = 0;
            strhdr.dwInitialFrames = 0;
            strhdr.dwSuggestedBufferSize = _height * _stride;
            strhdr.dwQuality = 0xffffffff;
            strhdr.dwSampleSize = 0;
            strhdr.rect_top = 0;
            strhdr.rect_left = 0;
            strhdr.rect_bottom = _height;
            strhdr.rect_right = _width;
            strhdr.dwEditCount = 0;
            strhdr.dwFormatChangeCount = 0;
            strhdr.szName0 = 0;
            strhdr.szName1 = 0;

            int hr = AVIFileCreateStream(_pfile, out _ps, ref strhdr);

            if (hr != 0)
            {
                throw new AviException("AVIFileCreateStream");
            }
        }

        /// <summary>
        /// 设置参数
        /// </summary>
        unsafe private void SetOptions()
        {
            AVICOMPRESSOPTIONS opts = new AVICOMPRESSOPTIONS();
            opts.fccType = _fccType;
            opts.fccHandler = 0;
            opts.dwKeyFrameEvery = 0;
            opts.dwQuality = 0;
            opts.dwFlags = 0;
            opts.dwBytesPerSecond = 0;
            opts.lpFormat = new IntPtr(0);
            opts.cbFormat = 0;
            opts.lpParms = new IntPtr(0);
            opts.cbParms = 0;
            opts.dwInterleaveEvery = 0;

            AVICOMPRESSOPTIONS* p = &opts;
            AVICOMPRESSOPTIONS** pp = &p;

            IntPtr x = _ps;
            IntPtr* ptr_ps = &x;

            AVISaveOptions(0, 0, 1, ptr_ps, pp);

            int hr = AVIMakeCompressedStream(out _psCompressed, _ps, ref
                opts, 0);
            if (hr != 0)
            {
                throw new AviException("AVIMakeCompressedStream");
            }

            BITMAPINFOHEADER bi = new BITMAPINFOHEADER();
            bi.biSize = 40;
            bi.biWidth = (Int32)_width;
            bi.biHeight = (Int32)_height;
            bi.biPlanes = 1;
            bi.biBitCount = 24;
            bi.biCompression = 0;
            bi.biSizeImage = _stride * _height;
            bi.biXPelsPerMeter = 0;
            bi.biYPelsPerMeter = 0;
            bi.biClrUsed = 0;
            bi.biClrImportant = 0;

            hr = AVIStreamSetFormat(_psCompressed, 0, ref bi, 40);
            if (hr != 0)
            {
                throw new AviException("AVIStreamSetFormat", hr);
            }
        }



    };
}

需要的工具

ffmpeg.exe

相关推荐
萧鼎1 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸1 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农1 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
秋の花1 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端1 小时前
第六章 7.0 LinkList
java·开发语言·网络
可峰科技1 小时前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
全栈开发圈1 小时前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
面试鸭1 小时前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫