From a7d15a24d0179b06b64daf1be5f4e08c488cb930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sun, 3 Jan 2021 00:47:20 +0000 Subject: [PATCH] v2.1.1 * (Add) About box: Primary screen identifier and open on screen identifier * (Add) Calibrator - External tests * (Change) Rewrite 'Action - Import Layer(s)' to support file formats and add the followig importation types: * **Insert:** Insert layers. (Requires images with bounds equal or less than file resolution) * **Replace:** Replace layers. (Requires images with bounds equal or less than file resolution) * **Stack:** Stack layers content. (Requires images with bounds equal or less than file resolution) * **Merge:** Merge/Sum layers content. (Requires images with same resolution) * **Subtract:** Subtract layers content. (Requires images with same resolution) * **BitwiseAnd:** Perform a 'bitwise and' operation over layer pixels. (Requires images with same resolution) * **BitwiseOr:** Perform a 'bitwise or' operation over layer pixels. (Requires images with same resolution) * **BitwiseXOr:** Perform a 'bitwise xor' operation over layer pixels. (Requires images with same resolution) * (Change) Icon for Tool - Raft Relief * (Change) Windows and dialogs max size are now calculated to where window is opened instead of use the primary or first screen all the time --- CHANGELOG.md | 16 + README.md | 13 +- UVtools.Core/Extensions/EmguExtensions.cs | 11 + UVtools.Core/FileFormats/SL1File.cs | 10 +- UVtools.Core/Layer/Layer.cs | 27 +- UVtools.Core/Layer/LayerManager.cs | 76 +++- UVtools.Core/Managers/ClipboardManager.cs | 2 +- .../OperationCalibrateExternalTests.cs | 47 ++ .../Operations/OperationLayerImport.cs | 401 ++++++++++++++---- UVtools.Core/Operations/OperationMove.cs | 8 + UVtools.Core/UVtools.Core.csproj | 2 +- UVtools.WPF/App.axaml.cs | 10 +- UVtools.WPF/Assets/Icons/bookmark-16x16.png | Bin 0 -> 114 bytes UVtools.WPF/Assets/Icons/cookie-16x16.png | Bin 0 -> 183 bytes .../CalibrateExternalTestsControl.axaml | 35 ++ .../CalibrateExternalTestsControl.axaml.cs | 30 ++ UVtools.WPF/Controls/Helpers.cs | 2 +- .../Tools/ToolLayerImportControl.axaml | 95 +++-- .../Tools/ToolLayerImportControl.axaml.cs | 40 +- UVtools.WPF/Extensions/WindowExtensions.cs | 16 +- UVtools.WPF/MainWindow.axaml.cs | 45 +- UVtools.WPF/UVtools.WPF.csproj | 5 +- UVtools.WPF/Windows/AboutWindow.axaml.cs | 12 +- UVtools.WPF/Windows/SettingsWindow.axaml.cs | 2 +- UVtools.WPF/Windows/ToolWindow.axaml.cs | 2 +- 25 files changed, 713 insertions(+), 194 deletions(-) create mode 100644 UVtools.Core/Operations/OperationCalibrateExternalTests.cs create mode 100644 UVtools.WPF/Assets/Icons/bookmark-16x16.png create mode 100644 UVtools.WPF/Assets/Icons/cookie-16x16.png create mode 100644 UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml create mode 100644 UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c9fb8..853079a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 03/12/2020 - v2.1.1 + +* (Add) About box: Primary screen identifier and open on screen identifier +* (Add) Calibrator - External tests +* (Change) Rewrite 'Action - Import Layer(s)' to support file formats and add the followig importation types: + * **Insert:** Insert layers. (Requires images with bounds equal or less than file resolution) + * **Replace:** Replace layers. (Requires images with bounds equal or less than file resolution) + * **Stack:** Stack layers content. (Requires images with bounds equal or less than file resolution) + * **Merge:** Merge/Sum layers content. (Requires images with same resolution) + * **Subtract:** Subtract layers content. (Requires images with same resolution) + * **BitwiseAnd:** Perform a 'bitwise and' operation over layer pixels. (Requires images with same resolution) + * **BitwiseOr:** Perform a 'bitwise or' operation over layer pixels. (Requires images with same resolution) + * **BitwiseXOr:** Perform a 'bitwise xor' operation over layer pixels. (Requires images with same resolution) +* (Change) Icon for Tool - Raft Relief +* (Change) Windows and dialogs max size are now calculated to where window is opened instead of use the primary or first screen all the time + ## 29/12/2020 - v2.1.0 * (Add) Tool - Redraw model/supports: Redraw the model or supports with a set brightness. This requires an extra sliced file from same object but without any supports and raft, straight to the build plate. diff --git a/README.md b/README.md index 0ee0652..bb9af0b 100644 --- a/README.md +++ b/README.md @@ -193,15 +193,15 @@ sudo apt-get install -y libjpeg-dev libpng-dev libgeotiff-dev libdc1394-22 libav **Arch/Manjaro/Similars** ```bash -sudo pacman -S openjpeg2 libjpeg-turbo libpng libgeotiff libdc1394 libdc1394 ffmpeg openexr tbb dotnet-runtime +sudo pacman -S openjpeg2 libjpeg-turbo libpng libgeotiff libdc1394 libdc1394 ffmpeg openexr tbb ``` To run UVtools open it folder on a terminal and call one of: * Double-click UVtools file * `./UVtools` -* `dotnet UVtools.dll` [For universal package only] -* `sh UVtools.sh` [For universal package only] +* `sh UVtools.sh` +* `dotnet UVtools.dll` [For universal package only, requires dotnet-runtime] * As a pratical alternative you can create a shortcut on Desktop ### Mac @@ -213,20 +213,19 @@ To run UVtools open it folder on a terminal and call one of: - ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" brew analytics off brew cask install dotnet ``` +--> To run UVtools open it folder on a terminal and call one of: * Double-click UVtools file * `./UVtools` -* `dotnet UVtools.dll` [For universal package only] -* `sh UVtools.sh` [For universal package only] +* `sh UVtools.sh` +* `dotnet UVtools.dll` [For universal package only, requires dotnet-runtime] * As a pratical alternative you can create a shortcut on Desktop ## How to use diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index a48a5c7..42db640 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -255,5 +255,16 @@ namespace UVtools.Core.Extensions return mat; } + public static Mat RoiFromCenter(this Mat mat, Size size) + { + if (size == mat.Size) return mat; + return new Mat(mat, new Rectangle( + mat.Size.Width / 2 - size.Width / 2, + mat.Size.Height / 2 - size.Height / 2, + size.Width, + size.Height + )); + } + } } diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs index 0db56ef..68229b9 100644 --- a/UVtools.Core/FileFormats/SL1File.cs +++ b/UVtools.Core/FileFormats/SL1File.cs @@ -275,15 +275,15 @@ namespace UVtools.Core.FileFormats #endregion #region Properties - public Printer PrinterSettings { get; private set; } + public Printer PrinterSettings { get; private set; } = new(); - public Material MaterialSettings { get; private set; } + public Material MaterialSettings { get; private set; } = new(); - public Print PrintSettings { get; private set; } + public Print PrintSettings { get; private set; } = new(); - public OutputConfig OutputConfigSettings { get; private set; } + public OutputConfig OutputConfigSettings { get; private set; } = new(); - public Statistics Statistics { get; } = new Statistics(); + public Statistics Statistics { get; } = new (); public override FileFormatType FileType => FileFormatType.Archive; diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs index 875ca1b..568692b 100644 --- a/UVtools.Core/Layer/Layer.cs +++ b/UVtools.Core/Layer/Layer.cs @@ -204,7 +204,7 @@ namespace UVtools.Core { get { - Mat mat = new Mat(); + Mat mat = new(); CvInvoke.Imdecode(CompressedBytes, ImreadModes.Grayscale, mat); return mat; } @@ -246,26 +246,28 @@ namespace UVtools.Core GetBoundingRectangle(); }*/ - if (!(parentLayerManager is null)) - { - _positionZ = SlicerFile.GetHeightFromLayer(index); - _exposureTime = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime); - _liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight); - _liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed); - _retractSpeed = SlicerFile.RetractSpeed; - _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); - } + if (parentLayerManager is null) return; + _positionZ = SlicerFile.GetHeightFromLayer(index); + _exposureTime = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime); + _liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight); + _liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed); + _retractSpeed = SlicerFile.RetractSpeed; + _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); } + public Layer(uint index, byte[] compressedBytes, FileFormat slicerFile) : this(index, compressedBytes, slicerFile.LayerManager) + {} + public Layer(uint index, Mat layerMat, LayerManager parentLayerManager) : this(index, new byte[0], parentLayerManager) { LayerMat = layerMat; IsModified = false; } + public Layer(uint index, Mat layerMat, FileFormat slicerFile) : this(index, layerMat, slicerFile.LayerManager) { } - public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream.ToArray(), parentLayerManager) - { } + public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream.ToArray(), parentLayerManager) { } + public Layer(uint index, Stream stream, FileFormat slicerFile) : this(index, stream.ToArray(), slicerFile.LayerManager) { } #endregion #region Equatables @@ -366,6 +368,7 @@ namespace UVtools.Core bool needDispose = false; if (mat is null) { + if (_compressedBytes is null || _compressedBytes.Length == 0) return Rectangle.Empty; mat = LayerMat; needDispose = true; } diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index f354ea2..5a2924c 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -203,17 +203,15 @@ namespace UVtools.Core public Rectangle GetBoundingRectangle(OperationProgress progress = null) { + progress ??= new OperationProgress(OperationProgress.StatusOptimizingBounds, Count-1); if (!_boundingRectangle.IsEmpty || Count == 0 || this[0] is null) return _boundingRectangle; _boundingRectangle = this[0].BoundingRectangle; if (_boundingRectangle.IsEmpty) // Safe checking { - progress?.Reset(OperationProgress.StatusOptimizingBounds, Count); + progress.Reset(OperationProgress.StatusOptimizingBounds, Count-1); Parallel.For(0, Count, layerIndex => { - if (!ReferenceEquals(progress, null) && progress.Token.IsCancellationRequested) - { - return; - } + if (progress.Token.IsCancellationRequested) return; this[layerIndex].GetBoundingRectangle(); @@ -233,12 +231,11 @@ namespace UVtools.Core } - progress?.Reset(OperationProgress.StatusCalculatingBounds, Count); + progress.Reset(OperationProgress.StatusCalculatingBounds, Count-1); for (int i = 1; i < Count; i++) { if(this[i].BoundingRectangle.IsEmpty) continue; _boundingRectangle = Rectangle.Union(_boundingRectangle, this[i].BoundingRectangle); - if (ReferenceEquals(progress, null)) continue; progress++; } @@ -1149,7 +1146,7 @@ namespace UVtools.Core /// Reallocate with new size /// /// - public LayerManager Reallocate(uint newLayerCount, bool makeClone = false) + public LayerManager ReallocateNew(uint newLayerCount, bool makeClone = false) { LayerManager layerManager = new LayerManager(newLayerCount, SlicerFile); foreach (var layer in this) @@ -1163,6 +1160,69 @@ namespace UVtools.Core return layerManager; } + /// + /// Reallocate with add size + /// + /// + public void Reallocate(uint insertAtLayerIndex, uint layerCount, bool initBlack = false) + { + var layers = Layers; + Layers = new Layer[Count + layerCount]; + + // Rearrange + for (uint layerIndex = 0; layerIndex < insertAtLayerIndex; layerIndex++) + { + Layers[layerIndex] = layers[layerIndex]; + } + + // Rearrange + for (uint layerIndex = insertAtLayerIndex; layerIndex < layers.Length; layerIndex++) + { + Layers[layerCount + layerIndex] = layers[layerIndex]; + Layers[layerCount + layerIndex].Index = layerCount + layerIndex; + } + + // Allocate new layers + if (initBlack) + { + Parallel.For(insertAtLayerIndex, insertAtLayerIndex + layerCount, layerIndex => + { + Layers[layerIndex] = new Layer((uint) layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this); + }); + } + /*for (uint layerIndex = insertAtLayerIndex; layerIndex < insertAtLayerIndex + layerCount; layerIndex++) + { + Layers[layerIndex] = initBlack ? new Layer(layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this) : null; + }*/ + } + + public void ReallocateRange(uint startLayerIndex, uint endLayerIndex) + { + var layers = Layers; + if ((int)(endLayerIndex - startLayerIndex) < 0) return; + Layers = new Layer[1 + endLayerIndex - startLayerIndex]; + + uint currentLayerIndex = 0; + for (uint layerIndex = startLayerIndex; layerIndex <= endLayerIndex; layerIndex++) + { + Layers[currentLayerIndex++] = layers[layerIndex]; + } + + BoundingRectangle = Rectangle.Empty; + } + + /// + /// Reallocate at start + /// + /// + public void ReallocateStart(uint layerCount, bool initBlack = false) => Reallocate(0, layerCount, initBlack); + + /// + /// Reallocate at end + /// + /// + public void ReallocateEnd(uint layerCount, bool initBlack = false) => Reallocate(Count, layerCount, initBlack); + /// /// Clone this object /// diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs index abb1a68..f87085f 100644 --- a/UVtools.Core/Managers/ClipboardManager.cs +++ b/UVtools.Core/Managers/ClipboardManager.cs @@ -122,7 +122,7 @@ namespace UVtools.Core.Managers var clip = this[i]; if (layerManager.Count != clip.LayerCount) // Need resize layer manager { - layerManager = layerManager.Reallocate(clip.LayerCount); + layerManager = layerManager.ReallocateNew(clip.LayerCount); ReallocatedLayerCount = true; } diff --git a/UVtools.Core/Operations/OperationCalibrateExternalTests.cs b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs new file mode 100644 index 0000000..64a5bb6 --- /dev/null +++ b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs @@ -0,0 +1,47 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + + +namespace UVtools.Core.Operations +{ + public class OperationCalibrateExternalTests : Operation + { + #region Members + #endregion + + #region Overrides + + public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None; + public override bool CanROI => false; + public override bool CanHaveProfiles => false; + public override string ButtonOkText => null; + public override string Title => "External tests"; + public override string Description => + "A set of useful external tests to run within your slicer.\nClick on a button to open website and instructions."; + + public override string ConfirmationText => null; + + public override string ProgressTitle => null; + + public override string ProgressAction => null; + + #endregion + + #region Properties + + #endregion + + #region Equality + + #endregion + + #region Methods + + #endregion + } +} diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs index 17c4dba..7e5b822 100644 --- a/UVtools.Core/Operations/OperationLayerImport.cs +++ b/UVtools.Core/Operations/OperationLayerImport.cs @@ -6,15 +6,17 @@ * of this license document, but changing it is not allowed. */ using System; -using System.Collections.Concurrent; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Serialization; using Emgu.CV; using Emgu.CV.CvEnum; +using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Objects; @@ -23,12 +25,26 @@ namespace UVtools.Core.Operations [Serializable] public sealed class OperationLayerImport : Operation { - private uint _insertAfterLayerIndex; - private bool _replaceStartLayer; - private bool _replaceSubsequentLayers; - private bool _discardRemainingLayers; - private bool _mergeImages; - private ObservableCollection _files = new ObservableCollection(); + #region Enums + public enum ImportTypes : byte + { + Insert, + Replace, + Stack, + Merge, + Subtract, + BitwiseAnd, + BitwiseOr, + BitwiseXOr, + } + #endregion + + private ImportTypes _importType = ImportTypes.Stack; + private uint _startLayerIndex; + private bool _extendBeyondLayerCount = true; + private bool _discardUnmodifiedLayers; + private ushort _stackMargin = 50; + private ObservableCollection _files = new(); #region Overrides @@ -37,26 +53,25 @@ namespace UVtools.Core.Operations public override string Title => "Import Layers"; public override string Description => - "Import layers from local files into the model at a selected layer height.\n\n" + + "Import layers from local files into the model at a selected layer height.\n" + "NOTE: Imported images must be greyscale and have the same resolution as the model."; - public override string ConfirmationText => $"import {Count} layer{(Count!=1?"s":"")}?"; + public override string ConfirmationText => $"{_importType} import {Count} file{(Count>=1?"s":"")}?"; public override string ProgressTitle => - $"Importing {Count} layer{(Count!=1 ? "s" : "")}"; + $"{_importType} importing {Count} file{(Count>=1 ? "s" : "")}"; public override string ProgressAction => "Imported layers"; public override bool CanCancel => true; - public override uint LayerIndexStart => InsertAfterLayerIndex + (ReplaceStartLayer ? 0u : 1); - public override uint LayerIndexEnd => (uint)(LayerIndexStart + Count - 1); + public override uint LayerIndexEnd => _startLayerIndex + Count - 1; public override bool CanHaveProfiles => false; public override StringTag Validate(params object[] parameters) { - var result = new ConcurrentBag(); + /*var result = new ConcurrentBag(); Parallel.ForEach(Files, file => { using (Mat mat = CvInvoke.Imread(file.TagString, ImreadModes.AnyColor)) @@ -83,52 +98,76 @@ namespace UVtools.Core.Operations } message.AppendLine(file.Content); } + - return new StringTag(message.ToString(), result); + return new StringTag(message.ToString(), result);*/ + + StringBuilder sb = new(); + + if (Files.Count == 0) + { + sb.AppendLine("No files to import."); + } + + return new StringTag(sb.ToString()); } #endregion #region Properties + [XmlIgnore] public Size FileResolution { get; } - public uint InsertAfterLayerIndex + public ImportTypes ImportType { - get => _insertAfterLayerIndex; - set => RaiseAndSetIfChanged(ref _insertAfterLayerIndex, value); + get => _importType; + set + { + if(!RaiseAndSetIfChanged(ref _importType, value)) return; + RaisePropertyChanged(nameof(IsImportStackType)); + RaisePropertyChanged(nameof(IsExtendBeyondLayerCountVisible)); + } } - public bool ReplaceStartLayer + + public static Array ImportTypesItems => Enum.GetValues(typeof(ImportTypes)); + + public bool IsImportStackType => _importType == ImportTypes.Stack; + + public uint StartLayerIndex { - get => _replaceStartLayer; - set => RaiseAndSetIfChanged(ref _replaceStartLayer, value); + get => _startLayerIndex; + set => RaiseAndSetIfChanged(ref _startLayerIndex, value); } - public bool ReplaceSubsequentLayers + public bool ExtendBeyondLayerCount { - get => _replaceSubsequentLayers; - set => RaiseAndSetIfChanged(ref _replaceSubsequentLayers, value); + get => _extendBeyondLayerCount; + set => RaiseAndSetIfChanged(ref _extendBeyondLayerCount, value); } - public bool DiscardRemainingLayers + public bool IsExtendBeyondLayerCountVisible => _importType == ImportTypes.Replace || _importType == ImportTypes.Stack || _importType == ImportTypes.Merge; + + public bool DiscardUnmodifiedLayers { - get => _discardRemainingLayers; - set => RaiseAndSetIfChanged(ref _discardRemainingLayers, value); + get => _discardUnmodifiedLayers; + set => RaiseAndSetIfChanged(ref _discardUnmodifiedLayers, value); } - public bool MergeImages + public ushort StackMargin { - get => _mergeImages; - set => RaiseAndSetIfChanged(ref _mergeImages, value); + get => _stackMargin; + set => RaiseAndSetIfChanged(ref _stackMargin, value); } + [XmlIgnore] public ObservableCollection Files { get => _files; set => RaiseAndSetIfChanged(ref _files, value); } - public int Count => Files.Count; + public uint Count => (uint) Files.Count; #endregion #region Constructor @@ -163,7 +202,7 @@ namespace UVtools.Core.Operations } - public uint CalculateTotalLayers(uint totalLayers) + /*public uint CalculateTotalLayers(uint totalLayers) { if (DiscardRemainingLayers) { @@ -176,7 +215,7 @@ namespace UVtools.Core.Operations } return (uint)(totalLayers + Files.Count - (ReplaceStartLayer ? 1 : 0)); - } + }*/ public override string ToString() { @@ -188,56 +227,36 @@ namespace UVtools.Core.Operations public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) { progress ??= new OperationProgress(); - progress.Reset(ProgressAction, (uint)Count); + slicerFile.SuppressRebuildProperties = true; + + List fileFormats = new(); + List> keyImage = new(); + int lastProcessedLayerIndex = -1; - var oldLayers = slicerFile.LayerManager.Layers; - uint newLayerCount = CalculateTotalLayers((uint)oldLayers.Length); - uint startIndex = LayerIndexStart; - var layers = new Layer[newLayerCount]; - - // Keep same layers up to InsertAfterLayerIndex - for (uint i = 0; i <= InsertAfterLayerIndex; i++) + // Order raw images + for (int i = 0; i < Count; i++) { - layers[i] = oldLayers[i]; + if (!Files[i].TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) && + !Files[i].TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) && + !Files[i].TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) && + !Files[i].TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) && + !Files[i].TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue; + keyImage.Add(new KeyValuePair((uint) keyImage.Count, Files[i].TagString)); } - // Keep all old layers if not discarding them - if (ReplaceSubsequentLayers) + // Create virtual file format with images + if (keyImage.Count > 0) { - if (!DiscardRemainingLayers) - { - for (uint i = InsertAfterLayerIndex + 1; i < oldLayers.Length; i++) - { - layers[i] = oldLayers[i]; - } - } - } - else // Push remaining layers to the end of imported layers - { - uint oldLayerIndex = InsertAfterLayerIndex; - for (uint i = LayerIndexEnd + 1; i < newLayerCount; i++) - { - oldLayerIndex++; - layers[i] = oldLayers[oldLayerIndex]; - } - } + progress.Reset("Packing images", (uint) keyImage.Count); + SL1File format = new SL1File(); + format.LayerManager = new LayerManager((uint) keyImage.Count, format); - - Parallel.For(0, Count, - //new ParallelOptions{MaxDegreeOfParallelism = 1}, - i => + Parallel.ForEach(keyImage, pair => { - var mat = CvInvoke.Imread(Files[i].TagString, ImreadModes.Grayscale); - uint layerIndex = (uint)(startIndex + i); - if (MergeImages) - { - if (layers[layerIndex] is not null) - { - using var oldMat = layers[layerIndex].LayerMat; - CvInvoke.Add(oldMat, mat, mat); - } - } - layers[layerIndex] = new Layer(layerIndex, mat, slicerFile.LayerManager); + if (progress.Token.IsCancellationRequested) return; + using var mat = CvInvoke.Imread(pair.Value, ImreadModes.Grayscale); + if (pair.Key == 0) format.Resolution = mat.Size; + format[pair.Key] = new Layer(pair.Key, mat, format); lock (progress.Mutex) { @@ -245,11 +264,239 @@ namespace UVtools.Core.Operations } }); - slicerFile.LayerManager.Layers = layers; - slicerFile.RequireFullEncode = true; + progress.Token.ThrowIfCancellationRequested(); + fileFormats.Add(format); + } + // Order remaining possible file formats + for (int i = 0; i < Count; i++) + { + if (Files[i].TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || + Files[i].TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) || + Files[i].TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) || + Files[i].TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || + Files[i].TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue; + + var fileFormat = FileFormat.FindByExtension(Files[i].TagString, true, true); + if(fileFormat is null) continue; + fileFormat.FileFullPath = Files[i].TagString; + fileFormats.Add(fileFormat); + } + progress.Token.ThrowIfCancellationRequested(); + if (fileFormats.Count == 0) return false; + + if (_importType == ImportTypes.Stack) + { + new OperationMove(slicerFile, Enumerations.Anchor.TopLeft){LayerIndexEnd = slicerFile.LastLayerIndex}.Execute(slicerFile, progress); + } + + foreach (var fileFormat in fileFormats) + { + if (!string.IsNullOrEmpty(fileFormat.FileFullPath)) + { + fileFormat.Decode(fileFormat.FileFullPath, progress); + } + + var boundingRectangle = slicerFile.LayerManager.GetBoundingRectangle(progress); + var fileFormatBoundingRectangle = fileFormat.LayerManager.GetBoundingRectangle(progress); + var roiRectangle = Rectangle.Empty; + + // Check if is possible to process this file + switch (_importType) + { + case ImportTypes.Insert: + if (slicerFile.Resolution != fileFormat.Resolution && + (slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || + slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; + slicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount); + break; + case ImportTypes.Replace: + case ImportTypes.Stack: + if (slicerFile.Resolution != fileFormat.Resolution && + (slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || + slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; + + + if(fileFormatBoundingRectangle.Width >= slicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= slicerFile.ResolutionY) + continue; + + int x = 0; + int y = 0; + + if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width < + slicerFile.ResolutionX) + { + x = boundingRectangle.Right + _stackMargin; + } + else + { + y = boundingRectangle.Bottom + _stackMargin; + } + + if (y >= slicerFile.ResolutionY) + continue; + + roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height); + + if (_extendBeyondLayerCount) + { + int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount); + if (layerCountDifference > 0) + { + slicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack); + } + } + + break; + case ImportTypes.Merge: + if (slicerFile.Resolution != fileFormat.Resolution) continue; + if (_extendBeyondLayerCount) + { + int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount); + if (layerCountDifference > 0) + { + slicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true); + } + } + break; + case ImportTypes.Subtract: + case ImportTypes.BitwiseAnd: + case ImportTypes.BitwiseOr: + case ImportTypes.BitwiseXOr: + if (slicerFile.Resolution != fileFormat.Resolution) continue; + break; + } + + progress.Reset(ProgressAction, fileFormat.LayerCount); + Parallel.For(0, fileFormat.LayerCount, + //new ParallelOptions{MaxDegreeOfParallelism = 1}, + i => + { + if (progress.Token.IsCancellationRequested) return; + uint layerIndex = (uint)(_startLayerIndex + i); + + switch (_importType) + { + case ImportTypes.Insert: + { + if (layerIndex >= slicerFile.LayerCount) return; + if (slicerFile.Resolution == fileFormat.Resolution) + { + slicerFile[layerIndex] = fileFormat[i]; + break; + } + + using var layer = fileFormat[i].LayerMat; + using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution); + slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile); + + break; + } + case ImportTypes.Replace: + { + if (layerIndex >= slicerFile.LayerCount) return; + if (slicerFile.Resolution == fileFormat.Resolution) + { + slicerFile[layerIndex] = fileFormat[i]; + break; + } + + using var layer = fileFormat[i].LayerMat; + using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution); + slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile); + break; + } + case ImportTypes.Stack: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var mat = slicerFile[layerIndex].LayerMat; + using var importMat = fileFormat[i].LayerMat; + var matRoi = new Mat(mat, roiRectangle); + var importMatRoi = new Mat(importMat, fileFormatBoundingRectangle); + importMatRoi.CopyTo(matRoi); + slicerFile[layerIndex].LayerMat = mat; + + break; + } + case ImportTypes.Merge: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var originalMat = slicerFile[layerIndex].LayerMat; + using var newMat = fileFormat[i].LayerMat; + CvInvoke.Add(originalMat, newMat, newMat); + slicerFile[layerIndex].LayerMat = newMat; + break; + } + case ImportTypes.Subtract: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var originalMat = slicerFile[layerIndex].LayerMat; + using var newMat = fileFormat[i].LayerMat; + CvInvoke.Subtract(originalMat, newMat, newMat); + slicerFile[layerIndex].LayerMat = newMat; + break; + } + case ImportTypes.BitwiseAnd: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var originalMat = slicerFile[layerIndex].LayerMat; + using var newMat = fileFormat[i].LayerMat; + CvInvoke.BitwiseAnd(originalMat, newMat, newMat); + slicerFile[layerIndex].LayerMat = newMat; + break; + } + case ImportTypes.BitwiseOr: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var originalMat = slicerFile[layerIndex].LayerMat; + using var newMat = fileFormat[i].LayerMat; + CvInvoke.BitwiseOr(originalMat, newMat, newMat); + slicerFile[layerIndex].LayerMat = newMat; + break; + } + case ImportTypes.BitwiseXOr: + { + if (layerIndex >= slicerFile.LayerCount) return; + using var originalMat = slicerFile[layerIndex].LayerMat; + using var newMat = fileFormat[i].LayerMat; + CvInvoke.BitwiseXor(originalMat, newMat, newMat); + slicerFile[layerIndex].LayerMat = newMat; + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + + + lock (progress.Mutex) + { + lastProcessedLayerIndex = Math.Max(lastProcessedLayerIndex, (int)layerIndex); + progress++; + } + }); + + fileFormat.Dispose(); + progress.Token.ThrowIfCancellationRequested(); + } + + if (_importType == ImportTypes.Stack) + { + new OperationMove(slicerFile) { LayerIndexEnd = slicerFile.LastLayerIndex }.Execute(slicerFile, progress); + } + + if (lastProcessedLayerIndex <= -1) return false; + + if (lastProcessedLayerIndex + 1 < slicerFile.LayerCount && _discardUnmodifiedLayers) + { + slicerFile.LayerManager.ReallocateRange(0, (uint) lastProcessedLayerIndex); + } + + slicerFile.LayerManager.RebuildLayersProperties(); + slicerFile.SuppressRebuildProperties = false; + slicerFile.RequireFullEncode = true; + return true; } diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs index 09f046d..12bcae0 100644 --- a/UVtools.Core/Operations/OperationMove.cs +++ b/UVtools.Core/Operations/OperationMove.cs @@ -227,6 +227,14 @@ namespace UVtools.Core.Operations { } + public OperationMove(FileFormat slicerFile, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) + { + ROI = slicerFile.LayerManager.BoundingRectangle; + ImageWidth = slicerFile.ResolutionX; + ImageHeight = slicerFile.ResolutionY; + Anchor = anchor; + } + public OperationMove(Rectangle srcRoi, uint imageWidth, uint imageHeight, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) { ROI = srcRoi; diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 73ec8e0..28f66fc 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, repair, conversion and manipulation - 2.1.0 + 2.1.1 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index 4d14ccc..c4b717a 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -13,9 +13,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using System.Threading; using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; @@ -38,8 +36,6 @@ namespace UVtools.WPF public static AppVersionChecker VersionChecker { get; } = new AppVersionChecker(); - public static Size MaxWindowSize = Size.Empty; - public override void Initialize() { AvaloniaXamlLoader.Load(this); @@ -124,15 +120,15 @@ namespace UVtools.WPF { try { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (OperatingSystem.IsWindows()) { Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }).Dispose(); } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + else if (OperatingSystem.IsLinux()) { Process.Start("xdg-open", url).Dispose(); } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + else if (OperatingSystem.IsMacOS()) { Process.Start("open", url).Dispose(); } diff --git a/UVtools.WPF/Assets/Icons/bookmark-16x16.png b/UVtools.WPF/Assets/Icons/bookmark-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e8b3e69727eb48372d7996d6a2bd8718978b49 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6EInNuLn;`P8Jerw{?8E5;9~#3 z(K$*>BD6q?qfqO|$q6iv7*5W=A@apop}8)Eb+^P4$qS7p0U{g>JCCm{j6Bi!7ib8B Mr>mdKI;Vst0Iks@T>t<8 literal 0 HcmV?d00001 diff --git a/UVtools.WPF/Assets/Icons/cookie-16x16.png b/UVtools.WPF/Assets/Icons/cookie-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..2c90a8b683eca602ec377291c978bda569e0b424 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6>O5T>Ln;_sCz>-JcHnW9pRO!o zr`hz-Ho8hNLG7he0mGD&>O24MUlGnF)RgqcVq=mcyQrjck@o>P=?C{V=eCGCXdTUN zk>Wn1GGP&yWAW_o-?`3N*KFi`Rp7AZXx)Jqmo+@jOEe$7UXq-C_NMdM`BfhxZ*G3P h`@P07VMWtt_T6)KYFv1ze+uXl22WQ%mvv4FO#oZ4Mx_7% literal 0 HcmV?d00001 diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml new file mode 100644 index 0000000..0b8421f --- /dev/null +++ b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml @@ -0,0 +1,35 @@ + + + +