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-05-09 01:37:59 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-05-09 01:37:59 +0300
commitdc0e90a61311b2d78104e46ac34c8faf382dcbd3 (patch)
tree03afc3cceb7dbacbddea34c535700f042d42502e /UVtools.Core
parentea410468fcb8c8ba93c955b3a69e6654e48f0b2f (diff)
v2.11.0v2.11.0
- **Tools:** - (Add) Pixel Arithmetic - (Add) Layer arithmetic: Operator $ to perform a absolute difference - (Add) Allow to save and auto restore operation settings per session (#195) - (Add) Allow to auto select the print volume ROI - (Add) Allow to export and import operation settings from files - (Improvement) Calculator - LightOff delay: Hide the bottom properties or the tab if the file format don't support them (#193) - (Change) 'Arithmetic' to 'Layer arithmetic' - (Remove) 'Threshold pixels' - (Fix) Solidfy was unable to save profiles - (Fix) A redo operation (Ctrl + Shift + Z) wasn't restoring the settings when a default profile is set - **Operations:** - (Fix) Passing a roi mat to `ApplyMask` would cause unwanted results - (Improvement) Allow pass a full/original size mask to `ApplyMask` - **Scripting:** - (Add) an script to create an printable file to clean the VAT (#170) - (Improvement) Allow to change user input properties outside the initialization - (Improvement) Auto format numerical input box with the fixed decimal cases - (Add) Settings: Section 'Tools' - (Improvement) GUI: The 'Lift, Retract and Light-off' at status bar now only shows for the supported formats - (Fix) Print time estimation calculation was wrong since v2.9.3 due a lacking of parentheses on the logic
Diffstat (limited to 'UVtools.Core')
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs183
-rw-r--r--UVtools.Core/Managers/OperationSessionManager.cs126
-rw-r--r--UVtools.Core/Operations/Operation.cs42
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs2
-rw-r--r--UVtools.Core/Operations/OperationFlip.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerArithmetic.cs (renamed from UVtools.Core/Operations/OperationArithmetic.cs)69
-rw-r--r--UVtools.Core/Operations/OperationMorph.cs2
-rw-r--r--UVtools.Core/Operations/OperationPixelArithmetic.cs362
-rw-r--r--UVtools.Core/Operations/OperationRaftRelief.cs10
-rw-r--r--UVtools.Core/Operations/OperationRedrawModel.cs2
-rw-r--r--UVtools.Core/Operations/OperationResize.cs2
-rw-r--r--UVtools.Core/Operations/OperationRotate.cs2
-rw-r--r--UVtools.Core/Operations/OperationSolidify.cs2
-rw-r--r--UVtools.Core/Operations/OperationThreshold.cs2
-rw-r--r--UVtools.Core/Scripting/ScriptBaseInput.cs6
-rw-r--r--UVtools.Core/Scripting/ScriptNumericalInput.cs8
-rw-r--r--UVtools.Core/Scripting/ScriptTextBoxInput.cs2
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
18 files changed, 755 insertions, 71 deletions
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index ac9a755..a8be672 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -774,7 +775,11 @@ namespace UVtools.Core.FileFormats
public virtual float BottomExposureTime
{
get => _bottomExposureTime;
- set => RaiseAndSet(ref _bottomExposureTime, value);
+ set
+ {
+ RaiseAndSet(ref _bottomExposureTime, value);
+ RaisePropertyChanged(nameof(ExposureRepresentation));
+ }
}
/// <summary>
@@ -783,7 +788,11 @@ namespace UVtools.Core.FileFormats
public virtual float ExposureTime
{
get => _exposureTime;
- set => RaiseAndSet(ref _exposureTime, value);
+ set
+ {
+ RaiseAndSet(ref _exposureTime, value);
+ RaisePropertyChanged(nameof(ExposureRepresentation));
+ }
}
/// <summary>
@@ -792,7 +801,11 @@ namespace UVtools.Core.FileFormats
public virtual float BottomLiftHeight
{
get => _bottomLiftHeight;
- set => RaiseAndSet(ref _bottomLiftHeight, value);
+ set
+ {
+ RaiseAndSet(ref _bottomLiftHeight, value);
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
}
/// <summary>
@@ -801,7 +814,11 @@ namespace UVtools.Core.FileFormats
public virtual float LiftHeight
{
get => _liftHeight;
- set => RaiseAndSet(ref _liftHeight, value);
+ set
+ {
+ RaiseAndSet(ref _liftHeight, value);
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
}
/// <summary>
@@ -810,7 +827,11 @@ namespace UVtools.Core.FileFormats
public virtual float BottomLiftSpeed
{
get => _bottomLiftSpeed;
- set => RaiseAndSet(ref _bottomLiftSpeed, value);
+ set
+ {
+ RaiseAndSet(ref _bottomLiftSpeed, value);
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
}
/// <summary>
@@ -819,7 +840,11 @@ namespace UVtools.Core.FileFormats
public virtual float LiftSpeed
{
get => _liftSpeed;
- set => RaiseAndSet(ref _liftSpeed, value);
+ set
+ {
+ RaiseAndSet(ref _liftSpeed, value);
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
}
/// <summary>
@@ -828,7 +853,11 @@ namespace UVtools.Core.FileFormats
public virtual float RetractSpeed
{
get => _retractSpeed;
- set => RaiseAndSet(ref _retractSpeed, value);
+ set
+ {
+ RaiseAndSet(ref _retractSpeed, value);
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
}
/// <summary>
@@ -837,7 +866,11 @@ namespace UVtools.Core.FileFormats
public virtual float BottomLightOffDelay
{
get => _bottomLightOffDelay;
- set => RaiseAndSet(ref _bottomLightOffDelay, value);
+ set
+ {
+ RaiseAndSet(ref _bottomLightOffDelay, value);
+ RaisePropertyChanged(nameof(LightOffDelayRepresentation));
+ }
}
/// <summary>
@@ -846,7 +879,11 @@ namespace UVtools.Core.FileFormats
public virtual float LightOffDelay
{
get => _lightOffDelay;
- set => RaiseAndSet(ref _lightOffDelay, value);
+ set
+ {
+ RaiseAndSet(ref _lightOffDelay, value);
+ RaisePropertyChanged(nameof(LightOffDelayRepresentation));
+ }
}
/// <summary>
@@ -867,6 +904,132 @@ namespace UVtools.Core.FileFormats
set => RaiseAndSet(ref _lightPwm, value);
}
+ public bool CanUseBottomExposureTime => HavePrintParameterModifier(PrintParameterModifier.BottomExposureSeconds);
+ public bool CanUseExposureTime => HavePrintParameterModifier(PrintParameterModifier.ExposureSeconds);
+ public bool CanUseAnyExposureTime => CanUseBottomExposureTime || CanUseExposureTime;
+
+ public bool CanUseBottomLiftHeight => HavePrintParameterModifier(PrintParameterModifier.BottomLiftHeight);
+ public bool CanUseLiftHeight => HavePrintParameterModifier(PrintParameterModifier.LiftHeight);
+ public bool CanUseAnyLiftHeight => CanUseBottomLiftHeight || CanUseLiftHeight;
+
+ public bool CanUseBottomLiftSpeed => HavePrintParameterModifier(PrintParameterModifier.BottomLiftSpeed);
+ public bool CanUseLiftSpeed => HavePrintParameterModifier(PrintParameterModifier.LiftHeight);
+ public bool CanUseAnyLiftSpeed => CanUseBottomLiftSpeed || CanUseLiftSpeed;
+
+ public bool CanUseRetractSpeed => HavePrintParameterModifier(PrintParameterModifier.RetractSpeed);
+
+ public bool CanUseBottomLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.BottomLightOffDelay);
+ public bool CanUseLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.LightOffDelay);
+ public bool CanUseAnyLightOffDelay => CanUseBottomLightOffDelay || CanUseLightOffDelay;
+
+ public bool CanUseBottomLightPWM => HavePrintParameterModifier(PrintParameterModifier.BottomLightPWM);
+ public bool CanUseLightPWM => HavePrintParameterModifier(PrintParameterModifier.LightPWM);
+ public bool CanUseAnyLightPWM => CanUseBottomLightPWM || CanUseLightPWM;
+
+ public string ExposureRepresentation
+ {
+ get
+ {
+ var str = string.Empty;
+
+ if (CanUseBottomExposureTime)
+ {
+ str += ExposureTime.ToString(CultureInfo.InvariantCulture);
+ }
+ if (CanUseExposureTime)
+ {
+ if (!string.IsNullOrEmpty(str)) str += '/';
+ str += BottomExposureTime.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (!string.IsNullOrEmpty(str)) str += 's';
+
+ return str;
+ }
+ }
+
+ public string LiftRepresentation
+ {
+ get
+ {
+ var str = string.Empty;
+
+ var haveBottomLiftHeight = CanUseBottomLiftHeight;
+ var haveLiftHeight = CanUseLiftHeight;
+
+ if (!haveBottomLiftHeight && !haveLiftHeight) return str;
+
+ if (haveBottomLiftHeight)
+ {
+ str += BottomLiftHeight.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveLiftHeight)
+ {
+ if (!string.IsNullOrEmpty(str)) str += '/';
+ str += LiftHeight.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (string.IsNullOrEmpty(str)) return str;
+
+ str += "mm @ ";
+
+ var haveBottomLiftSpeed = CanUseBottomLiftSpeed;
+ var haveLiftSpeed = CanUseLiftSpeed;
+ if (haveBottomLiftSpeed)
+ {
+ str += BottomLiftSpeed.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveLiftSpeed)
+ {
+ if (haveBottomLiftSpeed) str += '/';
+ str += LiftSpeed.ToString(CultureInfo.InvariantCulture);
+ }
+
+ str += "mm/min";
+
+ return str;
+ }
+ }
+
+ public string RetractRepresentation
+ {
+ get
+ {
+ var str = string.Empty;
+
+ if (CanUseRetractSpeed)
+ {
+ str += RetractSpeed.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (!string.IsNullOrEmpty(str)) str += "mm/min";
+
+ return str;
+ }
+ }
+
+ public string LightOffDelayRepresentation
+ {
+ get
+ {
+ var str = string.Empty;
+
+ if (CanUseBottomLightOffDelay)
+ {
+ str += BottomLightOffDelay.ToString(CultureInfo.InvariantCulture);
+ }
+ if (CanUseLightOffDelay)
+ {
+ if (!string.IsNullOrEmpty(str)) str += '/';
+ str += LightOffDelay.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (!string.IsNullOrEmpty(str)) str += 's';
+
+ return str;
+ }
+ }
+
#endregion
/// <summary>
@@ -915,7 +1078,7 @@ namespace UVtools.Core.FileFormats
}
var lightOffDelay = layer.CalculateLightOffDelay();
- time += layer.ExposureTime + lightOffDelay > layer.LightOffDelay ? lightOffDelay : layer.LightOffDelay;
+ time += layer.ExposureTime + (lightOffDelay > layer.LightOffDelay ? lightOffDelay : layer.LightOffDelay);
/*if (lightOffDelay >= layer.LightOffDelay)
time += lightOffDelay;
else
diff --git a/UVtools.Core/Managers/OperationSessionManager.cs b/UVtools.Core/Managers/OperationSessionManager.cs
new file mode 100644
index 0000000..f62093d
--- /dev/null
+++ b/UVtools.Core/Managers/OperationSessionManager.cs
@@ -0,0 +1,126 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using System.Linq;
+using UVtools.Core.Operations;
+
+namespace UVtools.Core.Managers
+{
+ public class OperationSessionManager : IList<Operation>
+ {
+ #region Settings
+
+ //public static string FilePath;
+ #endregion
+
+ #region Singleton
+
+ private static Lazy<OperationSessionManager> _instanceHolder =
+ new(() => new OperationSessionManager());
+
+ public static OperationSessionManager Instance => _instanceHolder.Value;
+
+ #endregion
+
+ #region Members
+
+ private readonly List<Operation> _operations = new();
+
+ #endregion
+
+ #region Properties
+
+
+ #endregion
+
+ #region Constructor
+ private OperationSessionManager()
+ {
+ }
+ #endregion
+
+ #region Methods
+
+ public Operation Find(Type type)
+ {
+ return this.FirstOrDefault(operation => operation.GetType() == type);
+ }
+
+ public Operation Find(Operation fromOperation) => Find(fromOperation.GetType());
+
+ #endregion
+
+ #region List Implementation
+ public IEnumerator<Operation> GetEnumerator()
+ {
+ return _operations.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable) _operations).GetEnumerator();
+ }
+
+ public void Add(Operation item)
+ {
+ if (item is null) return;
+ _operations.RemoveAll(operation => operation.GetType() == item.GetType());
+ _operations.Add(item.Clone());
+ }
+
+ public void Clear()
+ {
+ _operations.Clear();
+ }
+
+ public bool Contains(Operation item)
+ {
+ return _operations.Contains(item);
+ }
+
+ public void CopyTo(Operation[] array, int arrayIndex)
+ {
+ _operations.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(Operation item)
+ {
+ return _operations.Remove(item);
+ }
+
+ public int Count => _operations.Count;
+
+ public bool IsReadOnly => ((ICollection<Operation>) _operations).IsReadOnly;
+
+ public int IndexOf(Operation item)
+ {
+ return _operations.IndexOf(item);
+ }
+
+ public void Insert(int index, Operation item)
+ {
+ if (item is null) return;
+ _operations.RemoveAll(operation => operation.GetType() == item.GetType());
+ _operations.Insert(index, item.Clone());
+ }
+
+ public void RemoveAt(int index)
+ {
+ _operations.RemoveAt(index);
+ }
+
+ public Operation this[int index]
+ {
+ get => _operations[index];
+ set => _operations[index] = value;
+ }
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index 54abe03..56e2d12 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -13,6 +13,7 @@ using Emgu.CV;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
+using UVtools.Core.Managers;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
@@ -341,21 +342,37 @@ namespace UVtools.Core.Operations
/// </summary>
public virtual void InitWithSlicerFile() { }
+ public void ClearROI()
+ {
+ ROI = Rectangle.Empty;
+ }
+
+ public void ClearROIandMasks()
+ {
+ ClearROI();
+ ClearMasks();
+ }
+
public void SetROIIfEmpty(Rectangle roi)
{
if (HaveROI) return;
ROI = roi;
}
- public void SetMasksIfEmpty(Point[][] points)
+ public Mat GetRoiOrDefault(Mat defaultMat)
{
- if (HaveMask) return;
- MaskPoints = points;
+ return HaveROI && defaultMat.Size != _roi.Size ? new Mat(defaultMat, _roi) : defaultMat;
}
- public Mat GetRoiOrDefault(Mat defaultMat)
+ public void ClearMasks()
{
- return HaveROI && defaultMat.Size != _roi.Size ? new Mat(defaultMat, _roi) : defaultMat;
+ MaskPoints = null;
+ }
+
+ public void SetMasksIfEmpty(Point[][] points)
+ {
+ if (HaveMask) return;
+ MaskPoints = points;
}
public Mat GetMask(Mat mat) => GetMask(_maskPoints, mat);
@@ -379,8 +396,15 @@ namespace UVtools.Core.Operations
{
resultRoi = GetRoiOrDefault(result);
}
- resultRoi.CopyTo(originalRoi, mask);
- originalRoi.CopyTo(resultRoi);
+
+ if (mask.Size != resultRoi.Size) // Accept a full size mask
+ {
+ mask = GetRoiOrDefault(mask);
+ }
+
+ using var tempMat = originalRoi.Clone();
+ resultRoi.CopyTo(tempMat, mask);
+ tempMat.CopyTo(resultRoi);
}
/// <summary>
@@ -390,7 +414,7 @@ namespace UVtools.Core.Operations
/// <param name="result">Result image which will also be modified</param>
public void ApplyMask(Mat original, Mat result)
{
- using var mask = GetMask(result);
+ using var mask = GetMask(original);
ApplyMask(original, result, mask);
}
@@ -409,6 +433,8 @@ namespace UVtools.Core.Operations
if(!string.IsNullOrWhiteSpace(msg)) throw new InvalidOperationException($"{Title} can't execute due some errors:\n{msg}");
}
+
+
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
HaveExecuted = true;
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index c803177..b472d7d 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -175,7 +175,7 @@ namespace UVtools.Core.Operations
throw new ArgumentOutOfRangeException();
}
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationFlip.cs b/UVtools.Core/Operations/OperationFlip.cs
index 2badeca..b9befcc 100644
--- a/UVtools.Core/Operations/OperationFlip.cs
+++ b/UVtools.Core/Operations/OperationFlip.cs
@@ -152,7 +152,7 @@ namespace UVtools.Core.Operations
CvInvoke.Flip(target, target, FlipTypeOpenCV);
}
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationArithmetic.cs b/UVtools.Core/Operations/OperationLayerArithmetic.cs
index fd29f51..2ea9bc8 100644
--- a/UVtools.Core/Operations/OperationArithmetic.cs
+++ b/UVtools.Core/Operations/OperationLayerArithmetic.cs
@@ -13,19 +13,18 @@ using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using UVtools.Core.FileFormats;
-using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
[Serializable]
- public class OperationArithmetic : Operation
+ public class OperationLayerArithmetic : Operation
{
#region Members
private string _sentence;
#endregion
#region Enums
- public enum ArithmeticOperators : byte
+ public enum LayerArithmeticOperators : byte
{
None,
Add,
@@ -34,7 +33,8 @@ namespace UVtools.Core.Operations
Divide,
BitwiseAnd,
BitwiseOr,
- BitwiseXor
+ BitwiseXor,
+ AbsDiff
}
#endregion
@@ -42,23 +42,24 @@ namespace UVtools.Core.Operations
public sealed class ArithmeticOperation
{
public uint LayerIndex { get; }
- public ArithmeticOperators Operator { get; }
+ public LayerArithmeticOperators Operator { get; }
- public ArithmeticOperation(uint layerIndex, ArithmeticOperators arithmeticOperator)
+ public ArithmeticOperation(uint layerIndex, LayerArithmeticOperators layerArithmeticOperator)
{
LayerIndex = layerIndex;
- Operator = arithmeticOperator;
+ Operator = layerArithmeticOperator;
}
}
#endregion
#region Overrides
- public override string Title => "Arithmetic";
+ public override string Title => "Layer arithmetic";
public override string Description =>
- "Perform arithmetic operations over the layers pixels.\n\n" +
+ "Perform arithmetic operations over the layers\n" +
"Available operators:\n" +
" + - * / = Add, Subtract, Multiply, Divide\n" +
- " & | ^ = Bitwise AND, OR, XOR\n\n" +
+ " & | ^ = Bitwise AND, OR, XOR\n" +
+ " $ = Absolute difference\n\n" +
"Syntax: <set_to_layer_indexes> = <layer_index> <operator> <layer_index>\n" +
"When: \"<set_to_layer_indexes> =\" is omitted, the result will assign to the first layer on the sentence.\n\n" +
"Example 1: 10+11\n" +
@@ -115,9 +116,9 @@ namespace UVtools.Core.Operations
#region Constructor
- public OperationArithmetic() { }
+ public OperationLayerArithmetic() { }
- public OperationArithmetic(FileFormat slicerFile) : base(slicerFile) { }
+ public OperationLayerArithmetic(FileFormat slicerFile) : base(slicerFile) { }
#endregion
@@ -155,33 +156,36 @@ namespace UVtools.Core.Operations
continue;
}
- ArithmeticOperators op = ArithmeticOperators.None;
+ LayerArithmeticOperators op = LayerArithmeticOperators.None;
switch (c)
{
case '+':
- op = ArithmeticOperators.Add;
+ op = LayerArithmeticOperators.Add;
break;
case '-':
- op = ArithmeticOperators.Subtract;
+ op = LayerArithmeticOperators.Subtract;
break;
case '*':
- op = ArithmeticOperators.Multiply;
+ op = LayerArithmeticOperators.Multiply;
break;
case '/':
- op = ArithmeticOperators.Divide;
+ op = LayerArithmeticOperators.Divide;
break;
case '&':
- op = ArithmeticOperators.BitwiseAnd;
+ op = LayerArithmeticOperators.BitwiseAnd;
break;
case '|':
- op = ArithmeticOperators.BitwiseOr;
+ op = LayerArithmeticOperators.BitwiseOr;
break;
case '^':
- op = ArithmeticOperators.BitwiseXor;
+ op = LayerArithmeticOperators.BitwiseXor;
+ break;
+ case '$':
+ op = LayerArithmeticOperators.AbsDiff;
break;
}
- if (op == ArithmeticOperators.None // No valid operator
+ if (op == LayerArithmeticOperators.None // No valid operator
|| string.IsNullOrWhiteSpace(layerIndexStr) // Started with a operator instead of layer
) continue;
@@ -200,7 +204,7 @@ namespace UVtools.Core.Operations
{
if (uint.TryParse(layerIndexStr, out var layerIndex))
{
- Operations.Add(new ArithmeticOperation(layerIndex, ArithmeticOperators.None));
+ Operations.Add(new ArithmeticOperation(layerIndex, LayerArithmeticOperators.None));
}
}
@@ -227,27 +231,30 @@ namespace UVtools.Core.Operations
using var imageMask = GetMask(image);
switch (Operations[i - 1].Operator)
{
- case ArithmeticOperators.Add:
+ case LayerArithmeticOperators.Add:
CvInvoke.Add(resultRoi, imageRoi, resultRoi, imageMask);
break;
- case ArithmeticOperators.Subtract:
+ case LayerArithmeticOperators.Subtract:
CvInvoke.Subtract(resultRoi, imageRoi, resultRoi, imageMask);
break;
- case ArithmeticOperators.Multiply:
+ case LayerArithmeticOperators.Multiply:
CvInvoke.Multiply(resultRoi, imageRoi, resultRoi);
break;
- case ArithmeticOperators.Divide:
+ case LayerArithmeticOperators.Divide:
CvInvoke.Divide(resultRoi, imageRoi, resultRoi);
break;
- case ArithmeticOperators.BitwiseAnd:
+ case LayerArithmeticOperators.BitwiseAnd:
CvInvoke.BitwiseAnd(resultRoi, imageRoi, resultRoi, imageMask);
break;
- case ArithmeticOperators.BitwiseOr:
+ case LayerArithmeticOperators.BitwiseOr:
CvInvoke.BitwiseOr(resultRoi, imageRoi, resultRoi, imageMask);
break;
- case ArithmeticOperators.BitwiseXor:
+ case LayerArithmeticOperators.BitwiseXor:
CvInvoke.BitwiseXor(resultRoi, imageRoi, resultRoi, imageMask);
break;
+ case LayerArithmeticOperators.AbsDiff:
+ CvInvoke.AbsDiff(resultRoi, imageRoi, resultRoi);
+ break;
}
}
@@ -272,7 +279,7 @@ namespace UVtools.Core.Operations
#endregion
#region Equality
- protected bool Equals(OperationArithmetic other)
+ protected bool Equals(OperationLayerArithmetic other)
{
return _sentence == other._sentence;
}
@@ -282,7 +289,7 @@ namespace UVtools.Core.Operations
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
- return Equals((OperationArithmetic) obj);
+ return Equals((OperationLayerArithmetic) obj);
}
public override int GetHashCode()
diff --git a/UVtools.Core/Operations/OperationMorph.cs b/UVtools.Core/Operations/OperationMorph.cs
index f2c6804..8c5f561 100644
--- a/UVtools.Core/Operations/OperationMorph.cs
+++ b/UVtools.Core/Operations/OperationMorph.cs
@@ -183,7 +183,7 @@ namespace UVtools.Core.Operations
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
CvInvoke.MorphologyEx(target, target, (MorphOp) MorphOperation, Kernel.Matrix, Kernel.Anchor, iterations, BorderType.Reflect101, default);
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationPixelArithmetic.cs b/UVtools.Core/Operations/OperationPixelArithmetic.cs
new file mode 100644
index 0000000..0ce74e8
--- /dev/null
+++ b/UVtools.Core/Operations/OperationPixelArithmetic.cs
@@ -0,0 +1,362 @@
+/*
+ * 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.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;
+
+namespace UVtools.Core.Operations
+{
+ [Serializable]
+ public class OperationPixelArithmetic : Operation
+ {
+ #region Members
+ private PixelArithmeticOperators _operator = PixelArithmeticOperators.Set;
+ private byte _value = byte.MaxValue;
+ private ThresholdType _thresholdType = ThresholdType.Binary;
+ private byte _thresholdMaxValue = 255;
+ private bool _affectBackPixels;
+
+ #endregion
+
+ #region Enums
+ public enum PixelArithmeticOperators : byte
+ {
+ [Description("Set: to a brightness")]
+ Set,
+ [Description("Add: with a brightness")]
+ Add,
+ [Description("Subtract: with a brightness")]
+ Subtract,
+ [Description("Multiply: with a brightness")]
+ Multiply,
+ [Description("Divide: with a brightness")]
+ Divide,
+ //[Description("Exponential: pixels by a brightness")]
+ //Exponential,
+ [Description("Minimum: set to a brightness if is lower than the current pixel")]
+ Minimum,
+ [Description("Maximum: set to a brightness if is higher than the current pixel")]
+ Maximum,
+ [Description("Bitwise Not: invert pixels")]
+ BitwiseNot,
+ [Description("Bitwise And: with a brightness")]
+ BitwiseAnd,
+ [Description("Bitwise Or: with a brightness")]
+ BitwiseOr,
+ [Description("Bitwise Xor: with a brightness")]
+ BitwiseXor,
+ [Description("AbsDiff: perform a absolute difference between pixel and brightness")]
+ AbsDiff,
+ [Description("Threshold: between a minimum/maximum brightness")]
+ Threshold,
+ [Description("Keep Region: in the selected ROI or masks")]
+ KeepRegion,
+ [Description("Discard Region: in the selected ROI or masks")]
+ DiscardRegion
+ }
+ #endregion
+
+ #region Overrides
+ public override string Title => "Pixel arithmetic";
+
+ public override string Description =>
+ "Perform arithmetic operations over the pixels";
+
+ public override string ConfirmationText =>
+ $"arithmetic {_operator}" +
+ (ValueEnabled ? $"={_value}" : string.Empty) +
+ (_operator is PixelArithmeticOperators.Threshold ? $"/{_thresholdMaxValue}" : string.Empty)
+ + $" layers from {LayerIndexStart} through {LayerIndexEnd}";
+
+ public override string ProgressTitle =>
+ $"Arithmetic {_operator}"+
+ (ValueEnabled ? $"={_value}" : string.Empty)
+ +$" layers from {LayerIndexStart} through {LayerIndexEnd}";
+
+ public override string ProgressAction => "Calculated layers";
+
+ public override string ValidateInternally()
+ {
+ var sb = new StringBuilder();
+ if (_operator == PixelArithmeticOperators.KeepRegion && !HaveROI && !HaveMask)
+ {
+ sb.AppendLine("The 'Keep' operator requires selected ROI/masks.");
+ }
+ else if (_operator == PixelArithmeticOperators.DiscardRegion && !HaveROI && !HaveMask)
+ {
+ sb.AppendLine("The 'Discard' operator requires selected ROI/masks.");
+ }
+ else if (_operator
+ is PixelArithmeticOperators.Add
+ or PixelArithmeticOperators.Subtract
+ or PixelArithmeticOperators.Maximum
+ or PixelArithmeticOperators.BitwiseOr
+ or PixelArithmeticOperators.BitwiseXor
+ or PixelArithmeticOperators.AbsDiff
+ && _value == 0)
+ /*||
+ (_operator is PixelArithmeticOperators.Exponential && _value == 1)
+ )*/
+ {
+ sb.AppendLine($"{_operator} by {_value} will have no effect.");
+ }
+ else if (_operator == PixelArithmeticOperators.Divide && _value == 0)
+ {
+ sb.AppendLine("Can't divide by 0.");
+ }
+
+ return sb.ToString();
+ }
+
+ public override string ToString()
+ {
+ var result = $"[{_operator}: {_value}] [ABP: {_affectBackPixels}]"
+ + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+ #endregion
+
+ #region Properties
+
+ public PixelArithmeticOperators Operator
+ {
+ get => _operator;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _operator, value)) return;
+ RaisePropertyChanged(nameof(ValueEnabled));
+ RaisePropertyChanged(nameof(ThresholdEnabled));
+ RaisePropertyChanged(nameof(AffectBackPixelsEnabled));
+ }
+ }
+
+ public byte Value
+ {
+ get => _value;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _value, value)) return;
+ RaisePropertyChanged(nameof(ValuePercent));
+ }
+ }
+
+ // 255 - 100
+ //value - x
+ public float ValuePercent => (float) Math.Round(_value * 100f / byte.MaxValue, 2);
+
+ public bool ValueEnabled => _operator
+ is not PixelArithmeticOperators.BitwiseNot
+ and not PixelArithmeticOperators.KeepRegion
+ and not PixelArithmeticOperators.DiscardRegion
+ ;
+
+ public ThresholdType ThresholdType
+ {
+ get => _thresholdType;
+ set => RaiseAndSetIfChanged(ref _thresholdType, value);
+ }
+
+ public byte ThresholdMaxValue
+ {
+ get => _thresholdMaxValue;
+ set => RaiseAndSetIfChanged(ref _thresholdMaxValue, value);
+ }
+
+ public bool ThresholdEnabled => _operator is PixelArithmeticOperators.Threshold;
+
+ public bool AffectBackPixels
+ {
+ get => _affectBackPixels;
+ set => RaiseAndSetIfChanged(ref _affectBackPixels, value);
+ }
+
+ public bool AffectBackPixelsEnabled => _operator
+ is not PixelArithmeticOperators.Subtract
+ and not PixelArithmeticOperators.Multiply
+ and not PixelArithmeticOperators.Divide
+ and not PixelArithmeticOperators.BitwiseNot
+ and not PixelArithmeticOperators.BitwiseAnd
+ and not PixelArithmeticOperators.KeepRegion
+ and not PixelArithmeticOperators.DiscardRegion
+ and not PixelArithmeticOperators.Threshold
+ ;
+
+ #endregion
+
+ #region Constructor
+
+ public OperationPixelArithmetic() { }
+
+ public OperationPixelArithmetic(FileFormat slicerFile) : base(slicerFile) { }
+
+ #endregion
+
+ #region Methods
+
+ protected override bool ExecuteInternally(OperationProgress progress)
+ {
+ var tempMat = GetTempMat();
+
+ Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = SlicerFile[layerIndex].LayerMat)
+ {
+ Execute(mat, tempMat);
+ SlicerFile[layerIndex].LayerMat = mat;
+ }
+
+ progress.LockAndIncrement();
+ });
+
+ tempMat?.Dispose();
+
+ return !progress.Token.IsCancellationRequested;
+ }
+
+ public override bool Execute(Mat mat, params object[] arguments)
+ {
+ using var original = mat.Clone();
+ var target = GetRoiOrDefault(mat);
+
+ Mat tempMat;
+ bool needDispose = false;
+ if (arguments is not null && arguments.Length > 0)
+ {
+ tempMat = arguments[0] as Mat;
+ }
+ else
+ {
+ tempMat = GetTempMat();
+ needDispose = true;
+ }
+
+ switch (_operator)
+ {
+ case PixelArithmeticOperators.Set:
+ tempMat.CopyTo(target, _affectBackPixels ? null : target);
+ break;
+ case PixelArithmeticOperators.Add:
+ CvInvoke.Add(target, tempMat, target, _affectBackPixels ? null : target);
+ break;
+ case PixelArithmeticOperators.Subtract:
+ CvInvoke.Subtract(target, tempMat, target, _affectBackPixels ? null : target);
+ break;
+ case PixelArithmeticOperators.Multiply:
+ CvInvoke.Multiply(target, tempMat, target);
+ break;
+ case PixelArithmeticOperators.Divide:
+ CvInvoke.Divide(target, tempMat, target);
+ break;
+ /*case PixelArithmeticOperators.Exponential:
+ CvInvoke.Pow(target, _value, tempMat);
+ if(!_affectBackPixels) ApplyMask(original, mat, original);
+ break;*/
+ case PixelArithmeticOperators.Minimum:
+ CvInvoke.Min(target, tempMat, target);
+ if (!_affectBackPixels) ApplyMask(original, target, original);
+ break;
+ case PixelArithmeticOperators.Maximum:
+ CvInvoke.Max(target, tempMat, target);
+ if (!_affectBackPixels) ApplyMask(original, target, original);
+ break;
+ case PixelArithmeticOperators.BitwiseNot:
+ CvInvoke.BitwiseNot(target, target);
+ break;
+ case PixelArithmeticOperators.BitwiseAnd:
+ CvInvoke.BitwiseAnd(target, tempMat, target);
+ break;
+ case PixelArithmeticOperators.BitwiseOr:
+ CvInvoke.BitwiseOr(target, tempMat, target, _affectBackPixels ? null : target);
+ break;
+ case PixelArithmeticOperators.BitwiseXor:
+ CvInvoke.BitwiseXor(target, tempMat, target, _affectBackPixels ? null : target);
+ break;
+ case PixelArithmeticOperators.Threshold:
+ CvInvoke.Threshold(target, target, _value, _thresholdMaxValue, _thresholdType);
+ break;
+ case PixelArithmeticOperators.AbsDiff:
+ CvInvoke.AbsDiff(target, tempMat, target);
+ if (!_affectBackPixels) ApplyMask(original, target, original);
+ break;
+ case PixelArithmeticOperators.KeepRegion:
+ {
+ using var targetClone = target.Clone();
+ original.SetTo(EmguExtensions.BlackByte);
+ mat.SetTo(EmguExtensions.BlackByte);
+ targetClone.CopyTo(target);
+ break;
+ }
+ case PixelArithmeticOperators.DiscardRegion:
+ target.SetTo(EmguExtensions.BlackByte);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+
+ ApplyMask(original, target);
+
+ if (needDispose)
+ {
+ tempMat?.Dispose();
+ }
+
+ return true;
+ }
+
+ public Mat GetTempMat() => _operator
+ is not PixelArithmeticOperators.BitwiseNot
+ and not PixelArithmeticOperators.KeepRegion
+ and not PixelArithmeticOperators.DiscardRegion ? EmguExtensions.InitMat(HaveROI ? ROI.Size : SlicerFile.Resolution, new MCvScalar(_value)) : null;
+
+ public void PresetStripAntiAliasing()
+ {
+ Operator = PixelArithmeticOperators.Threshold;
+ Value = 127;
+ ThresholdMaxValue = 255;
+ ThresholdType = ThresholdType.Binary;
+ }
+
+ public void PresetHalfBrightness()
+ {
+ Value = 128;
+ }
+
+ #endregion
+
+ #region Equality
+
+ protected bool Equals(OperationPixelArithmetic other)
+ {
+ return _operator == other._operator && _value == other._value && _thresholdType == other._thresholdType && _thresholdMaxValue == other._thresholdMaxValue && _affectBackPixels == other._affectBackPixels;
+ }
+
+ 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((OperationPixelArithmetic) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int) _operator, _value, (int) _thresholdType, _thresholdMaxValue, _affectBackPixels);
+ }
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs
index ffbfe6e..93b8104 100644
--- a/UVtools.Core/Operations/OperationRaftRelief.cs
+++ b/UVtools.Core/Operations/OperationRaftRelief.cs
@@ -242,9 +242,9 @@ namespace UVtools.Core.Operations
Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var result = SlicerFile[layerIndex].LayerMat;
- using var original = result.Clone();
- var target = GetRoiOrDefault(result);
+ using var mat = SlicerFile[layerIndex].LayerMat;
+ using var original = mat.Clone();
+ var target = GetRoiOrDefault(mat);
switch (ReliefType)
{
@@ -268,8 +268,8 @@ namespace UVtools.Core.Operations
break;
}
- ApplyMask(original, result);
- SlicerFile[layerIndex].LayerMat = result;
+ ApplyMask(original, target);
+ SlicerFile[layerIndex].LayerMat = mat;
progress.LockAndIncrement();
});
diff --git a/UVtools.Core/Operations/OperationRedrawModel.cs b/UVtools.Core/Operations/OperationRedrawModel.cs
index 06f2c77..34b30e4 100644
--- a/UVtools.Core/Operations/OperationRedrawModel.cs
+++ b/UVtools.Core/Operations/OperationRedrawModel.cs
@@ -240,7 +240,7 @@ namespace UVtools.Core.Operations
if (modified)
{
- ApplyMask(original, fullMat);
+ ApplyMask(original, fullMatRoi);
SlicerFile[fullMatLayerIndex].LayerMat = fullMat;
}
diff --git a/UVtools.Core/Operations/OperationResize.cs b/UVtools.Core/Operations/OperationResize.cs
index 0565437..01e1c79 100644
--- a/UVtools.Core/Operations/OperationResize.cs
+++ b/UVtools.Core/Operations/OperationResize.cs
@@ -215,7 +215,7 @@ namespace UVtools.Core.Operations
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
target.TransformFromCenter((double) xScale, (double) yScale);
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationRotate.cs b/UVtools.Core/Operations/OperationRotate.cs
index 9498246..fe9e215 100644
--- a/UVtools.Core/Operations/OperationRotate.cs
+++ b/UVtools.Core/Operations/OperationRotate.cs
@@ -101,7 +101,7 @@ namespace UVtools.Core.Operations
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
target.Rotate((double)AngleDegrees);
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationSolidify.cs b/UVtools.Core/Operations/OperationSolidify.cs
index 9a97e1b..ea5e389 100644
--- a/UVtools.Core/Operations/OperationSolidify.cs
+++ b/UVtools.Core/Operations/OperationSolidify.cs
@@ -130,7 +130,7 @@ namespace UVtools.Core.Operations
CvInvoke.DrawContours(target, contours, i, EmguExtensions.WhiteByte, -1);
}
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Operations/OperationThreshold.cs b/UVtools.Core/Operations/OperationThreshold.cs
index d516b8e..4754f00 100644
--- a/UVtools.Core/Operations/OperationThreshold.cs
+++ b/UVtools.Core/Operations/OperationThreshold.cs
@@ -101,7 +101,7 @@ namespace UVtools.Core.Operations
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
CvInvoke.Threshold(target, target, Threshold, Maximum, Type);
- ApplyMask(original, mat);
+ ApplyMask(original, target);
return true;
}
diff --git a/UVtools.Core/Scripting/ScriptBaseInput.cs b/UVtools.Core/Scripting/ScriptBaseInput.cs
index b7f78ff..a7d764c 100644
--- a/UVtools.Core/Scripting/ScriptBaseInput.cs
+++ b/UVtools.Core/Scripting/ScriptBaseInput.cs
@@ -13,17 +13,17 @@ namespace UVtools.Core.Scripting
/// <summary>
/// Gets the input label
/// </summary>
- public string Label { get; init; }
+ public string Label { get; set; }
/// <summary>
/// Gets the hover tooltip for this input
/// </summary>
- public string ToolTip { get; init; }
+ public string ToolTip { get; set; }
/// <summary>
/// Gets the value representative unit name
/// </summary>
- public string Unit { get; init; }
+ public string Unit { get; set; }
}
public abstract class ScriptBaseInput<T> : ScriptBaseInput
diff --git a/UVtools.Core/Scripting/ScriptNumericalInput.cs b/UVtools.Core/Scripting/ScriptNumericalInput.cs
index f894bfa..8ce1a04 100644
--- a/UVtools.Core/Scripting/ScriptNumericalInput.cs
+++ b/UVtools.Core/Scripting/ScriptNumericalInput.cs
@@ -15,21 +15,21 @@ namespace UVtools.Core.Scripting
/// <summary>
/// Gets the minimum for this input
/// </summary>
- public T Minimum { get; init; }
+ public T Minimum { get; set; }
/// <summary>
/// Gets the minimum for this input
/// </summary>
- public T Maximum { get; init; }
+ public T Maximum { get; set; }
/// <summary>
/// Gets the increment value for this
/// </summary>
- public T Increment { get; init; }
+ public T Increment { get; set; }
/// <summary>
/// Gets the number of decimal plates to round the value
/// </summary>
- public byte DecimalPlates { get; init; } = 2;
+ public byte DecimalPlates { get; set; } = 2;
}
}
diff --git a/UVtools.Core/Scripting/ScriptTextBoxInput.cs b/UVtools.Core/Scripting/ScriptTextBoxInput.cs
index 9a31173..ae84e8d 100644
--- a/UVtools.Core/Scripting/ScriptTextBoxInput.cs
+++ b/UVtools.Core/Scripting/ScriptTextBoxInput.cs
@@ -13,6 +13,6 @@ namespace UVtools.Core.Scripting
/// <summary>
/// Gets if this input accepts multi lines
/// </summary>
- public bool MultiLine { get; init; }
+ public bool MultiLine { get; set; }
}
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 72fcd10..f9e1554 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.10.0</Version>
+ <Version>2.11.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>