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 /UVtools.Core
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
Diffstat (limited to 'UVtools.Core')
-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
17 files changed, 540 insertions, 383 deletions
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>