├── .gitignore ├── AnimatedGif ├── AnimatedGif.cs ├── AnimatedGif.csproj ├── AnimatedGifCreator.cs ├── Extensions.cs ├── GifClass.cs ├── GifProperties.cs ├── GrayscaleQuantizer.cs ├── Helper.cs ├── OctreeQuantizer.cs ├── PaletteQuantizer.cs ├── Quantizer.cs └── VideoEncoder.cs ├── GifCapture.Net ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Assets │ ├── IconFonts │ │ ├── Font Awesome 6 Pro-Light-300.otf │ │ └── Segoe MDL2 Assets.ttf │ └── Images │ │ ├── camera.png │ │ ├── logo.ico │ │ ├── stop.png │ │ ├── 录制区域.png │ │ ├── 录制屏幕.png │ │ ├── 录制窗口.png │ │ ├── 截取区域.png │ │ ├── 截取屏幕.png │ │ └── 截取窗口.png ├── Base │ ├── ComparableExtensions.cs │ ├── IScreen.cs │ ├── IWindow.cs │ ├── ScreenWrapper.cs │ └── Window.cs ├── Controls │ ├── Magnifier.xaml │ ├── Magnifier.xaml.cs │ ├── PuncturedRegion.xaml │ ├── PuncturedRegion.xaml.cs │ ├── StripedBorder.xaml │ └── StripedBorder.xaml.cs ├── Converters │ ├── NegatingConverter.cs │ └── VisibilityConverter.cs ├── Exceptions │ └── WindowClosedException.cs ├── Gif │ ├── GdiTargetDeviceContext.cs │ ├── GifFrame.cs │ ├── IImageProvider.cs │ ├── ITargetDeviceContext.cs │ └── RectangleProvider.cs ├── GifCapture.Net.csproj ├── Images │ ├── DrawingImage.cs │ └── IBitmapImage.cs ├── Models │ └── Dpi.cs ├── Native │ ├── DwmApi.cs │ ├── EnumWindowsProc.cs │ ├── Enums │ │ ├── DrawIconExFlags.cs │ │ ├── FileOperationFlags.cs │ │ ├── FileOperationType.cs │ │ ├── GetWindowEnum.cs │ │ ├── GetWindowLongValue.cs │ │ ├── SetWindowPositionFlags.cs │ │ └── WindowStyles.cs │ ├── Gdi32.cs │ ├── NativeExtensions.cs │ ├── Structs │ │ ├── CursorInfo.cs │ │ ├── IconInfo.cs │ │ ├── RECT.cs │ │ └── StockObjects.cs │ ├── UnsafeBitmap.cs │ └── User32.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Resources.zh-hant.resx │ └── Resources.zh.resx ├── Screen │ ├── GraphicsExtensions.cs │ ├── MouseCursor.cs │ ├── ScreenShot.cs │ ├── ScreenShotInternal.cs │ └── WindowScreenShotBackdrop.cs ├── Services │ ├── IPlatformServices.cs │ ├── NotificationsService.cs │ ├── ServiceProvider.cs │ └── WindowsPlatformServices.cs ├── Utils │ └── WpfExtensions.cs ├── ViewModels │ ├── MainViewModel.cs │ ├── NotifyPropertyChanged.cs │ ├── RegionSelectorViewModel.cs │ └── ScreenPickerViewModel.cs └── Windows │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── RecordBarWindow.xaml │ ├── RecordBarWindow.xaml.cs │ ├── RegionPickerWindow.xaml │ ├── RegionPickerWindow.xaml.cs │ ├── ScreenPickerWindow.xaml │ ├── ScreenPickerWindow.xaml.cs │ ├── VideoSourcePickerWindow.xaml │ └── VideoSourcePickerWindow.xaml.cs ├── GifCapture.sln ├── GifCapture.sln.DotSettings.user ├── GifCapture ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Assets │ ├── IconFonts │ │ ├── Font Awesome 6 Pro-Light-300.otf │ │ └── Segoe MDL2 Assets.ttf │ └── Images │ │ ├── camera.png │ │ ├── logo.ico │ │ ├── stop.png │ │ ├── 录制区域.png │ │ ├── 录制屏幕.png │ │ ├── 录制窗口.png │ │ ├── 截取区域.png │ │ ├── 截取屏幕.png │ │ └── 截取窗口.png ├── Base │ ├── ComparableExtensions.cs │ ├── IScreen.cs │ ├── IWindow.cs │ ├── ScreenWrapper.cs │ └── Window.cs ├── Controls │ ├── Magnifier.xaml │ ├── Magnifier.xaml.cs │ ├── PuncturedRegion.xaml │ ├── PuncturedRegion.xaml.cs │ ├── StripedBorder.xaml │ └── StripedBorder.xaml.cs ├── Converters │ ├── NegatingConverter.cs │ └── VisibilityConverter.cs ├── Exceptions │ └── WindowClosedException.cs ├── Gif │ ├── GdiTargetDeviceContext.cs │ ├── GifFrame.cs │ ├── IImageProvider.cs │ ├── ITargetDeviceContext.cs │ └── RectangleProvider.cs ├── GifCapture.csproj ├── Images │ ├── DrawingImage.cs │ └── IBitmapImage.cs ├── Models │ └── Dpi.cs ├── Native │ ├── DwmApi.cs │ ├── EnumWindowsProc.cs │ ├── Enums │ │ ├── DrawIconExFlags.cs │ │ ├── FileOperationFlags.cs │ │ ├── FileOperationType.cs │ │ ├── GetWindowEnum.cs │ │ ├── GetWindowLongValue.cs │ │ ├── SetWindowPositionFlags.cs │ │ └── WindowStyles.cs │ ├── Gdi32.cs │ ├── NativeExtensions.cs │ ├── Structs │ │ ├── CursorInfo.cs │ │ ├── IconInfo.cs │ │ ├── RECT.cs │ │ └── StockObjects.cs │ ├── UnsafeBitmap.cs │ └── User32.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Resources.zh-hant.resx │ └── Resources.zh.resx ├── Screen │ ├── GraphicsExtensions.cs │ ├── MouseCursor.cs │ ├── ScreenShot.cs │ ├── ScreenShotInternal.cs │ └── WindowScreenShotBackdrop.cs ├── Services │ ├── IPlatformServices.cs │ ├── NotificationsService.cs │ ├── ServiceProvider.cs │ └── WindowsPlatformServices.cs ├── StaticValue.cs ├── Utils │ └── WpfExtensions.cs ├── ViewModels │ ├── MainViewModel.cs │ ├── NotifyPropertyChanged.cs │ ├── RegionSelectorViewModel.cs │ └── ScreenPickerViewModel.cs └── Windows │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── RecordBarWindow.xaml │ ├── RecordBarWindow.xaml.cs │ ├── RegionPickerWindow.xaml │ ├── RegionPickerWindow.xaml.cs │ ├── ScreenPickerWindow.xaml │ ├── ScreenPickerWindow.xaml.cs │ ├── VideoSourcePickerWindow.xaml │ └── VideoSourcePickerWindow.xaml.cs ├── Illustrator ├── 录制区域.ai ├── 录制屏幕.ai ├── 录制窗口.ai ├── 截取区域.ai ├── 截取屏幕.ai └── 截取窗口.ai ├── LICENSE ├── README.md ├── donate.jpg ├── gifcapture.gif ├── icons8-paypal-48.png └── microsoft.svg /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .idea/ 4 | /packages/ 5 | riderModule.iml 6 | /_ReSharper.Caches/ 7 | /.vs/ 8 | AppStoreInstaller/ -------------------------------------------------------------------------------- /AnimatedGif/AnimatedGif.cs: -------------------------------------------------------------------------------- 1 | namespace AnimatedGif { 2 | public static class AnimatedGif { 3 | /// 4 | /// Create a new Animated GIF 5 | /// 6 | /// The Path where the Animated GIF gets saved 7 | /// Delay between frames 8 | /// GIF Repeat count (0 meaning forever) 9 | /// 10 | public static AnimatedGifCreator Create(string filePath, int delay, int repeat = 0) { 11 | return new AnimatedGifCreator(filePath, delay, repeat); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /AnimatedGif/AnimatedGif.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | true 8 | AnyCPU;x64 9 | 10 | 11 | none 12 | false 13 | true 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /AnimatedGif/Extensions.cs: -------------------------------------------------------------------------------- 1 | #region License Information (GPL v3) 2 | 3 | /* 4 | Source code provocatively stolen from ShareX: https://github.com/ShareX/ShareX. 5 | (Seriously, awesome work over there, I used some of the parts to create an easy 6 | to use .NET package for everyone.) 7 | Their License: 8 | 9 | ShareX - A program that allows you to take screenshots and share any file type 10 | Copyright (c) 2007-2017 ShareX Team 11 | This program is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU General Public License 13 | as published by the Free Software Foundation; either version 2 14 | of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | Optionally you can also view the license at . 23 | */ 24 | 25 | #endregion License Information (GPL v3) 26 | 27 | 28 | using System.Drawing; 29 | using System.Drawing.Imaging; 30 | using System.IO; 31 | 32 | namespace AnimatedGif 33 | { 34 | public static class Extensions 35 | { 36 | public static void SaveGif(this Image img, Stream stream, GifQuality quality) 37 | { 38 | if (quality == GifQuality.Default) 39 | { 40 | img.Save(stream, ImageFormat.Gif); 41 | } 42 | else 43 | { 44 | Quantizer quantizer; 45 | switch (quality) 46 | { 47 | case GifQuality.Grayscale: 48 | quantizer = new GrayscaleQuantizer(); 49 | break; 50 | case GifQuality.Bit4: 51 | quantizer = new OctreeQuantizer(15, 4); 52 | break; 53 | case GifQuality.Bit8: 54 | default: 55 | quantizer = new OctreeQuantizer(255, 4); 56 | break; 57 | } 58 | 59 | using (var quantized = quantizer.Quantize(img)) 60 | { 61 | quantized.Save(stream, ImageFormat.Gif); 62 | } 63 | } 64 | } 65 | 66 | public static void Write(this FileStream stream, byte[] array) 67 | { 68 | stream.Write(array, 0, array.Length); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /AnimatedGif/GifProperties.cs: -------------------------------------------------------------------------------- 1 | #region License Information (GPL v3) 2 | 3 | /* 4 | Source code provocatively stolen from ShareX: https://github.com/ShareX/ShareX. 5 | (Seriously, awesome work over there, I used some of the parts to create an easy 6 | to use .NET package for everyone.) 7 | Their License: 8 | 9 | ShareX - A program that allows you to take screenshots and share any file type 10 | Copyright (c) 2007-2017 ShareX Team 11 | This program is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU General Public License 13 | as published by the Free Software Foundation; either version 2 14 | of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | Optionally you can also view the license at . 23 | */ 24 | 25 | #endregion License Information (GPL v3) 26 | 27 | 28 | namespace AnimatedGif { 29 | public enum GifQuality { 30 | Default, 31 | Bit8, 32 | Bit4, 33 | Grayscale 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AnimatedGif/GrayscaleQuantizer.cs: -------------------------------------------------------------------------------- 1 | #region License Information (GPL v3) 2 | 3 | /* 4 | Source code provocatively stolen from ShareX: https://github.com/ShareX/ShareX. 5 | (Seriously, awesome work over there, I used some of the parts to create an easy 6 | to use .NET package for everyone.) 7 | Their License: 8 | 9 | ShareX - A program that allows you to take screenshots and share any file type 10 | Copyright (c) 2007-2017 ShareX Team 11 | This program is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU General Public License 13 | as published by the Free Software Foundation; either version 2 14 | of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | Optionally you can also view the license at . 23 | */ 24 | 25 | #endregion License Information (GPL v3) 26 | 27 | 28 | using System; 29 | using System.Collections; 30 | using System.Drawing; 31 | 32 | namespace AnimatedGif 33 | { 34 | /// 35 | /// Summary description for PaletteQuantizer. 36 | /// 37 | public class GrayscaleQuantizer : PaletteQuantizer 38 | { 39 | /// 40 | /// Construct the palette quantizer 41 | /// 42 | /// 43 | /// Palette quantization only requires a single quantization step 44 | /// 45 | public GrayscaleQuantizer() 46 | : base(new ArrayList()) 47 | { 48 | Colors = new Color[256]; 49 | 50 | const int nColors = 256; 51 | 52 | // Initialize a new color table with entries that are determined 53 | // by some optimal palette-finding algorithm; for demonstration 54 | // purposes, use a grayscale. 55 | for (uint i = 0; i < nColors; i++) 56 | { 57 | const uint alpha = 0xFF; // Colors are opaque. 58 | uint intensity = Convert.ToUInt32(i * 0xFF / (nColors - 1)); // Even distribution. 59 | 60 | // The GIF encoder makes the first entry in the palette 61 | // that has a ZERO alpha the transparent color in the GIF. 62 | // Pick the first one arbitrarily, for demonstration purposes. 63 | 64 | // Create a gray scale for demonstration purposes. 65 | // Otherwise, use your favorite color reduction algorithm 66 | // and an optimum palette for that algorithm generated here. 67 | // For example, a color histogram, or a median cut palette. 68 | Colors[i] = Color.FromArgb((int) alpha, 69 | (int) intensity, 70 | (int) intensity, 71 | (int) intensity); 72 | } 73 | } 74 | 75 | /// 76 | /// Override this to process the pixel in the second pass of the algorithm 77 | /// 78 | /// The pixel to quantize 79 | /// The quantized value 80 | protected override byte QuantizePixel(Color32 pixel) 81 | { 82 | double luminance = pixel.Red * 0.299 + pixel.Green * 0.587 + pixel.Blue * 0.114; 83 | 84 | // Gray scale is an intensity map from black to white. 85 | // Compute the index to the grayscale entry that 86 | // approximates the luminance, and then round the index. 87 | // Also, constrain the index choices by the number of 88 | // colors to do, and then set that pixel's index to the 89 | // byte value. 90 | byte colorIndex = (byte) (luminance + 0.5); 91 | 92 | return colorIndex; 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /AnimatedGif/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace AnimatedGif { 8 | public class Helper { 9 | public static readonly string[] ImageFileExtensions = 10 | {"jpg", "jpeg", "png", "apng", "gif", "bmp", "ico", "tif", "tiff"}; 11 | 12 | //Is File an Image 13 | public static bool IsImage(string filePath) { 14 | return CheckExtension(filePath, ImageFileExtensions); 15 | } 16 | 17 | //Check if extension is one of parameter extensions 18 | public static bool CheckExtension(string filePath, IEnumerable extensions) { 19 | string ext = GetFilenameExtension(filePath); 20 | 21 | return !string.IsNullOrEmpty(ext) && 22 | extensions.Any(x => ext.Equals(x, StringComparison.InvariantCultureIgnoreCase)); 23 | } 24 | 25 | //Get extension of file 26 | public static string GetFilenameExtension(string filePath) { 27 | if (!string.IsNullOrEmpty(filePath)) { 28 | int pos = filePath.LastIndexOf('.'); 29 | 30 | if (pos >= 0) return filePath.Substring(pos + 1); 31 | } 32 | 33 | return null; 34 | } 35 | 36 | //Load image without garbage leak 37 | public static Image LoadImage(string filePath) { 38 | try { 39 | if (!string.IsNullOrEmpty(filePath) && IsImage(filePath) && File.Exists(filePath)) 40 | return Image.FromStream(new MemoryStream(File.ReadAllBytes(filePath))); 41 | } catch (Exception e) { 42 | Console.WriteLine(e.Message); 43 | } 44 | 45 | return null; 46 | } 47 | 48 | //Create a Directory from File Path 49 | public static void CreateDirectoryFromFilePath(string path) { 50 | if (!string.IsNullOrEmpty(path)) CreateDirectoryFromDirectoryPath(Path.GetDirectoryName(path)); 51 | } 52 | 53 | public static void CreateDirectoryFromDirectoryPath(string path) { 54 | if (!string.IsNullOrEmpty(path) && !Directory.Exists(path)) 55 | try { 56 | Directory.CreateDirectory(path); 57 | } catch (Exception e) { 58 | Console.WriteLine(e.Message); 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /AnimatedGif/VideoEncoder.cs: -------------------------------------------------------------------------------- 1 | #region License Information (GPL v3) 2 | 3 | /* 4 | Source code provocatively stolen from ShareX: https://github.com/ShareX/ShareX. 5 | (Seriously, awesome work over there, I used some of the parts to create an easy 6 | to use .NET package for everyone.) 7 | Their License: 8 | 9 | ShareX - A program that allows you to take screenshots and share any file type 10 | Copyright (c) 2007-2017 ShareX Team 11 | This program is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU General Public License 13 | as published by the Free Software Foundation; either version 2 14 | of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | Optionally you can also view the license at . 23 | */ 24 | 25 | #endregion License Information (GPL v3) 26 | 27 | 28 | using System.Diagnostics; 29 | using System.IO; 30 | 31 | namespace AnimatedGif { 32 | public class VideoEncoder { 33 | public VideoEncoder() { 34 | Name = "x264 encoder to MP4"; 35 | Path = "x264.exe"; 36 | Args = "--output %output %input"; 37 | OutputExtension = "mp4"; 38 | } 39 | 40 | public string Name { get; set; } 41 | public string Path { get; set; } 42 | public string Args { get; set; } 43 | public string OutputExtension { get; set; } 44 | 45 | /// AVI file path 46 | /// Target file path without extension 47 | public void Encode(string sourceFilePath, string targetFilePath) { 48 | if (IsValid() && !string.IsNullOrEmpty(sourceFilePath) && !string.IsNullOrEmpty(targetFilePath)) { 49 | if (!targetFilePath.EndsWith(OutputExtension)) targetFilePath += "." + OutputExtension.TrimStart('.'); 50 | 51 | Helper.CreateDirectoryFromFilePath(targetFilePath); 52 | 53 | using (var process = new Process()) { 54 | var psi = new ProcessStartInfo(Path) { 55 | Arguments = Args.Replace("%input", "\"" + sourceFilePath + "\"") 56 | .Replace("%output", "\"" + targetFilePath + "\""), 57 | WindowStyle = ProcessWindowStyle.Hidden 58 | }; 59 | process.StartInfo = psi; 60 | process.Start(); 61 | process.WaitForExit(); 62 | } 63 | } 64 | } 65 | 66 | public bool IsValid() { 67 | return !string.IsNullOrEmpty(Path) && File.Exists(Path) && !string.IsNullOrEmpty(OutputExtension); 68 | } 69 | 70 | public override string ToString() { 71 | return Name; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /GifCapture.Net/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | pack://application:,,,/Assets/IconFonts/#Segoe MDL2 Assets 7 | 8 | 9 | 64 | 65 | -------------------------------------------------------------------------------- /GifCapture.Net/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using Windows.Foundation.Collections; 7 | using GifCapture.Services; 8 | using Microsoft.Toolkit.Uwp.Notifications; 9 | 10 | namespace GifCapture 11 | { 12 | public partial class App : Application 13 | { 14 | private bool _registered = false; 15 | 16 | protected override void OnStartup(StartupEventArgs e) 17 | { 18 | #region terminate if there's any existing instance 19 | 20 | Mutex procMutex = new System.Threading.Mutex(true, "_GIF_CAPTURE", out bool result); 21 | if (!result) 22 | { 23 | Application.Current.Shutdown(0); 24 | return; 25 | } 26 | 27 | procMutex.ReleaseMutex(); 28 | 29 | #endregion 30 | 31 | RegisterEvents(); 32 | // Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en"); 33 | // click on the notification tip 34 | ToastNotificationManagerCompat.OnActivated += toastArgs => 35 | { 36 | // Obtain the arguments from the notification 37 | ToastArguments args = ToastArguments.Parse(toastArgs.Argument); 38 | 39 | // Obtain any user input (text boxes, menu selections) from the notification 40 | ValueSet userInput = toastArgs.UserInput; 41 | 42 | // Need to dispatch to UI thread if performing UI operations 43 | Application.Current.Dispatcher.Invoke(delegate 44 | { 45 | if (args.Contains("imagePath")) 46 | { 47 | string s = args.Get("imagePath"); 48 | NotificationsService.OpenFile(s); 49 | } 50 | }); 51 | }; 52 | _registered = true; 53 | base.OnStartup(e); 54 | } 55 | 56 | protected override void OnExit(ExitEventArgs e) 57 | { 58 | base.OnExit(e); 59 | if (_registered) 60 | { 61 | //unload notifications 62 | ToastNotificationManagerCompat.Uninstall(); 63 | } 64 | } 65 | 66 | #region 异常处理 67 | 68 | private void RegisterEvents() 69 | { 70 | //Task线程内未捕获异常处理事件 71 | TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 72 | 73 | //UI线程未捕获异常处理事件(UI主线程) 74 | this.DispatcherUnhandledException += App_DispatcherUnhandledException; 75 | 76 | //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) 77 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 78 | } 79 | 80 | private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) 81 | { 82 | try 83 | { 84 | if (e.Exception is Exception exception) 85 | { 86 | HandleException(exception); 87 | } 88 | } 89 | catch (Exception ex) 90 | { 91 | HandleException(ex); 92 | } 93 | finally 94 | { 95 | e.SetObserved(); 96 | } 97 | } 98 | 99 | //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) 100 | private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 101 | { 102 | try 103 | { 104 | if (e.ExceptionObject is Exception exception) 105 | { 106 | HandleException(exception); 107 | } 108 | } 109 | catch (Exception ex) 110 | { 111 | HandleException(ex); 112 | } 113 | } 114 | 115 | //UI线程未捕获异常处理事件(UI主线程) 116 | private static void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) 117 | { 118 | try 119 | { 120 | HandleException(e.Exception); 121 | } 122 | catch (Exception ex) 123 | { 124 | HandleException(ex); 125 | } 126 | finally 127 | { 128 | e.Handled = true; 129 | } 130 | } 131 | 132 | private static void HandleException(Exception ex) 133 | { 134 | MessageBox.Show(ex.ToString(), "ERROR", MessageBoxButton.OK, MessageBoxImage.Error); 135 | } 136 | 137 | #endregion 138 | } 139 | } -------------------------------------------------------------------------------- /GifCapture.Net/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] -------------------------------------------------------------------------------- /GifCapture.Net/Assets/IconFonts/Font Awesome 6 Pro-Light-300.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/IconFonts/Font Awesome 6 Pro-Light-300.otf -------------------------------------------------------------------------------- /GifCapture.Net/Assets/IconFonts/Segoe MDL2 Assets.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/IconFonts/Segoe MDL2 Assets.ttf -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/camera.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/logo.ico -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/stop.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/录制区域.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/录制区域.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/录制屏幕.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/录制屏幕.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/录制窗口.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/录制窗口.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/截取区域.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/截取区域.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/截取屏幕.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/截取屏幕.png -------------------------------------------------------------------------------- /GifCapture.Net/Assets/Images/截取窗口.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture.Net/Assets/Images/截取窗口.png -------------------------------------------------------------------------------- /GifCapture.Net/Base/ComparableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Base 4 | { 5 | public static class ComparableExtensions 6 | { 7 | public static T Clip(this T value, T minimum, T maximum) where T : IComparable 8 | { 9 | if (value.CompareTo(minimum) < 0) 10 | return minimum; 11 | 12 | if (value.CompareTo(maximum) > 0) 13 | return maximum; 14 | 15 | return value; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /GifCapture.Net/Base/IScreen.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace GifCapture.Base 4 | { 5 | public interface IScreen 6 | { 7 | Rectangle Rectangle { get; } 8 | 9 | string DeviceName { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /GifCapture.Net/Base/IWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Base 5 | { 6 | /// 7 | /// Minimal representation of a Window. 8 | /// 9 | public interface IWindow 10 | { 11 | bool IsAlive { get; } 12 | 13 | bool IsVisible { get; } 14 | 15 | bool IsMaximized { get; } 16 | 17 | IntPtr Handle { get; } 18 | 19 | string Title { get; } 20 | 21 | Rectangle Rectangle { get; } 22 | } 23 | } -------------------------------------------------------------------------------- /GifCapture.Net/Base/ScreenWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Linq; 4 | 5 | namespace GifCapture.Base 6 | { 7 | class ScreenWrapper : IScreen 8 | { 9 | readonly System.Windows.Forms.Screen _screen; 10 | 11 | ScreenWrapper(System.Windows.Forms.Screen screen) 12 | { 13 | _screen = screen; 14 | } 15 | 16 | public Rectangle Rectangle => _screen.Bounds; 17 | 18 | public string DeviceName => _screen.DeviceName; 19 | 20 | public static IEnumerable Enumerate() => System.Windows.Forms.Screen.AllScreens.Select(m => new ScreenWrapper(m)); 21 | } 22 | } -------------------------------------------------------------------------------- /GifCapture.Net/Controls/Magnifier.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 22 | 23 | 24 | 26 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /GifCapture.Net/Controls/Magnifier.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace GifCapture.Controls 5 | { 6 | public partial class Magnifier : UserControl 7 | { 8 | public Magnifier() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | public static readonly DependencyProperty TargetProperty = 14 | DependencyProperty.Register(nameof(Target), typeof(UIElement), typeof(Magnifier)); 15 | 16 | 17 | public UIElement Target 18 | { 19 | get => (UIElement) GetValue(TargetProperty); 20 | set => SetValue(TargetProperty, value); 21 | } 22 | 23 | public void UpdateViewBox(Point point, Size size) 24 | { 25 | if (PART_VisualBrush != null) 26 | { 27 | PART_VisualBrush.Viewbox = new Rect(point, size); 28 | } 29 | } 30 | 31 | public void UpdatePositionTextBlock(Point point, Size size) 32 | { 33 | PositionTextBlock.Text = $"X,Y={point.X},{point.Y} WxH={(int) size.Width}x{(int) size.Height}"; 34 | } 35 | 36 | public void HideRectangle() 37 | { 38 | Rectangle1.Visibility = Visibility.Hidden; 39 | Rectangle2.Visibility = Visibility.Hidden; 40 | Rectangle3.Visibility = Visibility.Hidden; 41 | } 42 | 43 | public void ShowRectangle() 44 | { 45 | Rectangle1.Visibility = Visibility.Visible; 46 | Rectangle2.Visibility = Visibility.Visible; 47 | Rectangle3.Visibility = Visibility.Visible; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /GifCapture.Net/Controls/PuncturedRegion.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GifCapture.Net/Controls/PuncturedRegion.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using GifCapture.Base; 4 | 5 | namespace GifCapture.Controls 6 | { 7 | public partial class PuncturedRegion : UserControl 8 | { 9 | public Rect? Region 10 | { 11 | get => (Rect?) GetValue(RegionProperty); 12 | set => SetValue(RegionProperty, value); 13 | } 14 | 15 | public static readonly DependencyProperty RegionProperty = DependencyProperty.Register( 16 | nameof(Region), 17 | typeof(Rect?), 18 | typeof(PuncturedRegion), 19 | new PropertyMetadata(RegionChanged)); 20 | 21 | static void RegionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 22 | { 23 | if (obj is PuncturedRegion r) 24 | { 25 | switch (e.NewValue) 26 | { 27 | case null: 28 | // Must not be collapsed, since ActualWidth and ActualHeight are used. 29 | r.Visibility = Visibility.Hidden; 30 | break; 31 | 32 | case Rect region: 33 | var w = r.ActualWidth; 34 | var h = r.ActualHeight; 35 | 36 | r.BorderTop.Margin = new Thickness(); 37 | r.BorderTop.Width = w; 38 | r.BorderTop.Height = region.Top.Clip(0, h); 39 | 40 | r.BorderBottom.Margin = new Thickness(0, region.Bottom, 0, 0); 41 | r.BorderBottom.Width = w; 42 | r.BorderBottom.Height = (h - region.Bottom).Clip(0, h); 43 | 44 | r.BorderLeft.Margin = new Thickness(0, region.Top, 0, 0); 45 | r.BorderLeft.Width = region.Left.Clip(0, w); 46 | r.BorderLeft.Height = region.Height; 47 | 48 | r.BorderRight.Margin = new Thickness(region.Right, region.Top, 0, 0); 49 | r.BorderRight.Width = (w - region.Right).Clip(0, w); 50 | r.BorderRight.Height = region.Height; 51 | 52 | r.Visibility = Visibility.Visible; 53 | break; 54 | } 55 | } 56 | } 57 | 58 | public PuncturedRegion() 59 | { 60 | InitializeComponent(); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /GifCapture.Net/Controls/StripedBorder.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /GifCapture.Net/Controls/StripedBorder.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace GifCapture.Controls 4 | { 5 | public partial class StripedBorder : UserControl 6 | { 7 | public StripedBorder() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture.Net/Converters/NegatingConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace GifCapture.Converters 7 | { 8 | public class NegatingConverter : IValueConverter 9 | { 10 | static object DoConvert(object value) 11 | { 12 | if (value is bool b) 13 | return !b; 14 | 15 | return Binding.DoNothing; 16 | } 17 | 18 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | switch (value) 21 | { 22 | case bool b when targetType == typeof(Visibility): 23 | return b ? Visibility.Collapsed : Visibility.Visible; 24 | 25 | case bool b: 26 | return !b; 27 | 28 | case Visibility visibility when targetType == typeof(Visibility): 29 | return visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible; 30 | 31 | case Visibility visibility: 32 | return visibility == Visibility.Collapsed; 33 | 34 | default: 35 | return Binding.DoNothing; 36 | } 37 | } 38 | 39 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 40 | { 41 | return DoConvert(value); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /GifCapture.Net/Converters/VisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace GifCapture.Converters 7 | { 8 | public class VisibilityConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value is bool b && b) 13 | { 14 | return Visibility.Visible; 15 | } 16 | else 17 | { 18 | return Visibility.Collapsed; 19 | } 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /GifCapture.Net/Exceptions/WindowClosedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Exceptions 4 | { 5 | /// 6 | /// Thrown when a closed window is used. 7 | /// 8 | public class WindowClosedException : Exception 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /GifCapture.Net/Gif/GdiTargetDeviceContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Native; 4 | 5 | namespace GifCapture.Gif 6 | { 7 | public class GdiTargetDeviceContext : ITargetDeviceContext 8 | { 9 | readonly IntPtr _hdcDest, _hBitmap; 10 | 11 | public GdiTargetDeviceContext(IntPtr srcDc, int width, int height) 12 | { 13 | _hdcDest = Gdi32.CreateCompatibleDC(srcDc); 14 | _hBitmap = Gdi32.CreateCompatibleBitmap(srcDc, width, height); 15 | Gdi32.SelectObject(_hdcDest, _hBitmap); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | Gdi32.DeleteDC(_hdcDest); 21 | Gdi32.DeleteObject(_hBitmap); 22 | } 23 | 24 | public IntPtr GetDc() => _hdcDest; 25 | 26 | public Bitmap GetBitmap() 27 | { 28 | return Image.FromHbitmap(_hBitmap); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /GifCapture.Net/Gif/GifFrame.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace GifCapture.Gif 4 | { 5 | public class GifFrame 6 | { 7 | public Bitmap Bitmap { get; set; } 8 | public int Delay { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture.Net/Gif/IImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Gif 5 | { 6 | /// 7 | /// Provides images. 8 | /// Must provide in 32-bpp RGB. 9 | /// 10 | public interface IImageProvider : IDisposable 11 | { 12 | /// 13 | /// Capture an image. 14 | /// 15 | Bitmap Capture(); 16 | 17 | /// 18 | /// Height of Captured image. 19 | /// 20 | int Height { get; } 21 | 22 | /// 23 | /// Width of Captured image. 24 | /// 25 | int Width { get; } 26 | } 27 | } -------------------------------------------------------------------------------- /GifCapture.Net/Gif/ITargetDeviceContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Gif 5 | { 6 | public interface ITargetDeviceContext : IDisposable 7 | { 8 | IntPtr GetDc(); 9 | 10 | Bitmap GetBitmap(); 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture.Net/Gif/RectangleProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Native; 4 | using GifCapture.Screen; 5 | 6 | namespace GifCapture.Gif 7 | { 8 | public class RectangleProvider : IImageProvider 9 | { 10 | readonly Rectangle _rectangle; 11 | readonly bool _includeCursor; 12 | 13 | readonly IntPtr _hdcSrc; 14 | readonly ITargetDeviceContext _dcTarget; 15 | 16 | public RectangleProvider(Rectangle rectangle, bool includeCursor = false) 17 | { 18 | _rectangle = rectangle; 19 | _includeCursor = includeCursor; 20 | Width = rectangle.Size.Width; 21 | Height = rectangle.Size.Height; 22 | 23 | _hdcSrc = User32.GetDC(IntPtr.Zero); 24 | _dcTarget = new GdiTargetDeviceContext(_hdcSrc, Width, Height); 25 | } 26 | 27 | private void OnCapture() 28 | { 29 | Rectangle rect = _rectangle; 30 | IntPtr hdcDest = _dcTarget.GetDc(); 31 | 32 | Gdi32.StretchBlt(hdcDest, 0, 0, Width, Height, 33 | _hdcSrc, rect.X, rect.Y, Width, Height, 34 | (int) CopyPixelOperation.SourceCopy); 35 | 36 | if (_includeCursor) 37 | { 38 | MouseCursor.Draw(hdcDest, p => new Point(p.X - _rectangle.X, p.Y - _rectangle.Y)); 39 | } 40 | } 41 | 42 | public Bitmap Capture() 43 | { 44 | OnCapture(); 45 | Bitmap img = _dcTarget.GetBitmap(); 46 | return img; 47 | } 48 | 49 | /// 50 | /// Height of Captured image. 51 | /// 52 | public int Height { get; } 53 | 54 | /// 55 | /// Width of Captured image. 56 | /// 57 | public int Width { get; } 58 | 59 | public void Dispose() 60 | { 61 | _dcTarget.Dispose(); 62 | User32.ReleaseDC(IntPtr.Zero, _hdcSrc); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /GifCapture.Net/GifCapture.Net.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows10.0.17763.0 6 | Assets\Images\logo.ico 7 | enable 8 | GifCapture 9 | GifCapture 10 | true 11 | true 12 | true 13 | false 14 | false 15 | true 16 | AnyCPU;x64 17 | 18 | 19 | 20 | none 21 | false 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | MSBuild:Compile 46 | Wpf 47 | Designer 48 | 49 | 50 | 51 | 52 | PublicResXFileCodeGenerator 53 | Resources.Designer.cs 54 | 55 | 56 | 57 | 58 | True 59 | True 60 | Resources.resx 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /GifCapture.Net/Images/DrawingImage.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | using GifCapture.Screen; 5 | 6 | namespace GifCapture.Images 7 | { 8 | public class DrawingImage : IBitmapImage 9 | { 10 | public Image Image { get; } 11 | 12 | public DrawingImage(Image image) 13 | { 14 | this.Image = image; 15 | } 16 | 17 | public void Dispose() 18 | { 19 | Image.Dispose(); 20 | } 21 | 22 | public int Width => Image.Width; 23 | public int Height => Image.Height; 24 | 25 | public void Save(string fileName, ImageFormat format) 26 | { 27 | Image.Save(fileName, format); 28 | } 29 | 30 | public void Save(Stream stream, ImageFormat format) 31 | { 32 | Image.Save(stream, format); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /GifCapture.Net/Images/IBitmapImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | 5 | namespace GifCapture.Images 6 | { 7 | public interface IBitmapImage : IDisposable 8 | { 9 | int Width { get; } 10 | 11 | int Height { get; } 12 | 13 | void Save(string fileName, ImageFormat format); 14 | 15 | void Save(Stream stream, ImageFormat format); 16 | } 17 | } -------------------------------------------------------------------------------- /GifCapture.Net/Models/Dpi.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Interop; 2 | 3 | namespace GifCapture.Models 4 | { 5 | /// 6 | /// Provides DPI scaling factor. 7 | /// Only needs to be used when dealing with WPF since their sizes are specified in Device Independent Pixels. 8 | /// 9 | public class Dpi 10 | { 11 | static Dpi() 12 | { 13 | using (var src = new HwndSource(new HwndSourceParameters())) 14 | { 15 | if (src.CompositionTarget != null) 16 | { 17 | var matrix = src.CompositionTarget.TransformToDevice; 18 | 19 | X = (float) matrix.M11; 20 | Y = (float) matrix.M22; 21 | } 22 | } 23 | } 24 | 25 | public static float X { get; } 26 | 27 | public static float Y { get; } 28 | } 29 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/DwmApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using GifCapture.Native.Structs; 4 | 5 | namespace GifCapture.Native 6 | { 7 | static class DwmApi 8 | { 9 | const string DllName = "dwmapi.dll"; 10 | 11 | [DllImport(DllName)] 12 | public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, out bool Value, int Size); 13 | 14 | [DllImport(DllName)] 15 | public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, ref RECT Value, int Size); 16 | } 17 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/EnumWindowsProc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Native 4 | { 5 | public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); 6 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/DrawIconExFlags.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum DrawIconExFlags 4 | { 5 | Compat = 0x04, 6 | DefaultSize = 0x08, 7 | Image = 0x02, 8 | Mask = 0x01, 9 | NoMirror = 0x10, 10 | Normal = Image | Mask 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/FileOperationFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Native.Enums 4 | { 5 | [Flags] 6 | public enum FileOperationFlags 7 | { 8 | MultiDestFiles = 0x1, 9 | 10 | ConfirmMouse = 0x2, 11 | 12 | /// 13 | /// Don't create progress/report 14 | /// 15 | Silent = 0x4, 16 | 17 | RenameOnCollission = 0x8, 18 | 19 | /// 20 | /// Don't prompt the user. 21 | /// 22 | NoConfirmation = 0x10, 23 | 24 | /// 25 | /// Fill in . 26 | /// Must be freed using SHFreeNameMappings 27 | /// 28 | WantMappingHandle = 0x20, 29 | 30 | AllowUndo = 0x40, 31 | 32 | /// 33 | /// On *.*, do only files 34 | /// 35 | FilesOnly = 0x80, 36 | 37 | /// 38 | /// Don't show names of files 39 | /// 40 | SimpleProgress = 0x100, 41 | 42 | /// 43 | /// Don't confirm making any needed dirs 44 | /// 45 | NoConfirmMkdir = 0x200, 46 | 47 | /// 48 | /// Don't put up error UI 49 | /// 50 | // ReSharper disable once InconsistentNaming 51 | NoErrorUI = 0x400, 52 | 53 | /// 54 | /// Dont copy NT file Security Attributes 55 | /// 56 | NoCopySecurityAttribs = 0x800, 57 | 58 | /// 59 | /// Don't recurse into directories. 60 | /// 61 | NoRecursion = 0x1000, 62 | 63 | /// 64 | /// Don't operate on connected elements. 65 | /// 66 | NoConnectedElements = 0x2000, 67 | 68 | /// 69 | /// During delete operation, 70 | /// warn if nuking instead of recycling (partially overrides ) 71 | /// 72 | WantNukeWarning = 0x4000, 73 | 74 | /// 75 | /// Treat reparse points as objects, not containers 76 | /// 77 | NoRecurseReparse = 0x8000 78 | } 79 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/FileOperationType.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum FileOperationType 4 | { 5 | Move = 0x1, 6 | Copy = 0x2, 7 | Delete = 0x3, 8 | Rename = 0x4 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/GetWindowEnum.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum GetWindowEnum 4 | { 5 | Owner = 4 6 | } 7 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/GetWindowLongValue.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum GetWindowLongValue 4 | { 5 | Style = -16, 6 | ExStyle = -20 7 | } 8 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/SetWindowPositionFlags.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum SetWindowPositionFlags 4 | { 5 | ShowWindow = 0x400, 6 | NoActivate = 0x0010 7 | } 8 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Enums/WindowStyles.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum WindowStyles : long 4 | { 5 | Child = 0x40000000, 6 | ToolWindow = 0x00000080, 7 | AppWindow = 0x00040000, 8 | SizeBox = 0x00040000L 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Gdi32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using GifCapture.Native.Structs; 4 | 5 | 6 | namespace GifCapture.Native 7 | { 8 | static class Gdi32 9 | { 10 | const string DllName = "gdi32.dll"; 11 | 12 | [DllImport(DllName)] 13 | public static extern bool DeleteObject(IntPtr hObject); 14 | 15 | [DllImport(DllName)] 16 | public static extern bool BitBlt(IntPtr hObject, int XDest, int YDest, int Width, int Height, IntPtr ObjectSource, int XSrc, int YSrc, int Op); 17 | 18 | [DllImport(DllName)] 19 | public static extern bool StretchBlt(IntPtr hObject, int XDest, int YDest, int WDest, int HDest, IntPtr ObjectSource, int XSrc, int YSrc, int WSrc, 20 | int HSrc, int Op); 21 | 22 | [DllImport(DllName)] 23 | public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int Width, int Height); 24 | 25 | [DllImport(DllName)] 26 | public static extern IntPtr CreateCompatibleDC(IntPtr hDC); 27 | 28 | [DllImport(DllName)] 29 | public static extern bool DeleteDC(IntPtr hDC); 30 | 31 | [DllImport(DllName)] 32 | public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); 33 | 34 | [DllImport(DllName)] 35 | public static extern uint SetDCBrushColor(IntPtr hDC, uint color); //color=0x00bbggrr 36 | 37 | [DllImport(DllName)] 38 | public static extern uint SetDCPenColor(IntPtr hDC, uint color); 39 | 40 | [DllImport(DllName)] 41 | public static extern bool Ellipse(IntPtr hDC, int left, int top, int right, int bottom); 42 | 43 | [DllImport(DllName)] 44 | public static extern IntPtr GetStockObject(StockObjects fnObject); 45 | } 46 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/NativeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using GifCapture.Native.Structs; 3 | 4 | namespace GifCapture.Native 5 | { 6 | static class NativeExtensions 7 | { 8 | public static Rectangle ToRectangle(this RECT r) => Rectangle.FromLTRB(r.Left, r.Top, r.Right, r.Bottom); 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Structs/CursorInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | 5 | 6 | namespace GifCapture.Native.Structs 7 | { 8 | [StructLayout(LayoutKind.Sequential)] 9 | public struct CursorInfo 10 | { 11 | public int cbSize; 12 | public int flags; 13 | public IntPtr hCursor; 14 | public Point ptScreenPos; 15 | } 16 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Structs/IconInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | namespace GifCapture.Native.Structs 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct IconInfo 9 | { 10 | public bool fIcon; 11 | public int xHotspot; 12 | public int yHotspot; 13 | public IntPtr hbmMask; 14 | public IntPtr hbmColor; 15 | } 16 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Structs/RECT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace GifCapture.Native.Structs 5 | { 6 | [Serializable, StructLayout(LayoutKind.Sequential)] 7 | public struct RECT 8 | { 9 | public int Left; 10 | public int Top; 11 | public int Right; 12 | public int Bottom; 13 | 14 | public RECT(int dimension) 15 | { 16 | Left = Top = Right = Bottom = dimension; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/Structs/StockObjects.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Structs 2 | { 3 | public enum StockObjects 4 | { 5 | WHITE_BRUSH = 0, 6 | LTGRAY_BRUSH = 1, 7 | GRAY_BRUSH = 2, 8 | DKGRAY_BRUSH = 3, 9 | BLACK_BRUSH = 4, 10 | NULL_BRUSH = 5, 11 | HOLLOW_BRUSH = NULL_BRUSH, 12 | WHITE_PEN = 6, 13 | BLACK_PEN = 7, 14 | NULL_PEN = 8, 15 | OEM_FIXED_FONT = 10, 16 | ANSI_FIXED_FONT = 11, 17 | ANSI_VAR_FONT = 12, 18 | SYSTEM_FONT = 13, 19 | DEVICE_DEFAULT_FONT = 14, 20 | DEFAULT_PALETTE = 15, 21 | SYSTEM_FIXED_FONT = 16, 22 | DEFAULT_GUI_FONT = 17, 23 | DC_BRUSH = 18, 24 | DC_PEN = 19, 25 | } 26 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/UnsafeBitmap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace GifCapture.Native 7 | { 8 | [StructLayout(LayoutKind.Sequential)] 9 | struct PixelData 10 | { 11 | public byte Blue, Green, Red, Alpha; 12 | } 13 | 14 | unsafe class UnsafeBitmap : IDisposable 15 | { 16 | readonly Bitmap _inputBitmap; 17 | BitmapData _bitmapData; 18 | byte* _pBase; 19 | readonly int _width; 20 | 21 | public UnsafeBitmap(Bitmap InputBitmap) 22 | { 23 | _inputBitmap = InputBitmap; 24 | 25 | var bounds = new Rectangle(Point.Empty, _inputBitmap.Size); 26 | 27 | _width = bounds.Width * sizeof(PixelData); 28 | 29 | if (_width % 4 != 0) 30 | _width = 4 * (_width / 4 + 1); 31 | 32 | //Lock Image 33 | _bitmapData = _inputBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 34 | _pBase = (byte*) _bitmapData.Scan0; 35 | } 36 | 37 | public PixelData* this[int X, int Y] => (PixelData*) (_pBase + Y * _width + X * sizeof(PixelData)); 38 | 39 | public void Dispose() 40 | { 41 | _inputBitmap.UnlockBits(_bitmapData); 42 | _bitmapData = null; 43 | _pBase = null; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /GifCapture.Net/Native/User32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using GifCapture.Native.Enums; 6 | using GifCapture.Native.Structs; 7 | 8 | namespace GifCapture.Native 9 | { 10 | public static class User32 11 | { 12 | const string DllName = "user32.dll"; 13 | 14 | [DllImport(DllName)] 15 | public static extern bool GetCursorPos(ref Point lpPoint); 16 | 17 | [DllImport(DllName)] 18 | public static extern bool DrawIconEx( 19 | IntPtr hDC, 20 | int Left, 21 | int Top, 22 | IntPtr hIcon, 23 | int Width, 24 | int Height, 25 | int StepIfAniCur, 26 | IntPtr BrushForFlickerFreeDraw, 27 | DrawIconExFlags Flags); 28 | 29 | [DllImport(DllName)] 30 | public static extern WindowStyles GetWindowLong(IntPtr hWnd, GetWindowLongValue nIndex); 31 | 32 | [DllImport(DllName)] 33 | public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect); 34 | 35 | [DllImport(DllName)] 36 | public static extern bool IsWindow(IntPtr hWnd); 37 | 38 | [DllImport(DllName)] 39 | public static extern IntPtr GetDesktopWindow(); 40 | 41 | [DllImport(DllName)] 42 | public static extern IntPtr GetForegroundWindow(); 43 | 44 | [DllImport(DllName)] 45 | public static extern bool EnumWindows(EnumWindowsProc proc, IntPtr lParam); 46 | 47 | [DllImport(DllName)] 48 | public static extern bool EnumChildWindows(IntPtr hWnd, EnumWindowsProc proc, IntPtr lParam); 49 | 50 | [DllImport(DllName)] 51 | public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount); 52 | 53 | [DllImport(DllName)] 54 | public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowEnum uCmd); 55 | 56 | [DllImport(DllName)] 57 | public static extern int GetWindowTextLength(IntPtr hWnd); 58 | 59 | [DllImport(DllName)] 60 | public static extern bool IsWindowVisible(IntPtr hWnd); 61 | 62 | [DllImport(DllName)] 63 | public static extern bool SetForegroundWindow(IntPtr hWnd); 64 | 65 | [DllImport(DllName)] 66 | public static extern bool IsIconic(IntPtr hWnd); 67 | 68 | [DllImport(DllName)] 69 | public static extern bool IsZoomed(IntPtr hWnd); 70 | 71 | [DllImport(DllName)] 72 | public static extern bool DestroyIcon(IntPtr hIcon); 73 | 74 | [DllImport(DllName)] 75 | public static extern IntPtr CopyIcon(IntPtr hIcon); 76 | 77 | [DllImport(DllName)] 78 | public static extern bool GetCursorInfo(ref CursorInfo pci); 79 | 80 | [DllImport(DllName)] 81 | public static extern bool GetIconInfo(IntPtr hIcon, out IconInfo piconinfo); 82 | 83 | [DllImport(DllName)] 84 | public static extern IntPtr GetDC(IntPtr hWnd); 85 | 86 | [DllImport(DllName)] 87 | public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); 88 | 89 | [DllImport(DllName)] 90 | public static extern bool FillRect(IntPtr hDC, ref RECT Rect, IntPtr Brush); 91 | 92 | [DllImport(DllName)] 93 | public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPositionFlags wFlags); 94 | 95 | [DllImport(DllName)] 96 | public static extern int ShowWindow(IntPtr hWnd, int nCmdShow); 97 | } 98 | } -------------------------------------------------------------------------------- /GifCapture.Net/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | text/microsoft-resx 11 | 12 | 13 | 1.3 14 | 15 | 16 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 17 | 18 | 19 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 20 | 21 | 22 | http://www.redisant.com/gif 23 | 24 | 25 | Capture Window 26 | 27 | 28 | Capture Region 29 | 30 | 31 | Capture Screen 32 | 33 | 34 | Recorde Window 35 | 36 | 37 | Recorde Region 38 | 39 | 40 | Recorde Screen 41 | 42 | 43 | Stop Recording 44 | 45 | 46 | Exit 47 | 48 | 49 | Select the window to capture, or press Esc to exit 50 | 51 | 52 | Select the screen to capture, or press Esc to cancel 53 | 54 | 55 | Screenshot Saved 56 | 57 | 58 | Saved Path: 59 | 60 | 61 | Recording Saved: 62 | 63 | 64 | Recording: 65 | 66 | 67 | Delay: 68 | 69 | 70 | Contains Mouse 71 | 72 | 73 | 256 colors 74 | 75 | 76 | 16 colors 77 | 78 | 79 | Quality: 80 | 81 | -------------------------------------------------------------------------------- /GifCapture.Net/Properties/Resources.zh-hant.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | text/microsoft-resx 4 | 5 | 6 | 1.3 7 | 8 | 9 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 10 | 11 | 12 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 13 | 14 | 15 | http://www.redisant.cn/gif 16 | 17 | 18 | 截取窗口 19 | 20 | 21 | 截取區域 22 | 23 | 24 | 截取屏幕 25 | 26 | 27 | 錄製窗口 28 | 29 | 30 | 錄製區域 31 | 32 | 33 | 錄製屏幕 34 | 35 | 36 | 停止錄製 37 | 38 | 39 | 退出 40 | 41 | 42 | 選擇要捕獲的窗口,或者按下 Esc 退出 43 | 44 | 45 | 選擇要捕獲的屏幕,或按下 Esc 取消 46 | 47 | 48 | 截圖已保存 49 | 50 | 51 | 保存位置: 52 | 53 | 54 | 錄屏已保存 55 | 56 | 57 | 正在錄製: 58 | 59 | 60 | 延遲: 61 | 62 | 63 | 包含鼠標 64 | 65 | 66 | 256 色 67 | 68 | 69 | 16 色 70 | 71 | 72 | 圖像質量: 73 | 74 | -------------------------------------------------------------------------------- /GifCapture.Net/Properties/Resources.zh.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | text/microsoft-resx 4 | 5 | 6 | 1.3 7 | 8 | 9 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 10 | 11 | 12 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 13 | 14 | 15 | http://www.redisant.cn/gif 16 | 17 | 18 | 截取窗口 19 | 20 | 21 | 截取区域 22 | 23 | 24 | 截取屏幕 25 | 26 | 27 | 录制窗口 28 | 29 | 30 | 录制区域 31 | 32 | 33 | 录制屏幕 34 | 35 | 36 | 停止录制 37 | 38 | 39 | 退出 40 | 41 | 42 | 选择要捕获的窗口,或者按下 Esc 退出 43 | 44 | 45 | 选择要捕获的屏幕,或按下 Esc 取消 46 | 47 | 48 | 截图已保存 49 | 50 | 51 | 保存位置: 52 | 53 | 54 | 录屏已保存 55 | 56 | 57 | 正在录制: 58 | 59 | 60 | 延迟: 61 | 62 | 63 | 包含鼠标 64 | 65 | 66 | 256 色 67 | 68 | 69 | 16 色 70 | 71 | 72 | 图像质量: 73 | 74 | -------------------------------------------------------------------------------- /GifCapture.Net/Screen/MouseCursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using GifCapture.Native; 5 | using GifCapture.Native.Enums; 6 | using GifCapture.Native.Structs; 7 | 8 | namespace GifCapture.Screen 9 | { 10 | /// 11 | /// Draws the MouseCursor on an Image 12 | /// 13 | static class MouseCursor 14 | { 15 | const int CursorShowing = 1; 16 | 17 | /// 18 | /// Draws this overlay. 19 | /// 20 | /// A object to draw upon. 21 | /// Point Transform Function. 22 | public static void Draw(Graphics g, Func transform = null) 23 | { 24 | var hIcon = GetIcon(transform, out var location); 25 | 26 | if (hIcon == IntPtr.Zero) 27 | return; 28 | 29 | var bmp = Icon.FromHandle(hIcon).ToBitmap(); 30 | User32.DestroyIcon(hIcon); 31 | 32 | try 33 | { 34 | using (bmp) 35 | { 36 | // SolidBrush solidBrush = new SolidBrush(Color.FromArgb(200, 191, 222, 179)); 37 | Pen pen = new Pen(Color.Red); 38 | int width = 32; 39 | // g.FillEllipse(solidBrush, location.X - width, location.Y - width, width * 2, width * 2); 40 | g.DrawEllipse(pen, location.X - width, location.Y - width, width * 2, width * 2); 41 | g.DrawImage(bmp, new Rectangle(location, bmp.Size)); 42 | // solidBrush.Dispose(); 43 | pen.Dispose(); 44 | } 45 | } 46 | catch (ArgumentException) 47 | { 48 | } 49 | } 50 | 51 | public static void Draw(IntPtr deviceContext, Func transform = null) 52 | { 53 | var hIcon = GetIcon(transform, out var location); 54 | 55 | if (hIcon == IntPtr.Zero) 56 | return; 57 | 58 | try 59 | { 60 | // Select DC_PEN so you can change the color of the pen with COLORREF SetDCPenColor(HDC hdc, COLORREF color) 61 | Gdi32.SelectObject(deviceContext, Gdi32.GetStockObject(StockObjects.DC_PEN)); 62 | Gdi32.SelectObject(deviceContext, Gdi32.GetStockObject(StockObjects.NULL_BRUSH)); 63 | // Gdi32.SetDCBrushColor(deviceContext, 0x0000FF00); // 0x00bbggrr 64 | Gdi32.SetDCPenColor(deviceContext, 0x000000FF); 65 | int width = 32; 66 | Gdi32.Ellipse(deviceContext, location.X - width, location.Y - width, location.X + width, location.Y + width); 67 | User32.DrawIconEx(deviceContext, 68 | location.X, location.Y, 69 | hIcon, 70 | 0, 0, 0, IntPtr.Zero, 71 | DrawIconExFlags.Normal); 72 | } 73 | finally 74 | { 75 | User32.DestroyIcon(hIcon); 76 | } 77 | } 78 | 79 | static IntPtr GetIcon(Func transform, out Point location) 80 | { 81 | location = Point.Empty; 82 | 83 | var cursorInfo = new CursorInfo {cbSize = Marshal.SizeOf()}; 84 | 85 | if (!User32.GetCursorInfo(ref cursorInfo)) 86 | return IntPtr.Zero; 87 | 88 | if (cursorInfo.flags != CursorShowing) 89 | return IntPtr.Zero; 90 | 91 | var hIcon = User32.CopyIcon(cursorInfo.hCursor); 92 | 93 | if (hIcon == IntPtr.Zero) 94 | return IntPtr.Zero; 95 | 96 | if (!User32.GetIconInfo(hIcon, out var icInfo)) 97 | return IntPtr.Zero; 98 | 99 | var hotspot = new Point(icInfo.xHotspot, icInfo.yHotspot); 100 | 101 | location = new Point(cursorInfo.ptScreenPos.X - hotspot.X, cursorInfo.ptScreenPos.Y - hotspot.Y); 102 | 103 | if (transform != null) 104 | location = transform(location); 105 | 106 | Gdi32.DeleteObject(icInfo.hbmColor); 107 | Gdi32.DeleteObject(icInfo.hbmMask); 108 | 109 | return hIcon; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /GifCapture.Net/Screen/ScreenShot.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using GifCapture.Base; 3 | using GifCapture.Images; 4 | using GifCapture.Services; 5 | 6 | namespace GifCapture.Screen 7 | { 8 | /// 9 | /// Contains methods for taking ScreenShots 10 | /// 11 | public static class ScreenShot 12 | { 13 | /// 14 | /// Captures the entire Desktop. 15 | /// 16 | /// Whether to include the Mouse Cursor. 17 | /// The Captured Image. 18 | public static IBitmapImage Capture(bool includeCursor = false) 19 | { 20 | var platformServices = ServiceProvider.IPlatformServices; 21 | return Capture(platformServices.DesktopRectangle, includeCursor); 22 | } 23 | 24 | /// 25 | /// Capture transparent Screenshot of a Window. 26 | /// 27 | /// The to Capture. 28 | /// Whether to include Mouse Cursor. 29 | public static IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false) 30 | { 31 | var platformServices = ServiceProvider.IPlatformServices; 32 | return platformServices.CaptureTransparent(window, includeCursor); 33 | } 34 | 35 | /// 36 | /// Captures a Specific Region. 37 | /// 38 | /// A specifying the Region to Capture. 39 | /// Whether to include the Mouse Cursor. 40 | /// The Captured Image. 41 | public static IBitmapImage Capture(Rectangle region, bool includeCursor = false) 42 | { 43 | var platformServices = ServiceProvider.IPlatformServices; 44 | return platformServices.Capture(region, includeCursor); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /GifCapture.Net/Screen/ScreenShotInternal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Base; 4 | using GifCapture.Images; 5 | using GifCapture.Services; 6 | 7 | namespace GifCapture.Screen 8 | { 9 | /// 10 | /// Contains methods for taking ScreenShots 11 | /// 12 | static class ScreenShotInternal 13 | { 14 | /// 15 | /// Capture transparent Screenshot of a Window. 16 | /// 17 | public static IBitmapImage CaptureTransparent(IWindow window, bool includeCursor, IPlatformServices platformServices) 18 | { 19 | if (window == null) 20 | { 21 | throw new ArgumentNullException(nameof(window)); 22 | } 23 | 24 | var backdrop = new WindowScreenShotBackdrop(window, platformServices); 25 | 26 | backdrop.ShowWhite(); 27 | 28 | var r = backdrop.Rectangle; 29 | 30 | // Capture screenshot with white background 31 | using (var whiteShot = CaptureInternal(r)) 32 | { 33 | backdrop.ShowBlack(); 34 | 35 | // Capture screenshot with black background 36 | using (var blackShot = CaptureInternal(r)) 37 | { 38 | backdrop.Dispose(); 39 | 40 | var transparentImage = GraphicsExtensions.DifferentiateAlpha(whiteShot, blackShot); 41 | 42 | if (transparentImage == null) 43 | return null; 44 | 45 | // Include Cursor only if within window 46 | if (includeCursor && r.Contains(platformServices.CursorPosition)) 47 | { 48 | using (var g = Graphics.FromImage(transparentImage)) 49 | { 50 | MouseCursor.Draw(g, P => new Point(P.X - r.X, P.Y - r.Y)); 51 | } 52 | } 53 | 54 | return new DrawingImage(transparentImage.CropEmptyEdges()); 55 | } 56 | } 57 | } 58 | 59 | static Bitmap CaptureInternal(Rectangle region, bool includeCursor = false) 60 | { 61 | var bmp = new Bitmap(region.Width, region.Height); 62 | using (var g = Graphics.FromImage(bmp)) 63 | { 64 | g.CopyFromScreen(region.Location, Point.Empty, region.Size, CopyPixelOperation.SourceCopy); 65 | if (includeCursor) 66 | { 67 | MouseCursor.Draw(g, p => new Point(p.X - region.X, p.Y - region.Y)); 68 | } 69 | 70 | g.Flush(); 71 | } 72 | 73 | return bmp; 74 | } 75 | 76 | /// 77 | /// Captures a Specific Region. 78 | /// 79 | /// A specifying the Region to Capture. 80 | /// Whether to include the Mouse Cursor. 81 | /// The Captured Image. 82 | public static IBitmapImage Capture(Rectangle region, bool includeCursor = false) 83 | { 84 | return new DrawingImage(CaptureInternal(region, includeCursor)); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /GifCapture.Net/Screen/WindowScreenShotBackdrop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using GifCapture.Base; 5 | using GifCapture.Native; 6 | using GifCapture.Native.Enums; 7 | using GifCapture.Services; 8 | 9 | namespace GifCapture.Screen 10 | { 11 | class WindowScreenShotBackdrop : IDisposable 12 | { 13 | readonly IWindow _window; 14 | readonly Form _form; 15 | 16 | bool _shown; 17 | 18 | public Rectangle Rectangle { get; } 19 | 20 | public WindowScreenShotBackdrop(IWindow window, IPlatformServices platformServices) 21 | { 22 | _window = window; 23 | 24 | // Show and Focus 25 | User32.ShowWindow(window.Handle, 5); 26 | 27 | _form = new Form 28 | { 29 | AllowTransparency = true, 30 | BackColor = Color.White, 31 | FormBorderStyle = FormBorderStyle.None, 32 | ShowInTaskbar = false 33 | }; 34 | 35 | var r = window.Rectangle; 36 | 37 | // Add a margin for window shadows. Excess transparency is trimmed out later 38 | r.Inflate(20, 20); 39 | 40 | // Check if the window is outside of the visible screen 41 | r.Intersect(platformServices.DesktopRectangle); 42 | 43 | Rectangle = r; 44 | } 45 | 46 | void Show() 47 | { 48 | if (_shown) 49 | return; 50 | 51 | _shown = true; 52 | 53 | _form.Show(); 54 | 55 | User32.SetWindowPos(_form.Handle, _window.Handle, 56 | Rectangle.Left, Rectangle.Top, 57 | Rectangle.Width, Rectangle.Height, 58 | SetWindowPositionFlags.NoActivate); 59 | } 60 | 61 | public void ShowWhite() 62 | { 63 | Show(); 64 | 65 | _form.BackColor = Color.White; 66 | 67 | // Wait for Backdrop to update 68 | Application.DoEvents(); 69 | } 70 | 71 | public void ShowBlack() 72 | { 73 | Show(); 74 | 75 | _form.BackColor = Color.Black; 76 | 77 | // Wait for Backdrop to update 78 | Application.DoEvents(); 79 | } 80 | 81 | public void Dispose() 82 | { 83 | _form.Dispose(); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /GifCapture.Net/Services/IPlatformServices.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using GifCapture.Base; 4 | using GifCapture.Images; 5 | 6 | namespace GifCapture.Services 7 | { 8 | public interface IPlatformServices 9 | { 10 | IEnumerable EnumerateScreens(); 11 | IEnumerable EnumerateWindows(); 12 | IEnumerable EnumerateAllWindows(); 13 | IWindow DesktopWindow { get; } 14 | 15 | Rectangle DesktopRectangle { get; } 16 | 17 | IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false); 18 | 19 | Point CursorPosition { get; } 20 | 21 | IBitmapImage Capture(Rectangle region, bool includeCursor = false); 22 | } 23 | } -------------------------------------------------------------------------------- /GifCapture.Net/Services/NotificationsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Microsoft.Toolkit.Uwp.Notifications; 5 | 6 | namespace GifCapture.Services 7 | { 8 | public static class NotificationsService 9 | { 10 | public static void Notice(string title, string subTitle, string imageUri = null, Dictionary args = null) 11 | { 12 | try 13 | { 14 | ToastContentBuilder builder = new ToastContentBuilder(); 15 | if (args != null) 16 | { 17 | foreach (KeyValuePair pair in args) 18 | { 19 | builder.AddArgument(pair.Key, pair.Value); 20 | } 21 | } 22 | 23 | builder.AddText(title); 24 | builder.AddText(subTitle); 25 | if (!string.IsNullOrWhiteSpace(imageUri)) 26 | { 27 | builder.AddInlineImage(new Uri(imageUri)); 28 | } 29 | 30 | builder.Show(); 31 | } 32 | catch (Exception e) 33 | { 34 | //ignore 35 | } 36 | } 37 | 38 | public static void OpenFile(string fullNamePath) 39 | { 40 | Process process = new Process(); 41 | process.StartInfo = new ProcessStartInfo(fullNamePath) 42 | { 43 | UseShellExecute = true 44 | }; 45 | process.Start(); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /GifCapture.Net/Services/ServiceProvider.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Services 2 | { 3 | public static class ServiceProvider 4 | { 5 | public static readonly IPlatformServices IPlatformServices; 6 | 7 | static ServiceProvider() 8 | { 9 | IPlatformServices = new WindowsPlatformServices(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture.Net/Services/WindowsPlatformServices.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using System.Linq; 5 | using GifCapture.Base; 6 | using GifCapture.Images; 7 | using GifCapture.Native; 8 | using GifCapture.Screen; 9 | 10 | namespace GifCapture.Services 11 | { 12 | public class WindowsPlatformServices : IPlatformServices 13 | { 14 | public IEnumerable EnumerateScreens() 15 | { 16 | return ScreenWrapper.Enumerate(); 17 | } 18 | 19 | public IEnumerable EnumerateWindows() 20 | { 21 | return Window.EnumerateVisible(); 22 | } 23 | 24 | public IEnumerable EnumerateAllWindows() 25 | { 26 | return Window 27 | .Enumerate() 28 | .Where(w => w.IsVisible) 29 | .SelectMany(GetAllChildren); 30 | } 31 | 32 | public IWindow DesktopWindow => Window.DesktopWindow; 33 | 34 | public Rectangle DesktopRectangle => SystemInformation.VirtualScreen; 35 | 36 | public IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false) 37 | { 38 | return ScreenShotInternal.CaptureTransparent(window, includeCursor, this); 39 | } 40 | 41 | public Point CursorPosition 42 | { 43 | get 44 | { 45 | var p = new Point(); 46 | User32.GetCursorPos(ref p); 47 | return p; 48 | } 49 | } 50 | 51 | public IBitmapImage Capture(Rectangle region, bool includeCursor = false) 52 | { 53 | return ScreenShotInternal.Capture(region, includeCursor); 54 | } 55 | 56 | IEnumerable GetAllChildren(Window window) 57 | { 58 | var children = window 59 | .EnumerateChildren() 60 | .Where(w => w.IsVisible); 61 | 62 | foreach (var child in children) 63 | { 64 | foreach (var grandchild in GetAllChildren(child)) 65 | { 66 | yield return grandchild; 67 | } 68 | } 69 | 70 | yield return window; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /GifCapture.Net/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.ViewModels 2 | { 3 | public class MainViewModel : NotifyPropertyChanged 4 | { 5 | private bool _recoding = false; 6 | 7 | public bool Recoding 8 | { 9 | get => _recoding; 10 | set => Set(ref _recoding, value); 11 | } 12 | 13 | public readonly int Fps = 10; 14 | 15 | private int _elapsedSeconds; 16 | 17 | public int ElapsedSeconds 18 | { 19 | get => _elapsedSeconds; 20 | set => Set(ref _elapsedSeconds, value); 21 | } 22 | 23 | private bool _includeCursor = false; 24 | 25 | public bool IncludeCursor 26 | { 27 | get => _includeCursor; 28 | set => Set(ref _includeCursor, value); 29 | } 30 | 31 | private int _delayIndex = 0; 32 | 33 | public int DelayIndex 34 | { 35 | get => _delayIndex; 36 | set => Set(ref _delayIndex, value); 37 | } 38 | 39 | private int _quality = 0; 40 | 41 | public int Quality 42 | { 43 | get => _quality; 44 | set => Set(ref _quality, value); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /GifCapture.Net/ViewModels/NotifyPropertyChanged.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace GifCapture.ViewModels 6 | { 7 | public class NotifyPropertyChanged : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler PropertyChanged; 10 | 11 | protected void RaisePropertyChanged(string propertyName) 12 | { 13 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 14 | } 15 | 16 | protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 17 | { 18 | RaisePropertyChanged(propertyName); 19 | } 20 | 21 | protected void RaiseAllChanged() 22 | { 23 | RaisePropertyChanged(""); 24 | } 25 | 26 | protected bool Set(ref T field, T value, [CallerMemberName] string propertyName = null) 27 | { 28 | if (EqualityComparer.Default.Equals(field, value)) 29 | return false; 30 | 31 | field = value; 32 | 33 | RaisePropertyChanged(propertyName); 34 | 35 | return true; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /GifCapture.Net/ViewModels/ScreenPickerViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing.Imaging; 2 | using System.IO; 3 | using System.Windows; 4 | using System.Windows.Media; 5 | using System.Windows.Media.Imaging; 6 | using GifCapture.Base; 7 | using GifCapture.Images; 8 | using GifCapture.Models; 9 | using GifCapture.Screen; 10 | 11 | namespace GifCapture.ViewModels 12 | { 13 | public class ScreenPickerViewModel 14 | { 15 | public ScreenPickerViewModel(IScreen screen, double scale) 16 | { 17 | this.Screen = screen; 18 | using (IBitmapImage bmp = ScreenShot.Capture(screen.Rectangle)) 19 | { 20 | using (var stream = new MemoryStream()) 21 | { 22 | bmp.Save(stream, ImageFormat.Png); 23 | stream.Seek(0, SeekOrigin.Begin); 24 | PngBitmapDecoder decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 25 | Image = new ImageBrush(decoder.Frames[0]); 26 | 27 | Left = (screen.Rectangle.Left / Dpi.X - SystemParameters.VirtualScreenLeft) * scale; 28 | Top = (screen.Rectangle.Top / Dpi.Y - SystemParameters.VirtualScreenTop) * scale; 29 | Width = screen.Rectangle.Width / Dpi.X * scale; 30 | Height = screen.Rectangle.Height / Dpi.Y * scale; 31 | } 32 | } 33 | } 34 | 35 | public double Left { get; } 36 | public double Top { get; } 37 | 38 | public double Width { get; } 39 | public double Height { get; } 40 | 41 | public IScreen Screen { get; } 42 | 43 | public Brush Image { get; } 44 | } 45 | } -------------------------------------------------------------------------------- /GifCapture.Net/Windows/RecordBarWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /GifCapture.Net/Windows/RecordBarWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows; 3 | using System.Windows.Forms; 4 | using System.Windows.Input; 5 | using GifCapture.Models; 6 | using GifCapture.ViewModels; 7 | 8 | namespace GifCapture.Windows 9 | { 10 | public partial class RecordBarWindow : Window 11 | { 12 | private readonly int _width = 200; 13 | private readonly int _height = 30; 14 | 15 | public RecordBarWindow(MainViewModel mainViewModel, Rectangle rectangle) 16 | { 17 | this.DataContext = mainViewModel; 18 | InitializeComponent(); 19 | Rectangle screen = SystemInformation.VirtualScreen; 20 | int left = (int) ((rectangle.X + rectangle.Width / 2) / Dpi.X - _width / 2); 21 | int top = (int) ((rectangle.Y + rectangle.Height) / Dpi.Y + 10); 22 | if (top > screen.Height / Dpi.Y - _height) 23 | { 24 | top = (int) (screen.Height / Dpi.Y - _height); 25 | } 26 | 27 | if (left > screen.Width / Dpi.X - _width) 28 | { 29 | left = (int) (screen.Width / 2 / Dpi.X - _width / 2); 30 | } 31 | 32 | this.Top = top; 33 | this.Left = left; 34 | this.Width = _width; 35 | this.Height = _height; 36 | } 37 | 38 | private void StopButton_OnClick(object sender, RoutedEventArgs e) 39 | { 40 | MainWindow.Instance.StopRecord_OnClick(null, null); 41 | this.Close(); 42 | } 43 | 44 | private void UIElement_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 45 | { 46 | this.DragMove(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /GifCapture.Net/Windows/RegionPickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /GifCapture.Net/Windows/ScreenPickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  14 | 15 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 62 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /GifCapture.Net/Windows/ScreenPickerWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Input; 6 | using GifCapture.Base; 7 | using GifCapture.Services; 8 | using GifCapture.ViewModels; 9 | using Reactive.Bindings; 10 | using Window = System.Windows.Window; 11 | 12 | namespace GifCapture.Windows 13 | { 14 | public partial class ScreenPickerWindow : Window 15 | { 16 | const double Scale = 0.15; 17 | public ObservableCollection ScreenPickerViewModels { get; } = new ObservableCollection(); 18 | public ICommand SelectScreenCommand { get; } 19 | 20 | 21 | ScreenPickerWindow() 22 | { 23 | this.Deactivated += OnDeactivated; 24 | SelectScreenCommand = new ReactiveCommand() 25 | .WithSubscribe(m => 26 | { 27 | _onClosing = true; 28 | SelectedScreen = m; 29 | Close(); 30 | }); 31 | 32 | InitializeComponent(); 33 | var platformServices = ServiceProvider.IPlatformServices; 34 | var screens = platformServices.EnumerateScreens().ToArray(); 35 | 36 | foreach (var screen in screens) 37 | { 38 | ScreenPickerViewModels.Add(new ScreenPickerViewModel(screen, Scale)); 39 | } 40 | } 41 | 42 | 43 | private bool _onClosing = false; 44 | 45 | private void OnDeactivated(object sender, EventArgs e) 46 | { 47 | if (!_onClosing) 48 | { 49 | CloseClick(null, null); 50 | } 51 | } 52 | 53 | public IScreen SelectedScreen { get; private set; } 54 | 55 | void CloseClick(object sender, RoutedEventArgs e) 56 | { 57 | _onClosing = true; 58 | SelectedScreen = null; 59 | Close(); 60 | } 61 | 62 | public static IScreen PickScreen() 63 | { 64 | var picker = new ScreenPickerWindow(); 65 | picker.ShowDialog(); 66 | return picker.SelectedScreen; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /GifCapture.Net/Windows/VideoSourcePickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 26 | 27 | -------------------------------------------------------------------------------- /GifCapture.Net/Windows/VideoSourcePickerWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using System.Windows.Media.Animation; 11 | using System.Windows.Media.Imaging; 12 | using GifCapture.Base; 13 | using GifCapture.Images; 14 | using GifCapture.Models; 15 | using GifCapture.Screen; 16 | using GifCapture.Services; 17 | using Color = System.Windows.Media.Color; 18 | using Window = System.Windows.Window; 19 | 20 | namespace GifCapture.Windows 21 | { 22 | public partial class VideoSourcePickerWindow : Window 23 | { 24 | Predicate Predicate { get; set; } 25 | 26 | VideoSourcePickerWindow() 27 | { 28 | InitializeComponent(); 29 | 30 | Left = SystemParameters.VirtualScreenLeft; 31 | Top = SystemParameters.VirtualScreenTop; 32 | Width = SystemParameters.VirtualScreenWidth; 33 | Height = SystemParameters.VirtualScreenHeight; 34 | 35 | UpdateBackground(); 36 | 37 | var platformServices = ServiceProvider.IPlatformServices; 38 | _screens = platformServices.EnumerateScreens().ToArray(); 39 | _windows = platformServices.EnumerateWindows().ToArray(); 40 | 41 | ShowCancelText(); 42 | } 43 | 44 | readonly IScreen[] _screens; 45 | 46 | readonly IWindow[] _windows; 47 | 48 | public IWindow SelectedWindow { get; private set; } 49 | 50 | void UpdateBackground() 51 | { 52 | using (IBitmapImage bmp = ScreenShot.Capture()) 53 | { 54 | using (Stream stream = new MemoryStream()) 55 | { 56 | bmp.Save(stream, ImageFormat.Png); 57 | stream.Seek(0, SeekOrigin.Begin); 58 | var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 59 | this.Background = new ImageBrush(decoder.Frames[0]); 60 | } 61 | } 62 | } 63 | 64 | void ShowCancelText() 65 | { 66 | foreach (var screen in _screens) 67 | { 68 | var bounds = screen.Rectangle; 69 | 70 | var left = -Left + bounds.Left / Dpi.X; 71 | var top = -Top + bounds.Top / Dpi.Y; 72 | var width = bounds.Width / Dpi.X; 73 | var height = bounds.Height / Dpi.Y; 74 | 75 | var container = new ContentControl 76 | { 77 | Width = width, 78 | Height = height, 79 | Margin = new Thickness(left, top, 0, 0), 80 | VerticalAlignment = VerticalAlignment.Top, 81 | HorizontalAlignment = HorizontalAlignment.Left 82 | }; 83 | 84 | var textBlock = new TextBlock 85 | { 86 | Text = Properties.Resources.SelectWindowTip, 87 | FontSize = 15, 88 | HorizontalAlignment = HorizontalAlignment.Center, 89 | VerticalAlignment = VerticalAlignment.Center, 90 | Padding = new Thickness(10, 5, 10, 5), 91 | Foreground = new SolidColorBrush(Colors.Black), 92 | Background = new SolidColorBrush(Colors.White) 93 | }; 94 | container.Content = textBlock; 95 | RootGrid.Children.Add(container); 96 | } 97 | } 98 | 99 | void CloseClick(object sender, RoutedEventArgs e) 100 | { 101 | SelectedWindow = null; 102 | Close(); 103 | } 104 | 105 | Rectangle? _lastRectangle; 106 | 107 | void UpdateBorderAndCursor(Rectangle? rect) 108 | { 109 | if (_lastRectangle == rect) 110 | { 111 | return; 112 | } 113 | 114 | _lastRectangle = rect; 115 | if (rect == null) 116 | { 117 | Cursor = Cursors.Arrow; 118 | Border.Width = Border.Height = 0; 119 | } 120 | else 121 | { 122 | Cursor = Cursors.Hand; 123 | var r = rect.Value; 124 | 125 | var margin = new Thickness(-Left + r.Left / Dpi.X, -Top + r.Top / Dpi.Y, 0, 0); 126 | Border.Margin = margin; 127 | Border.Width = r.Width / Dpi.X; 128 | Border.Height = r.Height / Dpi.Y; 129 | } 130 | } 131 | 132 | void WindowMouseMove(object sender, MouseEventArgs e) 133 | { 134 | var platformServices = ServiceProvider.IPlatformServices; 135 | var point = platformServices.CursorPosition; 136 | SelectedWindow = _windows 137 | .Where(m => Predicate?.Invoke(m) ?? true) 138 | .FirstOrDefault(m => m.Rectangle.Contains(point)); 139 | UpdateBorderAndCursor(SelectedWindow?.Rectangle); 140 | } 141 | 142 | void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 143 | { 144 | if (SelectedWindow != null) 145 | { 146 | Close(); 147 | } 148 | } 149 | 150 | public static IWindow PickWindow() 151 | { 152 | var picker = new VideoSourcePickerWindow(); 153 | picker.ShowDialog(); 154 | return picker.SelectedWindow; 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /GifCapture.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33712.159 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GifCapture", "GifCapture\GifCapture.csproj", "{E1B321CC-6819-4810-BE3B-33D6B9E569D5}" 7 | EndProject 8 | Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AppStoreInstaller", "AppStoreInstaller\AppStoreInstaller.wapproj", "{3A405A4F-A9ED-47BC-869C-3538977FBE3B}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GifCapture.Net", "GifCapture.Net\GifCapture.Net.csproj", "{32645346-187E-4BDB-A97A-DF827A150FD0}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnimatedGif", "AnimatedGif\AnimatedGif.csproj", "{15B36346-6F8D-45B0-BB39-FE49015258B4}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Release|Any CPU = Release|Any CPU 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Debug|x64.ActiveCfg = Debug|x64 25 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Debug|x64.Build.0 = Debug|x64 26 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Release|x64.ActiveCfg = Release|x64 29 | {E1B321CC-6819-4810-BE3B-33D6B9E569D5}.Release|x64.Build.0 = Release|x64 30 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 33 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|x64.ActiveCfg = Debug|x64 34 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|x64.Build.0 = Debug|x64 35 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Debug|x64.Deploy.0 = Debug|x64 36 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|Any CPU.Deploy.0 = Release|Any CPU 39 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|x64.ActiveCfg = Release|x64 40 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|x64.Build.0 = Release|x64 41 | {3A405A4F-A9ED-47BC-869C-3538977FBE3B}.Release|x64.Deploy.0 = Release|x64 42 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Debug|x64.ActiveCfg = Debug|x64 45 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Debug|x64.Build.0 = Debug|x64 46 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Release|x64.ActiveCfg = Release|x64 49 | {32645346-187E-4BDB-A97A-DF827A150FD0}.Release|x64.Build.0 = Release|x64 50 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Debug|x64.ActiveCfg = Debug|x64 53 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Debug|x64.Build.0 = Debug|x64 54 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Release|x64.ActiveCfg = Release|x64 57 | {15B36346-6F8D-45B0-BB39-FE49015258B4}.Release|x64.Build.0 = Release|x64 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {B06581D8-468F-4DF8-8C4B-AB3BC4AADC7D} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /GifCapture.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 |  2 | True 3 | <AssemblyExplorer> 4 | <Assembly Path="C:\Users\chenjing\.nuget\packages\animatedgif\1.0.5\lib\netstandard2.0\AnimatedGif.dll" /> 5 | </AssemblyExplorer> 6 | True 7 | 8 | True 9 | True 10 | True 11 | 12 | 13 | -------------------------------------------------------------------------------- /GifCapture/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | pack://application:,,,/GifCapture;component/Assets/IconFonts/#Segoe MDL2 Assets 8 | 9 | 10 | 65 | 66 | -------------------------------------------------------------------------------- /GifCapture/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] -------------------------------------------------------------------------------- /GifCapture/Assets/IconFonts/Font Awesome 6 Pro-Light-300.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/IconFonts/Font Awesome 6 Pro-Light-300.otf -------------------------------------------------------------------------------- /GifCapture/Assets/IconFonts/Segoe MDL2 Assets.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/IconFonts/Segoe MDL2 Assets.ttf -------------------------------------------------------------------------------- /GifCapture/Assets/Images/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/camera.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/logo.ico -------------------------------------------------------------------------------- /GifCapture/Assets/Images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/stop.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/录制区域.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/录制区域.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/录制屏幕.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/录制屏幕.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/录制窗口.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/录制窗口.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/截取区域.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/截取区域.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/截取屏幕.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/截取屏幕.png -------------------------------------------------------------------------------- /GifCapture/Assets/Images/截取窗口.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/GifCapture/Assets/Images/截取窗口.png -------------------------------------------------------------------------------- /GifCapture/Base/ComparableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Base 4 | { 5 | public static class ComparableExtensions 6 | { 7 | public static T Clip(this T value, T minimum, T maximum) where T : IComparable 8 | { 9 | if (value.CompareTo(minimum) < 0) 10 | return minimum; 11 | 12 | if (value.CompareTo(maximum) > 0) 13 | return maximum; 14 | 15 | return value; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /GifCapture/Base/IScreen.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace GifCapture.Base 4 | { 5 | public interface IScreen 6 | { 7 | Rectangle Rectangle { get; } 8 | 9 | string DeviceName { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /GifCapture/Base/IWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Base 5 | { 6 | /// 7 | /// Minimal representation of a Window. 8 | /// 9 | public interface IWindow 10 | { 11 | bool IsAlive { get; } 12 | 13 | bool IsVisible { get; } 14 | 15 | bool IsMaximized { get; } 16 | 17 | IntPtr Handle { get; } 18 | 19 | string Title { get; } 20 | 21 | Rectangle Rectangle { get; } 22 | } 23 | } -------------------------------------------------------------------------------- /GifCapture/Base/ScreenWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Linq; 4 | 5 | namespace GifCapture.Base 6 | { 7 | class ScreenWrapper : IScreen 8 | { 9 | readonly System.Windows.Forms.Screen _screen; 10 | 11 | ScreenWrapper(System.Windows.Forms.Screen screen) 12 | { 13 | _screen = screen; 14 | } 15 | 16 | public Rectangle Rectangle => _screen.Bounds; 17 | 18 | public string DeviceName => _screen.DeviceName; 19 | 20 | public static IEnumerable Enumerate() => System.Windows.Forms.Screen.AllScreens.Select(m => new ScreenWrapper(m)); 21 | } 22 | } -------------------------------------------------------------------------------- /GifCapture/Controls/Magnifier.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 22 | 23 | 24 | 26 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /GifCapture/Controls/Magnifier.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace GifCapture.Controls 5 | { 6 | public partial class Magnifier : UserControl 7 | { 8 | public Magnifier() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | public static readonly DependencyProperty TargetProperty = 14 | DependencyProperty.Register(nameof(Target), typeof(UIElement), typeof(Magnifier)); 15 | 16 | 17 | public UIElement Target 18 | { 19 | get => (UIElement) GetValue(TargetProperty); 20 | set => SetValue(TargetProperty, value); 21 | } 22 | 23 | public void UpdateViewBox(Point point, Size size) 24 | { 25 | if (PART_VisualBrush != null) 26 | { 27 | PART_VisualBrush.Viewbox = new Rect(point, size); 28 | } 29 | } 30 | 31 | public void UpdatePositionTextBlock(Point point, Size size) 32 | { 33 | PositionTextBlock.Text = $"X,Y={point.X},{point.Y} WxH={(int) size.Width}x{(int) size.Height}"; 34 | } 35 | 36 | public void HideRectangle() 37 | { 38 | Rectangle1.Visibility = Visibility.Hidden; 39 | Rectangle2.Visibility = Visibility.Hidden; 40 | Rectangle3.Visibility = Visibility.Hidden; 41 | } 42 | 43 | public void ShowRectangle() 44 | { 45 | Rectangle1.Visibility = Visibility.Visible; 46 | Rectangle2.Visibility = Visibility.Visible; 47 | Rectangle3.Visibility = Visibility.Visible; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /GifCapture/Controls/PuncturedRegion.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GifCapture/Controls/PuncturedRegion.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using GifCapture.Base; 4 | 5 | namespace GifCapture.Controls 6 | { 7 | public partial class PuncturedRegion : UserControl 8 | { 9 | public Rect? Region 10 | { 11 | get => (Rect?) GetValue(RegionProperty); 12 | set => SetValue(RegionProperty, value); 13 | } 14 | 15 | public static readonly DependencyProperty RegionProperty = DependencyProperty.Register( 16 | nameof(Region), 17 | typeof(Rect?), 18 | typeof(PuncturedRegion), 19 | new PropertyMetadata(RegionChanged)); 20 | 21 | static void RegionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 22 | { 23 | if (obj is PuncturedRegion r) 24 | { 25 | switch (e.NewValue) 26 | { 27 | case null: 28 | // Must not be collapsed, since ActualWidth and ActualHeight are used. 29 | r.Visibility = Visibility.Hidden; 30 | break; 31 | 32 | case Rect region: 33 | var w = r.ActualWidth; 34 | var h = r.ActualHeight; 35 | 36 | r.BorderTop.Margin = new Thickness(); 37 | r.BorderTop.Width = w; 38 | r.BorderTop.Height = region.Top.Clip(0, h); 39 | 40 | r.BorderBottom.Margin = new Thickness(0, region.Bottom, 0, 0); 41 | r.BorderBottom.Width = w; 42 | r.BorderBottom.Height = (h - region.Bottom).Clip(0, h); 43 | 44 | r.BorderLeft.Margin = new Thickness(0, region.Top, 0, 0); 45 | r.BorderLeft.Width = region.Left.Clip(0, w); 46 | r.BorderLeft.Height = region.Height; 47 | 48 | r.BorderRight.Margin = new Thickness(region.Right, region.Top, 0, 0); 49 | r.BorderRight.Width = (w - region.Right).Clip(0, w); 50 | r.BorderRight.Height = region.Height; 51 | 52 | r.Visibility = Visibility.Visible; 53 | break; 54 | } 55 | } 56 | } 57 | 58 | public PuncturedRegion() 59 | { 60 | InitializeComponent(); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /GifCapture/Controls/StripedBorder.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /GifCapture/Controls/StripedBorder.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace GifCapture.Controls 4 | { 5 | public partial class StripedBorder : UserControl 6 | { 7 | public StripedBorder() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture/Converters/NegatingConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace GifCapture.Converters 7 | { 8 | public class NegatingConverter : IValueConverter 9 | { 10 | static object DoConvert(object value) 11 | { 12 | if (value is bool b) 13 | return !b; 14 | 15 | return Binding.DoNothing; 16 | } 17 | 18 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | switch (value) 21 | { 22 | case bool b when targetType == typeof(Visibility): 23 | return b ? Visibility.Collapsed : Visibility.Visible; 24 | 25 | case bool b: 26 | return !b; 27 | 28 | case Visibility visibility when targetType == typeof(Visibility): 29 | return visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible; 30 | 31 | case Visibility visibility: 32 | return visibility == Visibility.Collapsed; 33 | 34 | default: 35 | return Binding.DoNothing; 36 | } 37 | } 38 | 39 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 40 | { 41 | return DoConvert(value); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /GifCapture/Converters/VisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows; 4 | using System.Windows.Data; 5 | 6 | namespace GifCapture.Converters 7 | { 8 | public class VisibilityConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value is bool b && b) 13 | { 14 | return Visibility.Visible; 15 | } 16 | else 17 | { 18 | return Visibility.Collapsed; 19 | } 20 | } 21 | 22 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /GifCapture/Exceptions/WindowClosedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Exceptions 4 | { 5 | /// 6 | /// Thrown when a closed window is used. 7 | /// 8 | public class WindowClosedException : Exception 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /GifCapture/Gif/GdiTargetDeviceContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Native; 4 | 5 | namespace GifCapture.Gif 6 | { 7 | public class GdiTargetDeviceContext : ITargetDeviceContext 8 | { 9 | readonly IntPtr _hdcDest, _hBitmap; 10 | 11 | public GdiTargetDeviceContext(IntPtr srcDc, int width, int height) 12 | { 13 | _hdcDest = Gdi32.CreateCompatibleDC(srcDc); 14 | _hBitmap = Gdi32.CreateCompatibleBitmap(srcDc, width, height); 15 | Gdi32.SelectObject(_hdcDest, _hBitmap); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | Gdi32.DeleteDC(_hdcDest); 21 | Gdi32.DeleteObject(_hBitmap); 22 | } 23 | 24 | public IntPtr GetDc() => _hdcDest; 25 | 26 | public Bitmap GetBitmap() 27 | { 28 | return Image.FromHbitmap(_hBitmap); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /GifCapture/Gif/GifFrame.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace GifCapture.Gif 4 | { 5 | public class GifFrame 6 | { 7 | public Bitmap Bitmap { get; set; } 8 | public int Delay { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture/Gif/IImageProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Gif 5 | { 6 | /// 7 | /// Provides images. 8 | /// Must provide in 32-bpp RGB. 9 | /// 10 | public interface IImageProvider : IDisposable 11 | { 12 | /// 13 | /// Capture an image. 14 | /// 15 | Bitmap Capture(); 16 | 17 | /// 18 | /// Height of Captured image. 19 | /// 20 | int Height { get; } 21 | 22 | /// 23 | /// Width of Captured image. 24 | /// 25 | int Width { get; } 26 | } 27 | } -------------------------------------------------------------------------------- /GifCapture/Gif/ITargetDeviceContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace GifCapture.Gif 5 | { 6 | public interface ITargetDeviceContext : IDisposable 7 | { 8 | IntPtr GetDc(); 9 | 10 | Bitmap GetBitmap(); 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture/Gif/RectangleProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Native; 4 | using GifCapture.Screen; 5 | 6 | namespace GifCapture.Gif 7 | { 8 | public class RectangleProvider : IImageProvider 9 | { 10 | readonly Rectangle _rectangle; 11 | readonly bool _includeCursor; 12 | 13 | readonly IntPtr _hdcSrc; 14 | readonly ITargetDeviceContext _dcTarget; 15 | 16 | public RectangleProvider(Rectangle rectangle, bool includeCursor = false) 17 | { 18 | _rectangle = rectangle; 19 | _includeCursor = includeCursor; 20 | Width = rectangle.Size.Width; 21 | Height = rectangle.Size.Height; 22 | 23 | _hdcSrc = User32.GetDC(IntPtr.Zero); 24 | _dcTarget = new GdiTargetDeviceContext(_hdcSrc, Width, Height); 25 | } 26 | 27 | private void OnCapture() 28 | { 29 | Rectangle rect = _rectangle; 30 | IntPtr hdcDest = _dcTarget.GetDc(); 31 | 32 | Gdi32.StretchBlt(hdcDest, 0, 0, Width, Height, 33 | _hdcSrc, rect.X, rect.Y, Width, Height, 34 | (int) CopyPixelOperation.SourceCopy); 35 | 36 | if (_includeCursor) 37 | { 38 | MouseCursor.Draw(hdcDest, p => new Point(p.X - _rectangle.X, p.Y - _rectangle.Y)); 39 | } 40 | } 41 | 42 | public Bitmap Capture() 43 | { 44 | OnCapture(); 45 | Bitmap img = _dcTarget.GetBitmap(); 46 | return img; 47 | } 48 | 49 | /// 50 | /// Height of Captured image. 51 | /// 52 | public int Height { get; } 53 | 54 | /// 55 | /// Width of Captured image. 56 | /// 57 | public int Width { get; } 58 | 59 | public void Dispose() 60 | { 61 | _dcTarget.Dispose(); 62 | User32.ReleaseDC(IntPtr.Zero, _hdcSrc); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /GifCapture/GifCapture.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net472 6 | true 7 | Assets\Images\logo.ico 8 | false 9 | false 10 | true 11 | true 12 | GifCapture 13 | AnyCPU;x64 14 | 15 | 16 | 17 | none 18 | false 19 | true 20 | 21 | 22 | 23 | 24 | MSBuild:Compile 25 | Wpf 26 | Designer 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | PublicResXFileCodeGenerator 51 | Resources.Designer.cs 52 | 53 | 54 | 55 | 56 | True 57 | True 58 | Resources.resx 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /GifCapture/Images/DrawingImage.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | using GifCapture.Screen; 5 | 6 | namespace GifCapture.Images 7 | { 8 | public class DrawingImage : IBitmapImage 9 | { 10 | public Image Image { get; } 11 | 12 | public DrawingImage(Image image) 13 | { 14 | this.Image = image; 15 | } 16 | 17 | public void Dispose() 18 | { 19 | Image.Dispose(); 20 | } 21 | 22 | public int Width => Image.Width; 23 | public int Height => Image.Height; 24 | 25 | public void Save(string fileName, ImageFormat format) 26 | { 27 | Image.Save(fileName, format); 28 | } 29 | 30 | public void Save(Stream stream, ImageFormat format) 31 | { 32 | Image.Save(stream, format); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /GifCapture/Images/IBitmapImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | 5 | namespace GifCapture.Images 6 | { 7 | public interface IBitmapImage : IDisposable 8 | { 9 | int Width { get; } 10 | 11 | int Height { get; } 12 | 13 | void Save(string fileName, ImageFormat format); 14 | 15 | void Save(Stream stream, ImageFormat format); 16 | } 17 | } -------------------------------------------------------------------------------- /GifCapture/Models/Dpi.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Interop; 2 | 3 | namespace GifCapture.Models 4 | { 5 | /// 6 | /// Provides DPI scaling factor. 7 | /// Only needs to be used when dealing with WPF since their sizes are specified in Device Independent Pixels. 8 | /// 9 | public class Dpi 10 | { 11 | static Dpi() 12 | { 13 | using (var src = new HwndSource(new HwndSourceParameters())) 14 | { 15 | if (src.CompositionTarget != null) 16 | { 17 | var matrix = src.CompositionTarget.TransformToDevice; 18 | 19 | X = (float) matrix.M11; 20 | Y = (float) matrix.M22; 21 | } 22 | } 23 | } 24 | 25 | public static float X { get; } 26 | 27 | public static float Y { get; } 28 | } 29 | } -------------------------------------------------------------------------------- /GifCapture/Native/DwmApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using GifCapture.Native.Structs; 4 | 5 | namespace GifCapture.Native 6 | { 7 | static class DwmApi 8 | { 9 | const string DllName = "dwmapi.dll"; 10 | 11 | [DllImport(DllName)] 12 | public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, out bool Value, int Size); 13 | 14 | [DllImport(DllName)] 15 | public static extern int DwmGetWindowAttribute(IntPtr Window, int Attribute, ref RECT Value, int Size); 16 | } 17 | } -------------------------------------------------------------------------------- /GifCapture/Native/EnumWindowsProc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Native 4 | { 5 | public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); 6 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/DrawIconExFlags.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum DrawIconExFlags 4 | { 5 | Compat = 0x04, 6 | DefaultSize = 0x08, 7 | Image = 0x02, 8 | Mask = 0x01, 9 | NoMirror = 0x10, 10 | Normal = Image | Mask 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/FileOperationFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GifCapture.Native.Enums 4 | { 5 | [Flags] 6 | public enum FileOperationFlags 7 | { 8 | MultiDestFiles = 0x1, 9 | 10 | ConfirmMouse = 0x2, 11 | 12 | /// 13 | /// Don't create progress/report 14 | /// 15 | Silent = 0x4, 16 | 17 | RenameOnCollission = 0x8, 18 | 19 | /// 20 | /// Don't prompt the user. 21 | /// 22 | NoConfirmation = 0x10, 23 | 24 | /// 25 | /// Fill in . 26 | /// Must be freed using SHFreeNameMappings 27 | /// 28 | WantMappingHandle = 0x20, 29 | 30 | AllowUndo = 0x40, 31 | 32 | /// 33 | /// On *.*, do only files 34 | /// 35 | FilesOnly = 0x80, 36 | 37 | /// 38 | /// Don't show names of files 39 | /// 40 | SimpleProgress = 0x100, 41 | 42 | /// 43 | /// Don't confirm making any needed dirs 44 | /// 45 | NoConfirmMkdir = 0x200, 46 | 47 | /// 48 | /// Don't put up error UI 49 | /// 50 | // ReSharper disable once InconsistentNaming 51 | NoErrorUI = 0x400, 52 | 53 | /// 54 | /// Dont copy NT file Security Attributes 55 | /// 56 | NoCopySecurityAttribs = 0x800, 57 | 58 | /// 59 | /// Don't recurse into directories. 60 | /// 61 | NoRecursion = 0x1000, 62 | 63 | /// 64 | /// Don't operate on connected elements. 65 | /// 66 | NoConnectedElements = 0x2000, 67 | 68 | /// 69 | /// During delete operation, 70 | /// warn if nuking instead of recycling (partially overrides ) 71 | /// 72 | WantNukeWarning = 0x4000, 73 | 74 | /// 75 | /// Treat reparse points as objects, not containers 76 | /// 77 | NoRecurseReparse = 0x8000 78 | } 79 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/FileOperationType.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum FileOperationType 4 | { 5 | Move = 0x1, 6 | Copy = 0x2, 7 | Delete = 0x3, 8 | Rename = 0x4 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/GetWindowEnum.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum GetWindowEnum 4 | { 5 | Owner = 4 6 | } 7 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/GetWindowLongValue.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum GetWindowLongValue 4 | { 5 | Style = -16, 6 | ExStyle = -20 7 | } 8 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/SetWindowPositionFlags.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum SetWindowPositionFlags 4 | { 5 | ShowWindow = 0x400, 6 | NoActivate = 0x0010 7 | } 8 | } -------------------------------------------------------------------------------- /GifCapture/Native/Enums/WindowStyles.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Enums 2 | { 3 | public enum WindowStyles : long 4 | { 5 | Child = 0x40000000, 6 | ToolWindow = 0x00000080, 7 | AppWindow = 0x00040000, 8 | SizeBox = 0x00040000L 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture/Native/Gdi32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using GifCapture.Native.Structs; 4 | 5 | 6 | namespace GifCapture.Native 7 | { 8 | static class Gdi32 9 | { 10 | const string DllName = "gdi32.dll"; 11 | 12 | [DllImport(DllName)] 13 | public static extern bool DeleteObject(IntPtr hObject); 14 | 15 | [DllImport(DllName)] 16 | public static extern bool BitBlt(IntPtr hObject, int XDest, int YDest, int Width, int Height, IntPtr ObjectSource, int XSrc, int YSrc, int Op); 17 | 18 | [DllImport(DllName)] 19 | public static extern bool StretchBlt(IntPtr hObject, int XDest, int YDest, int WDest, int HDest, IntPtr ObjectSource, int XSrc, int YSrc, int WSrc, 20 | int HSrc, int Op); 21 | 22 | [DllImport(DllName)] 23 | public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int Width, int Height); 24 | 25 | [DllImport(DllName)] 26 | public static extern IntPtr CreateCompatibleDC(IntPtr hDC); 27 | 28 | [DllImport(DllName)] 29 | public static extern bool DeleteDC(IntPtr hDC); 30 | 31 | [DllImport(DllName)] 32 | public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); 33 | 34 | [DllImport(DllName)] 35 | public static extern uint SetDCBrushColor(IntPtr hDC, uint color); //color=0x00bbggrr 36 | 37 | [DllImport(DllName)] 38 | public static extern uint SetDCPenColor(IntPtr hDC, uint color); 39 | 40 | [DllImport(DllName)] 41 | public static extern bool Ellipse(IntPtr hDC, int left, int top, int right, int bottom); 42 | 43 | [DllImport(DllName)] 44 | public static extern IntPtr GetStockObject(StockObjects fnObject); 45 | } 46 | } -------------------------------------------------------------------------------- /GifCapture/Native/NativeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using GifCapture.Native.Structs; 3 | 4 | namespace GifCapture.Native 5 | { 6 | static class NativeExtensions 7 | { 8 | public static Rectangle ToRectangle(this RECT r) => Rectangle.FromLTRB(r.Left, r.Top, r.Right, r.Bottom); 9 | } 10 | } -------------------------------------------------------------------------------- /GifCapture/Native/Structs/CursorInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | 5 | 6 | namespace GifCapture.Native.Structs 7 | { 8 | [StructLayout(LayoutKind.Sequential)] 9 | public struct CursorInfo 10 | { 11 | public int cbSize; 12 | public int flags; 13 | public IntPtr hCursor; 14 | public Point ptScreenPos; 15 | } 16 | } -------------------------------------------------------------------------------- /GifCapture/Native/Structs/IconInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | namespace GifCapture.Native.Structs 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct IconInfo 9 | { 10 | public bool fIcon; 11 | public int xHotspot; 12 | public int yHotspot; 13 | public IntPtr hbmMask; 14 | public IntPtr hbmColor; 15 | } 16 | } -------------------------------------------------------------------------------- /GifCapture/Native/Structs/RECT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace GifCapture.Native.Structs 5 | { 6 | [Serializable, StructLayout(LayoutKind.Sequential)] 7 | public struct RECT 8 | { 9 | public int Left; 10 | public int Top; 11 | public int Right; 12 | public int Bottom; 13 | 14 | public RECT(int dimension) 15 | { 16 | Left = Top = Right = Bottom = dimension; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /GifCapture/Native/Structs/StockObjects.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Native.Structs 2 | { 3 | public enum StockObjects 4 | { 5 | WHITE_BRUSH = 0, 6 | LTGRAY_BRUSH = 1, 7 | GRAY_BRUSH = 2, 8 | DKGRAY_BRUSH = 3, 9 | BLACK_BRUSH = 4, 10 | NULL_BRUSH = 5, 11 | HOLLOW_BRUSH = NULL_BRUSH, 12 | WHITE_PEN = 6, 13 | BLACK_PEN = 7, 14 | NULL_PEN = 8, 15 | OEM_FIXED_FONT = 10, 16 | ANSI_FIXED_FONT = 11, 17 | ANSI_VAR_FONT = 12, 18 | SYSTEM_FONT = 13, 19 | DEVICE_DEFAULT_FONT = 14, 20 | DEFAULT_PALETTE = 15, 21 | SYSTEM_FIXED_FONT = 16, 22 | DEFAULT_GUI_FONT = 17, 23 | DC_BRUSH = 18, 24 | DC_PEN = 19, 25 | } 26 | } -------------------------------------------------------------------------------- /GifCapture/Native/UnsafeBitmap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace GifCapture.Native 7 | { 8 | [StructLayout(LayoutKind.Sequential)] 9 | struct PixelData 10 | { 11 | public byte Blue, Green, Red, Alpha; 12 | } 13 | 14 | unsafe class UnsafeBitmap : IDisposable 15 | { 16 | readonly Bitmap _inputBitmap; 17 | BitmapData _bitmapData; 18 | byte* _pBase; 19 | readonly int _width; 20 | 21 | public UnsafeBitmap(Bitmap InputBitmap) 22 | { 23 | _inputBitmap = InputBitmap; 24 | 25 | var bounds = new Rectangle(Point.Empty, _inputBitmap.Size); 26 | 27 | _width = bounds.Width * sizeof(PixelData); 28 | 29 | if (_width % 4 != 0) 30 | _width = 4 * (_width / 4 + 1); 31 | 32 | //Lock Image 33 | _bitmapData = _inputBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 34 | _pBase = (byte*) _bitmapData.Scan0; 35 | } 36 | 37 | public PixelData* this[int X, int Y] => (PixelData*) (_pBase + Y * _width + X * sizeof(PixelData)); 38 | 39 | public void Dispose() 40 | { 41 | _inputBitmap.UnlockBits(_bitmapData); 42 | _bitmapData = null; 43 | _pBase = null; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /GifCapture/Native/User32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using GifCapture.Native.Enums; 6 | using GifCapture.Native.Structs; 7 | 8 | namespace GifCapture.Native 9 | { 10 | public static class User32 11 | { 12 | const string DllName = "user32.dll"; 13 | 14 | [DllImport(DllName)] 15 | public static extern bool GetCursorPos(ref Point lpPoint); 16 | 17 | [DllImport(DllName)] 18 | public static extern bool DrawIconEx( 19 | IntPtr hDC, 20 | int Left, 21 | int Top, 22 | IntPtr hIcon, 23 | int Width, 24 | int Height, 25 | int StepIfAniCur, 26 | IntPtr BrushForFlickerFreeDraw, 27 | DrawIconExFlags Flags); 28 | 29 | [DllImport(DllName)] 30 | public static extern WindowStyles GetWindowLong(IntPtr hWnd, GetWindowLongValue nIndex); 31 | 32 | [DllImport(DllName)] 33 | public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect); 34 | 35 | [DllImport(DllName)] 36 | public static extern bool IsWindow(IntPtr hWnd); 37 | 38 | [DllImport(DllName)] 39 | public static extern IntPtr GetDesktopWindow(); 40 | 41 | [DllImport(DllName)] 42 | public static extern IntPtr GetForegroundWindow(); 43 | 44 | [DllImport(DllName)] 45 | public static extern bool EnumWindows(EnumWindowsProc proc, IntPtr lParam); 46 | 47 | [DllImport(DllName)] 48 | public static extern bool EnumChildWindows(IntPtr hWnd, EnumWindowsProc proc, IntPtr lParam); 49 | 50 | [DllImport(DllName)] 51 | public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount); 52 | 53 | [DllImport(DllName)] 54 | public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowEnum uCmd); 55 | 56 | [DllImport(DllName)] 57 | public static extern int GetWindowTextLength(IntPtr hWnd); 58 | 59 | [DllImport(DllName)] 60 | public static extern bool IsWindowVisible(IntPtr hWnd); 61 | 62 | [DllImport(DllName)] 63 | public static extern bool SetForegroundWindow(IntPtr hWnd); 64 | 65 | [DllImport(DllName)] 66 | public static extern bool IsIconic(IntPtr hWnd); 67 | 68 | [DllImport(DllName)] 69 | public static extern bool IsZoomed(IntPtr hWnd); 70 | 71 | [DllImport(DllName)] 72 | public static extern bool DestroyIcon(IntPtr hIcon); 73 | 74 | [DllImport(DllName)] 75 | public static extern IntPtr CopyIcon(IntPtr hIcon); 76 | 77 | [DllImport(DllName)] 78 | public static extern bool GetCursorInfo(ref CursorInfo pci); 79 | 80 | [DllImport(DllName)] 81 | public static extern bool GetIconInfo(IntPtr hIcon, out IconInfo piconinfo); 82 | 83 | [DllImport(DllName)] 84 | public static extern IntPtr GetDC(IntPtr hWnd); 85 | 86 | [DllImport(DllName)] 87 | public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); 88 | 89 | [DllImport(DllName)] 90 | public static extern bool FillRect(IntPtr hDC, ref RECT Rect, IntPtr Brush); 91 | 92 | [DllImport(DllName)] 93 | public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPositionFlags wFlags); 94 | 95 | [DllImport(DllName)] 96 | public static extern int ShowWindow(IntPtr hWnd, int nCmdShow); 97 | } 98 | } -------------------------------------------------------------------------------- /GifCapture/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | text/microsoft-resx 11 | 12 | 13 | 1.3 14 | 15 | 16 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 17 | 18 | 19 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 20 | 21 | 22 | http://www.redisant.com/gif 23 | 24 | 25 | Capture Window 26 | 27 | 28 | Capture Region 29 | 30 | 31 | Capture Screen 32 | 33 | 34 | Recorde Window 35 | 36 | 37 | Recorde Region 38 | 39 | 40 | Recorde Screen 41 | 42 | 43 | Stop Recording 44 | 45 | 46 | Exit 47 | 48 | 49 | Select the window to capture, or press Esc to exit 50 | 51 | 52 | Select the screen to capture, or press Esc to cancel 53 | 54 | 55 | Screenshot Saved 56 | 57 | 58 | Saved Path: 59 | 60 | 61 | Recording Saved: 62 | 63 | 64 | Recording: 65 | 66 | 67 | Delay: 68 | 69 | 70 | Contains Mouse 71 | 72 | -------------------------------------------------------------------------------- /GifCapture/Properties/Resources.zh-hant.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | text/microsoft-resx 4 | 5 | 6 | 1.3 7 | 8 | 9 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 10 | 11 | 12 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 13 | 14 | 15 | http://www.redisant.cn/gif 16 | 17 | 18 | 截取窗口 19 | 20 | 21 | 截取區域 22 | 23 | 24 | 截取屏幕 25 | 26 | 27 | 錄製窗口 28 | 29 | 30 | 錄製區域 31 | 32 | 33 | 錄製屏幕 34 | 35 | 36 | 停止錄製 37 | 38 | 39 | 退出 40 | 41 | 42 | 選擇要捕獲的窗口,或者按下 Esc 退出 43 | 44 | 45 | 選擇要捕獲的屏幕,或按下 Esc 取消 46 | 47 | 48 | 截圖已保存 49 | 50 | 51 | 保存位置: 52 | 53 | 54 | 錄屏已保存 55 | 56 | 57 | 正在錄製: 58 | 59 | 60 | 延遲: 61 | 62 | 63 | 包含鼠標 64 | 65 | -------------------------------------------------------------------------------- /GifCapture/Properties/Resources.zh.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | text/microsoft-resx 4 | 5 | 6 | 1.3 7 | 8 | 9 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 10 | 11 | 12 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 13 | 14 | 15 | http://www.redisant.cn/gif 16 | 17 | 18 | 截取窗口 19 | 20 | 21 | 截取区域 22 | 23 | 24 | 截取屏幕 25 | 26 | 27 | 录制窗口 28 | 29 | 30 | 录制区域 31 | 32 | 33 | 录制屏幕 34 | 35 | 36 | 停止录制 37 | 38 | 39 | 退出 40 | 41 | 42 | 选择要捕获的窗口,或者按下 Esc 退出 43 | 44 | 45 | 选择要捕获的屏幕,或按下 Esc 取消 46 | 47 | 48 | 截图已保存 49 | 50 | 51 | 保存位置: 52 | 53 | 54 | 录屏已保存 55 | 56 | 57 | 正在录制: 58 | 59 | 60 | 延迟: 61 | 62 | 63 | 包含鼠标 64 | 65 | -------------------------------------------------------------------------------- /GifCapture/Screen/MouseCursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using GifCapture.Native; 5 | using GifCapture.Native.Enums; 6 | using GifCapture.Native.Structs; 7 | 8 | namespace GifCapture.Screen 9 | { 10 | /// 11 | /// Draws the MouseCursor on an Image 12 | /// 13 | static class MouseCursor 14 | { 15 | const int CursorShowing = 1; 16 | 17 | /// 18 | /// Draws this overlay. 19 | /// 20 | /// A object to draw upon. 21 | /// Point Transform Function. 22 | public static void Draw(Graphics g, Func transform = null) 23 | { 24 | var hIcon = GetIcon(transform, out var location); 25 | 26 | if (hIcon == IntPtr.Zero) 27 | return; 28 | 29 | var bmp = Icon.FromHandle(hIcon).ToBitmap(); 30 | User32.DestroyIcon(hIcon); 31 | 32 | try 33 | { 34 | using (bmp) 35 | { 36 | // SolidBrush solidBrush = new SolidBrush(Color.FromArgb(200, 191, 222, 179)); 37 | Pen pen = new Pen(Color.Red); 38 | int width = 32; 39 | // g.FillEllipse(solidBrush, location.X - width, location.Y - width, width * 2, width * 2); 40 | g.DrawEllipse(pen, location.X - width, location.Y - width, width * 2, width * 2); 41 | g.DrawImage(bmp, new Rectangle(location, bmp.Size)); 42 | // solidBrush.Dispose(); 43 | pen.Dispose(); 44 | } 45 | } 46 | catch (ArgumentException) 47 | { 48 | } 49 | } 50 | 51 | public static void Draw(IntPtr deviceContext, Func transform = null) 52 | { 53 | var hIcon = GetIcon(transform, out var location); 54 | 55 | if (hIcon == IntPtr.Zero) 56 | return; 57 | 58 | try 59 | { 60 | // Select DC_PEN so you can change the color of the pen with COLORREF SetDCPenColor(HDC hdc, COLORREF color) 61 | Gdi32.SelectObject(deviceContext, Gdi32.GetStockObject(StockObjects.DC_PEN)); 62 | Gdi32.SelectObject(deviceContext, Gdi32.GetStockObject(StockObjects.NULL_BRUSH)); 63 | // Gdi32.SetDCBrushColor(deviceContext, 0x0000FF00); // 0x00bbggrr 64 | Gdi32.SetDCPenColor(deviceContext, 0x000000FF); 65 | int width = 32; 66 | Gdi32.Ellipse(deviceContext, location.X - width, location.Y - width, location.X + width, location.Y + width); 67 | User32.DrawIconEx(deviceContext, 68 | location.X, location.Y, 69 | hIcon, 70 | 0, 0, 0, IntPtr.Zero, 71 | DrawIconExFlags.Normal); 72 | } 73 | finally 74 | { 75 | User32.DestroyIcon(hIcon); 76 | } 77 | } 78 | 79 | static IntPtr GetIcon(Func transform, out Point location) 80 | { 81 | location = Point.Empty; 82 | 83 | var cursorInfo = new CursorInfo {cbSize = Marshal.SizeOf()}; 84 | 85 | if (!User32.GetCursorInfo(ref cursorInfo)) 86 | return IntPtr.Zero; 87 | 88 | if (cursorInfo.flags != CursorShowing) 89 | return IntPtr.Zero; 90 | 91 | var hIcon = User32.CopyIcon(cursorInfo.hCursor); 92 | 93 | if (hIcon == IntPtr.Zero) 94 | return IntPtr.Zero; 95 | 96 | if (!User32.GetIconInfo(hIcon, out var icInfo)) 97 | return IntPtr.Zero; 98 | 99 | var hotspot = new Point(icInfo.xHotspot, icInfo.yHotspot); 100 | 101 | location = new Point(cursorInfo.ptScreenPos.X - hotspot.X, cursorInfo.ptScreenPos.Y - hotspot.Y); 102 | 103 | if (transform != null) 104 | location = transform(location); 105 | 106 | Gdi32.DeleteObject(icInfo.hbmColor); 107 | Gdi32.DeleteObject(icInfo.hbmMask); 108 | 109 | return hIcon; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /GifCapture/Screen/ScreenShot.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using GifCapture.Base; 3 | using GifCapture.Images; 4 | using GifCapture.Services; 5 | 6 | namespace GifCapture.Screen 7 | { 8 | /// 9 | /// Contains methods for taking ScreenShots 10 | /// 11 | public static class ScreenShot 12 | { 13 | /// 14 | /// Captures the entire Desktop. 15 | /// 16 | /// Whether to include the Mouse Cursor. 17 | /// The Captured Image. 18 | public static IBitmapImage Capture(bool includeCursor = false) 19 | { 20 | var platformServices = ServiceProvider.IPlatformServices; 21 | return Capture(platformServices.DesktopRectangle, includeCursor); 22 | } 23 | 24 | /// 25 | /// Capture transparent Screenshot of a Window. 26 | /// 27 | /// The to Capture. 28 | /// Whether to include Mouse Cursor. 29 | public static IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false) 30 | { 31 | var platformServices = ServiceProvider.IPlatformServices; 32 | return platformServices.CaptureTransparent(window, includeCursor); 33 | } 34 | 35 | /// 36 | /// Captures a Specific Region. 37 | /// 38 | /// A specifying the Region to Capture. 39 | /// Whether to include the Mouse Cursor. 40 | /// The Captured Image. 41 | public static IBitmapImage Capture(Rectangle region, bool includeCursor = false) 42 | { 43 | var platformServices = ServiceProvider.IPlatformServices; 44 | return platformServices.Capture(region, includeCursor); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /GifCapture/Screen/ScreenShotInternal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using GifCapture.Base; 4 | using GifCapture.Images; 5 | using GifCapture.Services; 6 | 7 | namespace GifCapture.Screen 8 | { 9 | /// 10 | /// Contains methods for taking ScreenShots 11 | /// 12 | static class ScreenShotInternal 13 | { 14 | /// 15 | /// Capture transparent Screenshot of a Window. 16 | /// 17 | public static IBitmapImage CaptureTransparent(IWindow window, bool includeCursor, IPlatformServices platformServices) 18 | { 19 | if (window == null) 20 | { 21 | throw new ArgumentNullException(nameof(window)); 22 | } 23 | 24 | var backdrop = new WindowScreenShotBackdrop(window, platformServices); 25 | 26 | backdrop.ShowWhite(); 27 | 28 | var r = backdrop.Rectangle; 29 | 30 | // Capture screenshot with white background 31 | using (var whiteShot = CaptureInternal(r)) 32 | { 33 | backdrop.ShowBlack(); 34 | 35 | // Capture screenshot with black background 36 | using (var blackShot = CaptureInternal(r)) 37 | { 38 | backdrop.Dispose(); 39 | 40 | var transparentImage = GraphicsExtensions.DifferentiateAlpha(whiteShot, blackShot); 41 | 42 | if (transparentImage == null) 43 | return null; 44 | 45 | // Include Cursor only if within window 46 | if (includeCursor && r.Contains(platformServices.CursorPosition)) 47 | { 48 | using (var g = Graphics.FromImage(transparentImage)) 49 | { 50 | MouseCursor.Draw(g, P => new Point(P.X - r.X, P.Y - r.Y)); 51 | } 52 | } 53 | 54 | return new DrawingImage(transparentImage.CropEmptyEdges()); 55 | } 56 | } 57 | } 58 | 59 | static Bitmap CaptureInternal(Rectangle region, bool includeCursor = false) 60 | { 61 | var bmp = new Bitmap(region.Width, region.Height); 62 | using (var g = Graphics.FromImage(bmp)) 63 | { 64 | g.CopyFromScreen(region.Location, Point.Empty, region.Size, CopyPixelOperation.SourceCopy); 65 | if (includeCursor) 66 | { 67 | MouseCursor.Draw(g, p => new Point(p.X - region.X, p.Y - region.Y)); 68 | } 69 | 70 | g.Flush(); 71 | } 72 | 73 | return bmp; 74 | } 75 | 76 | /// 77 | /// Captures a Specific Region. 78 | /// 79 | /// A specifying the Region to Capture. 80 | /// Whether to include the Mouse Cursor. 81 | /// The Captured Image. 82 | public static IBitmapImage Capture(Rectangle region, bool includeCursor = false) 83 | { 84 | return new DrawingImage(CaptureInternal(region, includeCursor)); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /GifCapture/Screen/WindowScreenShotBackdrop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using GifCapture.Base; 5 | using GifCapture.Native; 6 | using GifCapture.Native.Enums; 7 | using GifCapture.Services; 8 | 9 | namespace GifCapture.Screen 10 | { 11 | class WindowScreenShotBackdrop : IDisposable 12 | { 13 | readonly IWindow _window; 14 | readonly Form _form; 15 | 16 | bool _shown; 17 | 18 | public Rectangle Rectangle { get; } 19 | 20 | public WindowScreenShotBackdrop(IWindow window, IPlatformServices platformServices) 21 | { 22 | _window = window; 23 | 24 | // Show and Focus 25 | User32.ShowWindow(window.Handle, 5); 26 | 27 | _form = new Form 28 | { 29 | AllowTransparency = true, 30 | BackColor = Color.White, 31 | FormBorderStyle = FormBorderStyle.None, 32 | ShowInTaskbar = false 33 | }; 34 | 35 | var r = window.Rectangle; 36 | 37 | // Add a margin for window shadows. Excess transparency is trimmed out later 38 | r.Inflate(20, 20); 39 | 40 | // Check if the window is outside of the visible screen 41 | r.Intersect(platformServices.DesktopRectangle); 42 | 43 | Rectangle = r; 44 | } 45 | 46 | void Show() 47 | { 48 | if (_shown) 49 | return; 50 | 51 | _shown = true; 52 | 53 | _form.Show(); 54 | 55 | User32.SetWindowPos(_form.Handle, _window.Handle, 56 | Rectangle.Left, Rectangle.Top, 57 | Rectangle.Width, Rectangle.Height, 58 | SetWindowPositionFlags.NoActivate); 59 | } 60 | 61 | public void ShowWhite() 62 | { 63 | Show(); 64 | 65 | _form.BackColor = Color.White; 66 | 67 | // Wait for Backdrop to update 68 | Application.DoEvents(); 69 | } 70 | 71 | public void ShowBlack() 72 | { 73 | Show(); 74 | 75 | _form.BackColor = Color.Black; 76 | 77 | // Wait for Backdrop to update 78 | Application.DoEvents(); 79 | } 80 | 81 | public void Dispose() 82 | { 83 | _form.Dispose(); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /GifCapture/Services/IPlatformServices.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using GifCapture.Base; 4 | using GifCapture.Images; 5 | 6 | namespace GifCapture.Services 7 | { 8 | public interface IPlatformServices 9 | { 10 | IEnumerable EnumerateScreens(); 11 | IEnumerable EnumerateWindows(); 12 | IEnumerable EnumerateAllWindows(); 13 | IWindow DesktopWindow { get; } 14 | 15 | Rectangle DesktopRectangle { get; } 16 | 17 | IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false); 18 | 19 | Point CursorPosition { get; } 20 | 21 | IBitmapImage Capture(Rectangle region, bool includeCursor = false); 22 | } 23 | } -------------------------------------------------------------------------------- /GifCapture/Services/NotificationsService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.Toolkit.Uwp.Notifications; 4 | 5 | namespace GifCapture.Services 6 | { 7 | public static class NotificationsService 8 | { 9 | public static void Notice(string title, string subTitle, string imageUri = null, Dictionary args = null) 10 | { 11 | try 12 | { 13 | ToastContentBuilder builder = new ToastContentBuilder(); 14 | if (args != null) 15 | { 16 | foreach (KeyValuePair pair in args) 17 | { 18 | builder.AddArgument(pair.Key, pair.Value); 19 | } 20 | } 21 | 22 | builder.AddText(title); 23 | builder.AddText(subTitle); 24 | if (!string.IsNullOrWhiteSpace(imageUri)) 25 | { 26 | builder.AddInlineImage(new Uri(imageUri)); 27 | } 28 | 29 | builder.Show(); 30 | } 31 | catch (Exception e) 32 | { 33 | //ignore 34 | } 35 | } 36 | 37 | public static void OpenFile(string fullNamePath) 38 | { 39 | System.Diagnostics.Process.Start(fullNamePath); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /GifCapture/Services/ServiceProvider.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.Services 2 | { 3 | public static class ServiceProvider 4 | { 5 | public static readonly IPlatformServices IPlatformServices; 6 | 7 | static ServiceProvider() 8 | { 9 | IPlatformServices = new WindowsPlatformServices(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /GifCapture/Services/WindowsPlatformServices.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using System.Linq; 5 | using GifCapture.Base; 6 | using GifCapture.Images; 7 | using GifCapture.Native; 8 | using GifCapture.Screen; 9 | 10 | namespace GifCapture.Services 11 | { 12 | public class WindowsPlatformServices : IPlatformServices 13 | { 14 | public IEnumerable EnumerateScreens() 15 | { 16 | return ScreenWrapper.Enumerate(); 17 | } 18 | 19 | public IEnumerable EnumerateWindows() 20 | { 21 | return Window.EnumerateVisible(); 22 | } 23 | 24 | public IEnumerable EnumerateAllWindows() 25 | { 26 | return Window 27 | .Enumerate() 28 | .Where(w => w.IsVisible) 29 | .SelectMany(GetAllChildren); 30 | } 31 | 32 | public IWindow DesktopWindow => Window.DesktopWindow; 33 | 34 | public Rectangle DesktopRectangle => SystemInformation.VirtualScreen; 35 | 36 | public IBitmapImage CaptureTransparent(IWindow window, bool includeCursor = false) 37 | { 38 | return ScreenShotInternal.CaptureTransparent(window, includeCursor, this); 39 | } 40 | 41 | public Point CursorPosition 42 | { 43 | get 44 | { 45 | var p = new Point(); 46 | User32.GetCursorPos(ref p); 47 | return p; 48 | } 49 | } 50 | 51 | public IBitmapImage Capture(Rectangle region, bool includeCursor = false) 52 | { 53 | return ScreenShotInternal.Capture(region, includeCursor); 54 | } 55 | 56 | IEnumerable GetAllChildren(Window window) 57 | { 58 | var children = window 59 | .EnumerateChildren() 60 | .Where(w => w.IsVisible); 61 | 62 | foreach (var child in children) 63 | { 64 | foreach (var grandchild in GetAllChildren(child)) 65 | { 66 | yield return grandchild; 67 | } 68 | } 69 | 70 | yield return window; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /GifCapture/StaticValue.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture 2 | { 3 | public static class StaticValue 4 | { 5 | public const string AppName = "GifCapture"; 6 | } 7 | } -------------------------------------------------------------------------------- /GifCapture/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GifCapture.ViewModels 2 | { 3 | public class MainViewModel : NotifyPropertyChanged 4 | { 5 | private bool _recoding = false; 6 | 7 | public bool Recoding 8 | { 9 | get => _recoding; 10 | set => Set(ref _recoding, value); 11 | } 12 | 13 | public readonly int Fps = 10; 14 | 15 | private int _elapsedSeconds; 16 | 17 | public int ElapsedSeconds 18 | { 19 | get => _elapsedSeconds; 20 | set => Set(ref _elapsedSeconds, value); 21 | } 22 | 23 | private bool _includeCursor = false; 24 | 25 | public bool IncludeCursor 26 | { 27 | get => _includeCursor; 28 | set => Set(ref _includeCursor, value); 29 | } 30 | 31 | private int _delayIndex = 0; 32 | 33 | public int DelayIndex 34 | { 35 | get => _delayIndex; 36 | set => Set(ref _delayIndex, value); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /GifCapture/ViewModels/NotifyPropertyChanged.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace GifCapture.ViewModels 6 | { 7 | public class NotifyPropertyChanged : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler PropertyChanged; 10 | 11 | protected void RaisePropertyChanged(string propertyName) 12 | { 13 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 14 | } 15 | 16 | protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 17 | { 18 | RaisePropertyChanged(propertyName); 19 | } 20 | 21 | protected void RaiseAllChanged() 22 | { 23 | RaisePropertyChanged(""); 24 | } 25 | 26 | protected bool Set(ref T field, T value, [CallerMemberName] string propertyName = null) 27 | { 28 | if (EqualityComparer.Default.Equals(field, value)) 29 | return false; 30 | 31 | field = value; 32 | 33 | RaisePropertyChanged(propertyName); 34 | 35 | return true; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /GifCapture/ViewModels/ScreenPickerViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing.Imaging; 2 | using System.IO; 3 | using System.Windows; 4 | using System.Windows.Media; 5 | using System.Windows.Media.Imaging; 6 | using GifCapture.Base; 7 | using GifCapture.Images; 8 | using GifCapture.Models; 9 | using GifCapture.Screen; 10 | 11 | namespace GifCapture.ViewModels 12 | { 13 | public class ScreenPickerViewModel 14 | { 15 | public ScreenPickerViewModel(IScreen screen, double scale) 16 | { 17 | this.Screen = screen; 18 | using (IBitmapImage bmp = ScreenShot.Capture(screen.Rectangle)) 19 | { 20 | using (var stream = new MemoryStream()) 21 | { 22 | bmp.Save(stream, ImageFormat.Png); 23 | stream.Seek(0, SeekOrigin.Begin); 24 | PngBitmapDecoder decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 25 | Image = new ImageBrush(decoder.Frames[0]); 26 | 27 | Left = (screen.Rectangle.Left / Dpi.X - SystemParameters.VirtualScreenLeft) * scale; 28 | Top = (screen.Rectangle.Top / Dpi.Y - SystemParameters.VirtualScreenTop) * scale; 29 | Width = screen.Rectangle.Width / Dpi.X * scale; 30 | Height = screen.Rectangle.Height / Dpi.Y * scale; 31 | } 32 | } 33 | } 34 | 35 | public double Left { get; } 36 | public double Top { get; } 37 | 38 | public double Width { get; } 39 | public double Height { get; } 40 | 41 | public IScreen Screen { get; } 42 | 43 | public Brush Image { get; } 44 | } 45 | } -------------------------------------------------------------------------------- /GifCapture/Windows/RecordBarWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /GifCapture/Windows/RecordBarWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows; 3 | using System.Windows.Forms; 4 | using System.Windows.Input; 5 | using GifCapture.Models; 6 | using GifCapture.ViewModels; 7 | 8 | namespace GifCapture.Windows 9 | { 10 | public partial class RecordBarWindow : Window 11 | { 12 | private readonly int _width = 200; 13 | private readonly int _height = 30; 14 | 15 | public RecordBarWindow(MainViewModel mainViewModel, Rectangle rectangle) 16 | { 17 | this.DataContext = mainViewModel; 18 | InitializeComponent(); 19 | Rectangle screen = SystemInformation.VirtualScreen; 20 | int left = (int) ((rectangle.X + rectangle.Width / 2) / Dpi.X - _width / 2); 21 | int top = (int) ((rectangle.Y + rectangle.Height) / Dpi.Y + 10); 22 | if (top > screen.Height / Dpi.Y - _height) 23 | { 24 | top = (int) (screen.Height / Dpi.Y - _height); 25 | } 26 | 27 | if (left > screen.Width / Dpi.X - _width) 28 | { 29 | left = (int) (screen.Width / 2 / Dpi.X - _width / 2); 30 | } 31 | 32 | this.Top = top; 33 | this.Left = left; 34 | this.Width = _width; 35 | this.Height = _height; 36 | } 37 | 38 | private void StopButton_OnClick(object sender, RoutedEventArgs e) 39 | { 40 | MainWindow.Instance.StopRecord_OnClick(null, null); 41 | this.Close(); 42 | } 43 | 44 | private void UIElement_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 45 | { 46 | this.DragMove(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /GifCapture/Windows/RegionPickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /GifCapture/Windows/ScreenPickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  14 | 15 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 62 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /GifCapture/Windows/ScreenPickerWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Input; 6 | using GifCapture.Base; 7 | using GifCapture.Services; 8 | using GifCapture.ViewModels; 9 | using Reactive.Bindings; 10 | using Window = System.Windows.Window; 11 | 12 | namespace GifCapture.Windows 13 | { 14 | public partial class ScreenPickerWindow : Window 15 | { 16 | const double Scale = 0.15; 17 | public ObservableCollection ScreenPickerViewModels { get; } = new ObservableCollection(); 18 | public ICommand SelectScreenCommand { get; } 19 | 20 | 21 | ScreenPickerWindow() 22 | { 23 | this.Deactivated += OnDeactivated; 24 | SelectScreenCommand = new ReactiveCommand() 25 | .WithSubscribe(m => 26 | { 27 | _onClosing = true; 28 | SelectedScreen = m; 29 | Close(); 30 | }); 31 | 32 | InitializeComponent(); 33 | var platformServices = ServiceProvider.IPlatformServices; 34 | var screens = platformServices.EnumerateScreens().ToArray(); 35 | 36 | foreach (var screen in screens) 37 | { 38 | ScreenPickerViewModels.Add(new ScreenPickerViewModel(screen, Scale)); 39 | } 40 | } 41 | 42 | 43 | private bool _onClosing = false; 44 | 45 | private void OnDeactivated(object sender, EventArgs e) 46 | { 47 | if (!_onClosing) 48 | { 49 | CloseClick(null, null); 50 | } 51 | } 52 | 53 | public IScreen SelectedScreen { get; private set; } 54 | 55 | void CloseClick(object sender, RoutedEventArgs e) 56 | { 57 | _onClosing = true; 58 | SelectedScreen = null; 59 | Close(); 60 | } 61 | 62 | public static IScreen PickScreen() 63 | { 64 | var picker = new ScreenPickerWindow(); 65 | picker.ShowDialog(); 66 | return picker.SelectedScreen; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /GifCapture/Windows/VideoSourcePickerWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 26 | 27 | -------------------------------------------------------------------------------- /GifCapture/Windows/VideoSourcePickerWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using System.Windows.Media.Animation; 11 | using System.Windows.Media.Imaging; 12 | using GifCapture.Base; 13 | using GifCapture.Images; 14 | using GifCapture.Models; 15 | using GifCapture.Screen; 16 | using GifCapture.Services; 17 | using Color = System.Windows.Media.Color; 18 | using Window = System.Windows.Window; 19 | 20 | namespace GifCapture.Windows 21 | { 22 | public partial class VideoSourcePickerWindow : Window 23 | { 24 | Predicate Predicate { get; set; } 25 | 26 | VideoSourcePickerWindow() 27 | { 28 | InitializeComponent(); 29 | 30 | Left = SystemParameters.VirtualScreenLeft; 31 | Top = SystemParameters.VirtualScreenTop; 32 | Width = SystemParameters.VirtualScreenWidth; 33 | Height = SystemParameters.VirtualScreenHeight; 34 | 35 | UpdateBackground(); 36 | 37 | var platformServices = ServiceProvider.IPlatformServices; 38 | _screens = platformServices.EnumerateScreens().ToArray(); 39 | _windows = platformServices.EnumerateWindows().ToArray(); 40 | 41 | ShowCancelText(); 42 | } 43 | 44 | readonly IScreen[] _screens; 45 | 46 | readonly IWindow[] _windows; 47 | 48 | public IWindow SelectedWindow { get; private set; } 49 | 50 | void UpdateBackground() 51 | { 52 | using (IBitmapImage bmp = ScreenShot.Capture()) 53 | { 54 | using (Stream stream = new MemoryStream()) 55 | { 56 | bmp.Save(stream, ImageFormat.Png); 57 | stream.Seek(0, SeekOrigin.Begin); 58 | var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 59 | this.Background = new ImageBrush(decoder.Frames[0]); 60 | } 61 | } 62 | } 63 | 64 | void ShowCancelText() 65 | { 66 | foreach (var screen in _screens) 67 | { 68 | var bounds = screen.Rectangle; 69 | 70 | var left = -Left + bounds.Left / Dpi.X; 71 | var top = -Top + bounds.Top / Dpi.Y; 72 | var width = bounds.Width / Dpi.X; 73 | var height = bounds.Height / Dpi.Y; 74 | 75 | var container = new ContentControl 76 | { 77 | Width = width, 78 | Height = height, 79 | Margin = new Thickness(left, top, 0, 0), 80 | VerticalAlignment = VerticalAlignment.Top, 81 | HorizontalAlignment = HorizontalAlignment.Left 82 | }; 83 | 84 | var textBlock = new TextBlock 85 | { 86 | Text = Properties.Resources.SelectWindowTip, 87 | FontSize = 15, 88 | HorizontalAlignment = HorizontalAlignment.Center, 89 | VerticalAlignment = VerticalAlignment.Center, 90 | Padding = new Thickness(10, 5, 10, 5), 91 | Foreground = new SolidColorBrush(Colors.Black), 92 | Background = new SolidColorBrush(Colors.White) 93 | }; 94 | container.Content = textBlock; 95 | RootGrid.Children.Add(container); 96 | } 97 | } 98 | 99 | void CloseClick(object sender, RoutedEventArgs e) 100 | { 101 | SelectedWindow = null; 102 | Close(); 103 | } 104 | 105 | Rectangle? _lastRectangle; 106 | 107 | void UpdateBorderAndCursor(Rectangle? rect) 108 | { 109 | if (_lastRectangle == rect) 110 | { 111 | return; 112 | } 113 | 114 | _lastRectangle = rect; 115 | if (rect == null) 116 | { 117 | Cursor = Cursors.Arrow; 118 | Border.Width = Border.Height = 0; 119 | } 120 | else 121 | { 122 | Cursor = Cursors.Hand; 123 | var r = rect.Value; 124 | 125 | var margin = new Thickness(-Left + r.Left / Dpi.X, -Top + r.Top / Dpi.Y, 0, 0); 126 | Border.Margin = margin; 127 | Border.Width = r.Width / Dpi.X; 128 | Border.Height = r.Height / Dpi.Y; 129 | } 130 | } 131 | 132 | void WindowMouseMove(object sender, MouseEventArgs e) 133 | { 134 | var platformServices = ServiceProvider.IPlatformServices; 135 | var point = platformServices.CursorPosition; 136 | SelectedWindow = _windows 137 | .Where(m => Predicate?.Invoke(m) ?? true) 138 | .FirstOrDefault(m => m.Rectangle.Contains(point)); 139 | UpdateBorderAndCursor(SelectedWindow?.Rectangle); 140 | } 141 | 142 | void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 143 | { 144 | if (SelectedWindow != null) 145 | { 146 | Close(); 147 | } 148 | } 149 | 150 | public static IWindow PickWindow() 151 | { 152 | var picker = new VideoSourcePickerWindow(); 153 | picker.ShowDialog(); 154 | return picker.SelectedWindow; 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /Illustrator/录制区域.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/录制区域.ai -------------------------------------------------------------------------------- /Illustrator/录制屏幕.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/录制屏幕.ai -------------------------------------------------------------------------------- /Illustrator/录制窗口.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/录制窗口.ai -------------------------------------------------------------------------------- /Illustrator/截取区域.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/截取区域.ai -------------------------------------------------------------------------------- /Illustrator/截取屏幕.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/截取屏幕.ai -------------------------------------------------------------------------------- /Illustrator/截取窗口.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/Illustrator/截取窗口.ai -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GifCapture 2 | 3 | 快速捕获桌面区域并将其直接保存为 .GIF 文件 4 | 5 | - 录制指定的区域 6 | - 录制指定的窗口 7 | - 多显示器环境下,录制指定的屏幕 8 | 9 | GifCapture can capture an area of your desktop and save it directly to .GIF 10 | 11 | - Record specified area 12 | - Record the specified window 13 | - In a multi-monitor environment, record the specified screen 14 | 15 | get from microsoft store 16 | 17 | ![](./gifcapture.gif) 18 | 19 | 20 | ## Donate 21 | 22 | Thank you for your donation, it will help the subsequent development, donations will be used for hardware, software, server hosting and other expenses. 23 | 24 | Thanks again for your support! 25 | 26 | ![](./icons8-paypal-48.png) 27 | [PayPal](https://paypal.me/chenjing9412) 28 | -------------------------------------------------------------------------------- /donate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/donate.jpg -------------------------------------------------------------------------------- /gifcapture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/gifcapture.gif -------------------------------------------------------------------------------- /icons8-paypal-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenjing1294/GifCapture/9342180c45950e7339d0d17d43d78d67fc34894a/icons8-paypal-48.png --------------------------------------------------------------------------------