using InABox.Core; using System; using System.Drawing; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using System.Windows.Media; using InABox.WPF; using Color = System.Drawing.Color; using Image = System.Windows.Controls.Image; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using Microsoft.Win32; using Syncfusion.UI.Xaml.ImageEditor; using InABox.Wpf; namespace InABox.DynamicGrid { public static class EmbeddedImageUtilities { private static BitmapImage? EmptyImage; private static BitmapImage? EmptySignature; public static ImageSource CreateEmptyImage() { EmptyImage ??= new Bitmap(256, 256).WatermarkImage("No Image", Color.Gray).AsBitmapImage(); return EmptyImage; } public static ImageSource CreateEmptySignature() { EmptySignature ??= new Bitmap(400, 400).WatermarkImage("No Signature", Color.Gray).AsBitmapImage(); return EmptySignature; } public static bool SelectImageFile([NotNullWhen(true)] out byte[]? data) { var dlg = new OpenFileDialog(); dlg.Filter = "Image Files (*.jpg;*.png;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp"; if (dlg.ShowDialog() == true) { var filename = Path.GetFileName(dlg.FileName).ToLower(); var timestamp = new FileInfo(dlg.FileName).LastWriteTime; data = File.ReadAllBytes(dlg.FileName); return true; } data = null; return false; } public static byte[]? SaveImageToBytes(Image? image, bool isEmpty, BitmapEncoder encoder) { if (image == null || image.Source is not BitmapImage bmpimg) return null; if (isEmpty) return null; byte[] data; encoder.Frames.Add(BitmapFrame.Create(bmpimg)); using (var ms = new MemoryStream()) { encoder.Save(ms); ms.Seek(0, SeekOrigin.Begin); data = ms.ToArray(); } return data; } public static string SaveImageToString(Image? image, bool isEmpty, BitmapEncoder encoder) { var data = SaveImageToBytes(image, isEmpty, encoder); return data != null ? Convert.ToBase64String(data) : ""; } /// /// Loads a value into an Image object. /// /// /// /// /// if the image is empty. public static bool LoadImageFromData(Image? image, object? value, Func? defImage = null) { if (image == null) return false; BitmapImage? source = null; try { if (value is string str) { source = ImageUtils.BitmapImageFromBase64(str); } else if (value is byte[] data) { source = ImageUtils.BitmapImageFromBytes(data); } } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } if (source != null) { image.Source = source; return true; } else { image.Source = defImage?.Invoke() ?? CreateEmptyImage(); return false; } } } public class DFEmbeddedImageControl : DynamicFormFieldControl { private Grid _grid = null!; // Late-initialised private Border? _border; private Image _image = null!; // Late-initialised private bool _isEmpty = true; private Button viewButton = null!; private Button pasteButton = null!; private Button clearButton = null!; private Button selectButton = null!; private DFLayoutEmbeddedMediaValue _value = null!; static DFEmbeddedImageControl() { IsEnabledProperty.OverrideMetadata( typeof(DFEmbeddedImageControl), new UIPropertyMetadata( true, ControlIsEnabledChanged)); } private static void ControlIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var control = (DFEmbeddedImageControl)obj; control.IsEnabled = true; var enabled = (bool)e.NewValue; control.pasteButton.Visibility = enabled ? Visibility.Visible : Visibility.Collapsed; control.clearButton.Visibility = enabled ? Visibility.Visible : Visibility.Collapsed; control.selectButton.Visibility = enabled ? Visibility.Visible : Visibility.Collapsed; } protected override FrameworkElement Create() { _value = new DFLayoutEmbeddedMediaValue(); _grid = new Grid(); _grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); _grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); _grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); _grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); _grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); _grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); _border = new Border() { BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(0.75), Background = new SolidColorBrush(Colors.White), Padding = new Thickness(4), Margin = new Thickness(0) }; _border.SetGridPosition(0,0,5,1); _grid.Children.Add(_border); _image = new Image { Stretch = Stretch.Uniform, //StretchDirection = StretchDirection.DownOnly, Source = EmbeddedImageUtilities.CreateEmptyImage(), }; _border.Child = _image; viewButton = new Button { Content = Content = new Image { Source = Wpf.Resources.zoomin.AsBitmapImage(24, 24), Margin = new Thickness(2) }, Margin = new Thickness(5, 0, 0, 0), Width = 30, Height = 30 }; viewButton.Click += ViewButton_Click; viewButton.SetGridPosition(0,1); _grid.Children.Add(viewButton); pasteButton = new Button { Content = Content = new Image { Source = Wpf.Resources.paste.AsBitmapImage(24, 24) }, Margin = new Thickness(5, 5, 0, 0), Width = 30, Height = 30 }; pasteButton.Click += PasteButton_Click; pasteButton.SetGridPosition(2, 1); _grid.Children.Add(pasteButton); clearButton = new Button { Content = Content = new Image { Source = Wpf.Resources.delete.AsBitmapImage(24, 24) }, Margin = new Thickness(5, 5, 0, 0), Width = 30, Height = 30 }; clearButton.Click += EmbeddedImageClear_Click; clearButton.SetGridPosition(3,1); _grid.Children.Add(clearButton); selectButton = new Button { Content = Content = new Image { Source = Wpf.Resources.load.AsBitmapImage(24, 24) }, Margin = new Thickness(5, 5, 0, 0), Width = 30, Height = 30 }; selectButton.Click += EmbeddedImageSelect_Click; selectButton.SetGridPosition(4, 1); _grid.Children.Add(selectButton); return _grid; } private static void ShowImage(byte[] data) { var src = ImageUtils.LoadImage(data); var editor = new SfImageEditor { ImageSource = src }; var window = new Window() { Content = editor, Height = 800, Width=800 }; window.ShowDialog(); } private void ViewButton_Click(object sender, RoutedEventArgs e) { if (_value.Data?.Any() == true) ShowImage(_value.Data); else { DigitalFormDocumentFactory.LoadDocument(_value.ID, (data) => { if(data.Length == 0) { Dispatcher.BeginInvoke(() => MessageWindow.ShowMessage("The image should be in the database, but it is not.", "Document not found", image: MessageWindow.WarningImage)); } else { _value.Data = data; Dispatcher.BeginInvoke(() => ShowImage(data)); } }); } } private void PasteButton_Click(object sender, RoutedEventArgs e) { if (Clipboard.ContainsImage()) { var paste = Clipboard.GetImage(); var bitmap = ImageUtils.BitmapSourceToBitmap(paste); var img = ImageUtils.ToBitmapImage(bitmap); var empty = img == null; if (_isEmpty != empty) { _isEmpty = empty; if (empty) _image.Source = EmbeddedImageUtilities.CreateEmptyImage(); else _image.Source = img; SetSerializedValue(new DFLayoutEmbeddedMediaValue { Data = EmbeddedImageUtilities.SaveImageToBytes(_image, _isEmpty, new JpegBitmapEncoder()) ?? Array.Empty() }); ChangeField(); } } } public override void SetSerializedValue(DFLayoutEmbeddedMediaValue value) { _value = value; _value.Thumbnail ??= _value.Data != null ? ImageUtils.BitmapImageFromBytes(_value.Data)?.Resize(200, 200).ToArray() : null; _isEmpty = !EmbeddedImageUtilities.LoadImageFromData(_image, _value.Data?.Any() == true ? _value.Data : _value.Thumbnail); } public override DFLayoutEmbeddedMediaValue GetSerializedValue() { if ((_value.Data?.Any() == true) && (_value.ID == Guid.Empty)) _value.ID = DigitalFormDocumentFactory.SaveDocument(_value.Data); return _value; } public override Guid GetValue() { return _value.ID; } public override void SetValue(Guid value) { SetSerializedValue(new DFLayoutEmbeddedMediaValue() { ID = value }); } private void EmbeddedImageClear_Click(object sender, RoutedEventArgs e) { if (!_isEmpty) { _image.Source = EmbeddedImageUtilities.CreateEmptyImage(); _isEmpty = true; SetSerializedValue(new DFLayoutEmbeddedMediaValue()); ChangeField(); } } private void EmbeddedImageSelect_Click(object sender, RoutedEventArgs e) { if (EmbeddedImageUtilities.SelectImageFile(out var data)) { var img = ImageUtils.BitmapImageFromBytes(data); var empty = img == null; if (_isEmpty != empty) { _isEmpty = empty; if (empty) _image.Source = EmbeddedImageUtilities.CreateEmptyImage(); else _image.Source = img; SetSerializedValue(new DFLayoutEmbeddedMediaValue { Data = data }); ChangeField(); } } } protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property == IsEnabledProperty) { _grid.RowDefinitions[1].Height = (bool)e.NewValue ? GridLength.Auto : new GridLength(0); } } protected override bool IsEmpty() => _isEmpty; } }