Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit a9b287f

Browse files
committed
Image Paste and Drop support
1 parent 9eb4aaf commit a9b287f

File tree

5 files changed

+159
-26
lines changed

5 files changed

+159
-26
lines changed

OnnxStack.UI/Dialogs/CropImageDialog.xaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,17 @@
2424
</StackPanel>
2525
<StackPanel >
2626
<TextBlock Text="Image File"/>
27-
<userControls:FilePickerTextBox FileName="{Binding ImageFile, Mode=TwoWay}" IsRequired="True"/>
27+
<userControls:FilePickerTextBox FileName="{Binding ImageFile, Mode=TwoWay}" IsEnabled="{Binding HasInitialImage, Converter={StaticResource InverseBoolConverter}}" IsRequired="True" />
28+
<StackPanel.Style>
29+
<Style TargetType="{x:Type StackPanel}">
30+
<Setter Property="Visibility" Value="Visible" />
31+
<Style.Triggers>
32+
<DataTrigger Binding="{Binding HasInitialImage, FallbackValue=Visible}" Value="True">
33+
<Setter Property="Visibility" Value="Hidden" />
34+
</DataTrigger>
35+
</Style.Triggers>
36+
</Style>
37+
</StackPanel.Style>
2838
</StackPanel>
2939
</DockPanel>
3040
<UniformGrid Columns="4" Margin="0,25,0,0">

OnnxStack.UI/Dialogs/CropImageDialog.xaml.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ public partial class CropImageDialog : Window, INotifyPropertyChanged
3838
private bool _cropIsDragging;
3939
private Point _cropClickPosition;
4040
private TranslateTransform _cropTransform;
41-
41+
private bool _hasInitialImage;
42+
private BitmapSource _initialImage;
4243

4344
/// <summary>
4445
/// Initializes a new instance of the <see cref="CropImageDialog"/> class.
@@ -101,16 +102,28 @@ public bool IsCropped
101102
set { _isCropped = value; NotifyPropertyChanged(); }
102103
}
103104

105+
public bool HasInitialImage
106+
{
107+
get { return _hasInitialImage; }
108+
set { _hasInitialImage = value; NotifyPropertyChanged(); }
109+
}
110+
104111

105112
/// <summary>
106113
/// Initializes the specified the Dialog.
107114
/// </summary>
108115
/// <param name="width">The width.</param>
109116
/// <param name="height">The height.</param>
110-
public void Initialize(int requiredWidth, int requiredHeight)
117+
public void Initialize(int requiredWidth, int requiredHeight, BitmapSource sourceImage = null)
111118
{
112119
_requiredWidth = requiredWidth;
113120
_requiredHeight = requiredHeight;
121+
if (sourceImage != null)
122+
{
123+
HasInitialImage = true;
124+
_initialImage = sourceImage;
125+
LoadImage();
126+
}
114127
}
115128

116129

@@ -197,7 +210,7 @@ private Task Crop()
197210
/// </returns>
198211
private bool CanExecuteCrop()
199212
{
200-
return !string.IsNullOrEmpty(ImageFile) && !IsCropped;
213+
return (!string.IsNullOrEmpty(ImageFile) || HasInitialImage) && !IsCropped;
201214
}
202215

203216

@@ -207,7 +220,9 @@ private bool CanExecuteCrop()
207220
private void LoadImage()
208221
{
209222
Reset();
210-
SourceImage = new BitmapImage(new Uri(ImageFile));
223+
SourceImage = _hasInitialImage
224+
? _initialImage.Clone()
225+
: new BitmapImage(new Uri(_imageFile));
211226
var actualWidth = (double)_sourceImage.PixelWidth;
212227
var actualHeight = (double)_sourceImage.PixelHeight;
213228

OnnxStack.UI/UserControls/ImageInputControl.xaml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,25 @@
99
xmlns:behaviors="clr-namespace:OnnxStack.UI.Behaviors"
1010
xmlns:models="clr-namespace:OnnxStack.UI.Models"
1111
mc:Ignorable="d"
12-
d:DesignWidth="500" Name="UI">
12+
d:DesignWidth="500" Name="UI" Focusable="True" PreviewKeyDown="OnPreviewKeyDown" MouseEnter="OnMouseEnter" AllowDrop="True" PreviewDrop="OnPreviewDrop">
1313
<UserControl.Resources>
1414
<Style TargetType="{x:Type Label}">
1515
<Setter Property="Margin" Value="-4,0,0,-4"/>
1616
</Style>
17-
<SolidColorBrush x:Key="RedHighlight" Color="Red" Opacity="0.5" />
17+
<SolidColorBrush x:Key="RedHighlight" Color="Red" Opacity="0.5" />
1818
</UserControl.Resources>
1919

2020
<Border DataContext="{Binding ElementName=UI}" BorderBrush="LightGray" BorderThickness="2" >
2121
<StackPanel Margin="2" >
2222
<Canvas MinHeight="512" MinWidth="512" >
23-
<Image Source="{Binding Result.Image, FallbackValue={StaticResource PlaceholderImage}, TargetNullValue={StaticResource PlaceholderImage}}" Width="{Binding SchedulerOptions.Width}" Height="{Binding SchedulerOptions.Height}" MinHeight="512" MinWidth="512"/>
23+
<Image Source="{Binding Result.Image, FallbackValue={StaticResource PlaceholderImage}, TargetNullValue={StaticResource PlaceholderImage}}" Width="{Binding SchedulerOptions.Width}" Height="{Binding SchedulerOptions.Height}" MinHeight="512" MinWidth="512">
24+
<Image.ContextMenu>
25+
<ContextMenu>
26+
<MenuItem Header="Copy" Command="{Binding CopyImageCommand}" IsEnabled="{Binding HasResult}" />
27+
<MenuItem Header="Paste" Command="{Binding PasteImageCommand}" />
28+
</ContextMenu>
29+
</Image.ContextMenu>
30+
</Image>
2431
<InkCanvas x:Name="MaskCanvas" Background="Transparent" ForceCursor="True" Cursor="Pen" MinHeight="512" MinWidth="512" PreviewMouseLeftButtonDown="MaskCanvas_MouseLeftButtonDown"
2532
IsEnabled="{Binding HasResult}"
2633
EditingMode="{Binding MaskEditingMode}"

OnnxStack.UI/UserControls/ImageInputControl.xaml.cs

Lines changed: 118 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
using OnnxStack.UI.Commands;
1+
using OnnxStack.Core;
2+
using OnnxStack.UI.Commands;
23
using OnnxStack.UI.Dialogs;
34
using OnnxStack.UI.Models;
45
using OnnxStack.UI.Services;
6+
using System;
57
using System.ComponentModel;
8+
using System.Linq;
69
using System.Runtime.CompilerServices;
710
using System.Threading.Tasks;
811
using System.Windows;
912
using System.Windows.Controls;
1013
using System.Windows.Ink;
14+
using System.Windows.Input;
1115
using System.Windows.Media;
1216
using System.Windows.Media.Imaging;
1317

@@ -36,14 +40,17 @@ public ImageInputControl()
3640
ClearImageCommand = new AsyncRelayCommand(ClearImage);
3741
MaskModeCommand = new AsyncRelayCommand(MaskMode);
3842
SaveMaskCommand = new AsyncRelayCommand(SaveMask);
43+
CopyImageCommand = new AsyncRelayCommand(CopyImage);
44+
PasteImageCommand = new AsyncRelayCommand(PasteImage);
3945
InitializeComponent();
4046
}
4147

4248
public AsyncRelayCommand LoadImageCommand { get; }
4349
public AsyncRelayCommand ClearImageCommand { get; }
4450
public AsyncRelayCommand MaskModeCommand { get; }
4551
public AsyncRelayCommand SaveMaskCommand { get; }
46-
52+
public AsyncRelayCommand CopyImageCommand { get; }
53+
public AsyncRelayCommand PasteImageCommand { get; }
4754
public ImageInput Result
4855
{
4956
get { return (ImageInput)GetValue(ResultProperty); }
@@ -146,18 +153,7 @@ public int MaskDrawSize
146153
/// <returns></returns>
147154
private Task LoadImage()
148155
{
149-
var loadImageDialog = _dialogService.GetDialog<CropImageDialog>();
150-
loadImageDialog.Initialize(SchedulerOptions.Width, SchedulerOptions.Height);
151-
if (loadImageDialog.ShowDialog() == true)
152-
{
153-
ClearImage();
154-
Result = new ImageInput
155-
{
156-
Image = loadImageDialog.GetImageResult(),
157-
FileName = loadImageDialog.ImageFile,
158-
};
159-
HasResult = true;
160-
}
156+
ShowCropImageDialog();
161157
return Task.CompletedTask;
162158
}
163159

@@ -260,6 +256,70 @@ public BitmapSource CreateMaskImage()
260256
return renderBitmap;
261257
}
262258

259+
private void ShowCropImageDialog(BitmapSource source = null, string sourceFile = null)
260+
{
261+
try
262+
{
263+
if (!string.IsNullOrEmpty(sourceFile))
264+
source = new BitmapImage(new Uri(sourceFile));
265+
}
266+
catch { }
267+
268+
var loadImageDialog = _dialogService.GetDialog<CropImageDialog>();
269+
loadImageDialog.Initialize(SchedulerOptions.Width, SchedulerOptions.Height, source);
270+
if (loadImageDialog.ShowDialog() == true)
271+
{
272+
ClearImage();
273+
Result = new ImageInput
274+
{
275+
Image = loadImageDialog.GetImageResult(),
276+
FileName = loadImageDialog.ImageFile,
277+
};
278+
HasResult = true;
279+
}
280+
}
281+
282+
283+
/// <summary>
284+
/// Copies the image.
285+
/// </summary>
286+
/// <returns></returns>
287+
private Task CopyImage()
288+
{
289+
if (Result?.Image != null)
290+
Clipboard.SetImage(Result.Image);
291+
return Task.CompletedTask;
292+
}
293+
294+
295+
/// <summary>
296+
/// Paste the image.
297+
/// </summary>
298+
/// <returns></returns>
299+
private Task PasteImage()
300+
{
301+
return HandleClipboardInput();
302+
}
303+
304+
305+
/// <summary>
306+
/// Handles the clipboard input.
307+
/// </summary>
308+
/// <returns></returns>
309+
private Task HandleClipboardInput()
310+
{
311+
if (Clipboard.ContainsImage())
312+
ShowCropImageDialog(Clipboard.GetImage());
313+
else if (Clipboard.ContainsFileDropList())
314+
{
315+
var imageFile = Clipboard.GetFileDropList()
316+
.OfType<string>()
317+
.FirstOrDefault();
318+
ShowCropImageDialog(null, imageFile);
319+
}
320+
return Task.CompletedTask;
321+
}
322+
263323

264324
/// <summary>
265325
/// Handles the MouseLeftButtonDown event of the MaskCanvas control.
@@ -272,15 +332,56 @@ private void MaskCanvas_MouseLeftButtonDown(object sender, System.Windows.Input.
272332
HasMaskChanged = true;
273333
}
274334

335+
336+
/// <summary>
337+
/// Called on key down.
338+
/// </summary>
339+
/// <param name="sender">The sender.</param>
340+
/// <param name="e">The <see cref="KeyEventArgs"/> instance containing the event data.</param>
341+
private async void OnPreviewKeyDown(object sender, KeyEventArgs e)
342+
{
343+
if (e.Key == Key.V && Keyboard.Modifiers == ModifierKeys.Control)
344+
{
345+
await HandleClipboardInput();
346+
e.Handled = true;
347+
}
348+
else if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control)
349+
{
350+
await CopyImage();
351+
e.Handled = true;
352+
}
353+
}
354+
355+
356+
/// <summary>
357+
/// Called when mouse enters.
358+
/// </summary>
359+
/// <param name="sender">The sender.</param>
360+
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
361+
private void OnMouseEnter(object sender, MouseEventArgs e)
362+
{
363+
Focus();
364+
}
365+
366+
367+
/// <summary>
368+
/// Called when [preview drop].
369+
/// </summary>
370+
/// <param name="sender">The sender.</param>
371+
/// <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
372+
private void OnPreviewDrop(object sender, DragEventArgs e)
373+
{
374+
var fileNames = (string[])e.Data.GetData(DataFormats.FileDrop);
375+
if (!fileNames.IsNullOrEmpty())
376+
ShowCropImageDialog(null, fileNames.FirstOrDefault());
377+
}
378+
275379
#region INotifyPropertyChanged
276380
public event PropertyChangedEventHandler PropertyChanged;
277381
public void NotifyPropertyChanged([CallerMemberName] string property = "")
278382
{
279383
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
280384
}
281-
282385
#endregion
283-
284-
285386
}
286387
}

OnnxStack.UI/UserControls/ImageResultControl.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<Image Source="{Binding Result.Image, FallbackValue={StaticResource PlaceholderImage}, TargetNullValue={StaticResource PlaceholderImage}}" Width="{Binding SchedulerOptions.Width, FallbackValue=512}" Height="{Binding SchedulerOptions.Height, FallbackValue=512}" MinHeight="512" MinWidth="512" >
2121
<Image.ContextMenu>
2222
<ContextMenu>
23-
<MenuItem Header="Copy" Command="{Binding CopyImageCommand}" />
23+
<MenuItem Header="Copy" Command="{Binding CopyImageCommand}" IsEnabled="{Binding HasResult}" />
2424
</ContextMenu>
2525
</Image.ContextMenu>
2626
</Image>

0 commit comments

Comments
 (0)