From 5bdc851fa0998f9ba782f4598654fae68e8f90b2 Mon Sep 17 00:00:00 2001 From: R0GGER Date: Mon, 9 Nov 2026 13:02:24 +0100 Subject: [PATCH] 1.1.3 --- CHANGELOG.md | 7 ++ README.md | 4 +- build.ps1 | 2 +- installer/Kniip.iss | 2 +- src/Kniip/App.xaml.cs | 3 +- src/Kniip/Capture/ClipboardImageReader.cs | 87 ++++++++++++++++------- src/Kniip/Editor/EditorWindow.xaml | 3 +- src/Kniip/Editor/EditorWindow.xaml.cs | 30 ++++++++ src/Kniip/Infrastructure/TrayIcon.cs | 8 ++- src/Kniip/Kniip.csproj | 2 +- src/Kniip/Settings/AppSettings.cs | 3 + src/Kniip/Settings/SettingsWindow.xaml | 9 ++- src/Kniip/Settings/SettingsWindow.xaml.cs | 4 ++ 13 files changed, 129 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5695b6..b1207e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Alle noemenswaardige wijzigingen in kniip staan in dit bestand. De nieuwste versie staat bovenaan. +## 1.1.3 - 2026-11-09 + +### Nieuw + +- **Sneltoets voor het klembord.** In de tab **Sneltoetsen** kun je een combinatie zetten op **Vanaf klembord**. Die opent de afbeelding op het klembord in de editor. Standaard is er geen sneltoets. De gekozen combinatie staat ook bij **Bewerken vanaf klembord** in het systeemvakmenu. +- **Afbeelding naar de editor slepen.** Sleep een afbeeldingsbestand, of een afbeelding uit een ander programma, naar het kniip-venster. kniip vraagt daarna of je die afbeelding wilt openen, zodat een lopende bewerking niet zomaar verdwijnt. + ## 1.1.2 - 2026-11-09 ### Opgelost diff --git a/README.md b/README.md index 067d441..47d4841 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ kniip is een annotatie-editor die naast het Windows Knipprogramma werkt. Maak ee | Versie | Installer | | ------ | --------- | -| 1.1.2 | [Kniip-Setup-1.1.2.exe](https://git.hibbit.net/rogier/kniip/releases/download/1.1.2/Kniip-Setup-1.1.2.exe) | +| 1.1.3 | [Kniip-Setup-1.1.3.exe](https://git.hibbit.net/rogier/kniip/releases/download/1.1.3/Kniip-Setup-1.1.3.exe) | Oudere versies vind je bij [alle releases](https://git.hibbit.net/rogier/kniip/releases). @@ -70,7 +70,7 @@ Vereisten: Bouwen: ```powershell -.\build.ps1 # versie 1.1.2 +.\build.ps1 # versie 1.1.3 .\build.ps1 -Version 1.2.0 # andere versie ``` diff --git a/build.ps1 b/build.ps1 index e3a2d5e..713a325 100644 --- a/build.ps1 +++ b/build.ps1 @@ -7,7 +7,7 @@ # .\build.ps1 -Version 1.2.0 param( - [string]$Version = "1.1.2", + [string]$Version = "1.1.3", [string]$Runtime = "win-x64" ) diff --git a/installer/Kniip.iss b/installer/Kniip.iss index 75b02f6..1025776 100644 --- a/installer/Kniip.iss +++ b/installer/Kniip.iss @@ -5,7 +5,7 @@ #define AppName "kniip" #define AppExe "Kniip.exe" #ifndef AppVersion - #define AppVersion "1.1.2" + #define AppVersion "1.1.3" #endif #ifndef PublishDir #define PublishDir "..\artifacts\publish" diff --git a/src/Kniip/App.xaml.cs b/src/Kniip/App.xaml.cs index 6acc5c7..d411597 100644 --- a/src/Kniip/App.xaml.cs +++ b/src/Kniip/App.xaml.cs @@ -298,11 +298,12 @@ public partial class App : Application Bind(Settings.WindowHotkey, BeginWindowSnip); Bind(Settings.RecordHotkey, () => Recorder.Toggle(ScreencastFormat.Mp4)); Bind(Settings.GifHotkey, () => Recorder.Toggle(ScreencastFormat.Gif)); + Bind(Settings.ClipboardHotkey, OpenFromClipboard); HotkeyHook.Bindings = bindings; } _tray?.SetHotkeys(HotkeyDisplay(Settings.SnipHotkey), HotkeyDisplay(Settings.WindowHotkey), - HotkeyDisplay(Settings.RecordHotkey), HotkeyDisplay(Settings.GifHotkey)); + HotkeyDisplay(Settings.RecordHotkey), HotkeyDisplay(Settings.GifHotkey), HotkeyDisplay(Settings.ClipboardHotkey)); } /// Start een screencast: eerst het gebied kiezen, daarna de knoppenbalk. diff --git a/src/Kniip/Capture/ClipboardImageReader.cs b/src/Kniip/Capture/ClipboardImageReader.cs index 0969a90..99dd6b8 100644 --- a/src/Kniip/Capture/ClipboardImageReader.cs +++ b/src/Kniip/Capture/ClipboardImageReader.cs @@ -41,33 +41,14 @@ internal static class ClipboardImageReader return null; } - if (includeFiles && TryReadFile(data) is { } fromFile) + if (ReadData(data, includeFiles) is { } image) { - return fromFile; + return image; } - if (data.GetDataPresent("PNG") && data.GetData("PNG") is MemoryStream png) + if (Clipboard.ContainsImage() && Clipboard.GetImage() is { } bitmap) { - return PixelUtil.Decode(png); - } - - if (data.GetDataPresent(DataFormats.Dib) && data.GetData(DataFormats.Dib) is MemoryStream dib) - { - BitmapSource? fromDib = FromDib(dib.ToArray()); - if (fromDib != null) - { - return fromDib; - } - } - - if (Clipboard.ContainsImage()) - { - BitmapSource? image = Clipboard.GetImage(); - if (image != null) - { - var copy = PixelUtil.CreateBitmap(PixelUtil.ToOpaqueBgra(image), image.PixelWidth, image.PixelHeight); - return copy; - } + return OpaqueCopy(bitmap); } } catch (Exception ex) when (ex is COMException or ExternalException or NotSupportedException or FileFormatException) @@ -78,6 +59,64 @@ internal static class ClipboardImageReader return null; } + /// Snelle controle tijdens het slepen, zonder te decoderen. + public static bool CanDrop(IDataObject data) + { + try + { + return data.GetDataPresent("PNG") || data.GetDataPresent(DataFormats.Dib) || data.GetDataPresent(DataFormats.Bitmap) + || (data.GetData(DataFormats.FileDrop) is string[] files && Array.Exists(files, IsImageFile)); + } + catch (Exception ex) when (ex is COMException or ExternalException) + { + return false; + } + } + + /// Afbeelding uit iets dat in kniip is neergezet: een afbeeldingsbestand of afbeeldingsdata. + public static BitmapSource? FromDrop(IDataObject data) + { + try + { + if (ReadData(data, includeFiles: true) is { } image) + { + return image; + } + + return data.GetData(DataFormats.Bitmap) is BitmapSource bitmap ? OpaqueCopy(bitmap) : null; + } + catch (Exception ex) when (ex is COMException or ExternalException or NotSupportedException or FileFormatException) + { + return null; + } + } + + private static BitmapSource? ReadData(IDataObject data, bool includeFiles) + { + if (includeFiles && TryReadFile(data) is { } fromFile) + { + return fromFile; + } + + if (data.GetDataPresent("PNG") && data.GetData("PNG") is MemoryStream png) + { + return PixelUtil.Decode(png); + } + + if (data.GetDataPresent(DataFormats.Dib) && data.GetData(DataFormats.Dib) is MemoryStream dib) + { + return FromDib(dib.ToArray()); + } + + return null; + } + + private static BitmapSource OpaqueCopy(BitmapSource image) => + PixelUtil.CreateBitmap(PixelUtil.ToOpaqueBgra(image), image.PixelWidth, image.PixelHeight); + + private static bool IsImageFile(string file) => + Array.IndexOf(ImageExtensions, Path.GetExtension(file).ToLowerInvariant()) >= 0; + private static BitmapSource? TryReadFile(IDataObject data) { if (!data.GetDataPresent(DataFormats.FileDrop) || data.GetData(DataFormats.FileDrop) is not string[] files) @@ -87,7 +126,7 @@ internal static class ClipboardImageReader foreach (string file in files) { - if (!File.Exists(file) || Array.IndexOf(ImageExtensions, Path.GetExtension(file).ToLowerInvariant()) < 0) + if (!File.Exists(file) || !IsImageFile(file)) { continue; } diff --git a/src/Kniip/Editor/EditorWindow.xaml b/src/Kniip/Editor/EditorWindow.xaml index d365cd8..8a2fc6f 100644 --- a/src/Kniip/Editor/EditorWindow.xaml +++ b/src/Kniip/Editor/EditorWindow.xaml @@ -5,7 +5,8 @@ Title="kniip" Width="1180" Height="780" MinWidth="760" MinHeight="420" WindowStartupLocation="CenterScreen" Background="{StaticResource WindowBrush}" FontFamily="Segoe UI" FontSize="13" UseLayoutRounding="True" - Icon="pack://application:,,,/AppIcon.ico"> + Icon="pack://application:,,,/AppIcon.ico" + AllowDrop="True" PreviewDragEnter="Window_PreviewDragOver" PreviewDragOver="Window_PreviewDragOver" PreviewDrop="Window_PreviewDrop"> diff --git a/src/Kniip/Editor/EditorWindow.xaml.cs b/src/Kniip/Editor/EditorWindow.xaml.cs index 428ad77..18a2da1 100644 --- a/src/Kniip/Editor/EditorWindow.xaml.cs +++ b/src/Kniip/Editor/EditorWindow.xaml.cs @@ -1595,6 +1595,36 @@ public partial class EditorWindow : Window ReplaceWith(image, "Wil je doorgaan en de afbeelding van het klembord openen?"); } + private void Window_PreviewDragOver(object sender, DragEventArgs e) + { + if (!ClipboardImageReader.CanDrop(e.Data)) + { + return; + } + + e.Effects = DragDropEffects.Copy; + e.Handled = true; + } + + private void Window_PreviewDrop(object sender, DragEventArgs e) + { + if (!ClipboardImageReader.CanDrop(e.Data)) + { + return; + } + + e.Handled = true; + BitmapSource? image = ClipboardImageReader.FromDrop(e.Data); + if (image == null) + { + ShowTemporaryHint("Deze afbeelding kon niet worden geopend."); + return; + } + + // Pas na het slepen vragen: een dialoog tijdens Drop blokkeert Verkenner. + Dispatcher.BeginInvoke(() => ReplaceWith(image, "Wil je doorgaan en deze afbeelding openen?")); + } + private void OpenImageFile() { CommitTextEdit(); diff --git a/src/Kniip/Infrastructure/TrayIcon.cs b/src/Kniip/Infrastructure/TrayIcon.cs index 1ae679d..6576441 100644 --- a/src/Kniip/Infrastructure/TrayIcon.cs +++ b/src/Kniip/Infrastructure/TrayIcon.cs @@ -9,6 +9,7 @@ internal sealed class TrayIcon : IDisposable private readonly NotifyIcon _icon; private const string RecordText = "Screencast opnemen (MP4)..."; + private readonly ToolStripMenuItem _clipboardItem; private readonly ToolStripMenuItem _pauseItem; private readonly ToolStripMenuItem _snipItem; private readonly ToolStripMenuItem _windowItem; @@ -28,11 +29,11 @@ internal sealed class TrayIcon : IDisposable public TrayIcon() { var menu = new ContextMenuStrip(); - var openClipboard = new ToolStripMenuItem("Bewerken vanaf klembord", null, (_, _) => OpenFromClipboardRequested?.Invoke()) + _clipboardItem = new ToolStripMenuItem("Bewerken vanaf klembord", null, (_, _) => OpenFromClipboardRequested?.Invoke()) { Font = new Font(SystemFonts.MenuFont ?? Control.DefaultFont, FontStyle.Bold) }; - menu.Items.Add(openClipboard); + menu.Items.Add(_clipboardItem); menu.Items.Add("Afbeelding openen...", null, (_, _) => OpenFileRequested?.Invoke()); menu.Items.Add(new ToolStripSeparator()); _snipItem = new ToolStripMenuItem("Rechthoek knippen", null, (_, _) => SnipRequested?.Invoke()); @@ -71,8 +72,9 @@ internal sealed class TrayIcon : IDisposable public bool IsPaused => _pauseItem.Checked; /// Toont de sneltoetsen naast de menu-items; null = geen sneltoets. - public void SetHotkeys(string? snip, string? window, string? record, string? gif) + public void SetHotkeys(string? snip, string? window, string? record, string? gif, string? clipboard) { + _clipboardItem.ShortcutKeyDisplayString = clipboard; _snipItem.ShortcutKeyDisplayString = snip; _windowItem.ShortcutKeyDisplayString = window; _recordItem.ShortcutKeyDisplayString = record; diff --git a/src/Kniip/Kniip.csproj b/src/Kniip/Kniip.csproj index 5637159..f231c16 100644 --- a/src/Kniip/Kniip.csproj +++ b/src/Kniip/Kniip.csproj @@ -18,7 +18,7 @@ app.manifest kniip Annotatie-editor naast het Windows Knipprogramma - 1.1.2 + 1.1.3 nl;en $(NoWarn);WFAC010 diff --git a/src/Kniip/Settings/AppSettings.cs b/src/Kniip/Settings/AppSettings.cs index 6821b63..c358592 100644 --- a/src/Kniip/Settings/AppSettings.cs +++ b/src/Kniip/Settings/AppSettings.cs @@ -63,6 +63,9 @@ public sealed class AppSettings /// Sneltoets voor een screencast die als GIF wordt aangeboden. public string GifHotkey { get; set; } = "Ctrl+Shift+G"; + + /// Sneltoets om de afbeelding op het klembord in de editor te openen; standaard geen. + public string ClipboardHotkey { get; set; } = ""; public bool RecordSystemAudio { get; set; } = true; public bool RecordMicrophone { get; set; } public bool RecordShowCursor { get; set; } = true; diff --git a/src/Kniip/Settings/SettingsWindow.xaml b/src/Kniip/Settings/SettingsWindow.xaml index f29a692..504129a 100644 --- a/src/Kniip/Settings/SettingsWindow.xaml +++ b/src/Kniip/Settings/SettingsWindow.xaml @@ -127,13 +127,20 @@