- (Add) Allow to pause and resume operations (#654)
- (Add) `Layer.FirstTransitionLayer`
- (Add) `Layer.LastTransitionLayer`
- (Add) File format: Elegoo GOO
- (Add) PrusaSlicer Printer: Elegoo Mars 4
- (Improvement) Allocate maximum GPU memory for Skia up to 256 MB
- (Improvement) Set and sanitize transition layers exposure time from last bottom layer and first normal layer instead of global times (#659)
- (Change) CXDLP: Default version from 2 to 3
- (Fix) UI was not rendering with GPU (ANGLE)
- (Fix) `Layer.IsTransitionLayer` was returning the wrong value
- (Upgrade) .NET from 6.0.13 to 6.0.14
This commit is contained in:
Tiago Conceição
2023-02-27 03:22:40 +00:00
parent 31416b619a
commit a626cfdc72
85 changed files with 1730 additions and 182 deletions
+4 -2
View File
@@ -469,6 +469,7 @@ public sealed class AnetFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using var mat = layer.LayerMat;
layerData[layerIndex] = new LayerDef();
@@ -479,7 +480,7 @@ public sealed class AnetFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
outputFile.WriteSerialize(layerData[layerIndex]);
outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
@@ -521,7 +522,7 @@ public sealed class AnetFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layersDefinitions[layerIndex] = layerDef;
@@ -543,6 +544,7 @@ public sealed class AnetFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = layersDefinitions[layerIndex].Decode(out var resolutionX, out var resolutionY);
if (layerIndex == 0) // Set file resolution from first layer RLE. Figure out other properties after that
{
+5 -3
View File
@@ -1157,7 +1157,7 @@ public sealed class CTBEncryptedFile : FileFormat
LayersPointer = new LayerPointer[Settings.LayerCount];
for (uint layerIndex = 0; layerIndex < Settings.LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
LayersPointer[layerIndex] = Helpers.Deserialize<LayerPointer>(inputFile);
Debug.WriteLine($"pointer[{layerIndex}]: {LayersPointer[layerIndex]}");
progress++;
@@ -1172,7 +1172,7 @@ public sealed class CTBEncryptedFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(LayersPointer[layerIndex].PageNumber * ChituboxFile.PageSize + LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
@@ -1185,6 +1185,7 @@ public sealed class CTBEncryptedFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layerDef = LayersDefinition[layerIndex];
@@ -1349,6 +1350,7 @@ public sealed class CTBEncryptedFile : FileFormat
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layerDef = new LayerDef(this, this[layerIndex]);
using (var mat = this[layerIndex].LayerMat)
{
@@ -1362,7 +1364,7 @@ public sealed class CTBEncryptedFile : FileFormat
progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = LayersDefinition[layerIndex];
LayersPointer[layerIndex] = new LayerPointer(outputFile.Position);
+10 -3
View File
@@ -33,9 +33,12 @@ namespace UVtools.Core.FileFormats;
public sealed class CXDLPFile : FileFormat
{
#region Constants
private const byte HEADER_SIZE = 9; // CXSW3DV2
private const string HEADER_VALUE = "CXSW3DV2";
private const string HEADER_VALUE_GENERIC = "CXSW3D";
private const byte DEFAULT_VERSION = 3;
#endregion
#region Sub Classes
@@ -62,7 +65,7 @@ public sealed class CXDLPFile : FileFormat
[FieldOrder(2)]
[FieldEndianness(Endianness.Big)]
public ushort Version { get; set; } = 2;
public ushort Version { get; set; } = DEFAULT_VERSION;
/// <summary>
/// Gets the size of the printer model
@@ -458,7 +461,7 @@ public sealed class CXDLPFile : FileFormat
public override uint[] AvailableVersions { get; } = { 2, 3 };
public override uint DefaultVersion => 2;
public override uint DefaultVersion => DEFAULT_VERSION;
public override uint Version
{
@@ -675,6 +678,7 @@ public sealed class CXDLPFile : FileFormat
// Previews
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null)
{
@@ -720,6 +724,7 @@ public sealed class CXDLPFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using (var mat = layer.LayerMat)
{
@@ -841,6 +846,7 @@ public sealed class CXDLPFile : FileFormat
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!;
});
@@ -868,7 +874,7 @@ public sealed class CXDLPFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(4, SeekOrigin.Current);
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
@@ -880,6 +886,7 @@ public sealed class CXDLPFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = EmguExtensions.InitMat(Resolution))
{
+5 -1
View File
@@ -492,6 +492,7 @@ public sealed class CXDLPv1File : FileFormat
// Previews
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null)
{
@@ -529,6 +530,7 @@ public sealed class CXDLPv1File : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using (var mat = layer.LayerMat)
{
@@ -611,6 +613,7 @@ public sealed class CXDLPv1File : FileFormat
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!;
});
@@ -631,7 +634,7 @@ public sealed class CXDLPv1File : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(4, SeekOrigin.Current);
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
@@ -644,6 +647,7 @@ public sealed class CXDLPv1File : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = EmguExtensions.InitMat(Resolution))
{
for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+5 -3
View File
@@ -1906,6 +1906,7 @@ public sealed class ChituboxFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
@@ -1923,7 +1924,7 @@ public sealed class ChituboxFile : FileFormat
if (layerIndex == 0) layerDefSize = Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]);
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = LayerDefinitions[aaIndex, layerIndex];
LayerDef? layerDefHash = null;
@@ -2087,7 +2088,7 @@ public sealed class ChituboxFile : FileFormat
Debug.WriteLine($"-Image GROUP {aaIndex}-");
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(layerOffset, SeekOrigin.Begin);
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this;
@@ -2125,7 +2126,7 @@ public sealed class ChituboxFile : FileFormat
{
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].PageNumber * PageSize + LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize);
@@ -2134,6 +2135,7 @@ public sealed class ChituboxFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex);
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
+4 -2
View File
@@ -959,6 +959,7 @@ public sealed class FDGFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -969,7 +970,7 @@ public sealed class FDGFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = LayersDefinitions[layerIndex];
LayerDef? layerDefHash = null;
@@ -1070,7 +1071,7 @@ public sealed class FDGFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this;
@@ -1090,6 +1091,7 @@ public sealed class FDGFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
if (DecodeType == FileDecodeType.Full)
{
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
+87 -15
View File
@@ -386,6 +386,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
//new CXDLPv1File(), // Creality Box v1
new CXDLPFile(), // Creality Box
new FDGFile(), // fdg
new GooFile(), // goo
new ZCodeFile(), // zcode
new JXSFile(), // jxs
new ZCodexFile(), // zcodex
@@ -1348,6 +1349,16 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </summary>
public Layer? LastBottomLayer => this.LastOrDefault(layer => layer.IsBottomLayer);
/// <summary>
/// Gets the first transition layer
/// </summary>
public Layer? FirstTransitionLayer => TransitionLayerCount == 0 ? null : this[BottomLayerCount];
/// <summary>
/// Gets the last transition layer
/// </summary>
public Layer? LastTransitionLayer => TransitionLayerCount == 0 ? null : this[BottomLayerCount + TransitionLayerCount - 1];
/// <summary>
/// Gets the first normal layer
/// </summary>
@@ -3604,7 +3615,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
DecodeInternally(progress);
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerHeightDigits = LayerHeight.DecimalDigits();
if (layerHeightDigits > Layer.HeightPrecision)
@@ -3624,7 +3635,14 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (CanUseTransitionLayerCount && TransitionLayerType == TransitionLayerTypes.Software)
{
SuppressRebuildPropertiesWork(() => TransitionLayerCount = ParseTransitionLayerCountFromLayers());
SuppressRebuildPropertiesWork(() =>
{
var transitionLayers = ParseTransitionLayerCountFromLayers();
if (transitionLayers > 0)
{
TransitionLayerCount = transitionLayers;
}
});
}
bool reSaveFile = Sanitize();
@@ -3684,6 +3702,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
if (matGenFunc is null)
{
switch (layerImageType)
@@ -3767,6 +3786,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
byte[] pngBytes;
lock (Mutex)
{
@@ -4007,6 +4027,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
{
Parallel.ForEach(this, CoreSettings.GetParallelOptions(progress), layer =>
{
progress.PauseIfRequested();
var byteArr = layer.CompressedPngBytes;
if (byteArr is null) return;
using var stream = new FileStream(Path.Combine(path, layer.Filename), FileMode.Create, FileAccess.Write);
@@ -4024,13 +4045,13 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
public ushort ParseTransitionLayerCountFromLayers()
{
ushort count = 0;
for (uint layerIndex = BottomLayerCount + 1u; layerIndex < LayerCount; layerIndex++)
for (uint layerIndex = BottomLayerCount; layerIndex < LastLayerIndex; layerIndex++)
{
if (Math.Abs(this[layerIndex - 1].ExposureTime - this[layerIndex].ExposureTime) < 0.009f) break; // First equal layer, transition ended
if (Math.Abs(this[layerIndex].ExposureTime - this[layerIndex + 1].ExposureTime) < 0.009f) break; // First equal layer, transition ended
count++;
}
return count;
return count > 0 ? count : TransitionLayerCount;
}
/// <summary>
@@ -4042,7 +4063,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
var transitionLayerCount = ParseTransitionLayerCountFromLayers();
return transitionLayerCount == 0
? 0
: (float)Math.Round(this[BottomLayerCount].ExposureTime - this[BottomLayerCount + 1].ExposureTime, 2);
: (float)Math.Round(this[BottomLayerCount].ExposureTime - this[BottomLayerCount + 1].ExposureTime, 2, MidpointRounding.AwayFromZero);
}
/// <summary>
@@ -4054,7 +4075,9 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <returns>Seconds</returns>
public static float GetTransitionStepTime(float longExposureTime, float shortExposureTime, ushort transitionLayerCount)
{
return transitionLayerCount == 0 ? 0 : (float)Math.Round((longExposureTime - shortExposureTime) / (transitionLayerCount + 1), 2, MidpointRounding.AwayFromZero);
return transitionLayerCount == 0
? 0
: (float)Math.Round((longExposureTime - shortExposureTime) / (transitionLayerCount + 1), 2, MidpointRounding.AwayFromZero);
}
/// <summary>
@@ -4067,6 +4090,21 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
return GetTransitionStepTime(BottomExposureTime, ExposureTime, transitionLayerCount);
}
/// <summary>
/// Gets the transition step time from <see cref="LastBottomLayer"/> and first normal layer after the last transition layer, value is returned as positive from normal perspective and logic (Longer - shorter)
/// </summary>
/// <param name="transitionLayerCount">Number of transition layers</param>
/// <returns>Seconds</returns>
public float GetTransitionStepTimeFromLayers(ushort transitionLayerCount)
{
var bottomExposureTime = LastBottomLayer?.ExposureTime ?? BottomExposureTime;
var exposureTime = TransitionLayerCount > 0
? this[BottomLayerCount + TransitionLayerCount - 1].ExposureTime
: this[BottomLayerCount].ExposureTime;
return GetTransitionStepTime(bottomExposureTime, exposureTime, transitionLayerCount);
}
/// <summary>
/// Gets the transition step time from <see cref="BottomExposureTime"/> and <see cref="ExposureTime"/>, value is returned as positive from normal perspective and logic (Longer - shorter)
/// </summary>
@@ -4100,6 +4138,25 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
return count;
}
/// <summary>
/// Gets the transition layer count based on <see cref="LastBottomLayer"/> and first normal layer after the last transition layer
/// </summary>
/// <param name="stepDecrementTime">Step decrement time in seconds</param>
/// <param name="constrainToLayerCount">True if transition layer count can't be higher than supported by the file, otherwise set to false to not look at possible file layers</param>
/// <param name="rounding">Midpoint rounding method</param>
/// <returns>Transition layer count</returns>
public ushort GetTransitionLayerCountFromLayers(float stepDecrementTime, bool constrainToLayerCount = true, MidpointRounding rounding = MidpointRounding.AwayFromZero)
{
var bottomExposureTime = LastBottomLayer?.ExposureTime ?? BottomExposureTime;
var exposureTime = TransitionLayerCount > 0
? this[BottomLayerCount + TransitionLayerCount - 1].ExposureTime
: this[BottomLayerCount].ExposureTime;
var count = GetTransitionLayerCount(bottomExposureTime, exposureTime, stepDecrementTime, rounding);
if (constrainToLayerCount) count = (ushort)Math.Min(count, MaximumPossibleTransitionLayerCount);
return count;
}
/// <summary>
/// Re-set exposure time to the transition layers
@@ -4118,27 +4175,37 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <param name="resetExposureTimes">True to default all the previous transition layers exposure time, otherwise false</param>
public void SetTransitionLayers(ushort transitionLayerCount, bool resetExposureTimes = true)
{
var bottomExposureTime = LastBottomLayer?.ExposureTime ?? BottomExposureTime;
var exposureTime = ExposureTime;
var layersToReset = new List<Layer>();
for (uint layerIndex = BottomLayerCount; layerIndex < LastLayerIndex; layerIndex++)
{
if (Math.Abs(this[layerIndex].ExposureTime - this[layerIndex + 1].ExposureTime) < 0.009)
{
exposureTime = this[layerIndex].ExposureTime;
break; // First equal layer, transition ended
}
layersToReset.Add(this[layerIndex]);
}
if (resetExposureTimes)
{
for (uint layerIndex = BottomLayerCount; layerIndex < LayerCount; layerIndex++)
foreach (var layer in layersToReset)
{
var layer = this[layerIndex];
if (Math.Abs(layer.ExposureTime - ExposureTime) < 0.009) break; // First equal layer, transition ended
layer.ExposureTime = ExposureTime;
layer.ExposureTime = exposureTime;
}
}
if (transitionLayerCount == 0) return;
float decrement = GetTransitionStepTime(transitionLayerCount);
float decrement = GetTransitionStepTime(bottomExposureTime, exposureTime, transitionLayerCount);
if (decrement <= 0) return;
uint appliedLayers = 0;
for (uint layerIndex = BottomLayerCount; appliedLayers < transitionLayerCount && layerIndex < LayerCount; layerIndex++)
{
appliedLayers++;
this[layerIndex].ExposureTime = Math.Clamp(BottomExposureTime - (decrement * appliedLayers), ExposureTime, BottomExposureTime);
this[layerIndex].ExposureTime = Math.Clamp(bottomExposureTime - (decrement * appliedLayers), exposureTime, bottomExposureTime);
}
}
@@ -5097,6 +5164,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
Parallel.ForEach(this, CoreSettings.GetParallelOptions(progress), layer =>
{
progress.PauseIfRequested();
layer.CompressionCodec = newCodec;
progress.LockAndIncrement();
});
@@ -5355,6 +5423,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
progress.Reset(OperationProgress.StatusOptimizingBounds, LayerCount - 1);
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
this[layerIndex].GetBoundingRectangle();
progress.LockAndIncrement();
});
@@ -5725,6 +5794,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
var layers = new Layer[mats.Length];
Parallel.For(0, mats.Length, CoreSettings.GetParallelOptions(progress), i =>
{
progress.PauseIfRequested();
layers[i] = new Layer((uint)i, mats[i], this);
});
@@ -6100,6 +6170,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
Parallel.ForEach(group1, CoreSettings.GetParallelOptions(progress), layerOperationGroup =>
{
progress.PauseIfRequested();
var layer = this[layerOperationGroup.Key];
using var mat = layer.LayerMat;
@@ -6176,7 +6247,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
var drawnDrainHoleLayers = 0;
for (int operationLayer = (int)layerOperationGroup.Key - 1; operationLayer >= 0 && toProcess.Count > 0; operationLayer--)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layer = this[operationLayer];
var mat = matCache.Get1((uint) operationLayer);
var isMatModified = false;
@@ -6426,6 +6497,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
Parallel.ForEach(layerRange, CoreSettings.GetParallelOptions(progress), layer =>
{
progress.PauseIfRequested();
using var mat = GetMergedMatForSequentialPositionedLayers(layer.Index);
using var mat32Roi = mat.Roi(roi);
@@ -490,6 +490,7 @@ public sealed class FlashForgeSVGXFile : FileFormat
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
groups[layerIndex] = new FlashForgeSVGXSvgGroup($"layer-{layerIndex}");
using var mat = this[layerIndex].LayerMat;
@@ -636,6 +637,7 @@ public sealed class FlashForgeSVGXFile : FileFormat
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var mat = EmguExtensions.InitMat(Resolution);
var group = SVGDocument.Groups.FirstOrDefault(g => g.Id == $"layer-{layerIndex}");
@@ -646,7 +648,7 @@ public sealed class FlashForgeSVGXFile : FileFormat
var points = new List<Point>();
foreach (var path in @group.Paths)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var spaceSplit = path.Value.Split(' ',
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
+5 -1
View File
@@ -338,6 +338,7 @@ public sealed class GR1File : FileFormat
// Previews
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null)
{
@@ -369,6 +370,7 @@ public sealed class GR1File : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using (var mat = layer.LayerMat)
{
@@ -450,6 +452,7 @@ public sealed class GR1File : FileFormat
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!;
});
@@ -468,7 +471,7 @@ public sealed class GR1File : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
linesBytes[layerIndex] = new byte[lineCount * 6];
@@ -478,6 +481,7 @@ public sealed class GR1File : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = EmguExtensions.InitMat(Resolution);
for (int i = 0; i < linesBytes[layerIndex].Length; i++)
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -494,6 +494,7 @@ public sealed class LGSFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
layerData[layerIndex] = new LayerDef(this);
@@ -504,7 +505,7 @@ public sealed class LGSFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
outputFile.WriteSerialize(layerData[layerIndex]);
layerData[layerIndex].EncodedRle = null!; // Free this
}
@@ -516,7 +517,7 @@ public sealed class LGSFile : FileFormat
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
outputFile.WriteSerialize(layerData[layerIndex]);
progress++;
}
@@ -565,7 +566,7 @@ public sealed class LGSFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
layerData[layerIndex].Parent = this;
@@ -573,6 +574,7 @@ public sealed class LGSFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = layerData[layerIndex].Decode();
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
+5 -1
View File
@@ -299,6 +299,7 @@ public sealed class MDLPFile : FileFormat
// Previews
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null)
{
@@ -330,6 +331,7 @@ public sealed class MDLPFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using (var mat = layer.LayerMat)
{
@@ -409,6 +411,7 @@ public sealed class MDLPFile : FileFormat
Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{
progress.PauseIfRequested();
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!;
});
@@ -426,7 +429,7 @@ public sealed class MDLPFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
@@ -437,6 +440,7 @@ public sealed class MDLPFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = EmguExtensions.InitMat(Resolution))
{
+4 -2
View File
@@ -714,6 +714,7 @@ public sealed class OSFFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = this[layerIndex];
using (var mat = layer.LayerMat)
@@ -730,7 +731,7 @@ public sealed class OSFFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
outputFile.WriteSerialize(layerDef[layerIndex]);
outputFile.WriteBytes(layerDef[layerIndex].EncodedRle);
layerDef[layerIndex].EncodedRle = null!; // Free this
@@ -781,7 +782,7 @@ public sealed class OSFFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
//Debug.WriteLine($"{layerIndex}: {inputFile.Position}");
layerDef[layerIndex] = Helpers.Deserialize<OSFLayerDef>(inputFile);
@@ -835,6 +836,7 @@ public sealed class OSFFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = layerDef[layerIndex].DecodeImage(this);
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
layerDef[layerIndex].EncodedRle = null!;
+8 -6
View File
@@ -461,7 +461,7 @@ public sealed class OSLAFile : FileFormat
var image = Thumbnails[i];
if(image is null) continue;
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var bytes = EncodeImage(HeaderSettings.PreviewDataType, image);
if (bytes.Length == 0) continue;
@@ -504,6 +504,7 @@ public sealed class OSLAFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
layerBytes[layerIndex] = EncodeImage(HeaderSettings.LayerDataType, mat);
@@ -514,7 +515,7 @@ public sealed class OSLAFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
// Try to reuse layers
var hash = CryptExtensions.ComputeSHA1Hash(layerBytes[layerIndex]);
@@ -540,7 +541,7 @@ public sealed class OSLAFile : FileFormat
outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
for (int layerIndex = 0; layerIndex < layerDataAddresses.Length; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layer = this[layerIndex];
var layerdef = new LayerDef(layer);
@@ -599,7 +600,7 @@ public sealed class OSLAFile : FileFormat
for (byte i = 0; i < HeaderSettings.PreviewCount; i++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var preview = Helpers.Deserialize<Preview>(inputFile);
Debug.Write($"Preview {i} -> ");
@@ -628,7 +629,7 @@ public sealed class OSLAFile : FileFormat
uint layerTableSize = 0;
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
layerDataAddresses[layerIndex] = inputFile.ReadUIntLittleEndian();
layerDef[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
@@ -654,7 +655,7 @@ public sealed class OSLAFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin);
layerBytes[layerIndex] = inputFile.ReadBytes(inputFile.ReadUIntLittleEndian());
@@ -662,6 +663,7 @@ public sealed class OSLAFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution);
layerBytes[layerIndex] = null!; // Clean
+4 -2
View File
@@ -981,6 +981,7 @@ public sealed class PHZFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -991,7 +992,7 @@ public sealed class PHZFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = LayersDefinitions[layerIndex];
LayerDef? layerDefHash = null;
@@ -1093,7 +1094,7 @@ public sealed class PHZFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this;
@@ -1113,6 +1114,7 @@ public sealed class PHZFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
+4 -2
View File
@@ -415,6 +415,7 @@ public sealed class PhotonSFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
layerData[layerIndex] = new LayerDef(mat);
@@ -425,7 +426,7 @@ public sealed class PhotonSFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
outputFile.WriteSerialize(layerData[layerIndex]);
outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
@@ -468,7 +469,7 @@ public sealed class PhotonSFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layersDefinitions[layerIndex] = layerDef;
@@ -491,6 +492,7 @@ public sealed class PhotonSFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = layersDefinitions[layerIndex].Decode();
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
@@ -1760,6 +1760,7 @@ public sealed class PhotonWorkshopFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = this[layerIndex].LayerMat)
{
LayersDefinition.Layers[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -1770,7 +1771,7 @@ public sealed class PhotonWorkshopFile : FileFormat
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layerDef = LayersDefinition.Layers[layerIndex];
@@ -1924,7 +1925,7 @@ public sealed class PhotonWorkshopFile : FileFormat
{
foreach (var layerIndex in batch)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
LayersDefinition[layerIndex].Parent = this;
@@ -1944,6 +1945,7 @@ public sealed class PhotonWorkshopFile : FileFormat
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = LayersDefinition[layerIndex].Decode();
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this)
{
+1 -1
View File
@@ -390,7 +390,7 @@ public sealed class ZCodexFile : FileFormat
float lastZPosition = 0;
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var layer = this[layerIndex];
GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}");
+2 -1
View File
@@ -292,7 +292,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// <summary>
/// Gets if this layer is also an transition layer
/// </summary>
public bool IsTransitionLayer => SlicerFile.TransitionLayerCount <= Number;
public bool IsTransitionLayer => SlicerFile.TransitionLayerCount > 0 &&
Index >= SlicerFile.BottomLayerCount && Index < SlicerFile.BottomLayerCount + SlicerFile.TransitionLayerCount;
/// <summary>
/// Gets the previous layer, returns null if no previous layer
+10 -1
View File
@@ -236,6 +236,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
// Detect contours
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.ParallelOptions, layerIndexInt =>
{
progress.PauseIfRequested();
if (progress.Token.IsCancellationRequested) return;
uint layerIndex = (uint)layerIndexInt;
var layer = SlicerFile[layerIndex];
@@ -706,6 +707,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
airContours[layerIndex] = new();
Parallel.For(0, hollows[layerIndex].Count, CoreSettings.ParallelOptions, i =>
{
progress.PauseIfRequested();
//for (var i = 0; i < hollows[layerIndex].Count; i++)
//{
if (progress.Token.IsCancellationRequested) return;
@@ -793,7 +795,10 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
if (airContours[layerIndex] is not null)
{
Parallel.ForEach(airContours[layerIndex], CoreSettings.ParallelOptions, vec =>
CvInvoke.DrawContours(layerAirMap, vec, -1, EmguExtensions.WhiteColor, -1)
{
progress.PauseIfRequested();
CvInvoke.DrawContours(layerAirMap, vec, -1, EmguExtensions.WhiteColor, -1);
}
);
}
@@ -810,6 +815,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
/* all we care about is contours the first pass thought were resin traps, since there was no access to air from the bottom */
Parallel.For(0, resinTraps[layerIndex].Count, CoreSettings.ParallelOptions, x =>
{
progress.PauseIfRequested();
if (progress.Token.IsCancellationRequested) return;
/* check if each contour overlaps known air */
@@ -949,6 +955,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
{
Parallel.ForEach(listOfLayers.Where(list => list is not null), contoursGroups =>
{
progress.PauseIfRequested();
for (var groupIndex = 0; groupIndex < contoursGroups.Count; groupIndex++)
{
var contours = contoursGroups[groupIndex];
@@ -985,6 +992,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
/* select new LayerIssue(this[layerIndex], LayerIssue.IssueType.ResinTrap, area.Contour, area.BoundingRectangle)) */
foreach (var trap in resinTraps[layerIndex])
{
progress.PauseIfRequested();
if (progress.Token.IsCancellationRequested) return;
var area = EmguContours.GetContourArea(trap);
@@ -1053,6 +1061,7 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
foreach (var trap in suctionCups[layerIndex])
{
progress.PauseIfRequested();
if (progress.Token.IsCancellationRequested) return;
var area = EmguContours.GetContourArea(trap);
+1 -1
View File
@@ -741,7 +741,7 @@ public abstract class Operation : BindableBase, IDisposable
var result = ExecuteInternally(progress);
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
return result;
}
+1
View File
@@ -133,6 +133,7 @@ public sealed class OperationBlur : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
@@ -1893,6 +1893,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
progress.ItemCount = (uint) (SlicerFile.LayerCount * table.Count);
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat;
var matRoi = new Mat(mat, boundingRectangle);
@@ -1970,7 +1971,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
Layer currentLayer = layers[0];
for (var layerIndex = 1; layerIndex < layers.Count; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
progress++;
var layer = layers[layerIndex];
if (currentLayer.PositionZ != layer.PositionZ ||
@@ -2203,7 +2204,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
currentHeight = Layer.RoundHeight(currentHeight);
for (decimal layerHeight = _layerHeight; layerHeight <= endLayerHeight; layerHeight += _multipleLayerHeightStep)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
layerHeight = Layer.RoundHeight(layerHeight);
if (_multipleExposures)
@@ -419,6 +419,7 @@ public sealed class OperationCalibrateStressTower : Operation
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true};
layers[layerIndex].Dispose();
progress.LockAndIncrement();
@@ -730,6 +730,7 @@ public sealed class OperationCalibrateTolerance : Operation
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true};
layers[layerIndex].Dispose();
progress.LockAndIncrement();
@@ -254,6 +254,7 @@ public sealed class OperationChangeResolution : Operation
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
if (mat.Size != newSize)
@@ -283,6 +283,7 @@ public class OperationDoubleExposure : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var firstLayer = SlicerFile[layerIndex];
var secondLayer = firstLayer.Clone();
var isBottomLayer = firstLayer.IsBottomLayer;
@@ -637,7 +637,7 @@ public sealed class OperationDynamicLayerHeight : Operation
while (true) // In a stack
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
progress.ProcessedItems = layerIndex - LayerIndexStart;
if (currentLayerHeight >= (float)_maximumLayerHeight || layerIndex == LayerIndexEnd)
@@ -289,7 +289,7 @@ public sealed class OperationDynamicLifts : Operation
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var calculateLayer = SlicerFile[layerIndex == 0 ? 0 : layerIndex - 1];
var setLayer = SlicerFile[layerIndex];
@@ -198,7 +198,7 @@ public class OperationFadeExposureTime : Operation
var exposure = _fromExposureTime;
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
exposure += increment;
SlicerFile[layerIndex].ExposureTime = (float)exposure;
}
+1
View File
@@ -102,6 +102,7 @@ public class OperationFlip : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
@@ -171,6 +171,7 @@ public sealed class OperationInfill : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, mask!);
SlicerFile[layerIndex].LayerMat = mat;
@@ -247,7 +247,7 @@ public class OperationLayerArithmetic : Operation
{
if(!operation.IsValid) continue;
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
using var result = SlicerFile[operation.Operations[0].LayerIndex].LayerMat;
using var resultRoi = GetRoiOrDefault(result);
using var imageMask = GetMask(resultRoi);
@@ -255,7 +255,7 @@ public class OperationLayerArithmetic : Operation
progress.ItemCount = (uint)operation.Operations.Count;
for (int i = 1; i < operation.Operations.Count; i++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
using var image = SlicerFile[operation.Operations[i].LayerIndex].LayerMat;
var imageRoi = GetRoiOrDefault(image);
@@ -293,6 +293,7 @@ public class OperationLayerArithmetic : Operation
progress.Reset("Applied layers", (uint)operation.SetLayers.Count);
Parallel.ForEach(operation.SetLayers, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
progress.LockAndIncrement();
if (operation.Operations.Count == 1 || HaveROIorMask)
{
@@ -226,6 +226,7 @@ public sealed class OperationLayerExportGif : Operation
Parallel.For(0, TotalLayers, CoreSettings.GetParallelOptions(progress), i =>
{
progress.PauseIfRequested();
uint layerIndex = (uint) (LayerIndexStart + i * (_skip + 1));
var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat;
@@ -269,7 +270,7 @@ public sealed class OperationLayerExportGif : Operation
progress.ResetNameAndProcessed("Packed layers");
foreach (var buffer in layerBuffer)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
using var stream = new MemoryStream(buffer);
using var img = Image.FromStream(stream);
gif.AddFrame(img, -1, GifQuality.Bit8);
@@ -138,6 +138,7 @@ public sealed class OperationLayerExportHeatMap : Operation
Parallel.ForEach(layerRange, CoreSettings.GetParallelOptions(progress), layer =>
{
progress.PauseIfRequested();
using var mat = _mergeSamePositionedLayers
? SlicerFile.GetMergedMatForSequentialPositionedLayers(layer.Index)
: layer.LayerMat;
@@ -582,6 +582,7 @@ public sealed class OperationLayerExportHtml : Operation
var layerSvgPath = new string[SlicerFile.LayerCount];
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.ParallelOptions, layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
CvInvoke.Threshold(mat, mat, 127, byte.MaxValue, ThresholdType.Binary); // Remove AA
@@ -181,6 +181,7 @@ public sealed class OperationLayerExportImage : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = mat;
if (_cropByRoi && HaveROI)
@@ -342,6 +342,7 @@ public sealed class OperationLayerExportMesh : Operation
/* Seems to be faster to parallel on the Y and not the X */
Parallel.For(0, curLayer!.Height, CoreSettings.GetParallelOptions(progress), y =>
{
progress.PauseIfRequested();
/* Collects all the faces found for this thread, will be combined into the main dictionary later */
var threadDict = new Dictionary<Voxelizer.FaceOrientation, List<Point>>();
for (var x = 0; x < curLayer.Width; x++)
@@ -545,6 +546,7 @@ public sealed class OperationLayerExportMesh : Operation
/* We build out a 3 dimensional KD tree for each layer, having 1 big KD tree is prohibitive when you get to millions and millions of faces. */
Parallel.For(0, distinctLayers.Length, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
/* Create the KD tree for the layer, in practice there should never be dups, but just in case, set to skip */
layerTrees[layerIndex] = new KdTree<float, Voxelizer.UVFace>(3, new FloatMath(), AddDuplicateBehavior.Skip);
@@ -577,6 +579,7 @@ public sealed class OperationLayerExportMesh : Operation
*/
Parallel.For(0, distinctLayers.Length, CoreSettings.GetParallelOptions(progress), i =>
{
progress.PauseIfRequested();
/* if no faces on this layer... skip.... needed for empty layers */
if (layerTrees[i] is null) return;
@@ -93,6 +93,7 @@ public sealed class OperationLayerExportSkeleton : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = GetRoiOrDefault(mat);
using var skeletonRoi = matRoi.Skeletonize();
@@ -268,6 +268,7 @@ public sealed class OperationLayerImport : Operation
Parallel.ForEach(keyImage, CoreSettings.GetParallelOptions(progress), pair =>
{
progress.PauseIfRequested();
using var mat = CvInvoke.Imread(pair.Value, ImreadModes.Grayscale);
if (pair.Key == 0) format.Resolution = mat.Size;
format[pair.Key] = new Layer(pair.Key, mat, format);
@@ -289,7 +290,7 @@ public sealed class OperationLayerImport : Operation
fileFormats.Add(fileFormat);
}
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
if (fileFormats.Count == 0) return false;
@@ -385,6 +386,7 @@ public sealed class OperationLayerImport : Operation
progress.Reset(ProgressAction, fileFormat.LayerCount);
Parallel.For(0, fileFormat.LayerCount, CoreSettings.GetParallelOptions(progress), i =>
{
progress.PauseIfRequested();
uint layerIndex = (uint)(_startLayerIndex + i);
switch (_importType)
@@ -296,7 +296,7 @@ public sealed class OperationLayerReHeight : Operation
uint newLayerIndex = 0;
for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
var oldLayer = SlicerFile[layerIndex];
for (byte i = 0; i < _selectedItem.Modifier; i++)
@@ -320,6 +320,7 @@ public sealed class OperationLayerReHeight : Operation
Parallel.ForEach(layerIndexes, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var oldLayer = SlicerFile[layerIndex];
using var matSum = oldLayer.LayerMat;
Mat? matXorSum = null;
@@ -205,6 +205,7 @@ public class OperationLightBleedCompensation : Operation
if (dimMats.Length == 0) return false;
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat;
using var original = mat.Clone();
@@ -394,6 +394,7 @@ public class OperationLithophane : Operation
progress.Reset("Threshold levels", byte.MaxValue);
Parallel.For(_startThresholdRange, _endThresholdRange, CoreSettings.GetParallelOptions(progress), threshold =>
{
progress.PauseIfRequested();
using var thresholdMat = new Mat();
CvInvoke.Threshold(mat, thresholdMat, threshold, byte.MaxValue, ThresholdType.Binary);
if (CvInvoke.CountNonZero(thresholdMat) == 0) return;
@@ -436,6 +437,7 @@ public class OperationLithophane : Operation
progress.ResetNameAndProcessed("Packed layers");
Parallel.ForEach(indexes, CoreSettings.GetParallelOptions(progress), i =>
{
progress.PauseIfRequested();
progress.LockAndIncrement();
using var mat = thresholdLayers[i].LayerMat;
for (int index = i+1; index < i + layerIncrement && index < thresholdLayers.Length; index++)
+1
View File
@@ -97,6 +97,7 @@ public class OperationMask : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
@@ -178,6 +178,7 @@ public sealed class OperationMorph : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
int iterations = FileFormat.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex);
using var mat = SlicerFile[layerIndex].LayerMat;
+1
View File
@@ -266,6 +266,7 @@ public class OperationMove : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
@@ -301,6 +301,7 @@ public class OperationPattern : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
using var layerRoi = new Mat(mat, ROI);
using var dstLayer = mat.NewBlank();
@@ -583,6 +583,7 @@ public class OperationPixelArithmetic : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = SlicerFile[layerIndex];
using (var mat = layer.LayerMat)
{
@@ -652,6 +652,7 @@ public class OperationPixelDimming : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, patternMask, alternatePatternMask);
SlicerFile[layerIndex].LayerMat = mat;
+45 -1
View File
@@ -12,7 +12,7 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations;
public sealed class OperationProgress : BindableBase
public sealed class OperationProgress : BindableBase, IDisposable
{
public const string StatusDecodePreviews = "Decoded Previews";
public const string StatusGatherLayers = "Gathered Layers";
@@ -39,7 +39,25 @@ public sealed class OperationProgress : BindableBase
public CancellationToken Token => TokenSource.Token;
public void ThrowIfCancellationRequested() => TokenSource.Token.ThrowIfCancellationRequested();
public ManualResetEvent ManualReset { get; } = new (true);
/// <summary>
/// Blocks the current thread until the current WaitHandle receives a signal.
/// </summary>
/// <returns>true if the current instance receives a signal. If the current instance is never signaled, WaitOne() never returns.</returns>
public bool PauseIfRequested() => ManualReset.WaitOne();
/// <summary>
/// Blocks or cancels the current thread until the current WaitHandle receives a signal.
/// </summary>
public void PauseOrCancelIfRequested()
{
ManualReset.WaitOne();
TokenSource.Token.ThrowIfCancellationRequested();
}
private bool _canCancel = true;
private bool _isPaused;
private string _title = "Operation";
private string _itemName = "Initializing";
private uint _processedItems;
@@ -77,6 +95,25 @@ public sealed class OperationProgress : BindableBase
set => RaiseAndSetIfChanged(ref _canCancel, value);
}
public bool IsPaused
{
get => _isPaused;
set
{
if(!RaiseAndSetIfChanged(ref _isPaused, value)) return;
if (value)
{
ManualReset.Reset(); // pause
StopWatch.Stop();
}
else
{
ManualReset.Set(); // resume
StopWatch.Start();
}
}
}
/// <summary>
/// Gets or sets the item name for the operation
/// </summary>
@@ -183,6 +220,7 @@ public sealed class OperationProgress : BindableBase
public void Init(bool canCancel = true)
{
CanCancel = canCancel;
IsPaused = false;
Title = "Operation";
ItemName = "Initializing";
ItemCount = 0;
@@ -250,4 +288,10 @@ $"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_item
RaisePropertyChanged(nameof(ProgressPercent));
RaisePropertyChanged(nameof(Description));
}
public void Dispose()
{
TokenSource.Dispose();
ManualReset.Dispose();
}
}
@@ -283,7 +283,7 @@ public class OperationRaftRelief : Operation
progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex);
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
{
progress.ThrowIfCancellationRequested();
progress.PauseOrCancelIfRequested();
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
//var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 255); // OLD
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.GradientAlt, 1.5, 25, 300, 0.80, 5, 255);
@@ -397,6 +397,7 @@ public class OperationRaftRelief : Operation
progress.Reset(ProgressAction, firstSupportLayerIndex - _ignoreFirstLayers);
Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
@@ -172,6 +172,7 @@ public class OperationRedrawModel : Operation
if (startLayerIndex < 0) return false;
Parallel.For(0, otherFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var fullMatLayerIndex = startLayerIndex + layerIndex;
using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat;
using var original = fullMat.Clone();
@@ -280,6 +280,7 @@ public class OperationRepairLayers : Operation
islandsToRecompute.Clear();
Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group =>
{
progress.PauseIfRequested();
var layer = SlicerFile[group.Key];
var image = layer.LayerMat;
var span = image.GetDataByteSpan();
@@ -327,6 +328,7 @@ public class OperationRepairLayers : Operation
var sync = new object();
Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[group.Key].LayerMat;
var matSpan = mat.GetDataByteSpan();
var matCache = new Dictionary<uint, Mat>();
@@ -417,6 +419,7 @@ public class OperationRepairLayers : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var layer = SlicerFile[layerIndex];
Mat? image = null;
@@ -159,6 +159,7 @@ public class OperationResize : Operation
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
var newX = _x;
var newY = _y;
if (IsFade)
@@ -97,6 +97,7 @@ public class OperationRotate : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
@@ -89,6 +89,7 @@ public sealed class OperationSolidify : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
@@ -84,6 +84,7 @@ public class OperationThreshold : Operation
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
progress.PauseIfRequested();
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
@@ -83,11 +83,16 @@ public sealed class SuggestionTransitionLayerCount : Suggestion
: SlicerFile.ParseTransitionLayerCountFromLayers();
var suggestedTransitionLayerCount = TransitionLayerCount;
var suggestedTransitionDecrementTime = SlicerFile.GetTransitionStepTime(suggestedTransitionLayerCount);
var suggestedTransitionDecrementTime = SlicerFile.GetTransitionStepTimeFromLayers(suggestedTransitionLayerCount);
var bottomExposureTime = SlicerFile.LastBottomLayer?.ExposureTime ?? SlicerFile.BottomExposureTime;
var exposureTime = SlicerFile.TransitionLayerCount > 0
? SlicerFile[SlicerFile.BottomLayerCount + SlicerFile.TransitionLayerCount - 1].ExposureTime
: SlicerFile[SlicerFile.BottomLayerCount].ExposureTime;
return IsApplied
? $"{GlobalAppliedMessage}: {SlicerFile.BottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{SlicerFile.ExposureTime}s"
: $"{GlobalNotAppliedMessage} {SlicerFile.BottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{SlicerFile.ExposureTime}s is out of the recommended {SlicerFile.BottomExposureTime}s » {(suggestedTransitionDecrementTime <= 0 || suggestedTransitionLayerCount == 0 ? string.Empty : $"[-{suggestedTransitionDecrementTime}s/{suggestedTransitionLayerCount} layers] » ")}{SlicerFile.ExposureTime}s";
? $"{GlobalAppliedMessage}: {bottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{exposureTime}s"
: $"{GlobalNotAppliedMessage} {bottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{exposureTime}s is out of the recommended {bottomExposureTime}s » {(suggestedTransitionDecrementTime <= 0 || suggestedTransitionLayerCount == 0 ? string.Empty : $"[-{suggestedTransitionDecrementTime}s/{suggestedTransitionLayerCount} layers] » ")}{exposureTime}s";
}
}
@@ -108,17 +113,22 @@ public sealed class SuggestionTransitionLayerCount : Suggestion
: SlicerFile.ParseTransitionLayerCountFromLayers();
var suggestedTransitionLayerCount = TransitionLayerCount;
var suggestedTransitionDecrementTime = SlicerFile.GetTransitionStepTime(suggestedTransitionLayerCount);
var suggestedTransitionDecrementTime = SlicerFile.GetTransitionStepTimeFromLayers(suggestedTransitionLayerCount);
var bottomExposureTime = SlicerFile.LastBottomLayer?.ExposureTime ?? SlicerFile.BottomExposureTime;
var exposureTime = SlicerFile.TransitionLayerCount > 0
? SlicerFile[SlicerFile.BottomLayerCount + SlicerFile.TransitionLayerCount - 1].ExposureTime
: SlicerFile[SlicerFile.BottomLayerCount].ExposureTime;
return
$"{Title}: ({SlicerFile.BottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{SlicerFile.ExposureTime}s) » ({SlicerFile.BottomExposureTime}s » {(suggestedTransitionDecrementTime <= 0 || suggestedTransitionLayerCount == 0 ? string.Empty : $"[-{suggestedTransitionDecrementTime}s/{suggestedTransitionLayerCount} layers] » ")}{SlicerFile.ExposureTime}s)";
$"{Title}: ({bottomExposureTime}s » {(actualTransitionDecrementTime <= 0 || actualTransitionLayerCount == 0 ? string.Empty : $"[-{actualTransitionDecrementTime}s/{actualTransitionLayerCount} layers] » ")}{exposureTime}s) » ({bottomExposureTime}s » {(suggestedTransitionDecrementTime <= 0 || suggestedTransitionLayerCount == 0 ? string.Empty : $"[-{suggestedTransitionDecrementTime}s/{suggestedTransitionLayerCount} layers] » ")}{exposureTime}s)";
}
}
public ushort TransitionLayerCount =>
(ushort)Math.Min(
Math.Clamp(
SlicerFile.GetTransitionLayerCount((float)_transitionStepTime, false),
SlicerFile.GetTransitionLayerCountFromLayers((float)_transitionStepTime, false),
_minimumTransitionLayerCount,
_maximumTransitionLayerCount)
, SlicerFile.MaximumPossibleTransitionLayerCount);
+4 -3
View File
@@ -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>3.11.2</Version>
<Version>3.12.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -78,18 +78,19 @@
<ItemGroup>
<PackageReference Include="AnimatedGif" Version="1.0.5" />
<PackageReference Include="BinarySerializer" Version="8.6.3.2" />
<PackageReference Include="CommunityToolkit.Diagnostics" Version="8.1.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.1.0" />
<PackageReference Include="Emgu.CV" Version="4.6.0.5131" />
<PackageReference Include="Emgu.CV.runtime.ubuntu-x64" Version="4.6.0.5131" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.6.0.5131" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.5" />
<PackageReference Include="KdTree" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.5.0" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="7.0.1" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup>
<Target Name="PreparePackageReleaseNotesFromFile" BeforeTargets="GenerateNuspec">