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-24 01:19:58 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-05-24 01:19:58 +0300
commitff4e0dfe28572b151b4831f905110eeeaf57fb62 (patch)
tree1b9c363009c3ab0c9dafbcc5f03eb038d0c413f9 /UVtools.Core
parentad92a0aa5cef5a9be46e2ba20ac5482fc9030015 (diff)
v2.13.0v2.13.0
- (Add) Tool - Light bleed compensation: Compensate the over-curing and light bleed from clear resins by dimming the sequential pixels - (Add) Infill: Honeycomb infill type - (Upgrade) MessageBox from 1.2.0 to 1.3.1 to fix the small size messages
Diffstat (limited to 'UVtools.Core')
-rw-r--r--UVtools.Core/Extensions/PointExtensions.cs2
-rw-r--r--UVtools.Core/Operations/Operation.cs8
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs6
-rw-r--r--UVtools.Core/Operations/OperationChangeResolution.cs3
-rw-r--r--UVtools.Core/Operations/OperationDynamicLifts.cs2
-rw-r--r--UVtools.Core/Operations/OperationInfill.cs158
-rw-r--r--UVtools.Core/Operations/OperationLayerExportGif.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerExportHeatMap.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerReHeight.cs3
-rw-r--r--UVtools.Core/Operations/OperationLightBleedCompensation.cs277
-rw-r--r--UVtools.Core/Operations/OperationPixelArithmetic.cs2
-rw-r--r--UVtools.Core/Operations/OperationScripting.cs3
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
13 files changed, 408 insertions, 62 deletions
diff --git a/UVtools.Core/Extensions/PointExtensions.cs b/UVtools.Core/Extensions/PointExtensions.cs
index 4ba31d8..8b0056c 100644
--- a/UVtools.Core/Extensions/PointExtensions.cs
+++ b/UVtools.Core/Extensions/PointExtensions.cs
@@ -16,7 +16,7 @@ namespace UVtools.Core.Extensions
public static Point Rotate(this Point point, double angleDegree, Point pivot = default)
{
- if (angleDegree == 0 || angleDegree == 360) return point;
+ if (angleDegree is 0 or 360) return point;
double angle = angleDegree * Math.PI / 180;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index f8b9b10..acf78b2 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -383,6 +383,14 @@ namespace UVtools.Core.Operations
ROI = roi;
}
+ public Size GetRoiSizeOrDefault() => GetRoiSizeOrDefault(SlicerFile.Resolution);
+ public Size GetRoiSizeOrDefault(Mat defaultMat) => GetRoiSizeOrDefault(defaultMat.Size);
+
+ public Size GetRoiSizeOrDefault(Size defaultSize)
+ {
+ return HaveROI && defaultSize != _roi.Size ? _roi.Size : defaultSize;
+ }
+
public Mat GetRoiOrDefault(Mat defaultMat)
{
return HaveROI && defaultMat.Size != _roi.Size ? new Mat(defaultMat, _roi) : defaultMat;
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index 255c57f..9642812 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -21,15 +21,17 @@ namespace UVtools.Core.Operations
[Serializable]
public sealed class OperationBlur : Operation
{
+ #region Members
private BlurAlgorithm _blurOperation = BlurAlgorithm.Blur;
private uint _size = 1;
+ #endregion
#region Overrides
public override string Title => "Blur";
public override string Description =>
- $"Blur layer images by applying a low pass filter\n\n" +
- "NOTE: Target printer must support AntiAliasing in order to use this function.\n\n" +
+ $"Blur layer images by applying a low pass filter.\n\n" +
+ "NOTE: Target printer must support AntiAliasing in order to use this function.\n" +
"See https://docs.opencv.org/master/d4/d13/tutorial_py_filtering.html";
public override string ConfirmationText =>
diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs
index 4982cd4..c40d3f7 100644
--- a/UVtools.Core/Operations/OperationChangeResolution.cs
+++ b/UVtools.Core/Operations/OperationChangeResolution.cs
@@ -12,7 +12,6 @@ using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using UVtools.Core.FileFormats;
-using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
@@ -58,7 +57,7 @@ namespace UVtools.Core.Operations
public override bool CanROI => false;
public override string Title => "Change print resolution";
public override string Description =>
- "Crops or resizes all layer images to fit an alternate print resolution\n" +
+ "Crops or resizes all layer images to fit an alternate print resolution.\n" +
"Useful to make files printable on a different printer than they were originally sliced for without the need to re-slice.\n\n" +
"NOTE: Please ensure that the actual model will fit within the new print resolution. The operation will be aborted if it will result in any of the actual model being clipped.\n" +
"Only use this tool if both source and target printer have the same pixel pitch spec, otherwise the model size will be invalidated and result in a different size than the originally sliced for. " +
diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs
index 7444f0f..5fab1d9 100644
--- a/UVtools.Core/Operations/OperationDynamicLifts.cs
+++ b/UVtools.Core/Operations/OperationDynamicLifts.cs
@@ -54,7 +54,7 @@ namespace UVtools.Core.Operations
public override string Title => "Dynamic lifts";
public override string Description =>
- "Generate dynamic lift height and speeds for each layer given it mass\n" +
+ "Generate dynamic lift height and speeds for each layer given it mass.\n" +
"Larger masses requires more lift height and less speed while smaller masses can go with shorter lift height and more speed.\n" +
"If you have a raft, start after it layer number to not influence the calculations.\n" +
"Note: Only few printers support this. Running this on an unsupported printer will cause no harm.";
diff --git a/UVtools.Core/Operations/OperationInfill.cs b/UVtools.Core/Operations/OperationInfill.cs
index b07ba06..01b3ae9 100644
--- a/UVtools.Core/Operations/OperationInfill.cs
+++ b/UVtools.Core/Operations/OperationInfill.cs
@@ -33,7 +33,7 @@ namespace UVtools.Core.Operations
public override string Title => "Infill";
public override string Description =>
- $"Generate infill patterns in the model\n\nNOTES:\n1) You must exclude floor and ceil layers from the range.\n2) You must take care of drain holes after the operation.";
+ $"Generate infill patterns in the model.\n\nNOTES:\n1) You must exclude floor and ceil layers from the range.\n2) You must take care of drain holes after the operation.";
public override string ConfirmationText =>
$"infill model with {InfillType} from layers {LayerIndexStart} through {LayerIndexEnd}?";
@@ -53,6 +53,7 @@ namespace UVtools.Core.Operations
CubicCenterLink,
CubicDynamicLink,
CubicInterlinked,
+ Honeycomb
}
#endregion
@@ -128,17 +129,23 @@ namespace UVtools.Core.Operations
protected override bool ExecuteInternally(OperationProgress progress)
{
+ Mat mask = null;
+ if (_infillType == InfillAlgorithm.Honeycomb)
+ {
+ mask = GetHoneycombMask(GetRoiSizeOrDefault());
+ }
+
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat;
- Execute(mat, layerIndex);
+ Execute(mat, layerIndex, mask);
SlicerFile[layerIndex].LayerMat = mat;
progress.LockAndIncrement();
});
-
+ mask?.Dispose();
return !progress.Token.IsCancellationRequested;
}
@@ -149,22 +156,22 @@ namespace UVtools.Core.Operations
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
uint index = Convert.ToUInt32(arguments[0]);
uint layerIndex = index - LayerIndexStart;
- var infillColor = new MCvScalar(InfillBrightness);
+ var infillColor = new MCvScalar(_infillBrightness);
Mat patternMask = null;
using Mat erode = new ();
using Mat diff = new ();
- Mat target = GetRoiOrDefault(mat);
+ var target = GetRoiOrDefault(mat);
using var mask = GetMask(mat);
-
+ bool disposeTargetMask = true;
- if (InfillType == InfillAlgorithm.Cubic ||
- InfillType == InfillAlgorithm.CubicCenterLink ||
- InfillType == InfillAlgorithm.CubicDynamicLink ||
- InfillType == InfillAlgorithm.CubicInterlinked)
+ if (_infillType is InfillAlgorithm.Cubic
+ or InfillAlgorithm.CubicCenterLink
+ or InfillAlgorithm.CubicDynamicLink
+ or InfillAlgorithm.CubicInterlinked)
{
- using var infillPattern = EmguExtensions.InitMat(new Size(InfillSpacing, InfillSpacing));
- using Mat matPattern = mat.CloneBlank();
+ using var infillPattern = EmguExtensions.InitMat(new Size(_infillSpacing, _infillSpacing));
+ using var matPattern = mat.CloneBlank();
bool firstPattern = true;
uint accumulator = 0;
bool dynamicCenter = false;
@@ -172,16 +179,16 @@ namespace UVtools.Core.Operations
{
dynamicCenter = !dynamicCenter;
firstPattern = true;
- accumulator += InfillSpacing;
+ accumulator += _infillSpacing;
if (accumulator >= layerIndex) break;
firstPattern = false;
- accumulator += InfillThickness;
+ accumulator += _infillThickness;
}
if (firstPattern)
{
- int thickness = InfillThickness / 2;
+ int thickness = _infillThickness / 2;
// Top Left
CvInvoke.Rectangle(infillPattern,
new Rectangle(0, 0, thickness, thickness),
@@ -207,106 +214,159 @@ namespace UVtools.Core.Operations
int margin = (int) (InfillSpacing - accumulator + layerIndex) - thickness;
int marginInv = (int) (accumulator - layerIndex) - thickness;
- if (InfillType == InfillAlgorithm.CubicCenterLink ||
- (InfillType == InfillAlgorithm.CubicDynamicLink &&
+ if (_infillType == InfillAlgorithm.CubicCenterLink ||
+ (_infillType == InfillAlgorithm.CubicDynamicLink &&
dynamicCenter) ||
- InfillType == InfillAlgorithm.CubicInterlinked)
+ _infillType == InfillAlgorithm.CubicInterlinked)
{
CvInvoke.Rectangle(infillPattern,
- new Rectangle(margin, margin, InfillThickness, InfillThickness),
+ new Rectangle(margin, margin, _infillThickness, _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(marginInv, marginInv, InfillThickness,
- InfillThickness),
+ new Rectangle(marginInv, marginInv, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(margin, marginInv, InfillThickness,
- InfillThickness),
+ new Rectangle(margin, marginInv, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(marginInv, margin, InfillThickness,
- InfillThickness),
+ new Rectangle(marginInv, margin, _infillThickness,
+ _infillThickness),
infillColor, -1);
}
- if (InfillType == InfillAlgorithm.CubicInterlinked ||
- (InfillType == InfillAlgorithm.CubicDynamicLink &&
+ if (_infillType == InfillAlgorithm.CubicInterlinked ||
+ (_infillType == InfillAlgorithm.CubicDynamicLink &&
!dynamicCenter))
{
CvInvoke.Rectangle(infillPattern,
- new Rectangle(margin, -thickness, InfillThickness,
- InfillThickness),
+ new Rectangle(margin, -thickness, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(marginInv, -thickness, InfillThickness,
- InfillThickness),
+ new Rectangle(marginInv, -thickness, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(-thickness, margin, InfillThickness,
- InfillThickness),
+ new Rectangle(-thickness, margin, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
- new Rectangle(-thickness, marginInv, InfillThickness,
- InfillThickness),
+ new Rectangle(-thickness, marginInv, _infillThickness,
+ _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
new Rectangle(InfillSpacing - thickness, margin,
- InfillThickness, InfillThickness),
+ _infillThickness, _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
new Rectangle(InfillSpacing - thickness, marginInv,
- InfillThickness, InfillThickness),
+ _infillThickness, _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
new Rectangle(margin, InfillSpacing - thickness,
- InfillThickness, InfillThickness),
+ _infillThickness, _infillThickness),
infillColor, -1);
CvInvoke.Rectangle(infillPattern,
new Rectangle(marginInv, InfillSpacing - thickness,
- InfillThickness, InfillThickness),
+ _infillThickness, _infillThickness),
infillColor, -1);
}
-
-
}
else
{
CvInvoke.Rectangle(infillPattern,
- new Rectangle(0, 0, InfillSpacing, InfillSpacing),
- infillColor, InfillThickness);
+ new Rectangle(0, 0, _infillSpacing, _infillSpacing),
+ infillColor, _infillThickness);
}
+ CvInvoke.Repeat(infillPattern, target.Rows / infillPattern.Rows + 1,
+ target.Cols / infillPattern.Cols + 1, matPattern);
+ patternMask = new Mat(matPattern, new Rectangle(0, 0, target.Width, target.Height));
+ disposeTargetMask = true;
+ }
+ else if (_infillType == InfillAlgorithm.Honeycomb)
+ {
+ if (arguments.Length >= 2)
+ {
+ patternMask = (Mat)arguments[1];
+ disposeTargetMask = false;
+ }
+ else
{
- CvInvoke.Repeat(infillPattern, target.Rows / infillPattern.Rows + 1,
- target.Cols / infillPattern.Cols + 1, matPattern);
- patternMask = new Mat(matPattern, new Rectangle(0, 0, target.Width, target.Height));
+ patternMask = GetHoneycombMask(target.Size);
+ disposeTargetMask = true;
}
}
-
+ //patternMask.Save("D:\\pattern.png");
CvInvoke.Erode(target, erode, kernel, anchor, WallThickness, BorderType.Reflect101,
default);
CvInvoke.Subtract(target, erode, diff);
-
+
CvInvoke.BitwiseAnd(erode, patternMask, target, mask);
CvInvoke.Add(target, diff, target, mask);
- patternMask?.Dispose();
+
+ if (disposeTargetMask)
+ {
+ patternMask.Dispose();
+ }
return true;
}
+ public Mat GetHoneycombMask(Size targetSize)
+ {
+ var patternMask = EmguExtensions.InitMat(targetSize);
+
+ var halfInfillSpacing = _infillSpacing / 2;
+ var halfThickenss = _infillThickness / 2;
+ int width = (int)Math.Round(4 * (_infillSpacing / 2.0 / Math.Sqrt(3)));
+ var infillColor = new MCvScalar(_infillBrightness);
+
+ for (int col = 0; col <= targetSize.Width / _infillSpacing; col++)
+ {
+ for (int row = 0; row <= targetSize.Height / _infillSpacing; row++)
+ {
+ // Move over for the column number.
+ int x = (int)Math.Round(col * (width * 0.75f));
+
+ // Move down the required number of rows.
+ int y = row * _infillSpacing;
+
+ // If the column is odd, move down half a hex more.
+ if (col % 2 == 1) y += halfInfillSpacing;
+
+ var points = new Point[]
+ {
+ new(x, y),
+ new((int) Math.Round(x + width * 0.25f), y - _infillSpacing / 2),
+ new((int) Math.Round(x + width * 0.75f), y - _infillSpacing / 2),
+ new(x + width, y),
+ new((int) Math.Round(x + width * 0.75f), y + _infillSpacing / 2),
+ new((int) Math.Round(x + width * 0.25f), y + _infillSpacing / 2),
+ };
+
+ CvInvoke.Polylines(patternMask, points, true, infillColor, _infillThickness);
+ }
+ }
+
+ return patternMask;
+ }
+
#endregion
}
}
diff --git a/UVtools.Core/Operations/OperationLayerExportGif.cs b/UVtools.Core/Operations/OperationLayerExportGif.cs
index e863f89..d0a0d24 100644
--- a/UVtools.Core/Operations/OperationLayerExportGif.cs
+++ b/UVtools.Core/Operations/OperationLayerExportGif.cs
@@ -65,7 +65,7 @@ namespace UVtools.Core.Operations
public override string Title => "Export layers to GIF";
public override string Description =>
- "Export a layer range to an animated GIF file\n" +
+ "Export a layer range to an animated GIF file.\n" +
"Note: This process is slow, optimize the parameters to output few layers as possible and/or scale them down.";
public override string ConfirmationText =>
diff --git a/UVtools.Core/Operations/OperationLayerExportHeatMap.cs b/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
index eb6482c..2c0bccb 100644
--- a/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
+++ b/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
@@ -28,7 +28,7 @@ namespace UVtools.Core.Operations
#region Overrides
public override bool CanHaveProfiles => false;
- public override string Title => "Export layers to heat map";
+ public override string Title => "Export layers to heat map.";
public override string Description =>
"Export a layer range to a grayscale heat map image that represents the median of the mass in the Z depth/perception\n" +
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index 1aee091..548c25c 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -34,6 +34,7 @@ namespace UVtools.Core.Operations
Average
}
#endregion
+
#region Members
private OperationLayerReHeightItem _selectedItem;
private OperationLayerReHeightAntiAliasingType _antiAliasingType;
@@ -46,7 +47,7 @@ namespace UVtools.Core.Operations
public override bool CanROI => false;
public override string Title => "Adjust layer height";
public override string Description =>
- "Adjust the layer height of the model\n\n" +
+ "Adjust the layer height of the model.\n\n" +
"Adjusting to values lower than current height will reduce layer lines, adjusting to values higher" +
" than current height will reduce model detail.\n\n" +
"Note: Using dedicated slicer software to re-slice will usually yeild better results.";
diff --git a/UVtools.Core/Operations/OperationLightBleedCompensation.cs b/UVtools.Core/Operations/OperationLightBleedCompensation.cs
new file mode 100644
index 0000000..c3175af
--- /dev/null
+++ b/UVtools.Core/Operations/OperationLightBleedCompensation.cs
@@ -0,0 +1,277 @@
+/*
+ * 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.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Emgu.CV;
+using Emgu.CV.Structure;
+using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.Core.Operations
+{
+ [Serializable]
+ public class OperationLightBleedCompensation : Operation
+ {
+ #region Enums
+
+ public enum LightBleedCompensationLookupMode : byte
+ {
+ [Description("Previous: Look for sequential pixels relative to the previous layers")]
+ Previous,
+
+ [Description("Next: Look for sequential pixels relative to the next layers")]
+ Next,
+
+ [Description("Both: Look for sequential pixels relative to the previous and next layers")]
+ Both
+ }
+
+ #endregion
+
+ #region Members
+
+ private LightBleedCompensationLookupMode _lookupMode = LightBleedCompensationLookupMode.Next;
+ private string _dimBy = "25,15,10,5";
+
+ #endregion
+
+ #region Overrides
+
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal;
+
+ public override string Title => "Light bleed compensation";
+ public override string Description =>
+ "Compensate the over-curing and light bleed from clear resins by dimming the sequential pixels.\n" +
+ "Note: You need to find the optimal minimum pixel brightness that such resin can print in order to optimize this process.\n" +
+ "With more translucent resins you can go with lower brightness but stick to a limit that can form the layer without loss." +
+ " Tiny details can be lost when using low brightness level.\n" +
+ "After apply a light bleed compensation, do not apply or re-run this tool over.";
+
+ public override string ConfirmationText =>
+ $"compensate layers {LayerIndexStart} through {LayerIndexEnd}?";
+
+ public override string ProgressTitle =>
+ $"Compensate layers {LayerIndexStart} through {LayerIndexEnd}";
+
+ public override string ProgressAction => "Compensated layers";
+
+ public override string ValidateInternally()
+ {
+ StringBuilder sb = new();
+
+ if (DimByArray.Length == 0)
+ {
+ sb.AppendLine($"The dim levels are invalid or not set.");
+ }
+
+ if (MaximumSubtraction >= byte.MaxValue)
+ {
+ sb.AppendLine($"The sum of dim levels are producing black pixels.");
+ }
+
+ return sb.ToString();
+ }
+
+ public override string ToString()
+ {
+ var result = $"[Lookup: {_lookupMode}]" +
+ $" [Dim by: {_dimBy}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+ #endregion
+
+ #region Constructor
+
+ public OperationLightBleedCompensation() { }
+
+ public OperationLightBleedCompensation(FileFormat slicerFile) : base(slicerFile) { }
+
+ #endregion
+
+ #region Properties
+
+ public LightBleedCompensationLookupMode LookupMode
+ {
+ get => _lookupMode;
+ set => RaiseAndSetIfChanged(ref _lookupMode, value);
+ }
+
+ public string DimBy
+ {
+ get => _dimBy;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _dimBy, value)) return;
+ RaisePropertyChanged(nameof(MinimumBrightness));
+ RaisePropertyChanged(nameof(MaximumSubtraction));
+ }
+ }
+
+ public int MinimumBrightness => 255 - MaximumSubtraction;
+ public int MaximumSubtraction => DimByArray.Aggregate(0, (current, dim) => current + dim);
+
+ public byte[] DimByArray
+ {
+ get
+ {
+ List<byte> levels = new();
+ var split = _dimBy.Split(',', StringSplitOptions.TrimEntries);
+ foreach (var str in split)
+ {
+ if (!byte.TryParse(str, out var brightness)) continue;
+ if (brightness is byte.MinValue or byte.MaxValue) continue;
+ levels.Add(brightness);
+ }
+
+ return levels.ToArray();
+ }
+ }
+
+ public MCvScalar[] DimByMCvScalar
+ {
+ get
+ {
+ List<MCvScalar> levels = new();
+ var split = _dimBy.Split(',', StringSplitOptions.TrimEntries);
+ foreach (var str in split)
+ {
+ if (!byte.TryParse(str, out var brightness)) continue;
+ if (brightness is byte.MinValue or byte.MaxValue) continue;
+ levels.Add(new MCvScalar(brightness));
+ }
+
+ return levels.ToArray();
+ }
+ }
+
+ #endregion
+
+ #region Equality
+
+ protected bool Equals(OperationLightBleedCompensation other)
+ {
+ return _lookupMode == other._lookupMode && _dimBy == other._dimBy;
+ }
+
+ 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((OperationLightBleedCompensation) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int) _lookupMode, _dimBy);
+ }
+
+ #endregion
+
+ #region Methods
+
+ /// <summary>
+ /// Get the cached dim mat's
+ /// </summary>
+ /// <returns></returns>
+ public Mat[] GetDimMats()
+ {
+ var dimLevels = DimByMCvScalar;
+ if (dimLevels.Length == 0) return Array.Empty<Mat>();
+ var mats = new Mat[dimLevels.Length];
+ var matSize = GetRoiSizeOrDefault();
+ for (var i = 0; i < mats.Length; i++)
+ {
+ mats[i] = EmguExtensions.InitMat(matSize, dimLevels[i]);
+ }
+
+ return mats;
+ }
+
+ protected override bool ExecuteInternally(OperationProgress progress)
+ {
+ var dimMats = GetDimMats();
+ if (dimMats.Length == 0) return false;
+ Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return; // Abort operation, user requested cancellation
+
+ var layer = SlicerFile[layerIndex];
+ using var mat = layer.LayerMat;
+ using var original = mat.Clone();
+ var target = GetRoiOrDefault(mat);
+
+ for (byte i = 0; i < dimMats.Length; i++)
+ {
+ Mat mask = null;
+ Mat previousMat = null;
+ Mat previousMatRoi = null;
+ Mat nextMat = null;
+ Mat nextMatRoi = null;
+
+
+ if (_lookupMode is LightBleedCompensationLookupMode.Previous or LightBleedCompensationLookupMode.Both)
+ {
+ int layerPreviousIndex = (int)layerIndex - i - 1;
+ if (layerPreviousIndex >= LayerIndexStart)
+ {
+ previousMat = SlicerFile[layerPreviousIndex].LayerMat;
+ mask = previousMatRoi = GetRoiOrDefault(previousMat);
+ }
+ }
+ if (_lookupMode is LightBleedCompensationLookupMode.Next or LightBleedCompensationLookupMode.Both)
+ {
+ uint layerIndexNext = (uint) (layerIndex + i + 1);
+ if (layerIndexNext <= LayerIndexEnd)
+ {
+ nextMat = SlicerFile[layerIndexNext].LayerMat;
+ mask = nextMatRoi = GetRoiOrDefault(nextMat);
+ }
+ }
+
+ if (previousMat is null && nextMat is null) break; // Nothing more to do
+ if (previousMat is not null && nextMat is not null) // both, need to merge previous with next layer
+ {
+ CvInvoke.Add(previousMatRoi, nextMatRoi, previousMatRoi);
+ mask = previousMatRoi;
+ }
+
+ CvInvoke.Subtract(target, dimMats[i], target, mask);
+
+ previousMat?.Dispose();
+ nextMat?.Dispose();
+ }
+
+ // Apply the results only to the selected masked area, if user selected one
+ ApplyMask(original, target);
+
+ // Set current layer image with the modified mat we just manipulated
+ layer.LayerMat = mat;
+
+ // Increment progress bar by 1
+ progress.LockAndIncrement();
+ });
+
+ foreach (var dimMat in dimMats)
+ {
+ dimMat.Dispose();
+ }
+
+ // return true if not cancelled by user
+ return !progress.Token.IsCancellationRequested;
+ }
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Operations/OperationPixelArithmetic.cs b/UVtools.Core/Operations/OperationPixelArithmetic.cs
index 0ce74e8..427d7be 100644
--- a/UVtools.Core/Operations/OperationPixelArithmetic.cs
+++ b/UVtools.Core/Operations/OperationPixelArithmetic.cs
@@ -72,7 +72,7 @@ namespace UVtools.Core.Operations
public override string Title => "Pixel arithmetic";
public override string Description =>
- "Perform arithmetic operations over the pixels";
+ "Perform arithmetic operations over the pixels.";
public override string ConfirmationText =>
$"arithmetic {_operator}" +
diff --git a/UVtools.Core/Operations/OperationScripting.cs b/UVtools.Core/Operations/OperationScripting.cs
index 661daad..a54326c 100644
--- a/UVtools.Core/Operations/OperationScripting.cs
+++ b/UVtools.Core/Operations/OperationScripting.cs
@@ -12,7 +12,6 @@ using System.Xml.Serialization;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using UVtools.Core.FileFormats;
-using UVtools.Core.Objects;
using UVtools.Core.Scripting;
namespace UVtools.Core.Operations
@@ -36,7 +35,7 @@ namespace UVtools.Core.Operations
public override string Title => "Scripting";
public override string Description =>
- $"Run external scripts to manipulate the loaded file\n" +
+ $"Run external scripts to manipulate the loaded file.\n" +
$"The scripts have wide access to your system and able to do modifications, read/write files, etc. " +
$"Make sure to run only the scripts you trust! Or run UVtools in a sandbox while executing this.";
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 5a6763a..4a97b3d 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.12.2</Version>
+ <Version>2.13.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>