├── .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 |
16 |
17 | 
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 | 
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
--------------------------------------------------------------------------------