Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2021-04-18 02:18:42 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-04-18 02:18:42 +0300
commit6cfedea4cc36200caab87301e0dd121e97ddc8f2 (patch)
tree3325980560fc5bb3fa8befea1b827a2ca945e9ea
parent4dae750e83987fde8b34087d26fc75407e88f55a (diff)
v2.9.1v2.9.1
* **File formats:** * PhotonS: Implement the write/encode method to allow to use this format and fix the thumbnail * VDT: Allow to auto convert the .vdt to the target printer format using the Machine - Notes, using a flag: FILEFORMAT_YourPrinterExtension, for example: FILEFORMAT_CTB * (Fix) Unable to convert files with no thumbnails to other file format that requires thumbnails * **Tools:** * (Add) Re-height: Option to Anti-Aliasing layers * (Fix) Morph and Blur: The combobox was not setting to the selected item when preform a redo operation (Ctrl+Shift+Z) * **GUI:** * (Change) Progress window to be a grid element inside MainWindow, this allow to reuse the graphics and its elements without the need of spawning a Window instance everytime a progress is shown, resulting in better performance and more fluid transaction * (Improvement) Clear issues when generating calibration tests
-rw-r--r--CHANGELOG.md13
-rw-r--r--README.md2
-rw-r--r--UVtools.Core/Extensions/BitExtensions.cs15
-rw-r--r--UVtools.Core/Extensions/EnumExtensions.cs39
-rw-r--r--UVtools.Core/FileFormats/CXDLPFile.cs1
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs1
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs40
-rw-r--r--UVtools.Core/FileFormats/MDLPFile.cs2
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs294
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs24
-rw-r--r--UVtools.Core/FileFormats/VDTFile.cs44
-rw-r--r--UVtools.Core/Objects/StringTag.cs100
-rw-r--r--UVtools.Core/Objects/ValueDescription.cs73
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs42
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs34
-rw-r--r--UVtools.Core/Operations/OperationLayerReHeight.cs142
-rw-r--r--UVtools.Core/Operations/OperationMorph.cs51
-rw-r--r--UVtools.Core/Operations/OperationProgress.cs19
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.ScriptSample/ScriptAutomateWorkflowSample.cs2
-rw-r--r--UVtools.WPF/App.axaml5
-rw-r--r--UVtools.WPF/Controls/Tools/ToolBlurControl.axaml15
-rw-r--r--UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs39
-rw-r--r--UVtools.WPF/Controls/Tools/ToolControl.axaml.cs2
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs22
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml29
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs11
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMorphControl.axaml4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs29
-rw-r--r--UVtools.WPF/Converters/EnumToCollectionConverter.cs29
-rw-r--r--UVtools.WPF/Converters/FromValueDescriptionToEnumConverter.cs31
-rw-r--r--UVtools.WPF/Extensions/BitmapExtension.cs3
-rw-r--r--UVtools.WPF/MainWindow.Information.cs37
-rw-r--r--UVtools.WPF/MainWindow.Issues.cs26
-rw-r--r--UVtools.WPF/MainWindow.PixelEditor.cs5
-rw-r--r--UVtools.WPF/MainWindow.Progress.cs95
-rw-r--r--UVtools.WPF/MainWindow.axaml64
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs108
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj3
-rw-r--r--UVtools.WPF/UserSettings.cs8
-rw-r--r--UVtools.WPF/Windows/SettingsWindow.axaml9
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml4
42 files changed, 917 insertions, 601 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef2019c..063050d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 18/04/2021 - v2.9.1
+
+* **File formats:**
+ * PhotonS: Implement the write/encode method to allow to use this format and fix the thumbnail
+ * VDT: Allow to auto convert the .vdt to the target printer format using the Machine - Notes, using a flag: FILEFORMAT_YourPrinterExtension, for example: FILEFORMAT_CTB
+ * (Fix) Unable to convert files with no thumbnails to other file format that requires thumbnails
+* **Tools:**
+ * (Add) Re-height: Option to Anti-Aliasing layers
+ * (Fix) Morph and Blur: The combobox was not setting to the selected item when preform a redo operation (Ctrl+Shift+Z)
+* **GUI:**
+ * (Change) Progress window to be a grid element inside MainWindow, this allow to reuse the graphics and its elements without the need of spawning a Window instance everytime a progress is shown, resulting in better performance and more fluid transaction
+ * (Improvement) Clear issues when generating calibration tests
+
## 14/04/2021 - v2.9.0
* **File formats:**
diff --git a/README.md b/README.md
index d21e628..21f8070 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ But also, i need victims for test subject. Proceed at your own risk!
* SL1 (PrusaSlicer)
* Zip (Chitubox)
* Photon (Chitubox)
-* Photons (Chitubox) [Read-only]
+* Photons (Chitubox)
* CBDDLP (Chitubox)
* CBT (Chitubox)
* PHZ (Chitubox)
diff --git a/UVtools.Core/Extensions/BitExtensions.cs b/UVtools.Core/Extensions/BitExtensions.cs
new file mode 100644
index 0000000..7df1876
--- /dev/null
+++ b/UVtools.Core/Extensions/BitExtensions.cs
@@ -0,0 +1,15 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+namespace UVtools.Core.Extensions
+{
+ public static class BitExtensions
+ {
+ public static ushort ToUShortLittleEndian(byte byte1, byte byte2) => (ushort)(byte1 + (byte2 << 8));
+ public static ushort ToUShortBigEndian(byte byte1, byte byte2) => (ushort)((byte1 << 8) + byte2);
+ }
+}
diff --git a/UVtools.Core/Extensions/EnumExtensions.cs b/UVtools.Core/Extensions/EnumExtensions.cs
new file mode 100644
index 0000000..493418c
--- /dev/null
+++ b/UVtools.Core/Extensions/EnumExtensions.cs
@@ -0,0 +1,39 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using UVtools.Core.Objects;
+
+namespace UVtools.Core.Extensions
+{
+ public static class EnumExtensions
+ {
+ public static string GetDescription(this Enum value)
+ {
+ var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
+ if (attributes.Any())
+ return (attributes.First() as DescriptionAttribute)?.Description;
+
+ // If no description is found, the least we can do is replace underscores with spaces
+ // You can add your own custom default formatting logic here
+ var ti = CultureInfo.CurrentCulture.TextInfo;
+ return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
+ }
+
+ public static IEnumerable<ValueDescription> GetAllValuesAndDescriptions(Type t)
+ {
+ if (!t.IsEnum)
+ throw new ArgumentException($"{nameof(t)} must be an enum type");
+
+ return Enum.GetValues(t).Cast<Enum>().Select(e => new ValueDescription(e, e.GetDescription())).ToList();
+ }
+ }
+}
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
index 2e680a3..bd44c26 100644
--- a/UVtools.Core/FileFormats/CXDLPFile.cs
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -255,6 +255,7 @@ namespace UVtools.Core.FileFormats
public string FooterValue { get; set; } = HEADER_VALUE;
[FieldOrder(2)]
+ [FieldEndianness(Endianness.Big)]
public uint Unknown { get; set; } = 7;
public void Validate()
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 2fe8a04..9b05d2e 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -1241,6 +1241,7 @@ namespace UVtools.Core.FileFormats
/// <param name="images"></param>
public void SetThumbnails(Mat[] images)
{
+ if (images is null || images.Length == 0) return;
byte imageIndex = 0;
for (int i = 0; i < ThumbnailsCount; i++)
{
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index cb3d38d..9a3a0a6 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -431,6 +431,26 @@ namespace UVtools.Core.FileFormats
return bytes;
}
+ public unsafe Mat PreviewDecode(byte[] data)
+ {
+ Mat mat = new((int)HeaderSettings.PreviewSizeY, (int)HeaderSettings.PreviewSizeX, DepthType.Cv8U, 3);
+ var span = mat.GetBytePointer();
+ int spanIndex = 0;
+ for (int i = 0; i < data.Length; i += 2)
+ {
+ ushort rgb15 = BitExtensions.ToUShortBigEndian(data[i], data[i + 1]);
+ byte r = (byte)((((rgb15 >> 11) & 0x1f) << 3) | 0x7);
+ byte g = (byte)((((rgb15 >> 6) & 0x1f) << 3) | 0x7);
+ byte b = (byte)((((rgb15 >> 0) & 0x1f) << 3) | 0x7);
+
+ span[spanIndex++] = b;
+ span[spanIndex++] = g;
+ span[spanIndex++] = r;
+ }
+
+ return mat;
+ }
+
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
if (ResolutionY >= 2560) // Longer Orange 30
@@ -474,26 +494,6 @@ namespace UVtools.Core.FileFormats
Debug.WriteLine("-End-");
}
- public unsafe Mat PreviewDecode(byte []data)
- {
- Mat mat = new Mat((int) HeaderSettings.PreviewSizeY, (int)HeaderSettings.PreviewSizeX, DepthType.Cv8U, 3);
- var span = mat.GetBytePointer();
- int spanIndex = 0;
- for (int i = 0; i < data.Length; i+=2)
- {
- ushort rgb15 = (ushort) ((ushort)(data[i + 0] << 8) | data[i + 1]);
- byte r = (byte) ((((rgb15 >> 11) & 0x1f) << 3) | 0x7);
- byte g = (byte) ((((rgb15 >> 6) & 0x1f) << 3) | 0x7);
- byte b = (byte) ((((rgb15 >> 0) & 0x1f) << 3) | 0x7);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- return mat;
- }
-
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
diff --git a/UVtools.Core/FileFormats/MDLPFile.cs b/UVtools.Core/FileFormats/MDLPFile.cs
index 784ad28..475150f 100644
--- a/UVtools.Core/FileFormats/MDLPFile.cs
+++ b/UVtools.Core/FileFormats/MDLPFile.cs
@@ -420,7 +420,7 @@ namespace UVtools.Core.FileFormats
int spanIndex = 0;
for (int i = 0; i < previews[previewIndex].Length; i += 2)
{
- ushort rgb15 = (ushort)((ushort)(previews[previewIndex][i + 0] << 8) | previews[previewIndex][i + 1]);
+ ushort rgb15 = BitExtensions.ToUShortBigEndian(previews[previewIndex][i], previews[previewIndex][i + 1]);
byte r = (byte)((rgb15 >> 11) << 3);
byte g = (byte)((rgb15 >> 5) << 2);
byte b = (byte)((rgb15 >> 0) << 3);
diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs
index e2391a7..6e6fe47 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -24,7 +24,7 @@ namespace UVtools.Core.FileFormats
{
public class PhotonSFile : FileFormat
{
- public const byte RLEEncodingLimit = 0x7f - 2; // 128;
+ public const byte RLEEncodingLimit = 128;
#region Sub Classes
@@ -37,7 +37,7 @@ namespace UVtools.Core.FileFormats
public const float DisplayWidth = 68.04f;
public const float DisplayHeight = 120.96f;
- public const float BuildZ = 150f;
+ public const float BuildZ = 165f;
public const uint TAG1 = 2;
public const ushort TAG2 = 49;
@@ -55,7 +55,7 @@ namespace UVtools.Core.FileFormats
[FieldOrder(9)] [FieldEndianness(Endianness.Big)] public double LiftSpeed { get; set; } // mm/s
[FieldOrder(10)] [FieldEndianness(Endianness.Big)] public double RetractSpeed { get; set; } // mm/s
[FieldOrder(11)] [FieldEndianness(Endianness.Big)] public double VolumeMl { get; set; } // ml
- [FieldOrder(12)] [FieldEndianness(Endianness.Big)] public uint PreviewResolutionX { get; set; } = 225;
+ [FieldOrder(12)] [FieldEndianness(Endianness.Big)] public uint PreviewResolutionX { get; set; } = 224;
[FieldOrder(13)] [FieldEndianness(Endianness.Big)] public uint Unknown2 { get; set; } = 42;
[FieldOrder(14)] [FieldEndianness(Endianness.Big)] public uint PreviewResolutionY { get; set; } = 168;
[FieldOrder(15)] [FieldEndianness(Endianness.Big)] public uint Unknown4 { get; set; } = 10;
@@ -88,7 +88,14 @@ namespace UVtools.Core.FileFormats
[FieldOrder(3)] [FieldEndianness(Endianness.Big)] public uint ResolutionX { get; set; } = 1440;
[FieldOrder(4)] [FieldEndianness(Endianness.Big)] public uint ResolutionY { get; set; } = 2560;
[FieldOrder(5)] [FieldEndianness(Endianness.Big)] public uint DataSize { get; set; }
- [Ignore] public uint RleDataSize => (DataSize >> 3) - 4;
+ [Ignore] public uint RleDataSize
+ {
+ get => (DataSize >> 3) - 4;
+ set => DataSize = (value + 4) << 3;
+ //get => DataSize / 8 - 4;
+ //set => DataSize = (value + 4) * 8;
+ }
+
[FieldOrder(6)] [FieldEndianness(Endianness.Big)] public uint Unknown5 { get; set; } = 2684702720;
[Ignore] public byte[] EncodedRle { get; set; }
@@ -100,33 +107,34 @@ namespace UVtools.Core.FileFormats
public unsafe byte[] Encode(Mat mat)
{
- List<byte> rawData = new List<byte>();
+ List<byte> rawData = new();
var spanMat = mat.GetBytePointer();
var imageLength = mat.GetLength();
int rep = 0;
byte color = 0;
+ int totalPixels = 0;
void AddRep()
{
if (rep <= 0) return;
+
+ totalPixels += rep;
rep--;
- byte rle =
- (byte) (((rep & 1) > 0 ? 128 : 0) |
- ((rep & 2) > 0 ? 64 : 0) |
- ((rep & 4) > 0 ? 32 : 0) |
- ((rep & 8) > 0 ? 16 : 0) |
- ((rep & 16) > 0 ? 8 : 0) |
- ((rep & 32) > 0 ? 4 : 0) |
- ((rep & 64) > 0 ? 2 : 0) | color);
+ byte rle = (byte) (((rep & 1) > 0 ? 128 : 0) |
+ ((rep & 2) > 0 ? 64 : 0) |
+ ((rep & 4) > 0 ? 32 : 0) |
+ ((rep & 8) > 0 ? 16 : 0) |
+ ((rep & 16) > 0 ? 8 : 0) |
+ ((rep & 32) > 0 ? 4 : 0) |
+ ((rep & 64) > 0 ? 2 : 0) | color);
rawData.Add(rle);
}
for (int i = 0; i < imageLength; i++)
{
- //color = color <= 127 ? 0 : 255; // Sanitize no AA
- byte thisColor = spanMat[i] <= 127 ? byte.MinValue : byte.MaxValue; // Sanitize no AA
+ byte thisColor = spanMat[i] <= 127 ? (byte)0 : (byte)1; // Sanitize no AA
if (thisColor != color)
{
AddRep();
@@ -146,8 +154,13 @@ namespace UVtools.Core.FileFormats
AddRep();
+ if (totalPixels != imageLength)
+ {
+ throw new FileLoadException($"Error image ran shortly or off the end, expecting {imageLength} pixels, got {totalPixels} pixels.");
+ }
+
EncodedRle = rawData.ToArray();
- DataSize = (uint)(EncodedRle.Length * 8 + 4);
+ RleDataSize = (uint) EncodedRle.Length;
return EncodedRle;
}
@@ -157,31 +170,43 @@ namespace UVtools.Core.FileFormats
var matSpan = mat.GetBytePointer();
var imageLength = mat.GetLength();
- int pixel = 0;
+ uint pixel = 0;
foreach (var run in EncodedRle)
{
- byte col = (byte) ((run & 0x01) * 255);
-
- var numPixelsInRun =
- (((run & 128) > 0 ? 1 : 0) |
- ((run & 64) > 0 ? 2 : 0) |
- ((run & 32) > 0 ? 4 : 0) |
- ((run & 16) > 0 ? 8 : 0) |
- ((run & 8) > 0 ? 16 : 0) |
- ((run & 4) > 0 ? 32 : 0) |
- ((run & 2) > 0 ? 64 : 0)) + 1;
-
+ byte brightness = (byte) ((run & 0x01) * 255);
+
+ uint numPixelsInRun =
+ (uint) ((((run & 128) > 0 ? 1 : 0) |
+ ((run & 64) > 0 ? 2 : 0) |
+ ((run & 32) > 0 ? 4 : 0) |
+ ((run & 16) > 0 ? 8 : 0) |
+ ((run & 8) > 0 ? 16 : 0) |
+ ((run & 4) > 0 ? 32 : 0) |
+ ((run & 2) > 0 ? 64 : 0)) + 1);
+
+ if (brightness == 0) // Don't fill black pixels
+ {
+ pixel += numPixelsInRun;
+ continue;
+ }
+
for (; numPixelsInRun > 0; numPixelsInRun--)
{
if (pixel > imageLength)
{
mat.Dispose();
- throw new FileLoadException($"Error image ran off the end, expecting {imageLength} pixels");
+ throw new FileLoadException($"Error image ran off the end, expecting {imageLength} pixels.");
}
- matSpan[pixel++] = col;
+ matSpan[pixel++] = brightness;
}
}
+ if (pixel != imageLength && pixel-1 != imageLength)
+ {
+ mat.Dispose();
+ throw new FileLoadException($"Error image ran shortly or off the end, expecting {imageLength} pixels, got {pixel} pixels.");
+ }
+
// Not required as mat is all black by default
//for (;pixel < imageLength; pixel++) matSpan[pixel] = 0;
@@ -197,8 +222,8 @@ namespace UVtools.Core.FileFormats
#region Properties
- public Header HeaderSettings { get; protected internal set; } = new Header();
- public LayerHeader LayerSettings { get; protected internal set; } = new LayerHeader();
+ public Header HeaderSettings { get; protected internal set; } = new();
+ public LayerHeader LayerSettings { get; protected internal set; } = new();
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
@@ -221,7 +246,7 @@ namespace UVtools.Core.FileFormats
};
- public override Size[] ThumbnailsOriginalSize { get; } = {new(225, 168) };
+ public override Size[] ThumbnailsOriginalSize { get; } = {new(224, 168) };
public override uint ResolutionX
{
@@ -261,7 +286,7 @@ namespace UVtools.Core.FileFormats
public override float LayerHeight
{
- get => (float) Math.Round(HeaderSettings.LayerHeight);
+ get => (float) Layer.RoundHeight(HeaderSettings.LayerHeight);
set
{
HeaderSettings.LayerHeight = Layer.RoundHeight(value);
@@ -269,6 +294,12 @@ namespace UVtools.Core.FileFormats
}
}
+ public override float MachineZ
+ {
+ get => Header.BuildZ;
+ set { }
+ }
+
public override uint LayerCount
{
get => base.LayerCount;
@@ -293,7 +324,7 @@ namespace UVtools.Core.FileFormats
set => base.ExposureTime = (float) (HeaderSettings.ExposureSeconds = Math.Round(value, 2));
}
- public override float BottomLiftHeight => LightOffDelay;
+ public override float BottomLiftHeight => LiftHeight;
public override float LiftHeight
{
@@ -306,21 +337,13 @@ namespace UVtools.Core.FileFormats
public override float LiftSpeed
{
get => (float) Math.Round(HeaderSettings.LiftSpeed * 60.0, 2);
- set
- {
- HeaderSettings.LiftSpeed = Math.Round(value / 60.0, 2);
- base.LiftSpeed = value;
- }
+ set => base.LiftSpeed = (float) (HeaderSettings.LiftSpeed = Math.Round(value / 60.0, 2));
}
public override float RetractSpeed
{
get => (float)Math.Round(HeaderSettings.RetractSpeed * 60.0, 2);
- set
- {
- HeaderSettings.RetractSpeed = (float) Math.Round(value / 60.0, 2);
- base.RetractSpeed = value;
- }
+ set => base.RetractSpeed = (float) (HeaderSettings.RetractSpeed = (float) Math.Round(value / 60.0, 2));
}
public override float BottomLightOffDelay => LightOffDelay;
@@ -365,14 +388,14 @@ namespace UVtools.Core.FileFormats
int index = 0;
for (int i = 0; i < imageLength; i+=3)
{
+ byte r = span[i + 2]; // 60
+ byte g = span[i + 1];
byte b = span[i];
- byte g = span[i+1];
- byte r = span[i+2];
- ushort rgb15 = (ushort) (((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 0));
+ ushort color = (ushort)(((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3));
- bytes[index++] = (byte) (rgb15 >> 8);
- bytes[index++] = (byte) (rgb15 & 0xff);
+ bytes[index++] = (byte)color;
+ bytes[index++] = (byte)(color >> 8);
}
if (index != bytes.Length)
@@ -383,41 +406,62 @@ namespace UVtools.Core.FileFormats
return bytes;
}
+ public unsafe Mat PreviewDecode(byte[] data)
+ {
+ Mat mat = new((int)HeaderSettings.PreviewResolutionY, (int)HeaderSettings.PreviewResolutionX, DepthType.Cv8U, 3);
+ var span = mat.GetBytePointer();
+ int spanIndex = 0;
+ for (int i = 0; i < data.Length; i += 2)
+ {
+ ushort color16 = BitExtensions.ToUShortLittleEndian(data[i], data[i + 1]);
+
+ //var r = (byte)((color16 & 0x1F) << 3);
+ //var g = (byte)(((color16 >> 5) & 0x3F) << 2);
+ //var b = (byte)(((color16 >> 11) & 0x1f) << 3);
+ var r = (byte)((color16 << 3) & 0xF8); // Mask: 11111000
+ var g = (byte)((color16 >> 3) & 0xFC); // Mask: 11111100
+ var b = (byte)((color16 >> 8) & 0xF8); // Mask: 11111000
+
+ span[spanIndex++] = b;
+ span[spanIndex++] = g;
+ span[spanIndex++] = r;
+ }
+
+ return mat;
+ }
+
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
- throw new NotSupportedException("PhotonS is read-only format, please use pws instead!");
+ //throw new NotSupportedException("PhotonS is read-only format, please use pws instead!");
//uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
- using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
- {
- outputFile.WriteSerialize(HeaderSettings);
- outputFile.WriteBytes(PreviewEncode(Thumbnails[0]));
- LayerSettings.LayerCount = LayerCount;
- outputFile.WriteSerialize(LayerSettings);
+ using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
+ outputFile.WriteSerialize(HeaderSettings);
+ outputFile.WriteBytes(PreviewEncode(Thumbnails[0]));
+ outputFile.WriteSerialize(LayerSettings);
- LayerData[] layerData = new LayerData[LayerCount];
+ var layerData = new LayerData[LayerCount];
- Parallel.For(0, LayerCount, layerIndex =>
+ Parallel.For(0, LayerCount, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
{
- if (progress.Token.IsCancellationRequested) return;
- using (var mat = this[layerIndex].LayerMat)
- {
- layerData[layerIndex] = new LayerData();
- layerData[layerIndex].Encode(mat);
- }
+ layerData[layerIndex] = new LayerData();
+ layerData[layerIndex].Encode(mat);
+ }
- progress.LockAndIncrement();
- });
+ progress.LockAndIncrement();
+ });
- progress.ItemName = "Saving layers";
- progress.ProcessedItems = 0;
+ progress.ItemName = "Saving layers";
+ progress.ProcessedItems = 0;
- for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
- {
- progress.Token.ThrowIfCancellationRequested();
- outputFile.WriteSerialize(layerData[layerIndex]);
- outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
- progress++;
- }
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ outputFile.WriteSerialize(layerData[layerIndex]);
+ outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
+ progress++;
}
Debug.WriteLine("Encode Results:");
@@ -425,84 +469,57 @@ namespace UVtools.Core.FileFormats
Debug.WriteLine("-End-");
}
- public unsafe Mat PreviewDecode(byte []data)
- {
- Mat mat = new Mat((int) HeaderSettings.PreviewResolutionX, (int)HeaderSettings.PreviewResolutionY, DepthType.Cv8U, 3);
- var span = mat.GetBytePointer();
- int spanIndex = 0;
- for (int i = 0; i < data.Length; i+=2)
- {
- ushort color16 = (ushort)(data[i] + (data[i + 1] << 8));
-
- var r = (color16 >> 11) & 0x1F;
- var g = (color16 >> 5) & 0x3F;
- var b = (color16 >> 0) & 0x1F;
-
- /*span[spanIndex++] = (byte)(b << 3);
- span[spanIndex++] = (byte)(g << 2);
- span[spanIndex++] = (byte)(r << 3);*/
-
- span[spanIndex++] = (byte)((b << 3) | (b & 0x7));
- span[spanIndex++] = (byte)((g << 2) | (g & 0x3));
- span[spanIndex++] = (byte)((r << 3) | (r & 0x7));
- }
-
- return mat;
- }
-
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
- using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
+ using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read);
+ HeaderSettings = Helpers.Deserialize<Header>(inputFile);
+ if (HeaderSettings.Tag1 != Header.TAG1 || HeaderSettings.Tag2 != Header.TAG2)
{
- HeaderSettings = Helpers.Deserialize<Header>(inputFile);
- if (HeaderSettings.Tag1 != Header.TAG1 || HeaderSettings.Tag2 != Header.TAG2)
- {
- throw new FileLoadException("Not a valid PHOTONS file! TAGs doesn't match", fileFullPath);
- }
+ throw new FileLoadException("Not a valid PHOTONS file! TAGs doesn't match", fileFullPath);
+ }
- int previewSize = (int) (HeaderSettings.PreviewResolutionX * HeaderSettings.PreviewResolutionY * 2);
- byte[] previewData = new byte[previewSize];
+ int previewSize = (int) (HeaderSettings.PreviewResolutionX * HeaderSettings.PreviewResolutionY * 2);
+ byte[] previewData = new byte[previewSize];
- uint currentOffset = (uint) Helpers.Serializer.SizeOf(HeaderSettings);
- currentOffset += inputFile.ReadBytes(previewData);
- Thumbnails[0] = PreviewDecode(previewData);
+ uint currentOffset = (uint) Helpers.Serializer.SizeOf(HeaderSettings);
+ currentOffset += inputFile.ReadBytes(previewData);
+ Thumbnails[0] = PreviewDecode(previewData);
- LayerSettings = Helpers.Deserialize<LayerHeader>(inputFile);
- currentOffset += (uint)Helpers.Serializer.SizeOf(LayerSettings);
+ LayerSettings = Helpers.Deserialize<LayerHeader>(inputFile);
+ currentOffset += (uint)Helpers.Serializer.SizeOf(LayerSettings);
- Debug.WriteLine(HeaderSettings);
- Debug.WriteLine(LayerSettings);
+ Debug.WriteLine(HeaderSettings);
+ Debug.WriteLine(LayerSettings);
- LayerData[] layerData = new LayerData[LayerSettings.LayerCount];
- progress.Reset(OperationProgress.StatusGatherLayers, LayerSettings.LayerCount);
+ var layerData = new LayerData[LayerSettings.LayerCount];
+ progress.Reset(OperationProgress.StatusGatherLayers, LayerSettings.LayerCount);
- for (int layerIndex = 0; layerIndex < LayerSettings.LayerCount; layerIndex++)
- {
- progress.Token.ThrowIfCancellationRequested();
- layerData[layerIndex] = Helpers.Deserialize<LayerData>(inputFile);
- layerData[layerIndex].EncodedRle = new byte[layerData[layerIndex].RleDataSize];
- currentOffset += inputFile.ReadBytes(layerData[layerIndex].EncodedRle);
- Debug.WriteLine($"Layer {layerIndex} -> {layerData[layerIndex]}");
- }
+ for (int layerIndex = 0; layerIndex < LayerSettings.LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ layerData[layerIndex] = Helpers.Deserialize<LayerData>(inputFile);
+ layerData[layerIndex].EncodedRle = new byte[layerData[layerIndex].RleDataSize];
+ currentOffset += inputFile.ReadBytes(layerData[layerIndex].EncodedRle);
+ Debug.WriteLine($"Layer {layerIndex} -> {layerData[layerIndex]}");
+ }
- LayerManager.Init(LayerSettings.LayerCount);
- progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ LayerManager.Init(LayerSettings.LayerCount);
+ progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
- Parallel.For(0, LayerCount,
- //new ParallelOptions{MaxDegreeOfParallelism = 1},
- layerIndex =>
+ Parallel.For(0, LayerCount,
+ //new ParallelOptions{MaxDegreeOfParallelism = 1},
+ layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var image = layerData[layerIndex].Decode();
- this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
+ this[layerIndex] = new Layer((uint) layerIndex, image, this);
progress.LockAndIncrement();
});
- LayerManager.RebuildLayersProperties();
- }
+ LayerManager.RebuildLayersProperties();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
@@ -524,12 +541,9 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
- using (var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write))
- {
-
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- }
+ using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
}
#endregion
diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
index 4fbe61f..abff762 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -423,16 +423,16 @@ namespace UVtools.Core.FileFormats
public unsafe Mat Decode(bool consumeData = true)
{
- Mat image = new Mat(new Size((int) Width, (int) Height), DepthType.Cv8U, 3);
+ Mat image = new(new Size((int) Width, (int) Height), DepthType.Cv8U, 3);
var span = image.GetBytePointer();
int pixel = 0;
for (uint i = 0; i < Data.Length; i += 2)
{
- ushort color16 = (ushort)(Data[i] + (Data[i+1] << 8));
- var r =(color16 >> 11) & 0x1f;
- var g = (color16 >> 5) & 0x3f;
- var b = (color16 >> 0) & 0x1f;
+ ushort color16 = BitExtensions.ToUShortLittleEndian(Data[i], Data[i+1]);
+ byte r = (byte)((color16 >> 11) & 0x1f);
+ byte g = (byte)((color16 >> 5) & 0x3f);
+ byte b = (byte)((color16 >> 0) & 0x1f);
span[pixel++] = (byte) ((b << 3) | (b & 0x7));
span[pixel++] = (byte) ((g << 2) | (g & 0x3));
@@ -456,9 +456,9 @@ namespace UVtools.Core.FileFormats
for (int pixel = 0; pixel < imageLength; pixel += image.NumberOfChannels)
{
// BGR
- int b = span[pixel] >> 3;
- int g = span[pixel+1] >> 2;
- int r = span[pixel+2] >> 3;
+ byte b = (byte)(span[pixel] >> 3);
+ byte g = (byte)(span[pixel+1] >> 2);
+ byte r = (byte)(span[pixel+2] >> 3);
ushort color = (ushort) ((r << 11) | (g << 5) | (b << 0));
@@ -699,19 +699,21 @@ namespace UVtools.Core.FileFormats
case 0x0:
color = 0x00;
index++;
- reps = reps * 256 + EncodedRle[index];
+ //reps = reps * 256 + EncodedRle[index];
+ reps = (reps << 8) + EncodedRle[index];
break;
case 0xf:
color = 0xff;
index++;
- reps = reps * 256 + EncodedRle[index];
+ //reps = reps * 256 + EncodedRle[index];
+ reps = (reps << 8) + EncodedRle[index];
break;
default:
color = (byte) ((code << 4) | code);
break;
}
- color &= 0xff;
+ //color &= 0xff;
// We only need to set the non-zero pixels
if (color != 0)
diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs
index 5dfa02c..5dc0e6b 100644
--- a/UVtools.Core/FileFormats/VDTFile.cs
+++ b/UVtools.Core/FileFormats/VDTFile.cs
@@ -82,6 +82,7 @@ namespace UVtools.Core.FileFormats
[JsonProperty("resolution_y")] public ushort ResolutionY { get; set; }
[JsonProperty("x_mirror")] public bool XMirror { get; set; }
[JsonProperty("y_mirror")] public bool YMirror { get; set; }
+ [JsonProperty("notes")] public string Notes { get; set; }
}
public sealed class VDTResin
@@ -89,6 +90,7 @@ namespace UVtools.Core.FileFormats
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("cost")] public float Cost { get; set; }
[JsonProperty("density")] public float Density { get; set; } = 1;
+ [JsonProperty("notes")] public string Notes { get; set; }
}
public sealed class VDTPrint
@@ -513,6 +515,48 @@ namespace UVtools.Core.FileFormats
//Decode(FileFullPath, progress);
}
+
+ public T LookupCustomValue<T>(string name, T defaultValue, bool existsOnly = false)
+ {
+ //if (string.IsNullOrEmpty(PrinterSettings.PrinterNotes)) return defaultValue;
+ var result = string.Empty;
+ if (!existsOnly) name += '_';
+
+ foreach (var notes in new[] { ManifestFile.Machine.Notes })
+ {
+ if (string.IsNullOrWhiteSpace(notes)) continue;
+
+ var lines = notes.Split(new[] { "\\r\\n", "\\r", "\\n" }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+
+ foreach (var line in lines)
+ {
+ if (!line.StartsWith(name)) continue;
+ if (existsOnly || line == name) return "true".Convert<T>();
+ var value = line.Remove(0, name.Length);
+ foreach (var c in value)
+ {
+ if (typeof(T) == typeof(string))
+ {
+ if (char.IsWhiteSpace(c)) break;
+ }
+ else
+ {
+ if (!char.IsLetterOrDigit(c) && c != '.')
+ {
+ break;
+ }
+ }
+
+
+ result += c;
+ }
+ }
+
+ if (!string.IsNullOrEmpty(result)) break; // Found a candidate
+ }
+
+ return string.IsNullOrWhiteSpace(result) ? defaultValue : result.Convert<T>();
+ }
#endregion
}
}
diff --git a/UVtools.Core/Objects/StringTag.cs b/UVtools.Core/Objects/StringTag.cs
deleted file mode 100644
index edaea6f..0000000
--- a/UVtools.Core/Objects/StringTag.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * GNU AFFERO GENERAL PUBLIC LICENSE
- * Version 3, 19 November 2007
- * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
- * Everyone is permitted to copy and distribute verbatim copies
- * of this license document, but changing it is not allowed.
- */
-
-using System;
-using System.Collections.Generic;
-
-namespace UVtools.Core.Objects
-{
- public class StringTag : BindableBase, IEquatable<StringTag>, IComparable<StringTag>
- {
- private string _content;
- private object _tag;
-
- public string Content
- {
- get => _content;
- set => RaiseAndSetIfChanged(ref _content, value);
- }
-
- public object Tag
- {
- get => _tag;
- set => RaiseAndSetIfChanged(ref _tag, value);
- }
-
- public string TagString
- {
- get => Tag?.ToString();
- set => Tag = value;
- }
-
- public StringTag(object content, object tag = null)
- {
- Content = content.ToString();
- Tag = tag;
- }
- public StringTag(string content, object tag = null)
- {
- Content = content;
- Tag = tag;
- }
-
- public bool Equals(StringTag other)
- {
- return _content == other._content && Equals(_tag, other._tag);
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((StringTag) obj);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- return ((_content != null ? _content.GetHashCode() : 0) * 397) ^ (_tag != null ? _tag.GetHashCode() : 0);
- }
- }
-
- private sealed class ContentEqualityComparer : IEqualityComparer<StringTag>
- {
- public bool Equals(StringTag x, StringTag y)
- {
- if (ReferenceEquals(x, y)) return true;
- if (ReferenceEquals(x, null)) return false;
- if (ReferenceEquals(y, null)) return false;
- if (x.GetType() != y.GetType()) return false;
- return x.Content == y.Content;
- }
-
- public int GetHashCode(StringTag obj)
- {
- return (obj.Content != null ? obj.Content.GetHashCode() : 0);
- }
- }
-
- public static IEqualityComparer<StringTag> ContentComparer { get; } = new ContentEqualityComparer();
-
- public int CompareTo(StringTag other)
- {
- if (ReferenceEquals(this, other)) return 0;
- if (ReferenceEquals(null, other)) return 1;
- return string.Compare(Content, other.Content, StringComparison.Ordinal);
- }
-
- public override string ToString()
- {
- return Content;
- }
- }
-}
diff --git a/UVtools.Core/Objects/ValueDescription.cs b/UVtools.Core/Objects/ValueDescription.cs
new file mode 100644
index 0000000..3f7372c
--- /dev/null
+++ b/UVtools.Core/Objects/ValueDescription.cs
@@ -0,0 +1,73 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace UVtools.Core.Objects
+{
+ public class ValueDescription : BindableBase, IEquatable<ValueDescription>
+ {
+ private object _value;
+ private string _description;
+
+ public object Value
+ {
+ get => _value;
+ set => RaiseAndSetIfChanged(ref _value, value);
+ }
+
+ public string Description
+ {
+ get => _description;
+ set => RaiseAndSetIfChanged(ref _description, value);
+ }
+
+ public string ValueAsString
+ {
+ get => Value?.ToString();
+ set => Value = value;
+ }
+
+ public ValueDescription(object value, string description = null)
+ {
+ Value = value;
+ Description = description;
+ }
+ public ValueDescription(object value, object description = null)
+ {
+ Value = value;
+ Description = description?.ToString();
+ }
+
+ public bool Equals(ValueDescription other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(_value, other._value) && _description == other._description;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((ValueDescription) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_value, _description);
+ }
+
+ public override string ToString()
+ {
+ return Description;
+ }
+ }
+}
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index ed65ac8..c803177 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
@@ -68,42 +69,30 @@ namespace UVtools.Core.Operations
#region Enums
public enum BlurAlgorithm
{
+ [Description("Blur: Normalized box filter")]
Blur,
+ [Description("Pyramid: Down/up-sampling step of Gaussian pyramid decomposition")]
Pyramid,
+ [Description("Median Blur: Each pixel becomes the median of its surrounding pixels")]
MedianBlur,
+ [Description("Gaussian Blur: Each pixel is a sum of fractions of each pixel in its neighborhood")]
GaussianBlur,
+ [Description("Filter 2D: Applies an arbitrary linear filter to an image")]
Filter2D
}
#endregion
#region Properties
- public static StringTag[] BlurTypes => new[]
- {
- new StringTag("Blur: Normalized box filter", BlurAlgorithm.Blur),
- new StringTag("Pyramid: Down/up-sampling step of Gaussian pyramid decomposition", BlurAlgorithm.Pyramid),
- new StringTag("Median Blur: Each pixel becomes the median of its surrounding pixels", BlurAlgorithm.MedianBlur),
- new StringTag("Gaussian Blur: Each pixel is a sum of fractions of each pixel in its neighborhood", BlurAlgorithm.GaussianBlur),
- new StringTag("Filter 2D: Applies an arbitrary linear filter to an image", BlurAlgorithm.Filter2D),
- };
-
- public byte BlurTypeIndex
- {
- get
- {
- for (byte i = 0; i < BlurTypes.Length; i++)
- {
- if ((BlurAlgorithm)BlurTypes[i].Tag == BlurOperation) return i;
- }
-
- return 0;
- }
- }
-
public BlurAlgorithm BlurOperation
{
get => _blurOperation;
- set => RaiseAndSetIfChanged(ref _blurOperation, value);
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _blurOperation, value)) return;
+ RaisePropertyChanged(nameof(IsSizeEnabled));
+ RaisePropertyChanged(nameof(IsKernelVisible));
+ }
}
public uint Size
@@ -112,8 +101,13 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _size, value);
}
+ public bool IsSizeEnabled => BlurOperation != BlurAlgorithm.Pyramid &&
+ BlurOperation != BlurAlgorithm.Filter2D;
+
+ public bool IsKernelVisible => BlurOperation == BlurAlgorithm.Filter2D;
+
[XmlIgnore]
- public Kernel Kernel { get; set; } = new Kernel();
+ public Kernel Kernel { get; set; } = new ();
public override string ToString()
{
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index fb69546..367e725 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -46,7 +46,7 @@ namespace UVtools.Core.Operations
private bool _extendBeyondLayerCount = true;
private bool _discardUnmodifiedLayers;
private ushort _stackMargin = 50;
- private ObservableCollection<StringTag> _files = new();
+ private ObservableCollection<ValueDescription> _files = new();
#endregion
#region Overrides
@@ -161,7 +161,7 @@ namespace UVtools.Core.Operations
}
[XmlIgnore]
- public ObservableCollection<StringTag> Files
+ public ObservableCollection<ValueDescription> Files
{
get => _files;
set => RaiseAndSetIfChanged(ref _files, value);
@@ -183,13 +183,13 @@ namespace UVtools.Core.Operations
public void AddFile(string file)
{
- Files.Add(new StringTag(Path.GetFileNameWithoutExtension(file), file));
+ Files.Add(new ValueDescription(file, Path.GetFileNameWithoutExtension(file)));
}
public void Sort()
{
var sortedFiles = Files.ToList();
- sortedFiles.Sort((file1, file2) => string.Compare(Path.GetFileNameWithoutExtension(file1.TagString), Path.GetFileNameWithoutExtension(file2.TagString), StringComparison.Ordinal));
+ sortedFiles.Sort((file1, file2) => string.Compare(Path.GetFileNameWithoutExtension(file1.ValueAsString), Path.GetFileNameWithoutExtension(file2.ValueAsString), StringComparison.Ordinal));
Files.Clear();
foreach (var file in sortedFiles)
{
@@ -232,12 +232,12 @@ namespace UVtools.Core.Operations
// Order raw images
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;
- keyImage.Add(new KeyValuePair<uint, string>((uint)keyImage.Count, Files[i].TagString));
+ if (!Files[i].ValueAsString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].ValueAsString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].ValueAsString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].ValueAsString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].ValueAsString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue;
+ keyImage.Add(new KeyValuePair<uint, string>((uint)keyImage.Count, Files[i].ValueAsString));
}
// Create virtual file format with images
@@ -264,15 +264,15 @@ namespace UVtools.Core.Operations
// 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;
+ if (Files[i].ValueAsString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].ValueAsString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].ValueAsString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].ValueAsString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].ValueAsString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue;
- var fileFormat = FileFormat.FindByExtension(Files[i].TagString, true, true);
+ var fileFormat = FileFormat.FindByExtension(Files[i].ValueAsString, true, true);
if (fileFormat is null) continue;
- fileFormat.FileFullPath = Files[i].TagString;
+ fileFormat.FileFullPath = Files[i].ValueAsString;
fileFormats.Add(fileFormat);
}
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index 6b45374..8a9d338 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -8,22 +8,35 @@
using System;
using System.Collections.Generic;
-using System.Linq;
+using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
-using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
[Serializable]
public sealed class OperationLayerReHeight : Operation
{
+ #region Enums
+
+ public enum OperationLayerReHeightAntiAliasingType : byte
+ {
+ //[Description("Hello")]
+ None,
+ [Description("Difference - Compute anti-aliasing by the layers difference and perform a down/up sample over pixels")]
+ Difference,
+ [Description("Average - Compute anti-aliasing by averaging the layers pixels")]
+ Average
+ }
+ #endregion
#region Members
- private OperationLayerReHeightItem _item;
- private bool _antiAliasing = true;
+ private OperationLayerReHeightItem _selectedItem;
+ private OperationLayerReHeightAntiAliasingType _antiAliasingType;
#endregion
@@ -38,10 +51,10 @@ namespace UVtools.Core.Operations
" than current height will reduce model detail.\n\n" +
"Note: Using dedicated slicer software to re-slice will usually yeild better results.";
public override string ConfirmationText =>
- $"adjust layer height to {Item.LayerHeight}mm?";
+ $"adjust layer height to {SelectedItem.LayerHeight}mm?";
public override string ProgressTitle =>
- $"Adjusting layer height to {Item.LayerHeight}mm";
+ $"Adjusting layer height to {SelectedItem.LayerHeight}mm";
public override string ProgressAction => "Height adjusted layers";
@@ -51,7 +64,7 @@ namespace UVtools.Core.Operations
{
var sb = new StringBuilder();
- if (Item is null)
+ if (SelectedItem is null)
{
sb.AppendLine("No valid configurations, unable to proceed.");
}
@@ -62,7 +75,7 @@ namespace UVtools.Core.Operations
public override string ToString()
{
- var result = $"[Layer Count: {Item.LayerCount}] [Layer Height: {Item.LayerHeight}]" + LayerRangeString;
+ var result = $"[Layer Count: {SelectedItem.LayerCount}] [Layer Height: {SelectedItem.LayerHeight}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -70,22 +83,24 @@ namespace UVtools.Core.Operations
#region Properties
- public OperationLayerReHeightItem Item
+ public OperationLayerReHeightItem[] Presets { get; }
+
+ public OperationLayerReHeightItem SelectedItem
{
- get => _item;
+ get => _selectedItem;
set
{
- if(!RaiseAndSetIfChanged(ref _item, value)) return;
- RaisePropertyChanged(nameof(AntiAliasing));
+ if(!RaiseAndSetIfChanged(ref _selectedItem, value)) return;
+ RaisePropertyChanged(nameof(CanAntiAliasing));
}
}
- public bool CanAntiAliasing => _item?.IsMultiply ?? false;
+ public bool CanAntiAliasing => _selectedItem?.IsMultiply ?? false;
- public bool AntiAliasing
+ public OperationLayerReHeightAntiAliasingType AntiAliasingType
{
- get => _antiAliasing;
- set => RaiseAndSetIfChanged(ref _antiAliasing, value);
+ get => _antiAliasingType;
+ set => RaiseAndSetIfChanged(ref _antiAliasingType, value);
}
@@ -120,7 +135,14 @@ namespace UVtools.Core.Operations
public OperationLayerReHeight() { }
- public OperationLayerReHeight(FileFormat slicerFile) : base(slicerFile) { }
+ public OperationLayerReHeight(FileFormat slicerFile) : base(slicerFile)
+ {
+ Presets = GetItems(slicerFile.LayerCount, (decimal) slicerFile.LayerHeight);
+ if (Presets is not null && Presets.Length > 0)
+ {
+ _selectedItem = Presets[0];
+ }
+ }
#endregion
@@ -151,11 +173,11 @@ namespace UVtools.Core.Operations
#region Methods
protected override bool ExecuteInternally(OperationProgress progress)
{
- progress.ItemCount = _item.LayerCount;
+ progress.ItemCount = _selectedItem.LayerCount;
- var layers = new Layer[_item.LayerCount];
+ var layers = new Layer[_selectedItem.LayerCount];
- if (_item.IsDivision)
+ if (_selectedItem.IsDivision)
{
uint newLayerIndex = 0;
for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
@@ -163,7 +185,7 @@ namespace UVtools.Core.Operations
progress.Token.ThrowIfCancellationRequested();
var oldLayer = SlicerFile[layerIndex];
- for (byte i = 0; i < _item.Modifier; i++)
+ for (byte i = 0; i < _selectedItem.Modifier; i++)
{
var newLayer = oldLayer.Clone();
//newLayer.Index = newLayerIndex;
@@ -176,48 +198,90 @@ namespace UVtools.Core.Operations
}
else
{
- var layerIndexes = new uint[SlicerFile.LayerCount / _item.Modifier];
+ var layerIndexes = new uint[SlicerFile.LayerCount / _selectedItem.Modifier];
for (uint i = 0; i < layerIndexes.Length; i++)
{
- layerIndexes[i] = i * _item.Modifier;
+ layerIndexes[i] = i * _selectedItem.Modifier;
}
Parallel.ForEach(layerIndexes, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
var oldLayer = SlicerFile[layerIndex];
- using var mat = oldLayer.LayerMat;
- using var original = mat.Clone();
+ using var matSum = oldLayer.LayerMat;
+ Mat matXorSum = null;
+ using Mat aaAverageSum = new();
+
+ if (_antiAliasingType == OperationLayerReHeightAntiAliasingType.Average)
+ {
+ matSum.ConvertTo(aaAverageSum, DepthType.Cv16U);
+ }
- for (byte i = 1; i < Item.Modifier; i++)
+ for (byte i = 1; i < SelectedItem.Modifier; i++)
{
using var nextMat = SlicerFile[layerIndex+i].LayerMat;
- CvInvoke.Add(mat, nextMat, mat);
+
+ switch (_antiAliasingType)
+ {
+ case OperationLayerReHeightAntiAliasingType.None:
+ CvInvoke.Add(matSum, nextMat, matSum);
+ break;
+ case OperationLayerReHeightAntiAliasingType.Difference:
+ {
+ using var previousMat = SlicerFile[layerIndex + i - 1].LayerMat;
+ var matXor = new Mat();
+ //CvInvoke.Threshold(previousMat, previousMat, 127, 255, ThresholdType.Binary);
+ //CvInvoke.Threshold(nextMat, nextMat, 127, 255, ThresholdType.Binary);
+ CvInvoke.BitwiseXor(previousMat, nextMat, matXor);
+ matXor.SetTo(new MCvScalar((byte)(byte.MaxValue / _selectedItem.Modifier)), matXor);
+ if (matXorSum is null)
+ {
+ matXorSum = matXor.Clone();
+ }
+ else
+ {
+ CvInvoke.Add(matXorSum, matXorSum, matXorSum);
+ CvInvoke.Add(matXorSum, matXor, matXorSum);
+ }
+ break;
+ }
+ case OperationLayerReHeightAntiAliasingType.Average:
+ nextMat.ConvertTo(nextMat, DepthType.Cv16U);
+ CvInvoke.Add(aaAverageSum, nextMat, aaAverageSum);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
}
- /*if (_antiAliasing)
+ switch (_antiAliasingType)
{
- CvInvoke.Subtract(mat, original, mat);
- CvInvoke.PyrDown(mat, mat);
- CvInvoke.PyrUp(mat, mat);
- CvInvoke.Add(original, mat, mat);
- }*/
+ case OperationLayerReHeightAntiAliasingType.Difference:
+ CvInvoke.Add(matSum, matXorSum, matSum);
+ CvInvoke.PyrDown(matSum, matSum);
+ CvInvoke.PyrUp(matSum, matSum);
+ matXorSum.Dispose();
+ break;
+ case OperationLayerReHeightAntiAliasingType.Average:
+ aaAverageSum.ConvertTo(matSum, DepthType.Cv8U, 1.0 / _selectedItem.Modifier);
+ CvInvoke.PyrDown(matSum, matSum);
+ CvInvoke.PyrUp(matSum, matSum);
+ break;
+ }
var newLayer = oldLayer.Clone();
//newLayer.Index = newLayerIndex;
//newLayer.PositionZ = (float)(Item.LayerHeight * (newLayerIndex + 1));
- newLayer.LayerMat = mat;
- layers[layerIndex / _item.Modifier] = newLayer;
+ newLayer.LayerMat = matSum;
+ layers[layerIndex / _selectedItem.Modifier] = newLayer;
progress.LockAndIncrement();
});
-
-
}
-
+ progress.Token.ThrowIfCancellationRequested();
- SlicerFile.LayerHeight = (float)Item.LayerHeight;
+ SlicerFile.LayerHeight = (float)SelectedItem.LayerHeight;
SlicerFile.LayerManager.Layers = layers;
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationMorph.cs b/UVtools.Core/Operations/OperationMorph.cs
index c3120cf..f2c6804 100644
--- a/UVtools.Core/Operations/OperationMorph.cs
+++ b/UVtools.Core/Operations/OperationMorph.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.ComponentModel;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
@@ -19,8 +20,28 @@ namespace UVtools.Core.Operations
[Serializable]
public sealed class OperationMorph : Operation
{
+ #region Enums
+ public enum MorphOperations
+ {
+ [Description("Erode: Contracts the boundaries within the object")]
+ Erode = MorphOp.Erode,
+
+ [Description("Dilate: Expands the boundaries within the object")]
+ Dilate = MorphOp.Dilate,
+
+ [Description("Gap Closing - Closes small holes inside the objects")]
+ Close = MorphOp.Close,
+
+ [Description("Noise Removal - Removes small isolated pixels")]
+ Open = MorphOp.Open,
+
+ [Description("Gradient - Removes the interior areas of objects")]
+ Gradient = MorphOp.Gradient,
+ }
+ #endregion
+
#region Members
- private MorphOp _morphOperation = MorphOp.Erode;
+ private MorphOperations _morphOperation = MorphOperations.Erode;
private uint _iterationsStart = 1;
private uint _iterationsEnd = 1;
private bool _chamfer;
@@ -43,31 +64,7 @@ namespace UVtools.Core.Operations
#endregion
#region Properties
-
-
- public static StringTag[] MorphOperations => new[]
- {
- new StringTag("Erode - Contracts the boundaries within the object", MorphOp.Erode),
- new StringTag("Dilate - Expands the boundaries within the object", MorphOp.Dilate),
- new StringTag("Gap Closing - Closes small holes inside the objects", MorphOp.Close),
- new StringTag("Noise Removal - Removes small isolated pixels", MorphOp.Open),
- new StringTag("Gradient - Removes the interior areas of objects", MorphOp.Gradient),
- };
-
- public byte MorphOperationIndex
- {
- get
- {
- for (byte i = 0; i < MorphOperations.Length; i++)
- {
- if ((MorphOp) MorphOperations[i].Tag == MorphOperation) return i;
- }
-
- return 0;
- }
- }
-
- public MorphOp MorphOperation
+ public MorphOperations MorphOperation
{
get => _morphOperation;
set => RaiseAndSetIfChanged(ref _morphOperation, value);
@@ -185,7 +182,7 @@ namespace UVtools.Core.Operations
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
- CvInvoke.MorphologyEx(target, target, MorphOperation, Kernel.Matrix, Kernel.Anchor, iterations, BorderType.Reflect101, default);
+ CvInvoke.MorphologyEx(target, target, (MorphOp) MorphOperation, Kernel.Matrix, Kernel.Anchor, iterations, BorderType.Reflect101, default);
ApplyMask(original, mat);
return true;
}
diff --git a/UVtools.Core/Operations/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs
index 0da2586..1771536 100644
--- a/UVtools.Core/Operations/OperationProgress.cs
+++ b/UVtools.Core/Operations/OperationProgress.cs
@@ -34,7 +34,7 @@ namespace UVtools.Core.Operations
public readonly object Mutex = new();
- public CancellationTokenSource TokenSource { get; } = new();
+ public CancellationTokenSource TokenSource { get; private set; }
public CancellationToken Token => TokenSource.Token;
private bool _canCancel = true;
@@ -47,14 +47,15 @@ namespace UVtools.Core.Operations
public
OperationProgress()
{
+ Init();
}
- public OperationProgress(string name, uint value = 0)
+ public OperationProgress(string name, uint value = 0) : this()
{
Reset(name, value);
}
- public OperationProgress(bool canCancel)
+ public OperationProgress(bool canCancel) : this()
{
_canCancel = canCancel;
}
@@ -164,6 +165,18 @@ namespace UVtools.Core.Operations
return progress;
}
+ public void Init(bool canCancel = true)
+ {
+ CanCancel = canCancel;
+ Title = "Operation";
+ ItemName = "Initializing";
+ ItemCount = 0;
+ ProcessedItems = 0;
+
+ TokenSource = new();
+ RaisePropertyChanged(nameof(CanCancel));
+ }
+
public void Reset(string name = "", uint itemCount = 0, uint items = 0)
{
ItemName = name;
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 63a0232..f3e2fba 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
- <Version>2.9.0</Version>
+ <Version>2.9.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.ScriptSample/ScriptAutomateWorkflowSample.cs b/UVtools.ScriptSample/ScriptAutomateWorkflowSample.cs
index ea9b5fa..8ec2695 100644
--- a/UVtools.ScriptSample/ScriptAutomateWorkflowSample.cs
+++ b/UVtools.ScriptSample/ScriptAutomateWorkflowSample.cs
@@ -73,7 +73,7 @@ namespace UVtools.ScriptSample
{
OperationMorph morph = new(SlicerFile)
{
- MorphOperation = MorphOp.Erode,
+ MorphOperation = OperationMorph.MorphOperations.Erode,
Iterations = 4,
};
morph.SelectBottomLayers();
diff --git a/UVtools.WPF/App.axaml b/UVtools.WPF/App.axaml
index ede140d..6a486e4 100644
--- a/UVtools.WPF/App.axaml
+++ b/UVtools.WPF/App.axaml
@@ -1,6 +1,11 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:converters="clr-namespace:UVtools.WPF.Converters"
x:Class="UVtools.WPF.App">
+ <Application.Resources>
+ <converters:EnumToCollectionConverter x:Key="EnumToCollectionConverter" />
+ <converters:FromValueDescriptionToEnumConverter x:Key="FromValueDescriptionToEnumConverter" />
+ </Application.Resources>
<Application.Styles>
<FluentTheme Mode="Light"/>
<StyleInclude Source="avares://ThemeEditor.Controls.ColorPicker/ColorPicker.axaml"/>
diff --git a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml
index e37b992..e2f466b 100644
--- a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml
@@ -17,16 +17,15 @@
<ComboBox
Grid.Column="2"
HorizontalAlignment="Left"
- SelectedIndex="{Binding SelectedAlgorithmIndex}"
Width="450"
HorizontalContentAlignment="Stretch"
- Items="{Binding Operation.BlurTypes}"
- />
+ Items="{Binding Operation.BlurOperation, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
+ SelectedItem="{Binding Operation.BlurOperation, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
<TextBlock
VerticalAlignment="Center"
Grid.Row="2"
- IsEnabled="{Binding IsSizeEnabled}"
+ IsEnabled="{Binding Operation.IsSizeEnabled}"
Text="Size:"/>
<NumericUpDown
Grid.Row="2"
@@ -34,15 +33,13 @@
HorizontalAlignment="Left"
Width="150"
Minimum="1"
- IsEnabled="{Binding IsSizeEnabled}"
+ IsEnabled="{Binding Operation.IsSizeEnabled}"
Value="{Binding Operation.Size}"
/>
</Grid>
- <uc:KernelControl
- Name="KernelCtrl"
- IsVisible="{Binding $parent[UserControl].IsKernelVisible}"
- />
+ <uc:KernelControl Name="KernelCtrl"
+ IsVisible="{Binding $parent[UserControl].DataContext.Operation.IsKernelVisible}"/>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
index 89f6322..86e5c19 100644
--- a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
@@ -7,37 +7,9 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolBlurControl : ToolControl
{
- private int _selectedAlgorithmIndex;
- private bool _isSizeEnabled = true;
- private bool _isKernelVisible;
private KernelControl _kernelCtrl;
public OperationBlur Operation => BaseOperation as OperationBlur;
- public int SelectedAlgorithmIndex
- {
- get => _selectedAlgorithmIndex;
- set
- {
- if(!RaiseAndSetIfChanged(ref _selectedAlgorithmIndex, value) || value < 0) return;
- Operation.BlurOperation = (OperationBlur.BlurAlgorithm) OperationBlur.BlurTypes[_selectedAlgorithmIndex].Tag;
- IsKernelVisible = Operation.BlurOperation == OperationBlur.BlurAlgorithm.Filter2D;
- IsSizeEnabled = Operation.BlurOperation != OperationBlur.BlurAlgorithm.Pyramid &&
- Operation.BlurOperation != OperationBlur.BlurAlgorithm.Filter2D;
- }
- }
-
- public bool IsSizeEnabled
- {
- get => _isSizeEnabled;
- set => RaiseAndSetIfChanged(ref _isSizeEnabled, value);
- }
-
- public bool IsKernelVisible
- {
- get => _isKernelVisible;
- set => RaiseAndSetIfChanged(ref _isKernelVisible, value);
- }
-
public ToolBlurControl()
{
InitializeComponent();
@@ -54,17 +26,8 @@ namespace UVtools.WPF.Controls.Tools
{
Operation.Kernel.Matrix = _kernelCtrl.GetMatrix();
Operation.Kernel.Anchor = _kernelCtrl.Anchor;
- return !(Operation.Kernel.Matrix is null);
+ return Operation.Kernel.Matrix is not null;
}
- public override void Callback(ToolWindow.Callbacks callback)
- {
- switch (callback)
- {
- case ToolWindow.Callbacks.ProfileLoaded:
- SelectedAlgorithmIndex = Operation.BlurTypeIndex;
- break;
- }
- }
}
}
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
index e88db59..09dc732 100644
--- a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
@@ -80,6 +80,6 @@ namespace UVtools.WPF.Controls.Tools
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
- public async Task<bool> ValidateFormFromString(StringTag text) => await ValidateFormFromString(text?.ToString());
+ public async Task<bool> ValidateFormFromString(ValueDescription text) => await ValidateFormFromString(text?.ToString());
}
}
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
index 0fc4755..7381dd6 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
@@ -20,7 +20,7 @@ namespace UVtools.WPF.Controls.Tools
public class ToolLayerImportControl : ToolControl
{
private bool _isAutoSortLayersByFileNameChecked;
- private StringTag _selectedFile;
+ private ValueDescription _selectedFile;
private Bitmap _previewImage;
private ListBox FilesListBox;
@@ -60,7 +60,7 @@ namespace UVtools.WPF.Controls.Tools
}
- public StringTag SelectedFile
+ public ValueDescription SelectedFile
{
get => _selectedFile;
set
@@ -71,12 +71,12 @@ namespace UVtools.WPF.Controls.Tools
PreviewImage = null;
return;
}
- if (!_selectedFile.TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
- !_selectedFile.TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) &&
- !_selectedFile.TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) &&
- !_selectedFile.TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
- !_selectedFile.TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) return;
- PreviewImage = new Bitmap(_selectedFile.TagString);
+ if (!_selectedFile.ValueAsString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.ValueAsString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.ValueAsString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.ValueAsString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.ValueAsString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) return;
+ PreviewImage = new Bitmap(_selectedFile.ValueAsString);
}
}
@@ -94,8 +94,8 @@ namespace UVtools.WPF.Controls.Tools
FilesListBox = this.Find<ListBox>("FilesListBox");
FilesListBox.DoubleTapped += (sender, args) =>
{
- if (!(FilesListBox.SelectedItem is StringTag file)) return;
- App.StartProcess(file.TagString);
+ if (!(FilesListBox.SelectedItem is ValueDescription file)) return;
+ App.StartProcess(file.ValueAsString);
};
FilesListBox.KeyUp += (sender, e) =>
{
@@ -197,7 +197,7 @@ namespace UVtools.WPF.Controls.Tools
public void RemoveFiles()
{
- Operation.Files.RemoveMany(FilesListBox.SelectedItems.OfType<StringTag>());
+ Operation.Files.RemoveMany(FilesListBox.SelectedItems.OfType<ValueDescription>());
}
public void ClearFiles()
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml
index 3db4d3c..168ac75 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml
@@ -4,17 +4,28 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="UVtools.WPF.Controls.Tools.ToolLayerReHeightControl">
- <StackPanel Orientation="Vertical" Spacing="10">
+
+
+ <StackPanel Orientation="Vertical" Spacing="10">
<TextBlock VerticalAlignment="Center" Text="{Binding CurrentLayers}"/>
- <StackPanel Orientation="Horizontal" Spacing="10">
- <TextBlock VerticalAlignment="Center" Text="Modifier:"/>
- <ComboBox
- MinWidth="300"
- SelectedItem="{Binding Operation.Item}"
- Items="{Binding Presets}"
+ <Grid RowDefinitions="Auto,10,Auto"
+ ColumnDefinitions="Auto,10,Auto">
+
+ <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="Modifier:"/>
+ <ComboBox
+ Grid.Row="0" Grid.Column="2" Width="500"
+ SelectedItem="{Binding Operation.SelectedItem}"
+ Items="{Binding Operation.Presets}"
/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Text="Anti-Aliasing:"/>
+ <ComboBox Grid.Row="2" Grid.Column="2" Width="500"
+ IsEnabled="{Binding Operation.CanAntiAliasing}"
+ Items="{Binding Operation.AntiAliasingType, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
+ SelectedItem="{Binding Operation.AntiAliasingType, Converter={StaticResource FromValueDescriptionToEnumConverter}}">
+ </ComboBox>
+ </Grid>
+
</StackPanel>
-
- </StackPanel>
</UserControl>
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
index 4b6e093..8a848b9 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
@@ -8,27 +8,18 @@ namespace UVtools.WPF.Controls.Tools
{
public OperationLayerReHeight Operation => BaseOperation as OperationLayerReHeight;
- public OperationLayerReHeight.OperationLayerReHeightItem[] Presets => App.SlicerFile is null ? null : OperationLayerReHeight.GetItems(
- App.SlicerFile.LayerCount,
- (decimal)App.SlicerFile.LayerHeight);
-
public string CurrentLayers => $"Current layers: {App.SlicerFile.LayerCount} at {App.SlicerFile.LayerHeight}mm";
public ToolLayerReHeightControl()
{
InitializeComponent();
BaseOperation = new OperationLayerReHeight(SlicerFile);
- var presets = Presets;
- if (presets is null || presets.Length == 0)
+ if (Operation.SelectedItem is null)
{
App.MainWindow.MessageBoxInfo("No valid configuration to be able to re-height.\n" +
"As workaround clone first or last layer and try re run this tool.", "Not possible to re-height");
CanRun = false;
}
- else
- {
- Operation.Item = presets[0];
- }
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
index 5611261..868a47c 100644
--- a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
@@ -56,8 +56,8 @@
Grid.Row="2"
Grid.Column="2"
HorizontalAlignment="Stretch"
- SelectedIndex="{Binding MorphSelectedIndex}"
- Items="{Binding Operation.MorphOperations}"
+ Items="{Binding Operation.MorphOperation, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
+ SelectedItem="{Binding Operation.MorphOperation, Converter={StaticResource FromValueDescriptionToEnumConverter}}"
/>
</Grid>
diff --git a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
index 9d17f05..b3ca26d 100644
--- a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
@@ -1,30 +1,15 @@
-using System;
-using System.Diagnostics;
-using Avalonia.Controls;
+using Avalonia.Controls;
using Avalonia.Markup.Xaml;
-using Emgu.CV.CvEnum;
using UVtools.Core.Operations;
-using UVtools.WPF.Windows;
namespace UVtools.WPF.Controls.Tools
{
public class ToolMorphControl : ToolControl
{
- private byte _morphSelectedIndex;
public OperationMorph Operation => BaseOperation as OperationMorph;
private KernelControl _kernelCtrl;
- public byte MorphSelectedIndex
- {
- get => _morphSelectedIndex;
- set
- {
- if(!RaiseAndSetIfChanged(ref _morphSelectedIndex, value)) return;
- Operation.MorphOperation = (MorphOp)OperationMorph.MorphOperations[_morphSelectedIndex].Tag;
- }
- }
-
public ToolMorphControl()
{
InitializeComponent();
@@ -41,17 +26,7 @@ namespace UVtools.WPF.Controls.Tools
{
Operation.Kernel.Matrix = _kernelCtrl.GetMatrix();
Operation.Kernel.Anchor = _kernelCtrl.Anchor;
- return !(Operation.Kernel.Matrix is null);
- }
-
- public override void Callback(ToolWindow.Callbacks callback)
- {
- switch (callback)
- {
- case ToolWindow.Callbacks.ProfileLoaded:
- MorphSelectedIndex = Operation.MorphOperationIndex;
- break;
- }
+ return Operation.Kernel.Matrix is not null;
}
}
}
diff --git a/UVtools.WPF/Converters/EnumToCollectionConverter.cs b/UVtools.WPF/Converters/EnumToCollectionConverter.cs
new file mode 100644
index 0000000..f585f86
--- /dev/null
+++ b/UVtools.WPF/Converters/EnumToCollectionConverter.cs
@@ -0,0 +1,29 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using Avalonia.Data.Converters;
+using UVtools.Core.Extensions;
+
+namespace UVtools.WPF.Converters
+{
+ public class EnumToCollectionConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return EnumExtensions.GetAllValuesAndDescriptions(value.GetType());
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ return null;
+ //string parameterString = parameter.ToString();
+ //return Enum.Parse(targetType, parameterString);
+ }
+ }
+}
diff --git a/UVtools.WPF/Converters/FromValueDescriptionToEnumConverter.cs b/UVtools.WPF/Converters/FromValueDescriptionToEnumConverter.cs
new file mode 100644
index 0000000..e37fb58
--- /dev/null
+++ b/UVtools.WPF/Converters/FromValueDescriptionToEnumConverter.cs
@@ -0,0 +1,31 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using System.Linq;
+using Avalonia.Data.Converters;
+using UVtools.Core.Extensions;
+
+namespace UVtools.WPF.Converters
+{
+ public class FromValueDescriptionToEnumConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ var list = EnumExtensions.GetAllValuesAndDescriptions(value.GetType());
+ return list.FirstOrDefault(vd => vd.Value.Equals(value));
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ if (value is null) return null;
+ var list = EnumExtensions.GetAllValuesAndDescriptions(targetType);
+ return list.FirstOrDefault(vd => vd.Description == value.ToString())?.Value;
+ }
+ }
+}
diff --git a/UVtools.WPF/Extensions/BitmapExtension.cs b/UVtools.WPF/Extensions/BitmapExtension.cs
index 662f9d0..ae5f5ce 100644
--- a/UVtools.WPF/Extensions/BitmapExtension.cs
+++ b/UVtools.WPF/Extensions/BitmapExtension.cs
@@ -6,15 +6,12 @@
* of this license document, but changing it is not allowed.
*/
using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Emgu.CV;
using Emgu.CV.CvEnum;
using SkiaSharp;
-using UVtools.Core.Extensions;
namespace UVtools.WPF.Extensions
{
diff --git a/UVtools.WPF/MainWindow.Information.cs b/UVtools.WPF/MainWindow.Information.cs
index 3822b94..8b40065 100644
--- a/UVtools.WPF/MainWindow.Information.cs
+++ b/UVtools.WPF/MainWindow.Information.cs
@@ -31,15 +31,15 @@ namespace UVtools.WPF
{
public partial class MainWindow
{
- public ObservableCollection<SlicerProperty> SlicerProperties { get; } = new ObservableCollection<SlicerProperty>();
+ public ObservableCollection<SlicerProperty> SlicerProperties { get; } = new();
public DataGrid PropertiesGrid;
public DataGrid CurrentLayerGrid;
private uint _visibleThumbnailIndex;
private Bitmap _visibleThumbnailImage;
- private ObservableCollection<StringTag> _currentLayerProperties = new ObservableCollection<StringTag>();
+ private ObservableCollection<ValueDescription> _currentLayerProperties = new();
- public ObservableCollection<StringTag> CurrentLayerProperties
+ public ObservableCollection<ValueDescription> CurrentLayerProperties
{
get => _currentLayerProperties;
set => RaiseAndSetIfChanged(ref _currentLayerProperties, value);
@@ -336,38 +336,33 @@ namespace UVtools.WPF
var layer = LayerCache.Layer;
CurrentLayerProperties.Clear();
- CurrentLayerProperties.Add(new StringTag(nameof(layer.Index), $"{layer.Index}"));
- CurrentLayerProperties.Add(new StringTag(nameof(layer.LayerHeight), $"{Layer.ShowHeight(layer.LayerHeight)}mm"));
- //CurrentLayerProperties.Add(new KeyValuePair<string, string>(nameof(layer.Filename), layer.Filename));
- CurrentLayerProperties.Add(new StringTag(nameof(layer.PositionZ), $"{Layer.ShowHeight(layer.PositionZ)}mm"));
- CurrentLayerProperties.Add(new StringTag(nameof(layer.IsBottomLayer), layer.IsBottomLayer.ToString()));
- CurrentLayerProperties.Add(new StringTag(nameof(layer.IsModified), layer.IsModified.ToString()));
- //CurrentLayerProperties.Add(new StringTag(nameof(layer.BoundingRectangle), layer.BoundingRectangle.ToString()));
- //CurrentLayerProperties.Add(new StringTag(nameof(layer.NonZeroPixelCount), layer.NonZeroPixelCount.ToString()));
- CurrentLayerProperties.Add(new StringTag(nameof(layer.ExposureTime), $"{layer.ExposureTime:F2}s"));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.Index}", nameof(layer.Index)));
+ CurrentLayerProperties.Add(new ValueDescription($"{Layer.ShowHeight(layer.LayerHeight)}mm", nameof(layer.LayerHeight)));
+ CurrentLayerProperties.Add(new ValueDescription($"{Layer.ShowHeight(layer.PositionZ)}mm", nameof(layer.PositionZ)));
+ CurrentLayerProperties.Add(new ValueDescription(layer.IsBottomLayer.ToString(), nameof(layer.IsBottomLayer)));
+ CurrentLayerProperties.Add(new ValueDescription(layer.IsModified.ToString(), nameof(layer.IsModified)));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.ExposureTime:F2}s", nameof(layer.ExposureTime)));
if (SlicerFile.PrintParameterPerLayerModifiers is not null)
{
if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LiftHeight))
- CurrentLayerProperties.Add(new StringTag(nameof(layer.LiftHeight),
- $"{layer.LiftHeight.ToString(CultureInfo.InvariantCulture)}mm @ {layer.LiftSpeed.ToString(CultureInfo.InvariantCulture)}mm/min"));
- //CurrentLayerProperties.Adnew StringTagg>(nameof(layer.LiftSpeed), $"{layer.LiftSpeed.ToString(CultureInfo.InvariantCulture)}mm/min"));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.LiftHeight.ToString(CultureInfo.InvariantCulture)}mm @ {layer.LiftSpeed.ToString(CultureInfo.InvariantCulture)}mm/min", nameof(layer.LiftHeight)));
if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.RetractSpeed))
- CurrentLayerProperties.Add(new StringTag(nameof(layer.RetractSpeed),
- $"{layer.RetractSpeed}mm/min"));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractSpeed}mm/min",
+ nameof(layer.RetractSpeed)));
if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LightOffDelay))
- CurrentLayerProperties.Add(new StringTag(nameof(layer.LightOffDelay),
- $"{layer.LightOffDelay}s"));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.LightOffDelay}s",
+ nameof(layer.LightOffDelay)));
if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LightPWM))
- CurrentLayerProperties.Add(new StringTag(nameof(layer.LightPWM), layer.LightPWM.ToString()));
+ CurrentLayerProperties.Add(new ValueDescription(layer.LightPWM.ToString(), nameof(layer.LightPWM)));
}
var materialMillilitersPercent = layer.MaterialMillilitersPercent;
if (!float.IsNaN(materialMillilitersPercent))
{
- CurrentLayerProperties.Add(new StringTag(nameof(layer.MaterialMilliliters), $"{layer.MaterialMilliliters}ml ({materialMillilitersPercent:F2}%)"));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.MaterialMilliliters}ml ({materialMillilitersPercent:F2}%)", nameof(layer.MaterialMilliliters)));
}
}
diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs
index 669b180..4d29d55 100644
--- a/UVtools.WPF/MainWindow.Issues.cs
+++ b/UVtools.WPF/MainWindow.Issues.cs
@@ -111,20 +111,19 @@ namespace UVtools.WPF
IsGUIEnabled = false;
+ ShowProgressWindow("Removing selected issues", false);
Clipboard.Snapshot();
var task = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow("Removing selected issues");
- var progress = ProgressWindow.RestartProgress(false);
- progress.Reset("Removing selected issues", (uint)processIssues.Count);
+ Progress.Reset("Removing selected issues", (uint)processIssues.Count);
bool result = false;
try
{
Parallel.ForEach(processIssues, layerIssues =>
{
- if (progress.Token.IsCancellationRequested) return;
+ if (Progress.Token.IsCancellationRequested) return;
using (var image = SlicerFile[layerIssues.Key].LayerMat)
{
var bytes = image.GetPixelSpan<byte>();
@@ -162,7 +161,7 @@ namespace UVtools.WPF
}
}
- progress.LockAndIncrement();
+ Progress.LockAndIncrement();
});
if (layersRemove.Count > 0)
@@ -275,6 +274,7 @@ namespace UVtools.WPF
IsGUIEnabled = false;
+ ShowProgressWindow("Updating Issues");
var issueList = Issues.ToList();
@@ -291,12 +291,10 @@ namespace UVtools.WPF
var resultIssues = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow("Updating Issues");
try
{
var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig,
- touchingBoundConfig, printHeightConfig, false, IgnoredIssues,
- ProgressWindow.RestartProgress());
+ touchingBoundConfig, printHeightConfig, false, IgnoredIssues, Progress);
issues.RemoveAll(issue => issue.Type != LayerIssue.IssueType.Island && issue.Type != LayerIssue.IssueType.Overhang); // Remove all non islands and overhangs
return issues;
@@ -450,15 +448,14 @@ namespace UVtools.WPF
Issues.Clear();
IsGUIEnabled = false;
-
+ ShowProgressWindow("Computing Issues");
var resultIssues = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow("Computing Issues");
try
{
var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig, touchingBoundConfig,
- printHeightConfig, emptyLayersConfig, IgnoredIssues, ProgressWindow.RestartProgress());
+ printHeightConfig, emptyLayersConfig, IgnoredIssues, Progress);
return issues;
}
catch (OperationCanceledException)
@@ -531,6 +528,13 @@ namespace UVtools.WPF
}
}
+ public void IssuesClear(bool clearIgnored = true)
+ {
+ Issues.Clear();
+ if(clearIgnored) IgnoredIssues.Clear();
+ UpdateLayerTrackerHighlightIssues();
+ }
+
public IslandDetectionConfiguration GetIslandDetectionConfiguration(bool enable)
{
diff --git a/UVtools.WPF/MainWindow.PixelEditor.cs b/UVtools.WPF/MainWindow.PixelEditor.cs
index e7984cd..1c4f0a4 100644
--- a/UVtools.WPF/MainWindow.PixelEditor.cs
+++ b/UVtools.WPF/MainWindow.PixelEditor.cs
@@ -378,15 +378,14 @@ namespace UVtools.WPF
if (result == ButtonResult.Yes)
{
IsGUIEnabled = false;
-
+ ShowProgressWindow("Drawing pixels");
Clipboard.Snapshot();
var task = await Task.Factory.StartNew(async () =>
{
- ShowProgressWindow("Drawing pixels");
try
{
- SlicerFile.LayerManager.DrawModifications(Drawings, ProgressWindow.RestartProgress());
+ SlicerFile.LayerManager.DrawModifications(Drawings, Progress);
return true;
}
catch (OperationCanceledException)
diff --git a/UVtools.WPF/MainWindow.Progress.cs b/UVtools.WPF/MainWindow.Progress.cs
new file mode 100644
index 0000000..6f2d304
--- /dev/null
+++ b/UVtools.WPF/MainWindow.Progress.cs
@@ -0,0 +1,95 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using System.Timers;
+using Avalonia.Threading;
+using UVtools.Core.Operations;
+using UVtools.WPF.Structures;
+
+namespace UVtools.WPF
+{
+ public partial class MainWindow
+ {
+ #region Members
+ public OperationProgress Progress { get; } = new();
+ private Timer _progressTimer = new(200) { AutoReset = true };
+ private long _progressLastTotalSeconds;
+ private LogItem _progressLogItem;
+ private bool _isProgressVisible;
+
+ #endregion
+
+ #region Properties
+
+ public bool IsProgressVisible
+ {
+ get => _isProgressVisible;
+ set => RaiseAndSetIfChanged(ref _isProgressVisible, value);
+ }
+
+ #endregion
+
+ public void InitProgress()
+ {
+ _progressTimer.Elapsed += (sender, args) =>
+ {
+ var elapsedSeconds = Progress.StopWatch.ElapsedMilliseconds / 1000;
+ if (_progressLastTotalSeconds == elapsedSeconds) return;
+ /*Debug.WriteLine(StopWatch.ElapsedMilliseconds);
+ Debug.WriteLine(elapsedSeconds);
+ Debug.WriteLine(_lastTotalSeconds);*/
+ _progressLastTotalSeconds = elapsedSeconds;
+
+
+ Dispatcher.UIThread.InvokeAsync(() => Progress.TriggerRefresh(), DispatcherPriority.Render);
+
+ };
+ }
+
+ public void ProgressOnClickCancel()
+ {
+ if (!Progress.CanCancel) return;
+ DialogResult = DialogResults.Cancel;
+ Progress.CanCancel = false;
+ Progress.TokenSource.Cancel();
+ }
+
+ public void ProgressShow(string title, bool canCancel = true)
+ {
+ IsGUIEnabled = false;
+ Progress.Init(canCancel);
+ Progress.Title = title;
+ _progressLogItem = new(title);
+
+ Progress.StopWatch.Restart();
+ _progressLastTotalSeconds = 0;
+
+ if (!_progressTimer.Enabled)
+ {
+ _progressTimer.Start();
+ }
+
+ Progress.TriggerRefresh();
+
+ IsProgressVisible = true;
+
+ InvalidateVisual();
+ }
+
+ public void ProgressFinish()
+ {
+ _progressTimer.Stop();
+ Progress.StopWatch.Stop();
+ _progressLogItem.ElapsedTime = Math.Round(Progress.StopWatch.Elapsed.TotalSeconds, 2);
+ App.MainWindow.AddLog(_progressLogItem);
+ IsProgressVisible = false;
+ InvalidateVisual();
+ }
+ }
+}
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 815468f..7b2f84e 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -9,10 +9,10 @@
Icon="/Assets/Icons/UVtools.ico"
MinWidth="1024"
MinHeight="600"
- DragDrop.AllowDrop="True"
- >
-
- <DockPanel>
+ DragDrop.AllowDrop="True">
+
+ <Grid RowDefinitions="*" ColumnDefinitions="*">
+ <DockPanel Grid.Row="0" Grid.Column="0" IsEnabled="{Binding IsGUIEnabled}">
<Menu DockPanel.Dock="Top">
<MenuItem Name="MainMenu.File" Header="_File">
<MenuItem
@@ -568,10 +568,10 @@
Items="{Binding CurrentLayerProperties}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
- Binding="{Binding Content}"
+ Binding="{Binding Description}"
Width="Auto" />
<DataGridTextColumn Header="Value"
- Binding="{Binding TagString}"
+ Binding="{Binding Value}"
Width="Auto" />
</DataGrid.Columns>
@@ -1751,9 +1751,9 @@
<Grid
IsEnabled="{Binding IsFileLoaded}"
ColumnDefinitions="*" RowDefinitions="Auto,*,Auto" Margin="5">
- <Grid
- IsEnabled="{Binding IsFileLoaded}"
- ColumnDefinitions="*,Auto" RowDefinitions="Auto" Margin="5">
+ <Grid Grid.Row="0" Grid.Column="0"
+ IsEnabled="{Binding IsFileLoaded}"
+ ColumnDefinitions="*,Auto" RowDefinitions="Auto" Margin="5">
<WrapPanel HorizontalAlignment="Left" Grid.Row="0" Orientation="Horizontal">
<ToggleButton
IsChecked="{Binding ShowLayerImageRotated}"
@@ -2037,4 +2037,50 @@
</DockPanel>
+ <Grid Grid.Row="0" Grid.Column="0"
+ RowDefinitions="*,Auto,*" ColumnDefinitions="*,Auto,*"
+ IsEnabled="{Binding IsProgressVisible}"
+ IsVisible="{Binding IsProgressVisible}">
+ <Border Grid.Row="1" Grid.Column="1" MinWidth="450"
+ Background="White"
+ BorderBrush="WhiteSmoke"
+ BorderThickness="5"
+ CornerRadius="5">
+ <Grid RowDefinitions="Auto,Auto,Auto,Auto"
+ ColumnDefinitions="*">
+ <TextBlock
+ Grid.Row="0"
+ Margin="10" Text="{Binding Progress.Title}"/>
+ <TextBlock
+ Grid.Row="1"
+ Margin="10,0,10,10" Text="{Binding Progress.ElapsedTimeStr, StringFormat=Elapsed Time: \{0\}}"/>
+ <TextBlock
+ Grid.Row="2"
+ Margin="10,0,10,10" Text="{Binding Progress.Description}" HorizontalAlignment="Center"/>
+
+ <Grid
+ Grid.Row="3"
+ RowDefinitions="30" ColumnDefinitions="*,100">
+ <ProgressBar
+ Grid.Column="0"
+ Minimum="0"
+ Maximum="100"
+ VerticalAlignment="Stretch"
+ IsIndeterminate="{Binding Progress.IsIndeterminate}"
+ Value="{Binding Progress.ProgressPercent}" ShowProgressText="True"/>
+ <Button
+ IsEnabled="{Binding Progress.CanCancel}"
+ Command="{Binding ProgressOnClickCancel}"
+ Grid.Column="1"
+ IsCancel="True"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ VerticalContentAlignment="Center"
+ HorizontalContentAlignment="Center"
+ Content="Cancel"/>
+ </Grid>
+ </Grid>
+ </Border>
+ </Grid>
+ </Grid>
</uc:WindowEx>
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 8ed3006..0f2fbe8 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -48,7 +48,7 @@ namespace UVtools.WPF
#region Controls
- public ProgressWindow ProgressWindow = new ();
+ //public ProgressWindow ProgressWindow = new ();
public static MenuItem[] MenuTools { get; } =
{
@@ -328,7 +328,7 @@ namespace UVtools.WPF
#region Members
- public Stopwatch LastStopWatch = new Stopwatch();
+ public Stopwatch LastStopWatch = new();
private bool _isGUIEnabled = true;
private uint _savesCount;
@@ -352,14 +352,14 @@ namespace UVtools.WPF
if (!RaiseAndSetIfChanged(ref _isGUIEnabled, value)) return;
if (!_isGUIEnabled)
{
- ProgressWindow = new ProgressWindow();
+ //ProgressWindow = new ProgressWindow();
return;
}
- //if (ProgressWindow is null) return;
- LastStopWatch = ProgressWindow.StopWatch;
- ProgressWindow.Close();
- ProgressWindow.Dispose();
+ LastStopWatch = Progress.StopWatch;
+ ProgressFinish();
+ //ProgressWindow.Close(DialogResults.OK);
+ //ProgressWindow.Dispose();
/*if (Dispatcher.UIThread.CheckAccess())
{
ProgressWindow.Close();
@@ -441,6 +441,7 @@ namespace UVtools.WPF
InitializeComponent();
App.ThemeSelector?.EnableThemes(this);
+ InitProgress();
InitInformation();
InitIssues();
InitPixelEditor();
@@ -757,9 +758,7 @@ namespace UVtools.WPF
SlicerFile = null;
SlicerProperties.Clear();
- Issues.Clear();
- IgnoredIssues.Clear();
- _issuesSliderCanvas.Children.Clear();
+ IssuesClear(true);
Drawings.Clear();
SelectedTabItem = TabInformation;
@@ -862,13 +861,13 @@ namespace UVtools.WPF
if (result == ButtonResult.Yes)
{
IsGUIEnabled = false;
+ ShowProgressWindow($"Downloading: {VersionChecker.Filename}", false);
var task = await Task.Factory.StartNew(async () =>
{
- ShowProgressWindow($"Downloading: {VersionChecker.Filename}");
try
{
- VersionChecker.AutoUpgrade(ProgressWindow.RestartProgress(false));
+ VersionChecker.AutoUpgrade(Progress);
return true;
}
catch (OperationCanceledException)
@@ -942,13 +941,13 @@ namespace UVtools.WPF
if (SlicerFile is null) return;
IsGUIEnabled = false;
-
+ ShowProgressWindow($"Opening: {fileNameOnly}");
+
var task = await Task.Factory.StartNew( () =>
{
- ShowProgressWindow($"Opening: {fileNameOnly}");
try
{
- SlicerFile.Decode(fileName, ProgressWindow.RestartProgress());
+ SlicerFile.Decode(fileName, Progress);
return true;
}
catch (OperationCanceledException)
@@ -985,27 +984,35 @@ namespace UVtools.WPF
return;
}
- if (SlicerFile is SL1File sl1File && Settings.Automations.AutoConvertSL1Files)
+ if (Settings.Automations.AutoConvertFiles)
{
- string fileExtension = sl1File.LookupCustomValue<string>(SL1File.Keyword_FileFormat, null);
- if (!string.IsNullOrWhiteSpace(fileExtension))
+ string convertFileExtension = SlicerFile switch
+ {
+ SL1File sl1File => sl1File.LookupCustomValue<string>(SL1File.Keyword_FileFormat, null),
+ VDTFile vdtFile => vdtFile.LookupCustomValue<string>(SL1File.Keyword_FileFormat, null),
+ _ => null
+ };
+
+ if (!string.IsNullOrWhiteSpace(convertFileExtension))
{
- fileExtension = fileExtension.ToLower(CultureInfo.InvariantCulture);
- var convertToFormat = FileFormat.FindByExtension(fileExtension);
+ convertFileExtension = convertFileExtension.ToLower(CultureInfo.InvariantCulture);
+ var convertToFormat = FileFormat.FindByExtension(convertFileExtension);
if (convertToFormat is not null)
{
- var directory = Path.GetDirectoryName(sl1File.FileFullPath);
- var filename = FileFormat.GetFileNameStripExtensions(sl1File.FileFullPath);
+ var directory = Path.GetDirectoryName(SlicerFile.FileFullPath);
+ var filename = FileFormat.GetFileNameStripExtensions(SlicerFile.FileFullPath);
FileFormat convertedFile = null;
IsGUIEnabled = false;
+ ShowProgressWindow($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {convertFileExtension}");
task = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {fileExtension}");
try
{
- convertedFile = sl1File.Convert(convertToFormat, Path.Combine(directory, $"{filename}.{fileExtension}"), ProgressWindow.RestartProgress());
+ convertedFile = SlicerFile.Convert(convertToFormat,
+ Path.Combine(directory, $"{filename}.{convertFileExtension}"),
+ Progress);
return true;
}
catch (OperationCanceledException)
@@ -1014,7 +1021,8 @@ namespace UVtools.WPF
catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
- await this.MessageBoxError(exception.ToString(), "Error while converting the file"));
+ await this.MessageBoxError(exception.ToString(),
+ "Error while converting the file"));
}
return false;
@@ -1181,38 +1189,35 @@ namespace UVtools.WPF
}
}
- private async void ShowProgressWindow(string title)
+ private async void ShowProgressWindow(string title, bool canCancel = true)
{
if (Dispatcher.UIThread.CheckAccess())
{
- ProgressWindow.SetTitle(title);
- await ProgressWindow.ShowDialog(this);
+ ProgressShow(title, canCancel);
+
+ //ProgressWindow.SetTitle(title);
+ //await ProgressWindow.ShowDialog(this);
}
else
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
- try
+ ProgressShow(title, canCancel);
+ /*try
{
- ProgressWindow.SetTitle(title);
- await ProgressWindow.ShowDialog(this);
+
+ //ProgressWindow.SetTitle(title);
+ //await ProgressWindow.ShowDialog(this);
}
catch (Exception e)
{
Debug.WriteLine(e);
- }
+ }*/
});
}
}
- private void ShowProgressWindowSync(string title)
- {
- ProgressWindow = new ProgressWindow(title);
- }
-
-
-
private async void ConvertToOnTapped(object? sender, RoutedEventArgs e)
{
if (sender is not MenuItem item) return;
@@ -1232,13 +1237,13 @@ namespace UVtools.WPF
IsGUIEnabled = false;
+ ShowProgressWindow($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {Path.GetExtension(result)}");
var task = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {Path.GetExtension(result)}");
try
{
- return SlicerFile.Convert(fileExtension.GetFileFormat(), result, ProgressWindow.RestartProgress()) is not null;
+ return SlicerFile.Convert(fileExtension.GetFileFormat(), result, Progress) is not null;
}
catch (OperationCanceledException)
{
@@ -1309,14 +1314,13 @@ namespace UVtools.WPF
var tempFile = filepath + FileFormat.TemporaryFileAppend;
IsGUIEnabled = false;
+ ShowProgressWindow($"Saving {Path.GetFileName(filepath)}");
var task = await Task.Factory.StartNew( () =>
{
- ShowProgressWindow($"Saving {Path.GetFileName(filepath)}");
-
try
{
- SlicerFile.SaveAs(tempFile, ProgressWindow.RestartProgress());
+ SlicerFile.SaveAs(tempFile, Progress);
if (File.Exists(filepath))
{
File.Delete(filepath);
@@ -1383,13 +1387,13 @@ namespace UVtools.WPF
string finalPath = Path.Combine(result, fileNameNoExt);
IsGUIEnabled = false;
+ ShowProgressWindow($"Extracting {Path.GetFileName(SlicerFile.FileFullPath)}");
await Task.Factory.StartNew(() =>
{
- ShowProgressWindow($"Extracting {Path.GetFileName(SlicerFile.FileFullPath)}");
try
{
- SlicerFile.Extract(finalPath, true, true, ProgressWindow.RestartProgress());
+ SlicerFile.Extract(finalPath, true, true, Progress);
}
catch (OperationCanceledException)
{
@@ -1508,16 +1512,15 @@ namespace UVtools.WPF
}
IsGUIEnabled = false;
+ ShowProgressWindow(baseOperation.ProgressTitle, baseOperation.CanCancel);
Clipboard.Snapshot();
var result = await Task.Factory.StartNew(() =>
{
- ShowProgressWindow(baseOperation.ProgressTitle);
-
try
{
- return baseOperation.Execute(ProgressWindow.RestartProgress(baseOperation.CanCancel));
+ return baseOperation.Execute(Progress);
}
catch (OperationCanceledException)
{
@@ -1544,11 +1547,16 @@ namespace UVtools.WPF
CanSave = true;
+ if(baseOperation.GetType().Name.StartsWith("OperationCalibrate"))
+ {
+ IssuesClear();
+ }
+
switch (baseOperation)
{
// Tools
case OperationRepairLayers operation:
- OnClickDetectIssues();
+ await OnClickDetectIssues();
break;
}
}
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 524c96d..ccdc2f6 100644
--- a/UVtools.WPF/UVtools.WPF.csproj
+++ b/UVtools.WPF/UVtools.WPF.csproj
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
- <Version>2.9.0</Version>
+ <Version>2.9.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -55,7 +55,6 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="..\CHANGELOG.md" Link="CHANGELOG.md" />
- <None Include="..\CreateRelease.WPF.ps1" Link="CreateRelease.WPF.ps1" />
<None Include="..\CREDITS.md" Link="CREDITS.md" />
<None Include="..\LICENSE">
<Pack>True</Pack>
diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs
index 9d2123f..288e0fe 100644
--- a/UVtools.WPF/UserSettings.cs
+++ b/UVtools.WPF/UserSettings.cs
@@ -1121,7 +1121,7 @@ namespace UVtools.WPF
public sealed class AutomationsUserSettings : BindableBase
{
private bool _saveFileAfterModifications = true;
- private bool _autoConvertSl1Files = true;
+ private bool _autoConvertFiles = true;
private bool _changeOnlyLightOffDelayIfZero = true;
private decimal _lightOffDelay = 2.5m;
private decimal _bottomLightOffDelay = 3m;
@@ -1132,10 +1132,10 @@ namespace UVtools.WPF
set => RaiseAndSetIfChanged(ref _saveFileAfterModifications, value);
}
- public bool AutoConvertSL1Files
+ public bool AutoConvertFiles
{
- get => _autoConvertSl1Files;
- set => RaiseAndSetIfChanged(ref _autoConvertSl1Files, value);
+ get => _autoConvertFiles;
+ set => RaiseAndSetIfChanged(ref _autoConvertFiles, value);
}
public bool ChangeOnlyLightOffDelayIfZero
diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml
index 1799cf3..16c1ab1 100644
--- a/UVtools.WPF/Windows/SettingsWindow.axaml
+++ b/UVtools.WPF/Windows/SettingsWindow.axaml
@@ -1431,13 +1431,14 @@
>
<StackPanel Orientation="Vertical">
- <TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="PrusaSlicer SL1 files"/>
+ <TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="File convertion"/>
<StackPanel Margin="10" Orientation="Vertical" Spacing="10">
- <CheckBox IsChecked="{Binding Settings.Automations.AutoConvertSL1Files}"
- ToolTip.Tip="Converts SL1 files to the format specified on 'PrusaSlicer - Printer - Notes' on 'FILEFORMAT_XXX' variable.
+ <CheckBox IsChecked="{Binding Settings.Automations.AutoConvertFiles}"
+ ToolTip.Tip="1) Converts the SL1 files to the format specified on 'PrusaSlicer - Printer - Notes' on 'FILEFORMAT_XXX' variable.
+&#x0a;2) Converts the VDT files to the format specified on 'Voxeldance Tango - Printer settings - Notes' on 'FILEFORMAT_XXX' variable.
&#x0a;A new file with same name but a new extension will be created and overwrite any previous file.
&#x0a;After a successful conversion the new file will automatically load in instead of the loaded SL1 file."
- Content="Auto convert SL1 files to the target format when possible and load it back"/>
+ Content="Auto convert SL1 and VDT files to the target format when possible and load it back"/>
</StackPanel>
</StackPanel>
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml b/UVtools.WPF/Windows/ToolWindow.axaml
index 6019b5f..ac5caa9 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml
+++ b/UVtools.WPF/Windows/ToolWindow.axaml
@@ -11,8 +11,7 @@
Title="Tool"
Icon="/Assets/Icons/UVtools.ico">
-
- <Grid RowDefinitions="Auto,Auto,Auto,Auto,*,Auto">
+ <Grid RowDefinitions="Auto,Auto,Auto,Auto,*,Auto">
<!-- Description -->
<Border Grid.Row="0"
@@ -420,4 +419,5 @@
</Border>
</Grid>
+
</controls:WindowEx>