mirror of
https://github.com/4sval/FModel.git
synced 2026-03-24 10:44:51 -05:00
302 lines
10 KiB
C#
302 lines
10 KiB
C#
using AdonisUI.Controls;
|
|
using FModel.Extensions;
|
|
using FModel.Settings;
|
|
using FModel.Views.Resources.Controls;
|
|
using Microsoft.Win32;
|
|
using Serilog;
|
|
using SkiaSharp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Controls.Primitives;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media.Imaging;
|
|
|
|
namespace FModel.Views;
|
|
|
|
public partial class ImageMerger
|
|
{
|
|
private const string FILENAME = "Preview.png";
|
|
private byte[] _imageBuffer;
|
|
|
|
public ImageMerger()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
private async void DrawPreview(object sender, DragCompletedEventArgs dragCompletedEventArgs)
|
|
{
|
|
if (ImagePreview.Source != null)
|
|
await DrawPreview().ConfigureAwait(false);
|
|
}
|
|
|
|
private async void Click_DrawPreview(object sender, MouseButtonEventArgs e)
|
|
{
|
|
if (ImagePreview.Source != null)
|
|
await DrawPreview().ConfigureAwait(false);
|
|
}
|
|
|
|
private async Task DrawPreview()
|
|
{
|
|
AddButton.IsEnabled = false;
|
|
UpButton.IsEnabled = false;
|
|
DownButton.IsEnabled = false;
|
|
DeleteButton.IsEnabled = false;
|
|
ClearButton.IsEnabled = false;
|
|
SizeSlider.IsEnabled = false;
|
|
OpenImageButton.IsEnabled = false;
|
|
SaveImageButton.IsEnabled = false;
|
|
|
|
var margin = UserSettings.Default.ImageMergerMargin;
|
|
int num = 1, curW = 0, curH = 0, maxWidth = 0, maxHeight = 0, lineMaxHeight = 0, imagesPerRow = Convert.ToInt32(SizeSlider.Value);
|
|
var positions = new Dictionary<int, SKPoint>();
|
|
var images = new SKBitmap[ImagesListBox.Items.Count];
|
|
for (var i = 0; i < images.Length; i++)
|
|
{
|
|
var item = (ListBoxItem) ImagesListBox.Items[i];
|
|
var ms = new MemoryStream();
|
|
var stream = new FileStream(item.ContentStringFormat, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
|
|
if (item.ContentStringFormat.EndsWith(".tif"))
|
|
{
|
|
await using var tmp = new MemoryStream();
|
|
await stream.CopyToAsync(tmp);
|
|
System.Drawing.Image.FromStream(tmp).Save(ms, ImageFormat.Png);
|
|
}
|
|
else
|
|
{
|
|
await stream.CopyToAsync(ms);
|
|
}
|
|
|
|
var image = SKBitmap.Decode(ms.ToArray());
|
|
positions[i] = new SKPoint(curW, curH);
|
|
images[i] = image;
|
|
|
|
if (image.Height > lineMaxHeight)
|
|
lineMaxHeight = image.Height;
|
|
|
|
if (num % imagesPerRow == 0)
|
|
{
|
|
maxWidth = curW + image.Width + margin;
|
|
curH += lineMaxHeight + margin;
|
|
if (curH > maxHeight)
|
|
maxHeight = curH;
|
|
|
|
curW = 0;
|
|
lineMaxHeight = 0;
|
|
}
|
|
else
|
|
{
|
|
maxHeight = curH + lineMaxHeight + margin;
|
|
curW += image.Width + margin;
|
|
if (curW > maxWidth)
|
|
maxWidth = curW;
|
|
}
|
|
|
|
num++;
|
|
}
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
using var bmp = new SKBitmap(maxWidth - margin, maxHeight - margin, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var canvas = new SKCanvas(bmp);
|
|
|
|
for (var i = 0; i < images.Length; i++)
|
|
{
|
|
using (images[i])
|
|
{
|
|
canvas.DrawBitmap(images[i], positions[i], new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true });
|
|
}
|
|
}
|
|
|
|
using var data = bmp.Encode(SKEncodedImageFormat.Png, 100);
|
|
using var stream = new MemoryStream(_imageBuffer = data.ToArray());
|
|
var photo = new BitmapImage();
|
|
photo.BeginInit();
|
|
photo.CacheOption = BitmapCacheOption.OnLoad;
|
|
photo.StreamSource = stream;
|
|
photo.EndInit();
|
|
photo.Freeze();
|
|
|
|
Application.Current.Dispatcher.Invoke(delegate { ImagePreview.Source = photo; });
|
|
}).ContinueWith(t =>
|
|
{
|
|
AddButton.IsEnabled = true;
|
|
UpButton.IsEnabled = true;
|
|
DownButton.IsEnabled = true;
|
|
DeleteButton.IsEnabled = true;
|
|
ClearButton.IsEnabled = true;
|
|
SizeSlider.IsEnabled = true;
|
|
OpenImageButton.IsEnabled = true;
|
|
SaveImageButton.IsEnabled = true;
|
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
|
}
|
|
|
|
private async void OnImageAdd(object sender, RoutedEventArgs e)
|
|
{
|
|
var fileBrowser = new OpenFileDialog
|
|
{
|
|
Title = "Add image(s)",
|
|
InitialDirectory = $"{UserSettings.Default.OutputDirectory}\\Exports",
|
|
Multiselect = true,
|
|
Filter = "Image Files (*.png,*.bmp,*.jpg,*.jpeg,*.jfif,*.jpe,*.tiff,*.tif)|*.png;*.bmp;*.jpg;*.jpeg;*.jfif;*.jpe;*.tiff;*.tif|All Files (*.*)|*.*"
|
|
};
|
|
var result = fileBrowser.ShowDialog();
|
|
if (!result.HasValue || !result.Value) return;
|
|
|
|
foreach (var file in fileBrowser.FileNames)
|
|
{
|
|
ImagesListBox.Items.Add(new ListBoxItem
|
|
{
|
|
ContentStringFormat = file,
|
|
Content = Path.GetFileNameWithoutExtension(file)
|
|
});
|
|
}
|
|
|
|
SizeSlider.Value = Math.Min(ImagesListBox.Items.Count, Math.Round(Math.Sqrt(ImagesListBox.Items.Count)));
|
|
await DrawPreview().ConfigureAwait(false);
|
|
}
|
|
|
|
private async void ModifyItemInList(object sender, RoutedEventArgs e)
|
|
{
|
|
if (ImagesListBox.Items.Count <= 0 || ImagesListBox.SelectedItems.Count <= 0) return;
|
|
var indices = ImagesListBox.SelectedItems.Cast<ListBoxItem>().Select(i => ImagesListBox.Items.IndexOf(i)).ToArray();
|
|
var reloadImage = false;
|
|
|
|
switch (((Button) sender).Name)
|
|
{
|
|
case "UpButton":
|
|
{
|
|
if (indices.Length > 0 && indices[0] > 0)
|
|
{
|
|
for (var i = 0; i < ImagesListBox.Items.Count; i++)
|
|
{
|
|
if (!indices.Contains(i)) continue;
|
|
var item = (ListBoxItem) ImagesListBox.Items[i];
|
|
ImagesListBox.Items.Remove(item);
|
|
ImagesListBox.Items.Insert(i - 1, item);
|
|
item.IsSelected = true;
|
|
reloadImage = true;
|
|
}
|
|
}
|
|
|
|
ImagesListBox.SelectedItems.Add(indices);
|
|
if (reloadImage)
|
|
{
|
|
await DrawPreview().ConfigureAwait(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case "DownButton":
|
|
{
|
|
if (indices.Length > 0 && indices[^1] < ImagesListBox.Items.Count - 1)
|
|
{
|
|
for (var i = ImagesListBox.Items.Count - 1; i > -1; --i)
|
|
{
|
|
if (!indices.Contains(i)) continue;
|
|
var item = (ListBoxItem) ImagesListBox.Items[i];
|
|
ImagesListBox.Items.Remove(item);
|
|
ImagesListBox.Items.Insert(i + 1, item);
|
|
item.IsSelected = true;
|
|
reloadImage = true;
|
|
}
|
|
}
|
|
|
|
if (reloadImage)
|
|
{
|
|
await DrawPreview().ConfigureAwait(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case "DeleteButton":
|
|
{
|
|
if (ImagesListBox.Items.Count > 0 && ImagesListBox.SelectedItems.Count > 0)
|
|
{
|
|
for (var i = ImagesListBox.SelectedItems.Count - 1; i >= 0; --i)
|
|
ImagesListBox.Items.Remove(ImagesListBox.SelectedItems[i]);
|
|
}
|
|
|
|
await DrawPreview().ConfigureAwait(false);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnClear(object sender, RoutedEventArgs e)
|
|
{
|
|
ImagesListBox.Items.Clear();
|
|
ImagePreview.Source = null;
|
|
}
|
|
|
|
private void OnOpenImage(object sender, RoutedEventArgs e)
|
|
{
|
|
if (ImagePreview.Source == null) return;
|
|
Helper.OpenWindow<AdonisWindow>("Merged Image", () =>
|
|
{
|
|
new ImagePopout
|
|
{
|
|
Title = "Merged Image",
|
|
Width = ImagePreview.Source.Width,
|
|
Height = ImagePreview.Source.Height,
|
|
WindowState = ImagePreview.Source.Height > 1000 ? WindowState.Maximized : WindowState.Normal,
|
|
ImageCtrl = { Source = ImagePreview.Source }
|
|
}.Show();
|
|
});
|
|
}
|
|
|
|
private void OnSaveImage(object sender, RoutedEventArgs e)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
if (ImagePreview.Source == null) return;
|
|
var saveFileDialog = new SaveFileDialog
|
|
{
|
|
Title = "Save Image",
|
|
FileName = FILENAME,
|
|
InitialDirectory = UserSettings.Default.OutputDirectory,
|
|
Filter = "Png Files (*.png)|*.png|All Files (*.*)|*.*"
|
|
};
|
|
var result = saveFileDialog.ShowDialog();
|
|
if (!result.HasValue || !result.Value) return;
|
|
|
|
using (var fs = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
{
|
|
fs.Write(_imageBuffer, 0, _imageBuffer.Length);
|
|
}
|
|
|
|
SaveCheck(saveFileDialog.FileName, Path.GetFileName(saveFileDialog.FileName));
|
|
});
|
|
}
|
|
|
|
private static void SaveCheck(string path, string fileName)
|
|
{
|
|
if (File.Exists(path))
|
|
{
|
|
Log.Information("{FileName} successfully saved", fileName);
|
|
FLogger.Append(ELog.Information, () =>
|
|
{
|
|
FLogger.Text("Successfully saved ", Constants.WHITE);
|
|
FLogger.Link(fileName, path, true);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Log.Error("{FileName} could not be saved", fileName);
|
|
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not save '{fileName}'", Constants.WHITE, true));
|
|
}
|
|
}
|
|
|
|
private void OnCopyImage(object sender, RoutedEventArgs e)
|
|
{
|
|
ClipboardExtensions.SetImage(_imageBuffer, FILENAME);
|
|
}
|
|
}
|