WPF調(diào)用WindowsAPI實(shí)現(xiàn)屏幕錄制
WPF 實(shí)現(xiàn)調(diào)用 WindowsAPI 實(shí)現(xiàn)屏幕錄制
- 框架使用
.NET4
Visual Studio 2022
- 接著上一篇做一個(gè)不依賴
ffmpeg
實(shí)現(xiàn)屏幕錄制 1000
毫秒調(diào)用WindowsAPI
進(jìn)行截取屏幕獲取圖像,并保存jpg
文件到指定路徑(保存的文件從0.jpg
至n.jpg
)。
實(shí)現(xiàn)代碼
1)獲取屏幕圖片并保存為 jpg
代碼如下:
????????private?static?BitmapSource?CaptureScreen() ????????{ ????????????IntPtr?desk?=?GetDesktopWindow(); ????????????IntPtr?dc?=?GetWindowDC(desk); ????????????IntPtr?memdc?=?CreateCompatibleDC(dc); ????????????IntPtr?bitmap?=?CreateCompatibleBitmap(dc,?screenWidth,?screenHeight); ????????????SelectObject(memdc,?bitmap); ????????????BitBlt(memdc,?0,?0,?screenWidth,?screenHeight,?dc,?0,?0,?0xCC0020); ????????????BitmapSource?source?=?Imaging.CreateBitmapSourceFromHBitmap(bitmap,?IntPtr.Zero,?Int32Rect.Empty,?BitmapSizeOptions.FromEmptyOptions()); ????????????ReleaseDC(desk,?dc); ????????????return?source; ????????} ????????Task.Factory.StartNew(()?=> ????????????{ ????????????????while?(IsRunning) ????????????????{ ????????????????????Thread.Sleep(1000); ????????????????????num?+=?1; ????????????????????Application.Current.Dispatcher.Invoke(new?Action(()?=> ????????????????????{ ????????????????????????var?drawingVisual?=?new?DrawingVisual(); ????????????????????????POINT?mousePosition; ????????????????????????using?(DrawingContext?drawingContext?=?drawingVisual.RenderOpen()) ????????????????????????{ ????????????????????????????drawingContext.DrawImage(CaptureScreen(), ????????????????????????????????new?Rect(new?Point(), ????????????????????????????????new?Size(screenWidth,?screenHeight))); ????????????????????????????if?(GetCursorPos(out?mousePosition)) ????????????????????????????{ ????????????????????????????????var?cursorSize?=?30; ????????????????????????????????var?cursorHalfSize?=?cursorSize?/?2; ????????????????????????????????var?cursorCenterX?=?mousePosition.X?-?SystemParameters.VirtualScreenLeft; ????????????????????????????????var?cursorCenterY?=?mousePosition.Y?-?SystemParameters.VirtualScreenTop; ????????????????????????????????drawingContext.DrawImage(GetCursorIcon(), ????????????????????????????????????new?Rect(new?Point(cursorCenterX,?cursorCenterY), ????????????????????????????????????new?Size(cursorSize,?cursorSize))); ????????????????????????????} ????????????????????????} ????????????????????????var?png?=?Path.Combine(tempDir,?$"{num}.jpg"); ????????????????????????using?(FileStream?stream?=?new?FileStream(png,?FileMode.Create)) ????????????????????????{ ????????????????????????????var?bitmap?=?new?RenderTargetBitmap((int)screenWidth,?(int)screenHeight,?96,?96,?PixelFormats.Pbgra32); ????????????????????????????bitmap.Render(drawingVisual); ????????????????????????????var?bitmapEncoder?=?BitmapFrame.Create(bitmap); ????????????????????????????bitmapEncoder.Freeze(); ????????????????????????????var?encoder?=?new?JpegBitmapEncoder(); ????????????????????????????encoder.QualityLevel?=?50; ????????????????????????????encoder.Frames.Add(bitmapEncoder); ????????????????????????????encoder.Save(stream); ????????????????????????????encoder.Frames.Clear(); ????????????????????????????GC.Collect(); ????????????????????????} ????????????????????})); ????????????????} ????????????});
當(dāng)點(diǎn)擊開始錄制按鈕時(shí)將窗體最小化,停止錄制時(shí)通過循環(huán)之前保存的文件夾地址排序循環(huán)添加每一幀圖像到 GifBitmapEncoder.Frames
中,但是在使用自帶的 GifBitmapEncoder
發(fā)現(xiàn)內(nèi)存占用很高,當(dāng)使用完成后沒有釋放 GC
,所以放棄了使用它。哪位大佬有好的方式歡迎分享
使用了GifEncoder
自己寫入 GIF
文件。
保存 gif
文件可以使用以下庫(kù)
- FreeImage.NET
- WpfAnimatedGif
- ImageTools
- Magick.NET
- GifRenderer
2) MainWindow.xaml
代碼如下:
<wd:Window ????x:Class="DesktopRecord.View.MainWindow" ????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ????xmlns:d="http://schemas.microsoft.com/expression/blend/2008" ????xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" ????xmlns:vm="clr-namespace:DesktopRecord.ViewModel" ????xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers" ????Title="屏幕錄制" ????Width="525" ????Height="200" ????Icon="/screen.ico" ????ResizeMode="CanMinimize" ????WindowStartupLocation="CenterScreen" ????mc:Ignorable="d"> ????<wd:Window.DataContext> ????????<vm:MainVM?/> ????</wd:Window.DataContext> ????<Grid> ????????<TabControl> ????????????<TabItem?Header="ffmpeg?錄制"> ????????????????<StackPanel ????????????????????HorizontalAlignment="Center" ????????????????????VerticalAlignment="Center" ????????????????????Orientation="Horizontal"> ????????????????????<Button ????????????????????????Margin="0,0,5,0" ????????????????????????Command="{Binding?MyStart}" ????????????????????????Content="{Binding?MyTime}" ????????????????????????Style="{StaticResource?WD.SuccessPrimaryButton}"?/> ????????????????????<Button ????????????????????????Margin="5,0,0,0" ????????????????????????Command="{Binding?MyStop}" ????????????????????????Content="停止錄制" ????????????????????????Style="{StaticResource?WD.DangerPrimaryButton}"?/> ????????????????</StackPanel> ????????????</TabItem> ????????????<TabItem?Header="WindowsAPI?錄制"> ????????????????<StackPanel ????????????????????HorizontalAlignment="Center" ????????????????????VerticalAlignment="Center" ????????????????????Orientation="Horizontal"> ????????????????????<Button ????????????????????????Margin="0,0,5,0" ????????????????????????Command="{Binding?RecordCommand}" ????????????????????????Content="開始錄制" ????????????????????????Style="{StaticResource?WD.SuccessPrimaryButton}"?/> ????????????????????<Button ????????????????????????Margin="5,0,0,0" ????????????????????????wd:Loading.Child="{x:Static?wd:NormalLoading.Default}" ????????????????????????wd:Loading.IsShow="{Binding?IsShow}" ????????????????????????Command="{Binding?RecordStopCommand}" ????????????????????????Content="停止錄制" ????????????????????????Style="{StaticResource?WD.DangerPrimaryButton}"?/> ????????????????</StackPanel> ????????????</TabItem> ????????</TabControl> ????</Grid> </wd:Window>
3)創(chuàng)建 MainVM.cs
代碼如下:
using?DesktopRecord.Helper; using?System; using?System.Diagnostics; using?System.Threading.Tasks; using?System.Windows.Input; using?System.Windows.Threading; using?WPFDevelopers.Controls; using?WPFDevelopers.Helpers; namespace?DesktopRecord.ViewModel { ????public?class?MainVM?:?ViewModelBase ????{ ????????private?DispatcherTimer?tm?=?new?DispatcherTimer(); ????????public?int?currentCount?=?0; ????????private?string?myTime?=?"開始錄制"; ????????public?string?MyTime ????????{ ????????????get?{?return?myTime;?} ????????????set ????????????{ ????????????????myTime?=?value; ????????????????NotifyPropertyChange("MyTime"); ????????????} ????????} ????????private?bool?isStart?=?true; ????????public?bool?IsStart ????????{ ????????????get?{?return?isStart;?} ????????????set ????????????{ ????????????????isStart?=?value; ????????????????NotifyPropertyChange("IsStart"); ????????????} ????????} ????????private?bool?_isShow; ????????public?bool?IsShow ????????{ ????????????get?{?return?_isShow;?} ????????????set ????????????{ ????????????????_isShow?=?value; ????????????????NotifyPropertyChange("IsShow"); ????????????} ????????} ????????private?ICommand?myStart; ????????public?ICommand?MyStart ????????{ ????????????get ????????????{ ????????????????return?myStart????(myStart?=?new?RelayCommand(p?=> ????????????????{ ????????????????????App.Current.MainWindow.WindowState?=?System.Windows.WindowState.Minimized; ????????????????????if?(!FFmpegHelper.Start()) ????????????????????{ ????????????????????????App.Current.MainWindow.WindowState?=?System.Windows.WindowState.Normal; ????????????????????????MessageBox.Show("未找到?【ffmpeg.exe】,請(qǐng)下載",?"錯(cuò)誤",?System.Windows.MessageBoxButton.OK,?System.Windows.MessageBoxImage.Error); ????????????????????????return; ????????????????????} ????????????????????tm.Tick?+=?tm_Tick; ????????????????????tm.Interval?=?TimeSpan.FromSeconds(1); ????????????????????tm.Start(); ????????????????????IsStart?=?false; ???????????????},?a?=> ????????????????{ ????????????????return?IsStart; ????????????????})); ????????????} ????????} ????????private?void?tm_Tick(object?sender,?EventArgs?e) ????????{ ????????????currentCount++; ????????????MyTime?=?"錄制中("?+?currentCount?+?"s)"; ????????} ????????///?<summary> ????????///?獲取或設(shè)置 ????????///?</summary> ????????private?ICommand?myStop; ????????///?<summary> ????????///?獲取或設(shè)置 ????????///?</summary> ????????public?ICommand?MyStop ????????{ ????????????get ????????????{ ????????????????return?myStop????(myStop?=?new?RelayCommand(p?=> ???????????????????????????{ ???????????????????????????????var?task?=?new?Task(()?=> ???????????????????????????????{ ???????????????????????????????????FFmpegHelper.Stop(); ???????????????????????????????????MyTime?=?"開始錄制"; ???????????????????????????????????tm.Stop(); ???????????????????????????????????currentCount?=?0; ???????????????????????????????????IsShow?=?true; ???????????????????????????????}); ???????????????????????????????task.ContinueWith(previousTask?=> ???????????????????????????????{ ???????????????????????????????????IsShow?=?false; ???????????????????????????????????IsStart?=?true; ???????????????????????????????????Process.Start(AppDomain.CurrentDomain.BaseDirectory); ???????????????????????????????},?TaskScheduler.FromCurrentSynchronizationContext()); ???????????????????????????????task.Start(); ???????????????????????????},?a?=> ????????????{ ????????????????return?!IsStart; ????????????})); ????????????} ????????} ????????public?ICommand?RecordCommand?{?get;?} ????????public?ICommand?RecordStopCommand?{?get;?} ????????public?MainVM() ????????{ ????????????RecordCommand?=?new?RelayCommand(Record,?CanExecuteRecordCommand); ????????????RecordStopCommand?=?new?RelayCommand(RecordStop); ????????} ????????void?Record(object?parameter) ????????{ ????????????App.Current.MainWindow.WindowState?=?System.Windows.WindowState.Minimized; ????????????Win32.Start(); ????????????IsStart?=?false; ????????} ????????private?bool?CanExecuteRecordCommand(object?parameter) ????????{ ????????????return?IsStart; ????????} ????????void?RecordStop(object?parameter) ????????{ ????????????var?task?=?new?Task(()?=> ????????????{ ????????????????Win32.Stop(); ????????????????IsShow?=?true; ????????????????Win32.Save($"DesktopRecord_{DateTime.Now.ToString("yyyyMMddHHmmss")}.gif"); ????????????}); ????????????task.ContinueWith(previousTask?=> ????????????{ ????????????????IsShow?=?false; ????????????????IsStart?=?true; ????????????????Process.Start(AppDomain.CurrentDomain.BaseDirectory); ????????????},?TaskScheduler.FromCurrentSynchronizationContext()); ????????????task.Start(); ????????} ????} }
4)創(chuàng)建 Win32.cs
代碼如下:
using?System; using?System.Collections.Generic; using?System.IO; using?System.Runtime.InteropServices; using?System.Threading; using?System.Threading.Tasks; using?System.Windows; using?System.Windows.Interop; using?System.Windows.Media; using?System.Windows.Media.Imaging; namespace?DesktopRecord.Helper { ????public?class?Win32 ????{ ????????[DllImport("user32.dll")] ????????public?static?extern?IntPtr?GetDesktopWindow(); ????????[DllImport("user32.dll")] ????????public?static?extern?IntPtr?GetWindowDC(IntPtr?hwnd); ????????[DllImport("user32.dll")] ????????public?static?extern?IntPtr?ReleaseDC(IntPtr?hwnd,?IntPtr?hdc); ????????[DllImport("gdi32.dll")] ????????public?static?extern?IntPtr?CreateCompatibleDC(IntPtr?hdc); ????????[DllImport("gdi32.dll")] ????????public?static?extern?IntPtr?CreateCompatibleBitmap(IntPtr?hdc,?int?nWidth,?int?nHeight); ????????[DllImport("gdi32.dll")] ????????public?static?extern?IntPtr?SelectObject(IntPtr?hdc,?IntPtr?hgdiobj); ????????[DllImport("gdi32.dll")] ????????public?static?extern?bool?BitBlt(IntPtr?hdcDest,?int?nXDest,?int?nYDest,?int?nWidth,?int?nHeight,?IntPtr?hdcSrc,?int?nXSrc,?int?nYSrc,?System.Int32?dwRop); ????????[DllImport("user32.dll")] ????????private?static?extern?bool?GetCursorInfo(out?CURSORINFO?pci); ????????[StructLayout(LayoutKind.Sequential)] ????????public?struct?POINT ????????{ ????????????public?int?X; ????????????public?int?Y; ????????} ????????[StructLayout(LayoutKind.Sequential)] ????????public?struct?CURSORINFO ????????{ ????????????public?Int32?cbSize; ????????????public?Int32?flags; ????????????public?IntPtr?hCursor; ????????????public?POINT?ptScreenPos; ????????} ????????[DllImport("user32.dll")] ????????public?static?extern?bool?GetCursorPos(out?POINT?lpPoint); ????????[DllImport("user32.dll")] ????????public?static?extern?bool?DestroyIcon(IntPtr?handle); ????????private?static?string?basePath?=?AppDomain.CurrentDomain.BaseDirectory; ????????private?static?string?tempDir?=?Path.Combine(Path.GetTempPath(),?"DesktopRecord"); ????????private?static?Thread?_thread?=?null; ????????public?static?bool?IsRunning?=?false; ????????static?int?screenWidth?=?Convert.ToInt32(SystemParameters.PrimaryScreenWidth); ????????static?int?screenHeight?=?Convert.ToInt32(SystemParameters.PrimaryScreenHeight); ????????private?static?BitmapSource?GetCursorIcon() ????????{ ????????????var?cursorInfo?=?new?CURSORINFO?{?cbSize?=?Marshal.SizeOf(typeof(CURSORINFO))?}; ????????????if?(GetCursorInfo(out?cursorInfo)?&&?cursorInfo.hCursor?!=?IntPtr.Zero) ????????????{ ????????????????try ????????????????{ ????????????????????return?Imaging.CreateBitmapSourceFromHIcon(cursorInfo.hCursor,?Int32Rect.Empty,?BitmapSizeOptions.FromEmptyOptions()); ????????????????} ????????????????finally ????????????????{ ????????????????????DestroyIcon(cursorInfo.hCursor); ????????????????} ????????????} ????????????return?null; ????????} ????????private?static?BitmapSource?CaptureScreen() ????????{ ????????????IntPtr?desk?=?GetDesktopWindow(); ????????????IntPtr?dc?=?GetWindowDC(desk); ????????????IntPtr?memdc?=?CreateCompatibleDC(dc); ????????????IntPtr?bitmap?=?CreateCompatibleBitmap(dc,?screenWidth,?screenHeight); ????????????SelectObject(memdc,?bitmap); ????????????BitBlt(memdc,?0,?0,?screenWidth,?screenHeight,?dc,?0,?0,?0xCC0020); ????????????BitmapSource?source?=?Imaging.CreateBitmapSourceFromHBitmap(bitmap,?IntPtr.Zero,?Int32Rect.Empty,?BitmapSizeOptions.FromEmptyOptions()); ????????????ReleaseDC(desk,?dc); ????????????return?source; ????????} ????????public?static?void?Start() ????????{ ????????????if?(_thread?==?null) ????????????{ ????????????????IsRunning?=?true; ????????????????_thread?=?new?Thread(Record); ????????????????_thread.Start(); ????????????} ????????} ????????public?static?void?Stop() ????????{ ????????????if?(_thread?!=?null) ????????????{ ????????????????IsRunning?=?false; ????????????????_thread?=?null; ????????????} ????????} ????????private?static?void?Record() ????????{ ????????????if?(!Directory.Exists(tempDir)) ????????????????Directory.CreateDirectory(tempDir); ????????????else ????????????{ ????????????????foreach?(string?file?in?Directory.GetFiles(tempDir)) ????????????????????File.Delete(file); ????????????} ????????????int?num?=?0; ????????????Task.Factory.StartNew(()?=>? ????????????{ ????????????????while?(IsRunning) ????????????????{ ????????????????????Thread.Sleep(20); ????????????????????num?+=?1; ????????????????????Application.Current.Dispatcher.Invoke(new?Action(()?=> ????????????????????{ ????????????????????????var?drawingVisual?=?new?DrawingVisual(); ????????????????????????POINT?mousePosition; ????????????????????????using?(DrawingContext?drawingContext?=?drawingVisual.RenderOpen()) ????????????????????????{ ????????????????????????????drawingContext.DrawImage(CaptureScreen(), ????????????????????????????????new?Rect(new?Point(), ????????????????????????????????new?Size(screenWidth,?screenHeight))); ????????????????????????????if?(GetCursorPos(out?mousePosition)) ????????????????????????????{ ????????????????????????????????var?cursorSize?=?30; ????????????????????????????????var?cursorHalfSize?=?cursorSize?/?2; ????????????????????????????????var?cursorCenterX?=?mousePosition.X?-?SystemParameters.VirtualScreenLeft; ????????????????????????????????var?cursorCenterY?=?mousePosition.Y?-?SystemParameters.VirtualScreenTop; ????????????????????????????????drawingContext.DrawImage(GetCursorIcon(), ????????????????????????????????????new?Rect(new?Point(cursorCenterX,?cursorCenterY), ????????????????????????????????????new?Size(cursorSize,?cursorSize))); ????????????????????????????} ????????????????????????} ????????????????????????var?png?=?Path.Combine(tempDir,?$"{num}.jpg"); ????????????????????????using?(FileStream?stream?=?new?FileStream(png,?FileMode.Create)) ????????????????????????{ ????????????????????????????var?bitmap?=?new?RenderTargetBitmap((int)screenWidth,?(int)screenHeight,?96,?96,?PixelFormats.Pbgra32); ????????????????????????????bitmap.Render(drawingVisual); ????????????????????????????var?bitmapEncoder?=?BitmapFrame.Create(bitmap); ????????????????????????????bitmapEncoder.Freeze(); ????????????????????????????var?encoder?=?new?JpegBitmapEncoder(); ????????????????????????????encoder.QualityLevel?=?50; ????????????????????????????encoder.Frames.Add(bitmapEncoder); ????????????????????????????encoder.Save(stream); ????????????????????????????encoder.Frames.Clear(); ????????????????????????????GC.Collect(); ????????????????????????} ????????????????????})); ????????????????} ????????????}); ????????} ????????public?static?void?ClearRecording() ????????{ ????????????if?(Directory.Exists(tempDir)) ????????????????Directory.Delete(tempDir,?true); ????????????Directory.CreateDirectory(tempDir); ????????} ????????public?static?void?Save(string?output) ????????{ ????????????try ????????????{ ????????????????output?=?Path.Combine(basePath,?output); ????????????????var?imagePaths?=?Directory.GetFiles(tempDir,?"*.jpg",?SearchOption.TopDirectoryOnly); ????????????????if?(imagePaths.Length?==?0)?return; ????????????????#region?GC不釋放,暫時(shí)棄用 ????????????????//using?(var?gifFileStream?=?new?FileStream(Output,?FileMode.Create)) ????????????????//{ ????????????????//????var?gifBitmapEncoder?=?new?GifBitmapEncoder(); ????????????????//????var?jpgs?=?Directory.GetFiles(tempDir,?"*.jpg",?SearchOption.TopDirectoryOnly); ????????????????//????if?(jpgs.Length?==?0)?return; ????????????????//????foreach?(string?file?in?jpgs) ????????????????//????{ ????????????????//????????using?(var?stream?=?new?FileStream(file,?FileMode.Open,?FileAccess.Read)) ????????????????//????????{ ????????????????//????????????var?bitmapDecoder?=?new?JpegBitmapDecoder(stream,?BitmapCreateOptions.None,?BitmapCacheOption.OnLoad); ????????????????//????????????var?bitmapFrame?=?bitmapDecoder.Frames[0]; ????????????????//????????????bitmapDecoder.Frames[0].Freeze(); ????????????????//????????????gifBitmapEncoder.Frames.Add(bitmapFrame); ????????????????//????????????bitmapFrame?=?null; ????????????????//????????????bitmapDecoder?=?null; ????????????????//????????????GC.Collect(); ????????????????//????????????stream.Dispose(); ????????????????//????????} ????????????????//????} ????????????????//????gifBitmapEncoder.Save(gifFileStream); ????????????????//????gifBitmapEncoder.Frames.Clear(); ????????????????//????gifBitmapEncoder?=?null; ????????????????//????GC.Collect(); ????????????????//????GC.WaitForPendingFinalizers(); ????????????????//}? ????????????????#endregion ????????????????var?bitmapFrames?=?new?List<BitmapFrame>(); ????????????????foreach?(string?imagePath?in?imagePaths) ????????????????{ ????????????????????var?frame?=?BitmapFrame.Create(new?Uri(imagePath,?UriKind.RelativeOrAbsolute)); ????????????????????bitmapFrames.Add(frame); ????????????????} ????????????????using?(var?gifStream?=?new?MemoryStream()) ????????????????{ ????????????????????using?(var?encoder?=?new?GifEncoder(gifStream)) ????????????????????{ ????????????????????????foreach?(var?imagePath?in?imagePaths) ????????????????????????{ ????????????????????????????var?image?=?System.Drawing.Image.FromFile(imagePath); ????????????????????????????encoder.AddFrame(image,?0,?0,?TimeSpan.FromSeconds(0)); ????????????????????????} ????????????????????} ????????????????????gifStream.Position?=?0; ????????????????????using?(var?fileStream?=?new?FileStream(output,?FileMode.Create)) ????????????????????{ ????????????????????????fileStream.Write(gifStream.ToArray(),?0,?gifStream.ToArray().Length); ????????????????????} ????????????????} ????????????} ????????????catch ????????????{ ????????????????throw; ????????????} ????????} ????} }
5)創(chuàng)建 GifEncoder.cs
代碼如下:
using?System; using?System.Drawing; using?System.Drawing.Imaging; using?System.IO; using?System.Linq; namespace?DesktopRecord.Helper { ????public?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; ????????public?TimeSpan?FrameDelay?{?get;?set;?} ????????///?<summary> ????????///?Encodes?multiple?images?as?an?animated?gif?to?a?stream.?<br?/> ????????///?ALWAYS?ALWAYS?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> ????????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> ????????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?File ????????????WriteByte(FileTrailer); ????????????//?Pushing?data ????????????_stream.Flush(); ????????} ????} }
效果圖
以上就是WPF調(diào)用WindowsAPI實(shí)現(xiàn)屏幕錄制的詳細(xì)內(nèi)容,更多關(guān)于WPF WindowsAPI屏幕錄制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#中實(shí)現(xiàn)插入、刪除Excel分頁符的方法
這篇文章主要給大家介紹了關(guān)于在C#中實(shí)現(xiàn)插入、刪除Excel分頁符的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05一文搞懂C#實(shí)現(xiàn)讀寫文本文件中的數(shù)據(jù)
這篇文章重點(diǎn)給大家介紹C#實(shí)現(xiàn)讀寫文本文件中的數(shù)據(jù)的一些知識(shí),讀取.txt文件數(shù)據(jù)的實(shí)例代碼及寫入讀取過程完整代碼,感興趣的朋友跟隨小編一起看看吧2021-06-06C#獲取微信小程序的云數(shù)據(jù)庫(kù)中數(shù)據(jù)的示例代碼
本文主要介紹了C#獲取微信小程序的云數(shù)據(jù)庫(kù)中數(shù)據(jù)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08