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 @@
-
+
+
+
+
+
+
diff --git a/src/Kniip/Settings/SettingsWindow.xaml.cs b/src/Kniip/Settings/SettingsWindow.xaml.cs
index ac8ddd8..c1d63fa 100644
--- a/src/Kniip/Settings/SettingsWindow.xaml.cs
+++ b/src/Kniip/Settings/SettingsWindow.xaml.cs
@@ -26,6 +26,7 @@ public partial class SettingsWindow : Window
["Window"] = "venster knippen",
["Record"] = "screencast (MP4)",
["Gif"] = "screencast (GIF)",
+ ["Clipboard"] = "bewerken vanaf klembord",
};
private readonly AppSettings _settings;
@@ -62,6 +63,7 @@ public partial class SettingsWindow : Window
["Window"] = WindowHotkeyButton,
["Record"] = RecordHotkeyButton,
["Gif"] = GifHotkeyButton,
+ ["Clipboard"] = ClipboardHotkeyButton,
};
HotkeyHint.Text = App.Instance.HotkeyHook?.IsActive == true
@@ -105,6 +107,7 @@ public partial class SettingsWindow : Window
_hotkeys["Window"] = settings.WindowHotkey;
_hotkeys["Record"] = settings.RecordHotkey;
_hotkeys["Gif"] = settings.GifHotkey;
+ _hotkeys["Clipboard"] = settings.ClipboardHotkey;
foreach (string id in _hotkeys.Keys)
{
ShowHotkey(id);
@@ -438,6 +441,7 @@ public partial class SettingsWindow : Window
_settings.WindowHotkey = _hotkeys["Window"];
_settings.RecordHotkey = _hotkeys["Record"];
_settings.GifHotkey = _hotkeys["Gif"];
+ _settings.ClipboardHotkey = _hotkeys["Clipboard"];
_settings.RecordSystemAudio = SystemAudioBox.IsChecked == true;
_settings.RecordMicrophone = MicrophoneBox.IsChecked == true;
_settings.RecordShowCursor = ShowCursorBox.IsChecked == true;