- **Benchmark:**
   - (Add) PNG, GZip, Deflate and LZ4 compress tests
   - (Change) Test against a known image instead of random noise
   - (Change) Single-thread tests from 100 to 200 and multi-thread tests from 1000 to 5000
   - (Improvement) Same image instance is shared between tests instead of create new per test
   - (Fix) Encode typo
- **Core:**
   - (Add) Layer compression method: Allow to choose the compression method for layer image
      - **PNG:** Compression=High Speed=Slow (Use with low RAM)
      - **GZip:** Compression=Medium Speed=Medium (Optimal)
      - **Deflate:** Compression=Medium Speed=Medium (Optimal)
      - **LZ4:** Compression=Low Speed=Fast (Use with high RAM)
   - (Improvement) Better handling on cancel operations and more immediate response
   - (Fix) Extract: Zip Slip Vulnerability (CWE-22)
- **File formats:**
   - (Improvement) Better handling of encode/decoding layers from zip files
   - (Fix) ZCode: Canceling the file load can trigger an error
   - (Fix) VDA: Unable to open vda zip files
- **Tools:**
   - (Improvement) Allow operations to be aware of ROI and Masks before execution (#436)
   - (Improvement) Scripting: Allow save and load profiles (#436)
   - (Fix) Adjust layer height: When using the Offset type the last layer in the range was not taken in account (#435)
- **UI:**
   - (Improvement) Allow layer zoom levels of 0.1x and 64x but constrain minimum zoom to the level of image fit
   - (Improvement) Update change log now shows with markdown style and more readable
   - (Fix) Windows MSI upgrade to this version (#432)
   - (Fix) Auto-updater for Mac ARM, was downloading x64 instead
This commit is contained in:
Tiago Conceição
2022-03-17 23:50:47 +00:00
parent 4a0c4adfc3
commit 22897ea389
101 changed files with 1455 additions and 1069 deletions
+30
View File
@@ -1,5 +1,35 @@
# Changelog # Changelog
## 17/03/2022 - v3.1.0
- **Benchmark:**
- (Add) PNG, GZip, Deflate and LZ4 compress tests
- (Change) Test against a known image instead of random noise
- (Change) Single-thread tests from 100 to 200 and multi-thread tests from 1000 to 5000
- (Improvement) Same image instance is shared between tests instead of create new per test
- (Fix) Encode typo
- **Core:**
- (Add) Layer compression method: Allow to choose the compression method for layer image
- **PNG:** Compression=High Speed=Slow (Use with low RAM)
- **GZip:** Compression=Medium Speed=Medium (Optimal)
- **Deflate:** Compression=Medium Speed=Medium (Optimal)
- **LZ4:** Compression=Low Speed=Fast (Use with high RAM)
- (Improvement) Better handling on cancel operations and more immediate response
- (Fix) Extract: Zip Slip Vulnerability (CWE-22)
- **File formats:**
- (Improvement) Better handling of encode/decoding layers from zip files
- (Fix) ZCode: Canceling the file load can trigger an error
- (Fix) VDA: Unable to open vda zip files
- **Tools:**
- (Improvement) Allow operations to be aware of ROI and Masks before execution (#436)
- (Improvement) Scripting: Allow save and load profiles (#436)
- (Fix) Adjust layer height: When using the Offset type the last layer in the range was not taken in account (#435)
- **UI:**
- (Improvement) Allow layer zoom levels of 0.1x and 64x but constrain minimum zoom to the level of image fit
- (Improvement) Update change log now shows with markdown style and more readable
- (Fix) Windows MSI upgrade to this version (#432)
- (Fix) Auto-updater for Mac ARM, was downloading x64 instead
## 12/03/2022 - v3.0.0 ## 12/03/2022 - v3.0.0
- **(Add) Suggestions:** - **(Add) Suggestions:**
+3 -1
View File
@@ -70,4 +70,6 @@
- Tim Anderson - Tim Anderson
- Sakari Toivonen - Sakari Toivonen
- Ed Wagaman - Ed Wagaman
- Marcin Chomiczuk - Marcin Chomiczuk
- Patrick Hofmann
- Ajilus
@@ -113,7 +113,7 @@ public class AdvancedImageBox : UserControl
/// </summary> /// </summary>
public static ZoomLevelCollection Default => public static ZoomLevelCollection Default =>
new(new[] { new(new[] {
7, 10, 15, 20, 25, 30, 50, 70, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 3200 7, 10, 15, 20, 25, 30, 50, 70, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 3200, 6400
}); });
#endregion #endregion
@@ -276,32 +276,28 @@ public class AdvancedImageBox : UserControl
/// Returns the next increased zoom level for the given current zoom. /// Returns the next increased zoom level for the given current zoom.
/// </summary> /// </summary>
/// <param name="zoomLevel">The current zoom level.</param> /// <param name="zoomLevel">The current zoom level.</param>
/// <param name="constrainZoomLevel">When positive, constrain maximum zoom to this value</param>
/// <returns>The next matching increased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns> /// <returns>The next matching increased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns>
public int NextZoom(int zoomLevel) public int NextZoom(int zoomLevel, int constrainZoomLevel = 0)
{ {
var index = IndexOf(FindNearest(zoomLevel)); var index = IndexOf(FindNearest(zoomLevel));
if (index < Count - 1) if (index < Count - 1) index++;
{
index++;
}
return this[index]; return constrainZoomLevel > 0 && this[index] >= constrainZoomLevel ? constrainZoomLevel : this[index];
} }
/// <summary> /// <summary>
/// Returns the next decreased zoom level for the given current zoom. /// Returns the next decreased zoom level for the given current zoom.
/// </summary> /// </summary>
/// <param name="zoomLevel">The current zoom level.</param> /// <param name="zoomLevel">The current zoom level.</param>
/// <param name="constrainZoomLevel">When positive, constrain minimum zoom to this value</param>
/// <returns>The next matching decreased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns> /// <returns>The next matching decreased zoom level for the given current zoom if applicable, otherwise the nearest zoom.</returns>
public int PreviousZoom(int zoomLevel) public int PreviousZoom(int zoomLevel, int constrainZoomLevel = 0)
{ {
var index = IndexOf(FindNearest(zoomLevel)); var index = IndexOf(FindNearest(zoomLevel));
if (index > 0) if (index > 0) index--;
{
index--;
}
return this[index]; return constrainZoomLevel > 0 && this[index] <= constrainZoomLevel ? constrainZoomLevel : this[index];
} }
/// <summary> /// <summary>
@@ -842,7 +838,7 @@ public class AdvancedImageBox : UserControl
} }
public static readonly StyledProperty<int> MaxZoomProperty = public static readonly StyledProperty<int> MaxZoomProperty =
AvaloniaProperty.Register<AdvancedImageBox, int>(nameof(MaxZoom), 3500); AvaloniaProperty.Register<AdvancedImageBox, int>(nameof(MaxZoom), 6400);
/// <summary> /// <summary>
/// Gets or sets the maximum possible zoom. /// Gets or sets the maximum possible zoom.
@@ -854,6 +850,18 @@ public class AdvancedImageBox : UserControl
set => SetValue(MaxZoomProperty, value); set => SetValue(MaxZoomProperty, value);
} }
public static readonly StyledProperty<bool> ConstrainZoomOutToFitLevelProperty =
AvaloniaProperty.Register<AdvancedImageBox, bool>(nameof(ConstrainZoomOutToFitLevel), true);
/// <summary>
/// Gets or sets if the zoom out should constrain to fit image as the lowest zoom level.
/// </summary>
public bool ConstrainZoomOutToFitLevel
{
get => GetValue(ConstrainZoomOutToFitLevelProperty);
set => SetValue(ConstrainZoomOutToFitLevelProperty, value);
}
public static readonly DirectProperty<AdvancedImageBox, int> OldZoomProperty = public static readonly DirectProperty<AdvancedImageBox, int> OldZoomProperty =
AvaloniaProperty.RegisterDirect<AdvancedImageBox, int>( AvaloniaProperty.RegisterDirect<AdvancedImageBox, int>(
@@ -884,12 +892,14 @@ public class AdvancedImageBox : UserControl
get => GetValue(ZoomProperty); get => GetValue(ZoomProperty);
set set
{ {
var newZoom = Math.Clamp(value, MinZoom, MaxZoom); var minZoom = MinZoom;
if (ConstrainZoomOutToFitLevel) minZoom = Math.Max(ZoomLevelToFit, minZoom);
var newZoom = Math.Clamp(value, minZoom, MaxZoom);
var previousZoom = Zoom; var previousZoom = Zoom;
if (previousZoom == newZoom) return; if (previousZoom == newZoom) return;
OldZoom = previousZoom; OldZoom = previousZoom;
SetValue(ZoomProperty, value); SetValue(ZoomProperty, newZoom);
UpdateViewPort(); UpdateViewPort();
TriggerRender(); TriggerRender();
@@ -899,13 +909,58 @@ public class AdvancedImageBox : UserControl
} }
} }
/// <summary>
/// <para>Gets if the image have zoom.</para>
/// <para>True if zoomed in or out</para>
/// <para>False if no zoom applied</para>
/// </summary>
public bool IsActualSize => Zoom == 100; public bool IsActualSize => Zoom == 100;
/// <summary> /// <summary>
/// Gets the zoom factor, the zoom / 100 /// Gets the zoom factor, the zoom / 100.0
/// </summary> /// </summary>
public double ZoomFactor => Zoom / 100.0; public double ZoomFactor => Zoom / 100.0;
/// <summary>
/// Gets the zoom to fit level which shows all the image
/// </summary>
public int ZoomLevelToFit
{
get
{
if (!IsImageLoaded) return 100;
var image = Image!;
double zoom;
double aspectRatio;
if (image.Size.Width > image.Size.Height)
{
aspectRatio = ViewPortSize.Width / image.Size.Width;
zoom = aspectRatio * 100.0;
if (ViewPortSize.Height < image.Size.Height * zoom / 100.0)
{
aspectRatio = ViewPortSize.Height / image.Size.Height;
zoom = aspectRatio * 100.0;
}
}
else
{
aspectRatio = ViewPortSize.Height / image.Size.Height;
zoom = aspectRatio * 100.0;
if (ViewPortSize.Width < image.Size.Width * zoom / 100.0)
{
aspectRatio = ViewPortSize.Width / image.Size.Width;
zoom = aspectRatio * 100.0;
}
}
return (int) zoom;
}
}
/// <summary> /// <summary>
/// Gets the width of the scaled image. /// Gets the width of the scaled image.
/// </summary> /// </summary>
@@ -1442,36 +1497,8 @@ public class AdvancedImageBox : UserControl
/// </summary> /// </summary>
public void ZoomToFit() public void ZoomToFit()
{ {
var image = Image; if (!IsImageLoaded) return;
if (image is null) return; Zoom = ZoomLevelToFit;
double zoom;
double aspectRatio;
if (image.Size.Width > image.Size.Height)
{
aspectRatio = ViewPortSize.Width / image.Size.Width;
zoom = aspectRatio * 100.0;
if (ViewPortSize.Height < image.Size.Height * zoom / 100.0)
{
aspectRatio = ViewPortSize.Height / image.Size.Height;
zoom = aspectRatio * 100.0;
}
}
else
{
aspectRatio = ViewPortSize.Height / image.Size.Height;
zoom = aspectRatio * 100.0;
if (ViewPortSize.Width < image.Size.Width * zoom / 100.0)
{
aspectRatio = ViewPortSize.Width / image.Size.Width;
zoom = aspectRatio * 100.0;
}
}
Zoom = (int)zoom;
} }
/// <summary> /// <summary>
@@ -10,11 +10,14 @@
<PackageIconUrl /> <PackageIconUrl />
<RepositoryUrl>https://github.com/sn4k3/UVtools/tree/master/UVtools.AvaloniaControls</RepositoryUrl> <RepositoryUrl>https://github.com/sn4k3/UVtools/tree/master/UVtools.AvaloniaControls</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<PackageTags>Advanced image box</PackageTags> <PackageTags>Advanced image box; Avalonia</PackageTags>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Description>AvaloniaUI Controls</Description> <Description>AvaloniaUI Controls
<Version>1.0.1</Version> - AdvancedImageBox: Pan, zoom, cursor, pixel grid and selections image box</Description>
<Version>2.0.0</Version>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -49,4 +52,11 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project> </Project>
+23
View File
@@ -10,7 +10,10 @@ using Emgu.CV.Cuda;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using UVtools.Core.Layers;
using UVtools.Core.Operations;
namespace UVtools.Core; namespace UVtools.Core;
@@ -40,6 +43,21 @@ public static class CoreSettings
/// </summary> /// </summary>
public static ParallelOptions ParallelOptions => new() {MaxDegreeOfParallelism = _maxDegreeOfParallelism}; public static ParallelOptions ParallelOptions => new() {MaxDegreeOfParallelism = _maxDegreeOfParallelism};
/// <summary>
/// Gets the ParallelOptions with <see cref="MaxDegreeOfParallelism"/> and the <see cref="CancellationToken"/> set
/// </summary>
public static ParallelOptions GetParallelOptions(CancellationToken token = default)
{
var options = ParallelOptions;
options.CancellationToken = token;
return options;
}
/// <summary>
/// Gets the ParallelOptions with <see cref="MaxDegreeOfParallelism"/> and the <see cref="CancellationToken"/> set
/// </summary>
public static ParallelOptions GetParallelOptions(OperationProgress progress) => GetParallelOptions(progress.Token);
/// <summary> /// <summary>
/// Gets or sets if operations run via CUDA when possible /// Gets or sets if operations run via CUDA when possible
/// </summary> /// </summary>
@@ -50,6 +68,11 @@ public static class CoreSettings
/// </summary> /// </summary>
public static bool CanUseCuda => EnableCuda && CudaInvoke.HasCuda; public static bool CanUseCuda => EnableCuda && CudaInvoke.HasCuda;
/// <summary>
/// Gets or sets the default compression type for layers
/// </summary>
public static Layer.LayerCompressionMethod DefaultLayerCompressionMethod { get; set; } = Layer.LayerCompressionMethod.Png;
/// <summary> /// <summary>
/// Gets the default folder to save the settings /// Gets the default folder to save the settings
/// </summary> /// </summary>
+9
View File
@@ -14,6 +14,15 @@ namespace UVtools.Core;
public class Enumerations public class Enumerations
{ {
/// <summary>
/// Gets index start number
/// </summary>
public enum IndexStartNumber : byte
{
Zero,
One
}
public enum LayerRangeSelection : byte public enum LayerRangeSelection : byte
{ {
None, None,
@@ -60,4 +60,9 @@ public static class StreamExtensions
{ {
await CopyToAsync(source, destination, DefaultCopyBufferSize, progress, cancellationToken); await CopyToAsync(source, destination, DefaultCopyBufferSize, progress, cancellationToken);
} }
public static MemoryStream ToStream(this byte[] arr)
{
return new MemoryStream(arr);
}
} }
+12 -14
View File
@@ -103,16 +103,12 @@ public static class ZipArchiveExtensions
{ {
//Gets the complete path for the destination file, including any //Gets the complete path for the destination file, including any
//relative paths that were in the zip file //relative paths that were in the zip file
string destinationFileName = Path.Combine(destinationPath, file.FullName); var destFileName = Path.Combine(destinationPath, file.FullName);
var fullDestDirPath = Path.GetFullPath(destinationPath + Path.DirectorySeparatorChar);
//Gets just the new path, minus the file name so we can create the if (!destFileName.StartsWith(fullDestDirPath)) return; // Entry is outside the target dir
//directory if it does not exist
string? destinationFilePath = Path.GetDirectoryName(destinationFileName);
destinationFilePath ??= string.Empty;
//Creates the directory (if it doesn't exist) for the new path //Creates the directory (if it doesn't exist) for the new path
Directory.CreateDirectory(destinationFilePath); Directory.CreateDirectory(fullDestDirPath);
//Determines what to do with the file based upon the //Determines what to do with the file based upon the
//method of overwriting chosen //method of overwriting chosen
@@ -120,26 +116,28 @@ public static class ZipArchiveExtensions
{ {
case Overwrite.Always: case Overwrite.Always:
//Just put the file in and overwrite anything that is found //Just put the file in and overwrite anything that is found
file.ExtractToFile(destinationFileName, true); file.ExtractToFile(destFileName, true);
break; break;
case Overwrite.IfNewer: case Overwrite.IfNewer:
//Checks to see if the file exists, and if so, if it should //Checks to see if the file exists, and if so, if it should
//be overwritten //be overwritten
if (!File.Exists(destinationFileName) || File.GetLastWriteTime(destinationFileName) < file.LastWriteTime) if (!File.Exists(destFileName) || File.GetLastWriteTime(destFileName) < file.LastWriteTime)
{ {
//Either the file didn't exist or this file is newer, so //Either the file didn't exist or this file is newer, so
//we will extract it and overwrite any existing file //we will extract it and overwrite any existing file
file.ExtractToFile(destinationFileName, true); file.ExtractToFile(destFileName, true);
} }
break; break;
case Overwrite.Never: case Overwrite.Never:
//Put the file in if it is new but ignores the //Put the file in if it is new but ignores the
//file if it already exists //file if it already exists
if (!File.Exists(destinationFileName)) if (!File.Exists(destFileName))
{ {
file.ExtractToFile(destinationFileName); file.ExtractToFile(destFileName);
} }
break; break;
default:
throw new ArgumentOutOfRangeException(nameof(overwriteMethod), overwriteMethod, null);
} }
} }
@@ -194,7 +192,7 @@ public static class ZipArchiveExtensions
//Throws an error if the file exists //Throws an error if the file exists
if (archiveExists) if (archiveExists)
{ {
throw new IOException(String.Format("The zip file {0} already exists.", archiveFullName)); throw new IOException(string.Format("The zip file {0} already exists.", archiveFullName));
} }
break; break;
case ArchiveAction.Ignore: case ArchiveAction.Ignore:
+5 -7
View File
@@ -1169,7 +1169,7 @@ public class CTBEncryptedFile : FileFormat
LayersPointer = new LayerPointer[Settings.LayerCount]; LayersPointer = new LayerPointer[Settings.LayerCount];
for (uint layerIndex = 0; layerIndex < Settings.LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < Settings.LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
LayersPointer[layerIndex] = Helpers.Deserialize<LayerPointer>(inputFile); LayersPointer[layerIndex] = Helpers.Deserialize<LayerPointer>(inputFile);
Debug.WriteLine($"pointer[{layerIndex}]: {LayersPointer[layerIndex]}"); Debug.WriteLine($"pointer[{layerIndex}]: {LayersPointer[layerIndex]}");
progress++; progress++;
@@ -1184,7 +1184,7 @@ public class CTBEncryptedFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin); inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
@@ -1195,10 +1195,8 @@ public class CTBEncryptedFile : FileFormat
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layerDef = LayersDefinition[layerIndex]; var layerDef = LayersDefinition[layerIndex];
@@ -1359,9 +1357,8 @@ public class CTBEncryptedFile : FileFormat
outputFile.Seek(outputFile.Position + layerTableSize, SeekOrigin.Begin); outputFile.Seek(outputFile.Position + layerTableSize, SeekOrigin.Begin);
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount); progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layerDef = new LayerDef(this, this[layerIndex]); var layerDef = new LayerDef(this, this[layerIndex]);
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
@@ -1375,6 +1372,7 @@ public class CTBEncryptedFile : FileFormat
progress.Reset(OperationProgress.StatusWritingFile, LayerCount); progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
progress.ThrowIfCancellationRequested();
var layerDef = LayersDefinition[layerIndex]; var layerDef = LayersDefinition[layerIndex];
LayersPointer[layerIndex] = new LayerPointer((uint)outputFile.Position); LayersPointer[layerIndex] = new LayerPointer((uint)outputFile.Position);
+69 -69
View File
@@ -17,6 +17,7 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
@@ -624,7 +625,7 @@ public class CWSFile : FileFormat
for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
manifest.Slices[layerIndex] = new CWSManifest.Slice(this[layerIndex].FormatFileName(filename)); manifest.Slices[layerIndex] = new CWSManifest.Slice(this[layerIndex].FormatFileNameWithLayerDigits(filename));
} }
var entry = outputFile.CreateEntry(CWSManifest.FileName); var entry = outputFile.CreateEntry(CWSManifest.FileName);
@@ -659,16 +660,27 @@ public class CWSFile : FileFormat
if (Printer == PrinterType.BeneMono) if (Printer == PrinterType.BeneMono)
{ {
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, EncodeLayersInZip(outputFile, filename, LayerDigits, Enumerations.IndexStartNumber.Zero, progress, matGenFunc:
(_, mat) =>
{
var matEncode = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3);
var span = mat.GetDataByteSpan();
var spanEncode = matEncode.GetDataByteSpan();
for (int i = 0; i < span.Length; i++)
{
spanEncode[i] = span[i];
}
return matEncode;
});
/*Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress),
//new ParallelOptions { MaxDegreeOfParallelism = Printer == PrinterType.BeneMono ? 1 : 1 }, //new ParallelOptions { MaxDegreeOfParallelism = Printer == PrinterType.BeneMono ? 1 : 1 },
layerIndex => layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex]; var layer = this[layerIndex];
var layerImagePath = layer.FormatFileName(filename); var layerImagePath = layer.FormatFileNameWithLayerDigits(filename);
using var mat = layer.LayerMat!; using var mat = layer.LayerMat;
using var matEncode = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3); using var matEncode = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3);
var span = mat.GetDataByteSpan(); var span = mat.GetDataByteSpan();
var spanEncode = matEncode.GetDataByteSpan(); var spanEncode = matEncode.GetDataByteSpan();
@@ -683,18 +695,11 @@ public class CWSFile : FileFormat
outputFile.PutFileContent(layerImagePath, bytes, ZipArchiveMode.Create); outputFile.PutFileContent(layerImagePath, bytes, ZipArchiveMode.Create);
progress++; progress++;
} }
}); });*/
} }
else else
{ {
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, filename, LayerDigits, Enumerations.IndexStartNumber.Zero, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
var layerImagePath = layer.FormatFileName(filename);
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
} }
RebuildGCode(); RebuildGCode();
@@ -822,70 +827,65 @@ public class CWSFile : FileFormat
Init(OutputSettings.LayersNum, DecodeType == FileDecodeType.Partial); Init(OutputSettings.LayersNum, DecodeType == FileDecodeType.Partial);
progress.ItemCount = OutputSettings.LayersNum; if (LayerCount <= 0) return;
if(LayerCount > 0) // Must discover png depth grayscale or color
if (DecodeType == FileDecodeType.Full && Printer == PrinterType.Unknown)
{ {
if (DecodeType == FileDecodeType.Full) var inputFilename = Path.GetFileNameWithoutExtension(FileFullPath)!;
foreach (var pngEntry in inputFile.Entries)
{ {
var inputFilename = Path.GetFileNameWithoutExtension(FileFullPath)!; if (!pngEntry.Name.EndsWith(".png")) continue;
foreach (var pngEntry in inputFile.Entries) var match = Regex.Match(pngEntry.Name, @"(\d+).png");
{ if (!match.Success || match.Groups.Count < 2) continue;
if (!pngEntry.Name.EndsWith(".png")) continue; if (!uint.TryParse(match.Groups[1].Value, out var layerIndex)) continue;
var filename = Path.GetFileNameWithoutExtension(pngEntry.Name).Replace(inputFilename, string.Empty, StringComparison.Ordinal);
var layerIndexStr = string.Empty;
var layerStr = filename;
for (int i = layerStr.Length - 1; i >= 0; i--)
{
if (layerStr[i] < '0' || layerStr[i] > '9') break;
layerIndexStr = $"{layerStr[i]}{layerIndexStr}";
}
if (string.IsNullOrEmpty(layerIndexStr)) continue;
if (!uint.TryParse(layerIndexStr, out var layerIndex)) continue;
using var stream = pngEntry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
}
GCode.ParseLayersFromGCode(this); /*var filename = Path.GetFileNameWithoutExtension(pngEntry.Name).Replace(inputFilename, string.Empty, StringComparison.Ordinal);
var firstLayer = FirstLayer; var layerIndexStr = string.Empty;
if (firstLayer is not null && DecodeType == FileDecodeType.Full) var layerStr = filename;
{ for (int i = layerStr.Length - 1; i >= 0; i--)
if (Printer == PrinterType.Unknown)
{ {
using Mat mat = new (); if (layerStr[i] < '0' || layerStr[i] > '9') break;
CvInvoke.Imdecode(firstLayer.CompressedBytes, ImreadModes.AnyColor, mat); layerIndexStr = $"{layerStr[i]}{layerIndexStr}";
Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono;
} }
if (Printer == PrinterType.BeneMono) if (string.IsNullOrEmpty(layerIndexStr)) continue;
{ if (!uint.TryParse(layerIndexStr, out var layerIndex)) continue;*/
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex =>
{ using var stream = pngEntry.Open();
if (progress.Token.IsCancellationRequested) return; using var mat = new Mat();
var layer = this[layerIndex]; CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, mat);
using Mat mat = new(); Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono;
CvInvoke.Imdecode(layer.CompressedBytes, ImreadModes.Color, mat); break;
using Mat matDecode = new(mat.Height, mat.GetRealStep(), DepthType.Cv8U, 1);
var span = mat.GetDataByteSpan();
var spanDecode = matDecode.GetDataByteSpan();
for (int i = 0; i < span.Length; i++)
{
spanDecode[i] = span[i];
}
layer.LayerMat = matDecode;
layer.IsModified = false;
progress.LockAndIncrement();
});
}
} }
} }
GetBoundingRectangle(progress); if (Printer == PrinterType.BeneMono)
{
DecodeLayersFromZipRegex(inputFile, @"(\d+).png", Enumerations.IndexStartNumber.Zero, progress,
(layerIndex, pngBytes) =>
{
using Mat mat = new();
CvInvoke.Imdecode(pngBytes, ImreadModes.AnyColor, mat);
var matDecode = new Mat(mat.Height, mat.GetRealStep(), DepthType.Cv8U, 1);
var span = mat.GetDataByteSpan();
var spanDecode = matDecode.GetDataByteSpan();
for (int i = 0; i < span.Length; i++)
{
spanDecode[i] = span[i];
}
return matDecode;
});
}
else
{
DecodeLayersFromZipRegex(inputFile, @"(\d+).png", Enumerations.IndexStartNumber.Zero, progress);
}
GCode.ParseLayersFromGCode(this);
} }
public override void RebuildGCode() public override void RebuildGCode()
+6 -19
View File
@@ -657,9 +657,8 @@ public class CXDLPFile : FileFormat
var previews = new byte[ThumbnailsOriginalSize!.Length][]; var previews = new byte[ThumbnailsOriginalSize!.Length][];
// Previews // Previews
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2; var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null) if (Thumbnails[previewIndex] is null)
{ {
@@ -707,11 +706,8 @@ public class CXDLPFile : FileFormat
var layerBytes = new List<byte>[LayerCount]; var layerBytes = new List<byte>[LayerCount];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested(); Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex]; var layer = this[layerIndex];
using (var mat = layer.LayerMat) using (var mat = layer.LayerMat)
{ {
@@ -762,8 +758,6 @@ public class CXDLPFile : FileFormat
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
outputFile.WriteBytes(layerBytes[layerIndex].ToArray()); outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
@@ -892,7 +886,7 @@ public class CXDLPFile : FileFormat
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
} }
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]); Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!; previews[previewIndex] = null!;
@@ -919,23 +913,20 @@ public class CXDLPFile : FileFormat
var linesBytes = new byte[LayerCount][]; var linesBytes = new byte[LayerCount][];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.ThrowIfCancellationRequested();
inputFile.Seek(4, SeekOrigin.Current); inputFile.Seek(4, SeekOrigin.Current);
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
linesBytes[layerIndex] = new byte[lineCount * 6]; linesBytes[layerIndex] = new byte[lineCount * 6];
inputFile.ReadBytes(linesBytes[layerIndex]); inputFile.ReadBytes(linesBytes[layerIndex]);
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
progress.Token.ThrowIfCancellationRequested();
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = EmguExtensions.InitMat(Resolution)) using (var mat = EmguExtensions.InitMat(Resolution))
{ {
@@ -973,10 +964,6 @@ public class CXDLPFile : FileFormat
inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End); inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End);
} }
progress.Token.ThrowIfCancellationRequested();
FooterSettings = Helpers.Deserialize<Footer>(inputFile); FooterSettings = Helpers.Deserialize<Footer>(inputFile);
FooterSettings.Validate(); FooterSettings.Validate();
} }
+6 -16
View File
@@ -519,9 +519,8 @@ public class CXDLPv1File : FileFormat
var previews = new byte[ThumbnailsOriginalSize!.Length][]; var previews = new byte[ThumbnailsOriginalSize!.Length][];
// Previews // Previews
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2; var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null) if (Thumbnails[previewIndex] is null)
{ {
@@ -557,11 +556,8 @@ public class CXDLPv1File : FileFormat
var layerBytes = new List<byte>[LayerCount]; var layerBytes = new List<byte>[LayerCount];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested(); Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex]; var layer = this[layerIndex];
using (var mat = layer.LayerMat) using (var mat = layer.LayerMat)
{ {
@@ -610,8 +606,6 @@ public class CXDLPv1File : FileFormat
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
outputFile.WriteBytes(layerBytes[layerIndex].ToArray()); outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
@@ -644,7 +638,7 @@ public class CXDLPv1File : FileFormat
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
} }
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]); Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!; previews[previewIndex] = null!;
@@ -664,10 +658,10 @@ public class CXDLPv1File : FileFormat
var linesBytes = new byte[LayerCount][]; var linesBytes = new byte[LayerCount][];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.ThrowIfCancellationRequested();
inputFile.Seek(4, SeekOrigin.Current); inputFile.Seek(4, SeekOrigin.Current);
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
@@ -675,12 +669,10 @@ public class CXDLPv1File : FileFormat
inputFile.ReadBytes(linesBytes[layerIndex]); inputFile.ReadBytes(linesBytes[layerIndex]);
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
progress.Token.ThrowIfCancellationRequested();
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = EmguExtensions.InitMat(Resolution)) using (var mat = EmguExtensions.InitMat(Resolution))
{ {
for (int i = 0; i < linesBytes[layerIndex].Length; i++) for (int i = 0; i < linesBytes[layerIndex].Length; i++)
@@ -717,8 +709,6 @@ public class CXDLPv1File : FileFormat
inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End); inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End);
} }
progress.Token.ThrowIfCancellationRequested();
FooterSettings = Helpers.Deserialize<Footer>(inputFile); FooterSettings = Helpers.Deserialize<Footer>(inputFile);
FooterSettings.Validate(); FooterSettings.Validate();
} }
+5 -7
View File
@@ -1914,9 +1914,8 @@ public class ChituboxFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
@@ -1934,7 +1933,7 @@ public class ChituboxFile : FileFormat
if (layerIndex == 0) layerDefSize = (uint)Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]); if (layerIndex == 0) layerDefSize = (uint)Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]);
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = LayerDefinitions[aaIndex, layerIndex]; var layerDef = LayerDefinitions[aaIndex, layerIndex];
LayerDef? layerDefHash = null; LayerDef? layerDefHash = null;
@@ -2098,7 +2097,7 @@ public class ChituboxFile : FileFormat
Debug.WriteLine($"-Image GROUP {aaIndex}-"); Debug.WriteLine($"-Image GROUP {aaIndex}-");
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
inputFile.Seek(layerOffset, SeekOrigin.Begin); inputFile.Seek(layerOffset, SeekOrigin.Begin);
var layerDef = Helpers.Deserialize<LayerDef>(inputFile); var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this; layerDef.Parent = this;
@@ -2136,16 +2135,15 @@ public class ChituboxFile : FileFormat
{ {
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin); inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize); LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize);
} }
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex); using var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex);
this[layerIndex] = new Layer((uint)layerIndex, mat, this); this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+64 -93
View File
@@ -426,116 +426,87 @@ public class ChituboxZipFile : FileFormat
outputFile.PutFileContent(GCodeFilename, GCodeStr, ZipArchiveMode.Create); outputFile.PutFileContent(GCodeFilename, GCodeStr, ZipArchiveMode.Create);
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
outputFile.PutFileContent($"{layerIndex + 1}.png", layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
} }
protected override void DecodeInternally(OperationProgress progress) protected override void DecodeInternally(OperationProgress progress)
{ {
using (var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read)) using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
var entry = inputFile.GetEntry(GCodeFilename);
if (entry is not null)
{ {
var entry = inputFile.GetEntry(GCodeFilename); //Clear();
if (entry is not null) //throw new FileLoadException("run.gcode not found", fileFullPath);
using TextReader tr = new StreamReader(entry.Open());
string? line;
GCode!.Clear();
while ((line = tr.ReadLine()) != null)
{ {
//Clear(); GCode.AppendLine(line);
//throw new FileLoadException("run.gcode not found", fileFullPath); if (string.IsNullOrEmpty(line)) continue;
using TextReader tr = new StreamReader(entry.Open());
string? line; if (line[0] != ';')
GCode!.Clear();
while ((line = tr.ReadLine()) != null)
{ {
GCode.AppendLine(line); continue;
if (string.IsNullOrEmpty(line)) continue;
if (line[0] != ';')
{
continue;
}
var splitLine = line.Split(':');
if (splitLine.Length < 2) continue;
foreach (var propertyInfo in HeaderSettings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var displayNameAttribute = propertyInfo.GetCustomAttributes(false).OfType<DisplayNameAttribute>().FirstOrDefault();
if (displayNameAttribute is null) continue;
if (!splitLine[0].Trim(' ', ';').Equals(displayNameAttribute.DisplayName)) continue;
Helpers.SetPropertyValue(propertyInfo, HeaderSettings, splitLine[1].Trim());
}
} }
tr.Close();
}
else
{
IsPHZZip = true;
}
if (HeaderSettings.LayerCount == 0) var splitLine = line.Split(':');
{ if (splitLine.Length < 2) continue;
foreach (var zipEntry in inputFile.Entries)
foreach (var propertyInfo in HeaderSettings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{ {
if(!zipEntry.Name.EndsWith(".png")) continue; var displayNameAttribute = propertyInfo.GetCustomAttributes(false).OfType<DisplayNameAttribute>().FirstOrDefault();
var filename = Path.GetFileNameWithoutExtension(zipEntry.Name); if (displayNameAttribute is null) continue;
if (!filename.All(char.IsDigit)) continue; if (!splitLine[0].Trim(' ', ';').Equals(displayNameAttribute.DisplayName)) continue;
if (!uint.TryParse(filename, out var layerIndex)) continue; Helpers.SetPropertyValue(propertyInfo, HeaderSettings, splitLine[1].Trim());
HeaderSettings.LayerCount = Math.Max(HeaderSettings.LayerCount, layerIndex);
} }
} }
tr.Close();
}
else
{
IsPHZZip = true;
}
Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); if (HeaderSettings.LayerCount == 0)
{
progress.ItemCount = LayerCount; foreach (var zipEntry in inputFile.Entries)
if (DecodeType == FileDecodeType.Full)
{ {
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) if(!zipEntry.Name.EndsWith(".png")) continue;
{ var filename = Path.GetFileNameWithoutExtension(zipEntry.Name);
if (progress.Token.IsCancellationRequested) break; if (!filename.All(char.IsDigit)) continue;
entry = inputFile.GetEntry($"{layerIndex + 1}.png"); if (!uint.TryParse(filename, out var layerIndex)) continue;
if (entry is null) HeaderSettings.LayerCount = Math.Max(HeaderSettings.LayerCount, layerIndex);
{
Clear();
throw new FileLoadException($"Layer {layerIndex + 1} not found", FileFullPath);
}
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
progress++;
}
}
if (IsPHZZip) // PHZ file
{
RebuildLayersProperties();
}
else
{
GCode?.ParseLayersFromGCode(this);
}
entry = inputFile.GetEntry("preview.png");
if (entry is not null)
{
Thumbnails![0] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
}
entry = inputFile.GetEntry("preview_cropping.png");
if (entry is not null)
{
var count = CreatedThumbnailsCount;
Thumbnails![count] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[count]);
} }
} }
GetBoundingRectangle(progress); Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial);
DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
if (IsPHZZip) // PHZ file
{
RebuildLayersProperties();
}
else
{
GCode?.ParseLayersFromGCode(this);
}
entry = inputFile.GetEntry("preview.png");
if (entry is not null)
{
Thumbnails![0] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
}
entry = inputFile.GetEntry("preview_cropping.png");
if (entry is not null)
{
var count = CreatedThumbnailsCount;
Thumbnails![count] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[count]);
}
} }
public override void RebuildGCode() public override void RebuildGCode()
+4 -6
View File
@@ -976,9 +976,8 @@ public class FDGFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]); LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -989,7 +988,7 @@ public class FDGFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = LayersDefinitions[layerIndex]; var layerDef = LayersDefinitions[layerIndex];
LayerDef? layerDefHash = null; LayerDef? layerDefHash = null;
@@ -1089,7 +1088,7 @@ public class FDGFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile); var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this; layerDef.Parent = this;
@@ -1107,9 +1106,8 @@ public class FDGFile : FileFormat
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex); using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
+149 -19
View File
@@ -19,8 +19,10 @@ using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers; using System.Timers;
using UVtools.Core.EmguCV; using UVtools.Core.EmguCV;
@@ -3229,7 +3231,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
DecodeInternally(progress); DecodeInternally(progress);
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerHeightDigits = LayerHeight.DecimalDigits(); var layerHeightDigits = LayerHeight.DecimalDigits();
if (layerHeightDigits > Layer.HeightPrecision) if (layerHeightDigits > Layer.HeightPrecision)
@@ -3243,8 +3245,128 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
{ {
Save(progress); Save(progress);
} }
GetBoundingRectangle(progress);
} }
public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default,
OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
{
if (DecodeType != FileDecodeType.Full || LayerCount == 0) return;
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
var batches = BatchLayersIndexes();
var pngLayerBytes = new byte[LayerCount][];
foreach (var batch in batches)
{
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
if (matGenFunc is null)
{
pngLayerBytes[layerIndex] = this[layerIndex].CompressedPngBytes!;
}
else
{
using var mat = this[layerIndex].LayerMat;
using var newMat = matGenFunc.Invoke((uint) layerIndex, mat);
pngLayerBytes[layerIndex] = newMat.GetPngByes();
}
progress.LockAndIncrement();
});
foreach (var layerIndex in batch)
{
zipArchive.PutFileContent(Path.Combine(path, this[layerIndex].FormatFileName(prepend, padDigits, layerIndexStartNumber)), pngLayerBytes[layerIndex], ZipArchiveMode.Create);
pngLayerBytes[layerIndex] = null!;
}
}
}
public void EncodeLayersInZip(ZipArchive zipArchive, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, string.Empty, padDigits, layerIndexStartNumber, progress, path, matGenFunc);
public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, Enumerations.IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, prepend, 0, layerIndexStartNumber, progress, path, matGenFunc);
public void EncodeLayersInZip(ZipArchive zipArchive, Enumerations.IndexStartNumber layerIndexStartNumber, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, string.Empty, 0, layerIndexStartNumber, progress, path, matGenFunc);
public void EncodeLayersInZip(ZipArchive zipArchive, OperationProgress progress, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, string.Empty, 0, Enumerations.IndexStartNumber.Zero, progress, path, matGenFunc);
public void DecodeLayersFromZip(ZipArchiveEntry[] layerEntries, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
{
if (DecodeType != FileDecodeType.Full || LayerCount == 0) return;
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
byte[] pngBytes;
lock (Mutex)
{
using var stream = layerEntries[layerIndex].Open();
pngBytes = stream.ToArray();
}
if (matGenFunc is null)
{
this[layerIndex] = new Layer((uint)layerIndex, pngBytes, this);
}
if (matGenFunc is not null)
{
using var mat = matGenFunc.Invoke((uint) layerIndex, pngBytes);
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
});
}
public void DecodeLayersFromZipRegex(ZipArchive zipArchive, string regex, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
{
var layerEntries = new ZipArchiveEntry?[LayerCount];
foreach (var entry in zipArchive.Entries)
{
var match = Regex.Match(entry.Name, regex);
if (!match.Success || match.Groups.Count < 2) continue;
if (!uint.TryParse(match.Groups[1].Value, out var layerIndex)) continue;
if (layerIndexStartNumber == Enumerations.IndexStartNumber.One && layerIndex > 0) layerIndex--;
if (layerIndex >= LayerCount)
{
continue;
}
layerEntries[layerIndex] = entry;
}
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (layerEntries[layerIndex] is not null) continue;
Clear();
throw new FileLoadException($"Layer {layerIndex} not found", FileFullPath);
}
DecodeLayersFromZip(layerEntries!, progress, matGenFunc);
}
public void DecodeLayersFromZip(ZipArchive zipArchive, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, $@"(\d{{{padDigits}}}).png", layerIndexStartNumber, progress, matGenFunc);
public void DecodeLayersFromZip(ZipArchive zipArchive, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, @"^(\d+).png", layerIndexStartNumber, progress, matGenFunc);
public void DecodeLayersFromZip(ZipArchive zipArchive, string prepend, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, $@"^{Regex.Escape(prepend)}(\d+).png", layerIndexStartNumber, progress, matGenFunc);
public void DecodeLayersFromZip(ZipArchive zipArchive, OperationProgress progress, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, @"^(\d+).png", Enumerations.IndexStartNumber.Zero, progress, matGenFunc);
/// <summary> /// <summary>
/// Extract contents to a folder /// Extract contents to a folder
/// </summary> /// </summary>
@@ -3389,10 +3511,9 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (LayerCount > 0 && DecodeType == FileDecodeType.Full) if (LayerCount > 0 && DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(this, CoreSettings.ParallelOptions, layer => Parallel.ForEach(this, CoreSettings.GetParallelOptions(progress), layer =>
{ {
if (progress.Token.IsCancellationRequested) return; var byteArr = layer.CompressedPngBytes;
var byteArr = layer.CompressedBytes;
if (byteArr is null) return; if (byteArr is null) return;
using var stream = new FileStream(Path.Combine(path, layer.Filename), FileMode.Create, FileAccess.Write); using var stream = new FileStream(Path.Combine(path, layer.Filename), FileMode.Create, FileAccess.Write);
stream.Write(byteArr, 0, byteArr.Length); stream.Write(byteArr, 0, byteArr.Length);
@@ -4366,6 +4487,23 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
public FileFormat? Convert(FileFormat to, string fileFullPath, uint version = 0, OperationProgress? progress = null) public FileFormat? Convert(FileFormat to, string fileFullPath, uint version = 0, OperationProgress? progress = null)
=> Convert(to.GetType(), fileFullPath, version, progress); => Convert(to.GetType(), fileFullPath, version, progress);
/// <summary>
/// Changes the compression method of all layers to a new method
/// </summary>
/// <param name="to">The new method to change to</param>
/// <param name="progress"></param>
public void ChangeLayersCompressionMethod(Layer.LayerCompressionMethod to, OperationProgress? progress = null)
{
progress ??= new OperationProgress($"Changing layers compress method to {to}");
progress.Reset("Layers", LayerCount);
Parallel.ForEach(this, CoreSettings.GetParallelOptions(progress), layer =>
{
layer.CompressionMethod = to;
progress.LockAndIncrement();
});
}
/// <summary> /// <summary>
/// Validate AntiAlias Level /// Validate AntiAlias Level
/// </summary> /// </summary>
@@ -4598,21 +4736,12 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (_boundingRectangle.IsEmpty) // Safe checking, all layers haven't a bounding rectangle if (_boundingRectangle.IsEmpty) // Safe checking, all layers haven't a bounding rectangle
{ {
progress.Reset(OperationProgress.StatusOptimizingBounds, LayerCount - 1); progress.Reset(OperationProgress.StatusOptimizingBounds, LayerCount - 1);
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
this[layerIndex].GetBoundingRectangle(); this[layerIndex].GetBoundingRectangle();
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
if (progress.Token.IsCancellationRequested)
{
_boundingRectangle = Rectangle.Empty;
progress.Token.ThrowIfCancellationRequested();
}
FindFirstBoundingRectangle(); FindFirstBoundingRectangle();
} }
@@ -4960,10 +5089,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </summary> /// </summary>
/// <param name="mats"></param> /// <param name="mats"></param>
/// <returns>The new Layer array</returns> /// <returns>The new Layer array</returns>
public Layer[] AllocateFromMat(Mat[] mats) public Layer[] AllocateFromMat(Mat[] mats, OperationProgress? progress = null)
{ {
progress ??= new OperationProgress();
var layers = new Layer[mats.Length]; var layers = new Layer[mats.Length];
Parallel.For(0, mats.Length, CoreSettings.ParallelOptions, i => Parallel.For(0, mats.Length, CoreSettings.GetParallelOptions(progress), i =>
{ {
layers[i] = new Layer((uint)i, mats[i], this); layers[i] = new Layer((uint)i, mats[i], this);
}); });
@@ -4976,9 +5106,9 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </summary> /// </summary>
/// <param name="mats"></param> /// <param name="mats"></param>
/// /// <returns>The new Layer array</returns> /// /// <returns>The new Layer array</returns>
public Layer[] AllocateAndSetFromMat(Mat[] mats) public Layer[] AllocateAndSetFromMat(Mat[] mats, OperationProgress? progress = null)
{ {
var layers = AllocateFromMat(mats); var layers = AllocateFromMat(mats, progress);
Layers = layers; Layers = layers;
return layers; return layers;
} }
@@ -5349,7 +5479,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
} }
progress.Reset("Saving", (uint)modifiedLayers.Count); progress.Reset("Saving", (uint)modifiedLayers.Count);
Parallel.ForEach(modifiedLayers, CoreSettings.ParallelOptions, modifiedLayer => Parallel.ForEach(modifiedLayers, CoreSettings.GetParallelOptions(progress), modifiedLayer =>
{ {
this[modifiedLayer.Key].LayerMat = modifiedLayer.Value; this[modifiedLayer.Key].LayerMat = modifiedLayer.Value;
modifiedLayer.Value.Dispose(); modifiedLayer.Value.Dispose();
@@ -503,10 +503,8 @@ public class FlashForgeSVGXFile : FileFormat
SVGDocument.Groups = new List<FlashForgeSVGXSvgGroup> { new("background") }; SVGDocument.Groups = new List<FlashForgeSVGXSvgGroup> { new("background") };
var groups = new FlashForgeSVGXSvgGroup[LayerCount]; var groups = new FlashForgeSVGXSvgGroup[LayerCount];
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
groups[layerIndex] = new FlashForgeSVGXSvgGroup($"layer-{layerIndex}"); groups[layerIndex] = new FlashForgeSVGXSvgGroup($"layer-{layerIndex}");
using var mat = this[layerIndex].LayerMat; using var mat = this[layerIndex].LayerMat;
@@ -651,10 +649,8 @@ public class FlashForgeSVGXFile : FileFormat
if (DecodeType != FileDecodeType.Full) return; if (DecodeType != FileDecodeType.Full) return;
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var mat = EmguExtensions.InitMat(Resolution); var mat = EmguExtensions.InitMat(Resolution);
var group = SVGDocument.Groups.FirstOrDefault(g => g.Id == $"layer-{layerIndex}"); var group = SVGDocument.Groups.FirstOrDefault(g => g.Id == $"layer-{layerIndex}");
@@ -665,7 +661,7 @@ public class FlashForgeSVGXFile : FileFormat
var points = new List<Point>(); var points = new List<Point>();
foreach (var path in @group.Paths) foreach (var path in @group.Paths)
{ {
if (progress.Token.IsCancellationRequested) break; progress.ThrowIfCancellationRequested();
var spaceSplit = path.Value.Split(' ', var spaceSplit = path.Value.Split(' ',
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
@@ -727,8 +723,6 @@ public class FlashForgeSVGXFile : FileFormat
} }
progress.Token.ThrowIfCancellationRequested();
this[layerIndex] = new Layer((uint)layerIndex, mat, this); this[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
+5 -15
View File
@@ -364,9 +364,8 @@ public class GR1File : FileFormat
var previews = new byte[ThumbnailsOriginalSize!.Length][]; var previews = new byte[ThumbnailsOriginalSize!.Length][];
// Previews // Previews
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2; var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null) if (Thumbnails[previewIndex] is null)
{ {
@@ -396,11 +395,8 @@ public class GR1File : FileFormat
var layerBytes = new List<byte>[LayerCount]; var layerBytes = new List<byte>[LayerCount];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested(); Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex]; var layer = this[layerIndex];
using (var mat = layer.LayerMat) using (var mat = layer.LayerMat)
{ {
@@ -446,8 +442,6 @@ public class GR1File : FileFormat
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
outputFile.WriteBytes(layerBytes[layerIndex].ToArray()); outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
@@ -482,7 +476,7 @@ public class GR1File : FileFormat
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
} }
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]); Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!; previews[previewIndex] = null!;
@@ -500,22 +494,18 @@ public class GR1File : FileFormat
var linesBytes = new byte[LayerCount][]; var linesBytes = new byte[LayerCount][];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.ThrowIfCancellationRequested();
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
linesBytes[layerIndex] = new byte[lineCount * 6]; linesBytes[layerIndex] = new byte[lineCount * 6];
inputFile.ReadBytes(linesBytes[layerIndex]); inputFile.ReadBytes(linesBytes[layerIndex]);
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
progress.Token.ThrowIfCancellationRequested();
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = EmguExtensions.InitMat(Resolution); using var mat = EmguExtensions.InitMat(Resolution);
for (int i = 0; i < linesBytes[layerIndex].Length; i++) for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+45 -76
View File
@@ -167,6 +167,7 @@ public class GenericZIPFile : FileFormat
{ {
if (entry.Name == ManifestFileName) return true; if (entry.Name == ManifestFileName) return true;
if (entry.Name.EndsWith(".gcode")) return false; if (entry.Name.EndsWith(".gcode")) return false;
if (entry.Name.EndsWith(".xml")) return false;
} }
} }
catch (Exception e) catch (Exception e)
@@ -201,14 +202,7 @@ public class GenericZIPFile : FileFormat
} }
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
var filename = $"{layerIndex + 1}.png";
outputFile.PutFileContent(filename, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
ManifestFile.Update(); ManifestFile.Update();
@@ -219,81 +213,56 @@ public class GenericZIPFile : FileFormat
protected override void DecodeInternally(OperationProgress progress) protected override void DecodeInternally(OperationProgress progress)
{ {
using (var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read)) using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
var entry = inputFile.Entries.FirstOrDefault(zipEntry => zipEntry.Name == ManifestFileName);
if (entry is not null)
{ {
var entry = inputFile.Entries.FirstOrDefault(zipEntry => zipEntry.Name == ManifestFileName); try
if (entry is not null)
{ {
try using var stream = entry.Open();
{ ManifestFile = XmlExtensions.DeserializeFromStream<GenericZipManifest>(stream);
using var stream = entry.Open();
ManifestFile = XmlExtensions.DeserializeFromStream<GenericZipManifest>(stream);
}
catch (Exception)
{
// Not required
//Clear();
//throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
}
} }
catch (Exception)
uint layerCount = 0;
foreach (var zipEntry in inputFile.Entries)
{ {
if (!zipEntry.Name.EndsWith(".png")) continue; // Not required
var filename = Path.GetFileNameWithoutExtension(zipEntry.Name); //Clear();
if (!filename.All(char.IsDigit)) continue; //throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
if (!uint.TryParse(filename, out var layerIndex)) continue;
layerCount = Math.Max(layerCount, layerIndex);
}
if (layerCount == 0)
{
Clear();
throw new FileLoadException("Unable to detect layer images in the file", FileFullPath);
}
Init(layerCount, DecodeType == FileDecodeType.Partial);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (progress.Token.IsCancellationRequested) break;
var filename = $"{layerIndex + 1}.png";
entry = inputFile.GetEntry(filename);
if (entry is null)
{
Clear();
throw new FileLoadException($"Layer {filename} not found", FileFullPath);
}
if (DecodeType == FileDecodeType.Full)
{
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
progress++;
}
entry = inputFile.GetEntry("preview.png");
if (entry is not null)
{
Thumbnails[0] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
}
entry = inputFile.GetEntry("preview_cropping.png");
if (entry is not null)
{
var count = CreatedThumbnailsCount;
Thumbnails[count] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[count]);
} }
} }
GetBoundingRectangle(progress); uint layerCount = 0;
foreach (var zipEntry in inputFile.Entries)
{
if (!zipEntry.Name.EndsWith(".png")) continue;
var filename = Path.GetFileNameWithoutExtension(zipEntry.Name);
if (!filename.All(char.IsDigit)) continue;
if (!uint.TryParse(filename, out var layerIndex)) continue;
layerCount = Math.Max(layerCount, layerIndex);
}
if (layerCount == 0)
{
Clear();
throw new FileLoadException("Unable to detect layer images in the file", FileFullPath);
}
Init(layerCount, DecodeType == FileDecodeType.Partial);
DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
entry = inputFile.GetEntry("preview.png");
if (entry is not null)
{
Thumbnails[0] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
}
entry = inputFile.GetEntry("preview_cropping.png");
if (entry is not null)
{
var count = CreatedThumbnailsCount;
Thumbnails[count] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[count]);
}
} }
protected override void PartialSaveInternally(OperationProgress progress) protected override void PartialSaveInternally(OperationProgress progress)
+5 -7
View File
@@ -530,9 +530,8 @@ public class LGSFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
layerData[layerIndex] = new LayerDef(this); layerData[layerIndex] = new LayerDef(this);
@@ -543,7 +542,7 @@ public class LGSFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
outputFile.WriteSerialize(layerData[layerIndex]); outputFile.WriteSerialize(layerData[layerIndex]);
layerData[layerIndex].EncodedRle = null!; // Free this layerData[layerIndex].EncodedRle = null!; // Free this
} }
@@ -555,7 +554,7 @@ public class LGSFile : FileFormat
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
outputFile.WriteSerialize(layerData[layerIndex]); outputFile.WriteSerialize(layerData[layerIndex]);
progress++; progress++;
} }
@@ -604,15 +603,14 @@ public class LGSFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
layerData[layerIndex].Parent = this; layerData[layerIndex].Parent = this;
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = layerData[layerIndex].Decode(); using var mat = layerData[layerIndex].Decode();
this[layerIndex] = new Layer((uint)layerIndex, mat, this); this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+6 -15
View File
@@ -323,9 +323,8 @@ public class MDLPFile : FileFormat
var previews = new byte[ThumbnailsOriginalSize!.Length][]; var previews = new byte[ThumbnailsOriginalSize!.Length][];
// Previews // Previews
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2; var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
if (Thumbnails[previewIndex] is null) if (Thumbnails[previewIndex] is null)
{ {
@@ -355,11 +354,8 @@ public class MDLPFile : FileFormat
var layerBytes = new List<byte>[LayerCount]; var layerBytes = new List<byte>[LayerCount];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested(); Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex]; var layer = this[layerIndex];
using (var mat = layer.LayerMat) using (var mat = layer.LayerMat)
{ {
@@ -405,8 +401,6 @@ public class MDLPFile : FileFormat
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
outputFile.WriteBytes(layerBytes[layerIndex].ToArray()); outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
@@ -439,7 +433,7 @@ public class MDLPFile : FileFormat
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
} }
Parallel.For(0, previews.Length, CoreSettings.ParallelOptions, previewIndex => Parallel.For(0, previews.Length, CoreSettings.GetParallelOptions(progress), previewIndex =>
{ {
Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]); Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
previews[previewIndex] = null!; previews[previewIndex] = null!;
@@ -456,22 +450,19 @@ public class MDLPFile : FileFormat
var linesBytes = new byte[LayerCount][]; var linesBytes = new byte[LayerCount][];
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
progress.Token.ThrowIfCancellationRequested();
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.ThrowIfCancellationRequested();
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
linesBytes[layerIndex] = new byte[lineCount * 6]; linesBytes[layerIndex] = new byte[lineCount * 6];
inputFile.ReadBytes(linesBytes[layerIndex]); inputFile.ReadBytes(linesBytes[layerIndex]);
inputFile.Seek(2, SeekOrigin.Current); inputFile.Seek(2, SeekOrigin.Current);
progress.Token.ThrowIfCancellationRequested();
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = EmguExtensions.InitMat(Resolution)) using (var mat = EmguExtensions.InitMat(Resolution))
{ {
+8 -10
View File
@@ -476,7 +476,7 @@ public class OSLAFile : FileFormat
var image = Thumbnails[i]; var image = Thumbnails[i];
if(image is null) continue; if(image is null) continue;
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var bytes = EncodeImage(HeaderSettings.PreviewDataType, image); var bytes = EncodeImage(HeaderSettings.PreviewDataType, image);
if (bytes.Length == 0) continue; if (bytes.Length == 0) continue;
@@ -517,9 +517,8 @@ public class OSLAFile : FileFormat
{ {
var layerBytes = new byte[LayerCount][]; var layerBytes = new byte[LayerCount][];
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
layerBytes[layerIndex] = EncodeImage(HeaderSettings.LayerDataType, mat); layerBytes[layerIndex] = EncodeImage(HeaderSettings.LayerDataType, mat);
@@ -530,7 +529,7 @@ public class OSLAFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
// Try to reuse layers // Try to reuse layers
var hash = CryptExtensions.ComputeSHA1Hash(layerBytes[layerIndex]); var hash = CryptExtensions.ComputeSHA1Hash(layerBytes[layerIndex]);
@@ -556,7 +555,7 @@ public class OSLAFile : FileFormat
outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin); outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
for (int layerIndex = 0; layerIndex < layerDataAddresses.Length; layerIndex++) for (int layerIndex = 0; layerIndex < layerDataAddresses.Length; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layer = this[layerIndex]; var layer = this[layerIndex];
var layerdef = new LayerDef(layer); var layerdef = new LayerDef(layer);
@@ -615,7 +614,7 @@ public class OSLAFile : FileFormat
for (byte i = 0; i < HeaderSettings.PreviewCount; i++) for (byte i = 0; i < HeaderSettings.PreviewCount; i++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var preview = Helpers.Deserialize<Preview>(inputFile); var preview = Helpers.Deserialize<Preview>(inputFile);
Debug.Write($"Preview {i} -> "); Debug.Write($"Preview {i} -> ");
@@ -644,7 +643,7 @@ public class OSLAFile : FileFormat
uint layerTableSize = 0; uint layerTableSize = 0;
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
layerDataAddresses[layerIndex] = inputFile.ReadUIntLittleEndian(); layerDataAddresses[layerIndex] = inputFile.ReadUIntLittleEndian();
layerDef[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); layerDef[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
@@ -670,15 +669,14 @@ public class OSLAFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin); inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin);
layerBytes[layerIndex] = inputFile.ReadBytes(inputFile.ReadUIntLittleEndian()); layerBytes[layerIndex] = inputFile.ReadBytes(inputFile.ReadUIntLittleEndian());
} }
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution); using var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution);
layerBytes[layerIndex] = null!; // Clean layerBytes[layerIndex] = null!; // Clean
+4 -7
View File
@@ -1002,9 +1002,8 @@ public class PHZFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]); LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -1015,7 +1014,7 @@ public class PHZFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = LayersDefinitions[layerIndex]; var layerDef = LayersDefinitions[layerIndex];
LayerDef? layerDefHash = null; LayerDef? layerDefHash = null;
@@ -1116,7 +1115,7 @@ public class PHZFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile); var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this; layerDef.Parent = this;
@@ -1134,10 +1133,8 @@ public class PHZFile : FileFormat
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex); using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
this[layerIndex] = new Layer((uint)layerIndex, mat, this); this[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement(); progress.LockAndIncrement();
+4 -6
View File
@@ -447,9 +447,8 @@ public class PhotonSFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
layerData[layerIndex] = new LayerDef(mat); layerData[layerIndex] = new LayerDef(mat);
@@ -460,7 +459,7 @@ public class PhotonSFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
outputFile.WriteSerialize(layerData[layerIndex]); outputFile.WriteSerialize(layerData[layerIndex]);
outputFile.WriteBytes(layerData[layerIndex].EncodedRle); outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
@@ -503,7 +502,7 @@ public class PhotonSFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = Helpers.Deserialize<LayerDef>(inputFile); var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layersDefinitions[layerIndex] = layerDef; layersDefinitions[layerIndex] = layerDef;
@@ -524,9 +523,8 @@ public class PhotonSFile : FileFormat
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = layersDefinitions[layerIndex].Decode(); using var mat = layersDefinitions[layerIndex].Decode();
this[layerIndex] = new Layer((uint)layerIndex, mat, this); this[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement(); progress.LockAndIncrement();
@@ -1695,9 +1695,8 @@ public class PhotonWorkshopFile : FileFormat
foreach (var batch in BatchLayersIndexes()) foreach (var batch in BatchLayersIndexes())
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat) using (var mat = this[layerIndex].LayerMat)
{ {
LayersDefinition.Layers[layerIndex] = new LayerDef(this, this[layerIndex]); LayersDefinition.Layers[layerIndex] = new LayerDef(this, this[layerIndex]);
@@ -1708,7 +1707,7 @@ public class PhotonWorkshopFile : FileFormat
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layerDef = LayersDefinition.Layers[layerIndex]; var layerDef = LayersDefinition.Layers[layerIndex];
@@ -1822,7 +1821,7 @@ public class PhotonWorkshopFile : FileFormat
{ {
foreach (var layerIndex in batch) foreach (var layerIndex in batch)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
LayersDefinition[layerIndex].Parent = this; LayersDefinition[layerIndex].Parent = this;
@@ -1840,10 +1839,8 @@ public class PhotonWorkshopFile : FileFormat
if (DecodeType == FileDecodeType.Full) if (DecodeType == FileDecodeType.Full)
{ {
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = LayersDefinition[layerIndex].Decode(); using var mat = LayersDefinition[layerIndex].Decode();
this[layerIndex] = new Layer((uint)layerIndex, mat, this) this[layerIndex] = new Layer((uint)layerIndex, mat, this)
{ {
+96 -121
View File
@@ -614,15 +614,7 @@ public class SL1File : FileFormat
stream.Close(); stream.Close();
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, filename, 5, Enumerations.IndexStartNumber.Zero, progress);
{
progress.Token.ThrowIfCancellationRequested();
Layer layer = this[layerIndex];
var layerImagePath = $"{filename}{layerIndex:D5}.png";
//layer.Filename = layerImagePath;
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
} }
@@ -635,135 +627,118 @@ public class SL1File : FileFormat
Statistics.ExecutionTime.Restart(); Statistics.ExecutionTime.Restart();
using (var inputFile = ZipFile.OpenRead(FileFullPath!)) using var inputFile = ZipFile.OpenRead(FileFullPath!);
List<string> iniFiles = new();
foreach (var entity in inputFile.Entries)
{ {
List<string> iniFiles = new(); if (!entity.Name.EndsWith(".ini")) continue;
foreach (ZipArchiveEntry entity in inputFile.Entries) iniFiles.Add(entity.Name);
using StreamReader streamReader = new(entity.Open());
string? line;
while ((line = streamReader.ReadLine()) != null)
{ {
if (!entity.Name.EndsWith(".ini")) continue; string[] keyValue = line.Split(new[] {'='}, 2);
iniFiles.Add(entity.Name); if (keyValue.Length < 2) continue;
using StreamReader streamReader = new(entity.Open()); keyValue[0] = keyValue[0].Trim();
string? line; keyValue[1] = keyValue[1].Trim();
while ((line = streamReader.ReadLine()) != null)
{
string[] keyValue = line.Split(new[] {'='}, 2);
if (keyValue.Length < 2) continue;
keyValue[0] = keyValue[0].Trim();
keyValue[1] = keyValue[1].Trim();
var fieldName = IniKeyToMemberName(keyValue[0]); var fieldName = IniKeyToMemberName(keyValue[0]);
bool foundMember = false; bool foundMember = false;
foreach (var obj in Configs) foreach (var obj in Configs)
{ {
var attribute = obj.GetType().GetProperty(fieldName); var attribute = obj.GetType().GetProperty(fieldName);
if (attribute is null || !attribute.CanWrite) continue; if (attribute is null || !attribute.CanWrite) continue;
//Debug.WriteLine(attribute.Name); //Debug.WriteLine(attribute.Name);
Helpers.SetPropertyValue(attribute, obj, keyValue[1]); Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
Statistics.ImplementedKeys.Add(keyValue[0]); Statistics.ImplementedKeys.Add(keyValue[0]);
foundMember = true; foundMember = true;
} }
if (!foundMember) if (!foundMember)
{
Statistics.MissingKeys.Add(keyValue[0]);
}
}
}
if (!iniFiles.Contains(IniConfig))
{
throw new FileLoadException($"Malformed file: {IniConfig} is missing.");
}
if (!iniFiles.Contains(IniPrusaslicer))
{
throw new FileLoadException($"Malformed file: {IniPrusaslicer} is missing.");
}
SuppressRebuildPropertiesWork(() =>
{
TransitionLayerCount = LookupCustomValue<ushort>(Keyword_TransitionLayerCount, 0);
BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, 0f);
LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, 0f);
BottomWaitTimeBeforeCure = LookupCustomValue(Keyword_BottomWaitTimeBeforeCure, 0f);
WaitTimeBeforeCure = LookupCustomValue(Keyword_WaitTimeBeforeCure, 0f);
BottomWaitTimeAfterCure = LookupCustomValue(Keyword_BottomWaitTimeAfterCure, 0f);
WaitTimeAfterCure = LookupCustomValue(Keyword_WaitTimeAfterCure, 0f);
BottomLiftHeight = LookupCustomValue(Keyword_BottomLiftHeight, DefaultBottomLiftHeight);
BottomLiftSpeed = LookupCustomValue(Keyword_BottomLiftSpeed, DefaultBottomLiftSpeed);
LiftHeight = LookupCustomValue(Keyword_LiftHeight, DefaultLiftHeight);
LiftSpeed = LookupCustomValue(Keyword_LiftSpeed, DefaultLiftSpeed);
BottomLiftHeight2 = LookupCustomValue(Keyword_BottomLiftHeight2, DefaultBottomLiftHeight2);
BottomLiftSpeed2 = LookupCustomValue(Keyword_BottomLiftSpeed2, DefaultBottomLiftSpeed2);
LiftHeight2 = LookupCustomValue(Keyword_LiftHeight2, DefaultLiftHeight2);
LiftSpeed2 = LookupCustomValue(Keyword_LiftSpeed2, DefaultLiftSpeed2);
BottomWaitTimeAfterLift = LookupCustomValue(Keyword_BottomWaitTimeAfterLift, 0f);
WaitTimeAfterLift = LookupCustomValue(Keyword_WaitTimeAfterLift, 0f);
BottomRetractSpeed = LookupCustomValue(Keyword_BottomRetractSpeed, DefaultBottomRetractSpeed);
RetractSpeed = LookupCustomValue(Keyword_RetractSpeed, DefaultRetractSpeed);
BottomRetractHeight2 = LookupCustomValue(Keyword_BottomRetractHeight2, DefaultBottomRetractHeight2);
RetractHeight2 = LookupCustomValue(Keyword_RetractHeight2, DefaultRetractHeight2);
BottomRetractSpeed2 = LookupCustomValue(Keyword_BottomRetractSpeed2, DefaultBottomRetractSpeed2);
RetractSpeed2 = LookupCustomValue(Keyword_RetractSpeed2, DefaultRetractSpeed2);
BottomLightPWM = LookupCustomValue(Keyword_BottomLightPWM, DefaultLightPWM);
LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM);
});
Init(OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast, DecodeType == FileDecodeType.Partial);
progress.ItemCount = LayerCount;
foreach (var entity in inputFile.Entries)
{
if (!entity.Name.EndsWith(".png")) continue;
if (entity.Name.StartsWith("thumbnail"))
{ {
using var stream = entity.Open(); Statistics.MissingKeys.Add(keyValue[0]);
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
byte thumbnailIndex =
(byte) (image.Width == ThumbnailsOriginalSize![(int) FileThumbnailSize.Small].Width &&
image.Height == ThumbnailsOriginalSize[(int) FileThumbnailSize.Small].Height
? FileThumbnailSize.Small
: FileThumbnailSize.Large);
Thumbnails[thumbnailIndex] = image;
//thumbnailIndex++;
continue;
} }
if (DecodeType == FileDecodeType.Full)
{
// - .png - 5 numbers
string layerStr = entity.Name.Substring(entity.Name.Length - 4 - 5, 5);
uint iLayer = uint.Parse(layerStr);
using var stream = entity.Open();
this[iLayer] = new Layer(iLayer, stream, this);
}
progress.ProcessedItems++;
} }
} }
if (!iniFiles.Contains(IniConfig))
{
throw new FileLoadException($"Malformed file: {IniConfig} is missing.");
}
if (!iniFiles.Contains(IniPrusaslicer))
{
throw new FileLoadException($"Malformed file: {IniPrusaslicer} is missing.");
}
SuppressRebuildPropertiesWork(() =>
{
TransitionLayerCount = LookupCustomValue<ushort>(Keyword_TransitionLayerCount, 0);
BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, 0f);
LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, 0f);
BottomWaitTimeBeforeCure = LookupCustomValue(Keyword_BottomWaitTimeBeforeCure, 0f);
WaitTimeBeforeCure = LookupCustomValue(Keyword_WaitTimeBeforeCure, 0f);
BottomWaitTimeAfterCure = LookupCustomValue(Keyword_BottomWaitTimeAfterCure, 0f);
WaitTimeAfterCure = LookupCustomValue(Keyword_WaitTimeAfterCure, 0f);
BottomLiftHeight = LookupCustomValue(Keyword_BottomLiftHeight, DefaultBottomLiftHeight);
BottomLiftSpeed = LookupCustomValue(Keyword_BottomLiftSpeed, DefaultBottomLiftSpeed);
LiftHeight = LookupCustomValue(Keyword_LiftHeight, DefaultLiftHeight);
LiftSpeed = LookupCustomValue(Keyword_LiftSpeed, DefaultLiftSpeed);
BottomLiftHeight2 = LookupCustomValue(Keyword_BottomLiftHeight2, DefaultBottomLiftHeight2);
BottomLiftSpeed2 = LookupCustomValue(Keyword_BottomLiftSpeed2, DefaultBottomLiftSpeed2);
LiftHeight2 = LookupCustomValue(Keyword_LiftHeight2, DefaultLiftHeight2);
LiftSpeed2 = LookupCustomValue(Keyword_LiftSpeed2, DefaultLiftSpeed2);
BottomWaitTimeAfterLift = LookupCustomValue(Keyword_BottomWaitTimeAfterLift, 0f);
WaitTimeAfterLift = LookupCustomValue(Keyword_WaitTimeAfterLift, 0f);
BottomRetractSpeed = LookupCustomValue(Keyword_BottomRetractSpeed, DefaultBottomRetractSpeed);
RetractSpeed = LookupCustomValue(Keyword_RetractSpeed, DefaultRetractSpeed);
BottomRetractHeight2 = LookupCustomValue(Keyword_BottomRetractHeight2, DefaultBottomRetractHeight2);
RetractHeight2 = LookupCustomValue(Keyword_RetractHeight2, DefaultRetractHeight2);
BottomRetractSpeed2 = LookupCustomValue(Keyword_BottomRetractSpeed2, DefaultBottomRetractSpeed2);
RetractSpeed2 = LookupCustomValue(Keyword_RetractSpeed2, DefaultRetractSpeed2);
BottomLightPWM = LookupCustomValue(Keyword_BottomLightPWM, DefaultLightPWM);
LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM);
});
Init(OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast, DecodeType == FileDecodeType.Partial);
progress.ItemCount = LayerCount;
foreach (var entity in inputFile.Entries)
{
if (!entity.Name.EndsWith(".png")) continue;
if (!entity.Name.StartsWith("thumbnail")) continue;
using var stream = entity.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
byte thumbnailIndex =
(byte) (image.Width == ThumbnailsOriginalSize![(int) FileThumbnailSize.Small].Width &&
image.Height == ThumbnailsOriginalSize[(int) FileThumbnailSize.Small].Height
? FileThumbnailSize.Small
: FileThumbnailSize.Large);
Thumbnails[thumbnailIndex] = image;
//thumbnailIndex++;
}
DecodeLayersFromZip(inputFile, 5, Enumerations.IndexStartNumber.Zero, progress);
if (TransitionLayerCount > 0) if (TransitionLayerCount > 0)
{ {
SetTransitionLayers(TransitionLayerCount, false); SetTransitionLayers(TransitionLayerCount, false);
} }
GetBoundingRectangle(progress);
Statistics.ExecutionTime.Stop(); Statistics.ExecutionTime.Stop();
Debug.WriteLine(Statistics); Debug.WriteLine(Statistics);
+39 -62
View File
@@ -502,75 +502,52 @@ public class UVJFile : FileFormat
stream.Close(); stream.Close();
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, 8, Enumerations.IndexStartNumber.Zero, progress, FolderImageName);
{
progress.Token.ThrowIfCancellationRequested();
Layer layer = this[layerIndex];
var layerimagePath = $"{FolderImageName}/{layerIndex:D8}.png";
outputFile.PutFileContent(layerimagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
} }
protected override void DecodeInternally(OperationProgress progress) protected override void DecodeInternally(OperationProgress progress)
{ {
using (var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read)) using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
var entry = inputFile.GetEntry(FileConfigName);
if (entry is null)
{ {
var entry = inputFile.GetEntry(FileConfigName); Clear();
if (entry is null) throw new FileLoadException($"{FileConfigName} not found", FileFullPath);
{
Clear();
throw new FileLoadException($"{FileConfigName} not found", FileFullPath);
}
JsonSettings = JsonSerializer.Deserialize<Settings>(entry.Open())!;
Init(JsonSettings.Properties.Size.Layers, DecodeType == FileDecodeType.Partial);
entry = inputFile.GetEntry(FilePreviewTinyName);
if (entry is not null)
{
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[0] = image;
stream.Close();
}
entry = inputFile.GetEntry(FilePreviewHugeName);
if (entry is not null)
{
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[1] = image;
stream.Close();
}
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
entry = inputFile.GetEntry($"{FolderImageName}/{layerIndex:D8}.png");
if (entry is null) continue;
if (DecodeType == FileDecodeType.Full)
{
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
if (JsonSettings.Layers?.Count > layerIndex)
{
JsonSettings.Layers[(int)layerIndex].CopyTo(this[layerIndex]);
}
}
progress.ProcessedItems++;
} }
GetBoundingRectangle(progress); JsonSettings = JsonSerializer.Deserialize<Settings>(entry.Open())!;
Init(JsonSettings.Properties.Size.Layers, DecodeType == FileDecodeType.Partial);
entry = inputFile.GetEntry(FilePreviewTinyName);
if (entry is not null)
{
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[0] = image;
stream.Close();
}
entry = inputFile.GetEntry(FilePreviewHugeName);
if (entry is not null)
{
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[1] = image;
stream.Close();
}
DecodeLayersFromZip(inputFile, progress);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (JsonSettings.Layers?.Count > layerIndex)
{
JsonSettings.Layers[(int)layerIndex].CopyTo(this[layerIndex]);
}
}
} }
protected override void PartialSaveInternally(OperationProgress progress) protected override void PartialSaveInternally(OperationProgress progress)
+22 -54
View File
@@ -309,15 +309,8 @@ public class VDAFile : FileFormat
Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml"). Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml").
Replace($".{FileExtensions[0].Extension}", ".xml"); Replace($".{FileExtensions[0].Extension}", ".xml");
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, 4, Enumerations.IndexStartNumber.One, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
var filename = $"{layerIndex + 1}".PadLeft(4, '0') + ".png";
outputFile.PutFileContent(filename, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
UpdateManifest(); UpdateManifest();
var entry = outputFile.CreateEntry(manifestFilename); var entry = outputFile.CreateEntry(manifestFilename);
@@ -327,53 +320,28 @@ public class VDAFile : FileFormat
protected override void DecodeInternally(OperationProgress progress) protected override void DecodeInternally(OperationProgress progress)
{ {
using (var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read)) using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
var entry = inputFile.Entries.FirstOrDefault(zipEntry => zipEntry.Name.EndsWith(".xml"));
if (entry is null)
{ {
var entry = inputFile.Entries.FirstOrDefault(zipEntry => zipEntry.Name.EndsWith(".xml")); Clear();
if (entry is null) throw new FileLoadException($".xml manifest not found", FileFullPath);
{
Clear();
throw new FileLoadException($".xml manifest not found", FileFullPath);
}
try
{
using var stream = entry.Open();
ManifestFile = XmlExtensions.DeserializeFromStream<VDARoot>(stream);
}
catch (Exception e)
{
Clear();
throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
}
Init(ManifestFile.Slices.LayerCount, DecodeType == FileDecodeType.Partial);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (progress.Token.IsCancellationRequested) break;
var filename = $"{layerIndex + 1}".PadLeft(4, '0')+".png";
entry = inputFile.GetEntry(filename);
if (entry is null)
{
Clear();
throw new FileLoadException($"Layer {filename} not found", FileFullPath);
}
if (DecodeType == FileDecodeType.Full)
{
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
progress++;
}
} }
GetBoundingRectangle(progress); try
{
using var stream = entry.Open();
ManifestFile = XmlExtensions.DeserializeFromStream<VDARoot>(stream);
}
catch (Exception e)
{
Clear();
throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
}
Init(ManifestFile.Slices.LayerCount, DecodeType == FileDecodeType.Partial);
DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
} }
protected override void PartialSaveInternally(OperationProgress progress) protected override void PartialSaveInternally(OperationProgress progress)
@@ -413,7 +381,7 @@ public class VDAFile : FileFormat
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
var layer = this[layerIndex]; var layer = this[layerIndex];
ManifestFile.Layers.Add(new VDARoot.VDALayer(layerIndex, layer.PositionZ, layer.FormatFileName(4, false))); ManifestFile.Layers.Add(new VDARoot.VDALayer(layerIndex, layer.PositionZ, layer.FormatFileName(4, Enumerations.IndexStartNumber.One)));
} }
} }
#endregion #endregion
+32 -51
View File
@@ -651,64 +651,45 @@ public class VDTFile : FileFormat
} }
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
var layerImagePath = $"{layerIndex}.png";
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
} }
protected override void DecodeInternally(OperationProgress progress) protected override void DecodeInternally(OperationProgress progress)
{ {
using (var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read)) using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
var entry = inputFile.GetEntry(FileManifestName);
if (entry is null)
{ {
var entry = inputFile.GetEntry(FileManifestName); Clear();
if (entry is null) throw new FileLoadException($"{FileManifestName} not found", FileFullPath);
{
Clear();
throw new FileLoadException($"{FileManifestName} not found", FileFullPath);
}
ManifestFile = JsonSerializer.Deserialize<VDTManifest>(entry.Open())!;
Init((uint) ManifestFile.Layers!.Length, DecodeType == FileDecodeType.Partial);
for (int i = 0; i < FilePreviewNames.Length; i++)
{
if (Thumbnails.Length <= i) break;
entry = inputFile.GetEntry(FilePreviewNames[i]);
if (entry is null) continue;
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[i] = image;
stream.Close();
}
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var manifestLayer = ManifestFile.Layers[layerIndex];
entry = inputFile.GetEntry($"{layerIndex}.png");
if (entry is null) continue;
if (DecodeType == FileDecodeType.Full)
{
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
manifestLayer.CopyTo(this[layerIndex]);
}
progress.ProcessedItems++;
} }
GetBoundingRectangle(progress); ManifestFile = JsonSerializer.Deserialize<VDTManifest>(entry.Open())!;
Init((uint) ManifestFile.Layers!.Length, DecodeType == FileDecodeType.Partial);
for (int i = 0; i < FilePreviewNames.Length; i++)
{
if (Thumbnails.Length <= i) break;
entry = inputFile.GetEntry(FilePreviewNames[i]);
if (entry is null) continue;
using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[i] = image;
stream.Close();
}
DecodeLayersFromZip(inputFile, progress);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var manifestLayer = ManifestFile.Layers[layerIndex];
manifestLayer.CopyTo(this[layerIndex]);
}
progress.ProcessedItems++;
} }
protected override void PartialSaveInternally(OperationProgress progress) protected override void PartialSaveInternally(OperationProgress progress)
+4 -31
View File
@@ -13,11 +13,13 @@ using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.OpenSsl;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.GCode; using UVtools.Core.GCode;
@@ -477,13 +479,7 @@ public class ZCodeFile : FileFormat
thumbnailsStream.Close(); thumbnailsStream.Close();
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
{
progress.Token.ThrowIfCancellationRequested();
var layer = this[layerIndex];
outputFile.PutFileContent($"{layerIndex + 1}.png", layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
var entry = outputFile.CreateEntry(ManifestFilename); var entry = outputFile.CreateEntry(ManifestFilename);
using (var stream = entry.Open()) using (var stream = entry.Open())
@@ -549,29 +545,8 @@ public class ZCodeFile : FileFormat
} }
Init(ManifestFile.Job.LayerCount, DecodeType == FileDecodeType.Partial); Init(ManifestFile.Job.LayerCount, DecodeType == FileDecodeType.Partial);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
//var gcode = GCode.ToString(); DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
//float lastPostZ = LayerHeight;
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (progress.Token.IsCancellationRequested) break;
entry = inputFile.GetEntry($"{layerIndex+1}.png");
if (entry is null)
{
Clear();
throw new FileLoadException($"Layer {layerIndex+1} not found", FileFullPath);
}
if (DecodeType == FileDecodeType.Full)
{
using var stream = entry.Open();
this[layerIndex] = new Layer(layerIndex, stream, this);
}
progress++;
}
GCode!.ParseLayersFromGCode(this); GCode!.ParseLayersFromGCode(this);
@@ -581,8 +556,6 @@ public class ZCodeFile : FileFormat
Thumbnails[0] = new Mat(); Thumbnails[0] = new Mat();
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]); CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
} }
GetBoundingRectangle(progress);
} }
protected override void PartialSaveInternally(OperationProgress progress) protected override void PartialSaveInternally(OperationProgress progress)
+7 -18
View File
@@ -401,12 +401,14 @@ public class ZCodexFile : FileFormat
stream.Close(); stream.Close();
} }
EncodeLayersInZip(outputFile, FolderImageName, 5, Enumerations.IndexStartNumber.Zero, progress, FolderImages);
GCode!.Clear(); GCode!.Clear();
float lastZPosition = 0; float lastZPosition = 0;
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layer = this[layerIndex]; var layer = this[layerIndex];
GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}"); GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}");
@@ -436,19 +438,7 @@ public class ZCodexFile : FileFormat
GCode.AppendLine(GCodeKeywordDelayModel); GCode.AppendLine(GCodeKeywordDelayModel);
GCode.AppendLine("M106 S0"); GCode.AppendLine("M106 S0");
var layerimagePath = $"{FolderImages}/{FolderImageName}{layerIndex:D5}.png";
using (var stream = outputFile.CreateEntry(layerimagePath).Open())
{
//image.Save(stream, Helpers.PngEncoder);
var byteArr = this[layerIndex].CompressedBytes;
stream.Write(byteArr!, 0, byteArr!.Length);
stream.Close();
}
lastZPosition = layer.PositionZ; lastZPosition = layer.PositionZ;
progress++;
} }
GCode.AppendLine($"G1 Z40.0 F{UserSettings.ZLiftFeedRate}"); GCode.AppendLine($"G1 Z40.0 F{UserSettings.ZLiftFeedRate}");
@@ -496,6 +486,8 @@ public class ZCodexFile : FileFormat
} }
Init(ResinMetadataSettings.TotalLayersCount, DecodeType == FileDecodeType.Partial); Init(ResinMetadataSettings.TotalLayersCount, DecodeType == FileDecodeType.Partial);
DecodeLayersFromZip(inputFile, FolderImageName, Enumerations.IndexStartNumber.Zero, progress);
GCode!.Clear(); GCode!.Clear();
using (TextReader tr = new StreamReader(entry.Open())) using (TextReader tr = new StreamReader(entry.Open()))
{ {
@@ -576,11 +568,11 @@ M106 S0
LayersSettings[layerIndex].LayerFileIndex = layerFileIndex; LayersSettings[layerIndex].LayerFileIndex = layerFileIndex;
LayersSettings[layerIndex].LayerEntry = inputFile.GetEntry(layerimagePath); LayersSettings[layerIndex].LayerEntry = inputFile.GetEntry(layerimagePath);
if (DecodeType == FileDecodeType.Full) /*if (DecodeType == FileDecodeType.Full)
{ {
using var stream = LayersSettings[layerIndex].LayerEntry!.Open(); using var stream = LayersSettings[layerIndex].LayerEntry!.Open();
this[layerIndex] = new Layer((uint)layerIndex, stream, this); this[layerIndex] = new Layer((uint)layerIndex, stream, this);
} }*/
this[layerIndex].PositionZ = currentHeight; this[layerIndex].PositionZ = currentHeight;
this[layerIndex].LiftHeight = liftHeight; this[layerIndex].LiftHeight = liftHeight;
@@ -588,8 +580,6 @@ M106 S0
this[layerIndex].RetractSpeed = retractSpeed; this[layerIndex].RetractSpeed = retractSpeed;
this[layerIndex].LightPWM = pwm; this[layerIndex].LightPWM = pwm;
layerIndex++; layerIndex++;
progress++;
} }
} }
@@ -606,7 +596,6 @@ M106 S0
} }
BottomRetractSpeed = RetractSpeed; // Compability BottomRetractSpeed = RetractSpeed; // Compability
GetBoundingRectangle(progress);
} }
public override void RebuildGCode() public override void RebuildGCode()
+214 -25
View File
@@ -10,9 +10,12 @@ using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using K4os.Compression.LZ4;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
using UVtools.Core.Objects; using UVtools.Core.Objects;
@@ -25,6 +28,24 @@ namespace UVtools.Core.Layers;
/// </summary> /// </summary>
public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint> public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
{ {
#region Enums
public enum LayerCompressionMethod : byte
{
[Description("PNG: Compression=High Speed=Slow (Use with low RAM)")]
Png,
[Description("GZip: Compression=Medium Speed=Medium (Optimal)")]
GZip,
[Description("Deflate: Compression=Medium Speed=Medium (Optimal)")]
Deflate,
[Description("LZ4: Compression=Low Speed=Fast (Use with high RAM)")]
Lz4,
//[Description("None: Compression=None Speed=Fastest (Your soul belongs to RAM)")]
//None
}
#endregion
#region Constants #region Constants
public const byte HeightPrecision = 3; public const byte HeightPrecision = 3;
public const decimal HeightPrecisionIncrement = 0.001M; public const decimal HeightPrecisionIncrement = 0.001M;
@@ -35,6 +56,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
#region Members #region Members
public object Mutex = new(); public object Mutex = new();
private LayerCompressionMethod _compressionMethod;
private byte[]? _compressedBytes; private byte[]? _compressedBytes;
private uint _nonZeroPixelCount; private uint _nonZeroPixelCount;
private Rectangle _boundingRectangle = Rectangle.Empty; private Rectangle _boundingRectangle = Rectangle.Empty;
@@ -55,6 +77,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
private float _retractSpeed2 = FileFormat.DefaultRetractSpeed2; private float _retractSpeed2 = FileFormat.DefaultRetractSpeed2;
private byte _lightPWM = FileFormat.DefaultLightPWM; private byte _lightPWM = FileFormat.DefaultLightPWM;
private float _materialMilliliters; private float _materialMilliliters;
#endregion #endregion
#region Properties #region Properties
@@ -567,6 +590,29 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// </summary> /// </summary>
public float MaterialMillilitersPercent => _materialMilliliters * 100 / SlicerFile.MaterialMilliliters; public float MaterialMillilitersPercent => _materialMilliliters * 100 / SlicerFile.MaterialMilliliters;
/// <summary>
/// Gets or sets the compression method used to cache the image
/// </summary>
public LayerCompressionMethod CompressionMethod
{
get => _compressionMethod;
set
{
if (!HaveImage)
{
RaiseAndSetIfChanged(ref _compressionMethod, value);
return;
}
// Handle conversion
if (_compressionMethod == value) return;
using var mat = LayerMat;
_compressionMethod = value;
_compressedBytes = CompressMat(mat, value);
RaisePropertyChanged();
}
}
/// <summary> /// <summary>
/// Gets or sets layer image compressed data /// Gets or sets layer image compressed data
/// </summary> /// </summary>
@@ -583,6 +629,18 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
} }
} }
public byte[]? CompressedPngBytes
{
get
{
if (_compressedBytes is null) return null;
if (_compressionMethod == LayerCompressionMethod.Png) return _compressedBytes;
using var mat = LayerMat;
return mat.GetPngByes();
}
}
/// <summary> /// <summary>
/// True if this layer have an valid initialized image, otherwise false /// True if this layer have an valid initialized image, otherwise false
/// </summary> /// </summary>
@@ -596,13 +654,70 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
get get
{ {
if (!HaveImage) return null!; if (!HaveImage) return null!;
Mat mat = new();
CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat); Mat mat;
return mat; switch (_compressionMethod)
{
case LayerCompressionMethod.Png:
mat = new Mat();
CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat);
break;
case LayerCompressionMethod.Lz4:
mat = new Mat(SlicerFile.Resolution, DepthType.Cv8U, 1);
LZ4Codec.Decode(_compressedBytes.AsSpan(), mat.GetDataByteSpan());
break;
case LayerCompressionMethod.GZip:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
var matSpan = mat.GetDataByteSpan();
unsafe
{
fixed (byte* pBuffer = _compressedBytes)
{
using var compressedStream = new UnmanagedMemoryStream(pBuffer, _compressedBytes!.Length);
using var matStream = new UnmanagedMemoryStream(mat.GetBytePointer(), matSpan.Length, matSpan.Length, FileAccess.Write);
using var gZipStream = new GZipStream(compressedStream, CompressionMode.Decompress);
gZipStream.CopyTo(matStream);
}
}
break;
}
case LayerCompressionMethod.Deflate:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
var matSpan = mat.GetDataByteSpan();
unsafe
{
fixed (byte* pBuffer = _compressedBytes)
{
using var compressedStream = new UnmanagedMemoryStream(pBuffer, _compressedBytes!.Length);
using var matStream = new UnmanagedMemoryStream(mat.GetBytePointer(), matSpan.Length, matSpan.Length, FileAccess.Write);
using var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress);
deflateStream.CopyTo(matStream);
}
}
break;
}
/*case LayerCompressionMethod.None:
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
//mat.SetBytes(_compressedBytes!);
_compressedBytes.CopyTo(mat.GetDataByteSpan());
break;*/
default:
throw new ArgumentOutOfRangeException(nameof(LayerMat));
}
return mat;
} }
set set
{ {
CompressedBytes = value?.GetPngByes(); if (value is not null)
{
CompressedBytes = CompressMat(value, _compressionMethod);
}
GetBoundingRectangle(value, true); GetBoundingRectangle(value, true);
RaisePropertyChanged(); RaisePropertyChanged();
} }
@@ -627,7 +742,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// <summary> /// <summary>
/// Gets a computed layer filename, padding zeros are equal to layer count digits /// Gets a computed layer filename, padding zeros are equal to layer count digits
/// </summary> /// </summary>
public string Filename => FormatFileName("layer"); public string Filename => FormatFileNameWithLayerDigits("layer");
/// <summary> /// <summary>
/// Gets if layer image has been modified /// Gets if layer image has been modified
@@ -700,29 +815,55 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
#region Constructor #region Constructor
public Layer(uint index, FileFormat slicerFile) public Layer(uint index, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null)
{ {
compressionMethod ??= CoreSettings.DefaultLayerCompressionMethod;
_compressionMethod = compressionMethod.Value;
SlicerFile = slicerFile; SlicerFile = slicerFile;
_index = index; _index = index;
//if (slicerFile is null) return; //if (slicerFile is null) return;
_positionZ = SlicerFile.GetHeightFromLayer(index); _positionZ = SlicerFile.GetHeightFromLayer(index);
ResetParameters(); ResetParameters();
} }
public Layer(uint index, byte[] compressedBytes, FileFormat slicerFile) : this(index, slicerFile) public Layer(uint index, byte[] pngBytes, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, slicerFile, compressionMethod)
{ {
CompressedBytes = compressedBytes; if (_compressionMethod == LayerCompressionMethod.Png)
{
CompressedBytes = pngBytes;
}
else
{
var mat = new Mat();
CvInvoke.Imdecode(pngBytes, ImreadModes.Grayscale, mat);
LayerMat = mat;
}
_isModified = false; _isModified = false;
} }
public Layer(uint index, Mat layerMat, FileFormat slicerFile) : this(index, slicerFile) public Layer(uint index, Mat layerMat, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, slicerFile, compressionMethod)
{ {
LayerMat = layerMat; LayerMat = layerMat;
_isModified = false; _isModified = false;
} }
public Layer(uint index, Stream stream, FileFormat slicerFile) : this(index, stream.ToArray(), slicerFile) { } public Layer(uint index, Stream stream, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, stream.ToArray(), slicerFile, compressionMethod)
{ }
public Layer(FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, slicerFile, compressionMethod)
{ }
public Layer(byte[] pngBytes, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, pngBytes, slicerFile, compressionMethod)
{ }
public Layer(Mat layerMat, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, layerMat, slicerFile, compressionMethod)
{ }
public Layer(Stream stream, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, stream, slicerFile, compressionMethod) { }
#endregion #endregion
#region Equatables #region Equatables
@@ -946,22 +1087,22 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
WaitTimeAfterLift = 0; WaitTimeAfterLift = 0;
} }
public string FormatFileName(string prepend, byte padDigits, bool layerIndexZeroStarted = true, string appendExt = ".png") public string FormatFileName(string prepend = "", byte padDigits = 0, Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
{ {
var index = Index; var index = Index;
if (!layerIndexZeroStarted) if (layerIndexStartNumber == Enumerations.IndexStartNumber.One)
{ {
index++; index++;
} }
return $"{prepend}{index.ToString().PadLeft(padDigits, '0')}{appendExt}"; return $"{prepend}{index.ToString().PadLeft(padDigits, '0')}{appendExt}";
} }
public string FormatFileName(string prepend = "", bool layerIndexZeroStarted = true, string appendExt = ".png") public string FormatFileName(byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
=> FormatFileName(prepend, SlicerFile.LayerDigits, layerIndexZeroStarted, appendExt); => FormatFileName(string.Empty, padDigits, layerIndexStartNumber, appendExt);
public string FormatFileName(byte padDigits, bool layerIndexZeroStarted = true, string appendExt = ".png") public string FormatFileNameWithLayerDigits(string prepend = "", Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
=> FormatFileName(string.Empty, padDigits, layerIndexZeroStarted, appendExt); => FormatFileName(prepend, SlicerFile.LayerDigits, layerIndexStartNumber, appendExt);
public Rectangle GetBoundingRectangle(Mat? mat = null, bool reCalculate = false) public Rectangle GetBoundingRectangle(Mat? mat = null, bool reCalculate = false)
{ {
@@ -1314,12 +1455,13 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
public Layer Clone() public Layer Clone()
{ {
//var layer = (Layer)MemberwiseClone(); var layer = (Layer)MemberwiseClone();
//layer.CompressedBytes = _compressedBytes.ToArray(); layer._compressedBytes = _compressedBytes?.ToArray();
//Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes)); //Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes));
//return layer; return layer;
return new (_index, CompressedBytes?.ToArray()!, SlicerFile) /*return new (_index, CompressedBytes?.ToArray()!, SlicerFile)
{ {
_compressionMethod = _compressionMethod,
_positionZ = _positionZ, _positionZ = _positionZ,
_lightOffDelay = _lightOffDelay, _lightOffDelay = _lightOffDelay,
_waitTimeBeforeCure = _waitTimeBeforeCure, _waitTimeBeforeCure = _waitTimeBeforeCure,
@@ -1337,8 +1479,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
_boundingRectangle = _boundingRectangle, _boundingRectangle = _boundingRectangle,
_nonZeroPixelCount = _nonZeroPixelCount, _nonZeroPixelCount = _nonZeroPixelCount,
_isModified = _isModified, _isModified = _isModified,
_materialMilliliters = _materialMilliliters _materialMilliliters = _materialMilliliters,
}; };*/
} }
#endregion #endregion
@@ -1362,5 +1504,52 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
return clonedLayers; return clonedLayers;
} }
public static byte[] CompressMat(Mat mat, LayerCompressionMethod method)
{
switch (method)
{
case LayerCompressionMethod.Png:
return mat.GetPngByes();
case LayerCompressionMethod.Lz4:
{
var span = mat.GetDataByteSpan();
var target = new byte[LZ4Codec.MaximumOutputSize(span.Length)];
var encodedLength = LZ4Codec.Encode(span, target.AsSpan());
return target[..encodedLength];
}
case LayerCompressionMethod.GZip:
{
/*var matSpan = mat.GetDataByteSpan();
var compressedBytes = new byte[matSpan.Length];
unsafe
{
fixed (byte* pBuffer = compressedBytes)
{
using var compressedStream = new UnmanagedMemoryStream(pBuffer, compressedBytes.Length, compressedBytes.Length, FileAccess.Write);
using var gZipStream = new GZipStream(compressedStream, CompressionLevel.Fastest);
gZipStream.Write(mat.GetDataByteSpan());
//return compressedBytes;
}
}*/
using var compressedStream = new MemoryStream();
using var gZipStream = new GZipStream(compressedStream, CompressionLevel.Fastest);
gZipStream.Write(mat.GetDataByteSpan());
return compressedStream.ToArray();
}
case LayerCompressionMethod.Deflate:
{
using var compressedStream = new MemoryStream();
using var deflateStream = new DeflateStream(compressedStream, CompressionLevel.Fastest);
deflateStream.Write(mat.GetDataByteSpan());
return compressedStream.ToArray();
}
/*case LayerCompressionMethod.None:
return mat.GetBytes();*/
default:
throw new ArgumentOutOfRangeException(nameof(method));
}
}
#endregion #endregion
} }
+1 -1
View File
@@ -553,7 +553,7 @@ public abstract class Operation : BindableBase, IDisposable
var result = ExecuteInternally(progress); var result = ExecuteInternally(progress);
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
return result; return result;
} }
+1 -2
View File
@@ -130,9 +130,8 @@ public sealed class OperationBlur : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = SlicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
@@ -1892,9 +1892,8 @@ public sealed class OperationCalibrateExposureFinder : Operation
var tableGrouped = table.GroupBy(pair => new {pair.Key.LayerHeight, pair.Key.BottomExposure, pair.Key.Exposure}).Distinct(); var tableGrouped = table.GroupBy(pair => new {pair.Key.LayerHeight, pair.Key.BottomExposure, pair.Key.Exposure}).Distinct();
SlicerFile.BottomLayerCount = _bottomLayers; SlicerFile.BottomLayerCount = _bottomLayers;
progress.ItemCount = (uint) (SlicerFile.LayerCount * table.Count); progress.ItemCount = (uint) (SlicerFile.LayerCount * table.Count);
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, SlicerFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat; using var mat = layer.LayerMat;
var matRoi = new Mat(mat, boundingRectangle); var matRoi = new Mat(mat, boundingRectangle);
@@ -1964,7 +1963,6 @@ public sealed class OperationCalibrateExposureFinder : Operation
} }
}); });
progress.Token.ThrowIfCancellationRequested();
if (parallelLayers.IsEmpty) return false; if (parallelLayers.IsEmpty) return false;
var layers = parallelLayers.OrderBy(layer => layer.PositionZ).ThenBy(layer => layer.ExposureTime).ToList(); var layers = parallelLayers.OrderBy(layer => layer.PositionZ).ThenBy(layer => layer.ExposureTime).ToList();
@@ -1973,7 +1971,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
Layer currentLayer = layers[0]; Layer currentLayer = layers[0];
for (var layerIndex = 1; layerIndex < layers.Count; layerIndex++) for (var layerIndex = 1; layerIndex < layers.Count; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
progress++; progress++;
var layer = layers[layerIndex]; var layer = layers[layerIndex];
if (currentLayer.PositionZ != layer.PositionZ || if (currentLayer.PositionZ != layer.PositionZ ||
@@ -2206,7 +2204,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
currentHeight = Layer.RoundHeight(currentHeight); currentHeight = Layer.RoundHeight(currentHeight);
for (decimal layerHeight = _layerHeight; layerHeight <= endLayerHeight; layerHeight += _multipleLayerHeightStep) for (decimal layerHeight = _layerHeight; layerHeight <= endLayerHeight; layerHeight += _multipleLayerHeightStep)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
layerHeight = Layer.RoundHeight(layerHeight); layerHeight = Layer.RoundHeight(layerHeight);
if (_multipleExposures) if (_multipleExposures)
@@ -418,7 +418,7 @@ public sealed class OperationCalibrateStressTower : Operation
var layers = GetLayers(); var layers = GetLayers();
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true}; newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true};
layers[layerIndex].Dispose(); layers[layerIndex].Dispose();
@@ -729,7 +729,7 @@ public sealed class OperationCalibrateTolerance : Operation
var layers = GetLayers(); var layers = GetLayers();
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true}; newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile) {IsModified = true};
layers[layerIndex].Dispose(); layers[layerIndex].Dispose();
@@ -205,10 +205,8 @@ public sealed class OperationChangeResolution : Operation
var finalBounds = new Size((int)finalBoundsWidth, (int)finalBoundsHeight); var finalBounds = new Size((int)finalBoundsWidth, (int)finalBoundsHeight);
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, SlicerFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
if (mat.Size != newSize) if (mat.Size != newSize)
@@ -230,8 +228,6 @@ public sealed class OperationChangeResolution : Operation
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
SlicerFile.ResolutionX = NewResolutionX; SlicerFile.ResolutionX = NewResolutionX;
SlicerFile.ResolutionY = NewResolutionY; SlicerFile.ResolutionY = NewResolutionY;
@@ -283,10 +283,8 @@ public class OperationDoubleExposure : Operation
layers[i] = SlicerFile[i]; layers[i] = SlicerFile[i];
} }
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var firstLayer = SlicerFile[layerIndex]; var firstLayer = SlicerFile[layerIndex];
var secondLayer = firstLayer.Clone(); var secondLayer = firstLayer.Clone();
var isBottomLayer = firstLayer.IsBottomLayer; var isBottomLayer = firstLayer.IsBottomLayer;
@@ -669,7 +669,7 @@ public sealed class OperationDynamicLayerHeight : Operation
while (true) // In a stack while (true) // In a stack
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
progress.ProcessedItems = layerIndex - LayerIndexStart; progress.ProcessedItems = layerIndex - LayerIndexStart;
if (currentLayerHeight >= (float)_maximumLayerHeight || layerIndex == LayerIndexEnd) if (currentLayerHeight >= (float)_maximumLayerHeight || layerIndex == LayerIndexEnd)
@@ -325,7 +325,7 @@ public sealed class OperationDynamicLifts : Operation
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++) for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
// Height // Height
@@ -191,7 +191,7 @@ public class OperationFadeExposureTime : Operation
var exposure = _fromExposureTime; var exposure = _fromExposureTime;
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++) for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
exposure += increment; exposure += increment;
SlicerFile[layerIndex].ExposureTime = (float)exposure; SlicerFile[layerIndex].ExposureTime = (float)exposure;
} }
+1 -2
View File
@@ -101,9 +101,8 @@ public class OperationFlip : Operation
#region Methods #region Methods
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
+1 -3
View File
@@ -135,10 +135,8 @@ public sealed class OperationInfill : Operation
mask = GetHoneycombMask(GetRoiSizeOrDefault()); mask = GetHoneycombMask(GetRoiSizeOrDefault());
} }
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, mask!); Execute(mat, layerIndex, mask!);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
@@ -253,7 +253,7 @@ public class OperationLayerArithmetic : Operation
progress.ItemCount = (uint) Operations.Count; progress.ItemCount = (uint) Operations.Count;
for (int i = 1; i < Operations.Count; i++) for (int i = 1; i < Operations.Count; i++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
using var image = SlicerFile[Operations[i].LayerIndex].LayerMat; using var image = SlicerFile[Operations[i].LayerIndex].LayerMat;
var imageRoi = GetRoiOrDefault(image); var imageRoi = GetRoiOrDefault(image);
@@ -289,9 +289,8 @@ public class OperationLayerArithmetic : Operation
} }
progress.Reset("Applied layers", (uint) SetLayers.Count); progress.Reset("Applied layers", (uint) SetLayers.Count);
Parallel.ForEach(SetLayers, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(SetLayers, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
progress.LockAndIncrement(); progress.LockAndIncrement();
if (Operations.Count == 1 || HaveROIorMask) if (Operations.Count == 1 || HaveROIorMask)
{ {
@@ -224,9 +224,8 @@ public sealed class OperationLayerExportGif : Operation
ROI = SlicerFile.BoundingRectangle; ROI = SlicerFile.BoundingRectangle;
} }
Parallel.For(0, TotalLayers, CoreSettings.ParallelOptions, i => Parallel.For(0, TotalLayers, CoreSettings.GetParallelOptions(progress), i =>
{ {
if (progress.Token.IsCancellationRequested) return;
uint layerIndex = (uint) (LayerIndexStart + i * (_skip + 1)); uint layerIndex = (uint) (LayerIndexStart + i * (_skip + 1));
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat; using var mat = layer.LayerMat;
@@ -270,8 +269,8 @@ public sealed class OperationLayerExportGif : Operation
progress.ResetNameAndProcessed("Packed layers"); progress.ResetNameAndProcessed("Packed layers");
foreach (var buffer in layerBuffer) foreach (var buffer in layerBuffer)
{ {
if (progress.Token.IsCancellationRequested) break; progress.ThrowIfCancellationRequested();
using Stream stream = new MemoryStream(buffer); using var stream = new MemoryStream(buffer);
using var img = Image.FromStream(stream); using var img = Image.FromStream(stream);
gif.AddFrame(img, -1, GifQuality.Bit8); gif.AddFrame(img, -1, GifQuality.Bit8);
progress++; progress++;
@@ -152,10 +152,8 @@ public sealed class OperationLayerExportHeatMap : Operation
} }
});*/ });*/
Parallel.ForEach(layerRange, CoreSettings.ParallelOptions, layer => Parallel.ForEach(layerRange, CoreSettings.GetParallelOptions(progress), layer =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = _mergeSamePositionedLayers using var mat = _mergeSamePositionedLayers
? SlicerFile.GetMergedMatForSequentialPositionedLayers(layer.Index) ? SlicerFile.GetMergedMatForSequentialPositionedLayers(layer.Index)
: layer.LayerMat; : layer.LayerMat;
@@ -171,32 +169,31 @@ public sealed class OperationLayerExportHeatMap : Operation
} }
}); });
if (!progress.Token.IsCancellationRequested)
using var sumMat = EmguExtensions.InitMat(sumMat32.Size);
sumMat32.ConvertTo(sumMat, DepthType.Cv8U, 1.0 / layerRange.Length);
if (_flipDirection != Enumerations.FlipDirection.None)
{ {
using var sumMat = EmguExtensions.InitMat(sumMat32.Size); CvInvoke.Flip(sumMat, sumMat, Enumerations.ToOpenCVFlipType(_flipDirection));
sumMat32.ConvertTo(sumMat, DepthType.Cv8U, 1.0 / layerRange.Length);
if (_flipDirection != Enumerations.FlipDirection.None)
{
CvInvoke.Flip(sumMat, sumMat, Enumerations.ToOpenCVFlipType(_flipDirection));
}
if (_rotateDirection != Enumerations.RotateDirection.None)
{
CvInvoke.Rotate(sumMat, sumMat, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
}
if (_cropByRoi && HaveROI)
{
var sumMatRoi = GetRoiOrDefault(sumMat);
sumMatRoi.Save(_filePath);
}
else
{
sumMat.Save(_filePath);
}
} }
if (_rotateDirection != Enumerations.RotateDirection.None)
{
CvInvoke.Rotate(sumMat, sumMat, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
}
if (_cropByRoi && HaveROI)
{
var sumMatRoi = GetRoiOrDefault(sumMat);
sumMatRoi.Save(_filePath);
}
else
{
sumMat.Save(_filePath);
}
return !progress.Token.IsCancellationRequested; return !progress.Token.IsCancellationRequested;
} }
@@ -180,10 +180,8 @@ public sealed class OperationLayerExportImage : Operation
var slicedFileNameNoExt = SlicerFile.FilenameNoExt; var slicedFileNameNoExt = SlicerFile.FilenameNoExt;
Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = mat; var matRoi = mat;
if (_cropByRoi && HaveROI) if (_cropByRoi && HaveROI)
@@ -201,7 +199,7 @@ public sealed class OperationLayerExportImage : Operation
CvInvoke.Rotate(matRoi, matRoi, Enumerations.ToOpenCVRotateFlags(_rotateDirection)); CvInvoke.Rotate(matRoi, matRoi, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
} }
var filename = SlicerFile[layerIndex].FormatFileName(_filename, _padLayerIndex ? SlicerFile.LayerDigits : byte.MinValue, true, string.Empty); var filename = SlicerFile[layerIndex].FormatFileName(_filename, _padLayerIndex ? SlicerFile.LayerDigits : byte.MinValue, Enumerations.IndexStartNumber.Zero, string.Empty);
var fileFullPath = Path.Combine(_outputFolder, $"{filename}.{_imageType.ToString().ToLower()}"); var fileFullPath = Path.Combine(_outputFolder, $"{filename}.{_imageType.ToString().ToLower()}");
if (_imageType != LayerExportImageTypes.SVG) if (_imageType != LayerExportImageTypes.SVG)
@@ -274,7 +274,7 @@ public sealed class OperationLayerExportMesh : Operation
var voxelSpan = voxelLayer.GetBytePointer(); var voxelSpan = voxelLayer.GetBytePointer();
/* Seems to be faster to parallel on the Y and not the X */ /* Seems to be faster to parallel on the Y and not the X */
Parallel.For(0, curLayer!.Height, CoreSettings.ParallelOptions, y => Parallel.For(0, curLayer!.Height, CoreSettings.GetParallelOptions(progress), y =>
{ {
/* Collects all the faces found for this thread, will be combined into the main dictionary later */ /* Collects all the faces found for this thread, will be combined into the main dictionary later */
var threadDict = new Dictionary<Voxelizer.FaceOrientation, List<Point>>(); var threadDict = new Dictionary<Voxelizer.FaceOrientation, List<Point>>();
@@ -477,10 +477,8 @@ public sealed class OperationLayerExportMesh : Operation
progress.ProcessedItems = 0; progress.ProcessedItems = 0;
/* 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. */ /* 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, layerIndex => Parallel.For(0, distinctLayers.Length, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
/* Create the KD tree for the layer, in practice there should never be dups, but just in case, set to skip */ /* 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); layerTrees[layerIndex] = new KdTree<float, Voxelizer.UVFace>(3, new FloatMath(), AddDuplicateBehavior.Skip);
@@ -91,10 +91,8 @@ public sealed class OperationLayerExportSkeleton : Operation
using var mask = GetMask(skeletonSum); using var mask = GetMask(skeletonSum);
Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = GetRoiOrDefault(mat); var matRoi = GetRoiOrDefault(mat);
using var skeletonRoi = matRoi.Skeletonize(); using var skeletonRoi = matRoi.Skeletonize();
@@ -104,17 +102,14 @@ public sealed class OperationLayerExportSkeleton : Operation
progress++; progress++;
} }
}); });
if (!progress.Token.IsCancellationRequested) if (_cropByRoi && HaveROI)
{ {
if (_cropByRoi && HaveROI) skeletonSumRoi.Save(_filePath);
{ }
skeletonSumRoi.Save(_filePath); else
} {
else skeletonSum.Save(_filePath);
{
skeletonSum.Save(_filePath);
}
} }
return !progress.Token.IsCancellationRequested; return !progress.Token.IsCancellationRequested;
@@ -255,9 +255,8 @@ public sealed class OperationLayerImport : Operation
SL1File format = new(); SL1File format = new();
format.Init((uint)keyImage.Count); format.Init((uint)keyImage.Count);
Parallel.ForEach(keyImage, CoreSettings.ParallelOptions, pair => Parallel.ForEach(keyImage, CoreSettings.GetParallelOptions(progress), pair =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = CvInvoke.Imread(pair.Value, ImreadModes.Grayscale); using var mat = CvInvoke.Imread(pair.Value, ImreadModes.Grayscale);
if (pair.Key == 0) format.Resolution = mat.Size; if (pair.Key == 0) format.Resolution = mat.Size;
format[pair.Key] = new Layer(pair.Key, mat, format); format[pair.Key] = new Layer(pair.Key, mat, format);
@@ -265,7 +264,6 @@ public sealed class OperationLayerImport : Operation
progress.LockAndIncrement(); progress.LockAndIncrement();
}); });
progress.Token.ThrowIfCancellationRequested();
fileFormats.Add(format); fileFormats.Add(format);
} }
@@ -284,7 +282,7 @@ public sealed class OperationLayerImport : Operation
fileFormats.Add(fileFormat); fileFormats.Add(fileFormat);
} }
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
if (fileFormats.Count == 0) return false; if (fileFormats.Count == 0) return false;
@@ -379,9 +377,8 @@ public sealed class OperationLayerImport : Operation
} }
progress.Reset(ProgressAction, fileFormat.LayerCount); progress.Reset(ProgressAction, fileFormat.LayerCount);
Parallel.For(0, fileFormat.LayerCount, CoreSettings.ParallelOptions, i => Parallel.For(0, fileFormat.LayerCount, CoreSettings.GetParallelOptions(progress), i =>
{ {
if (progress.Token.IsCancellationRequested) return;
uint layerIndex = (uint)(_startLayerIndex + i); uint layerIndex = (uint)(_startLayerIndex + i);
switch (_importType) switch (_importType)
@@ -503,7 +500,6 @@ public sealed class OperationLayerImport : Operation
}); });
fileFormat.Dispose(); fileFormat.Dispose();
progress.Token.ThrowIfCancellationRequested();
} }
if (_importType == ImportTypes.Stack) if (_importType == ImportTypes.Stack)
@@ -296,7 +296,7 @@ public sealed class OperationLayerReHeight : Operation
uint newLayerIndex = 0; uint newLayerIndex = 0;
for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.ThrowIfCancellationRequested();
var oldLayer = SlicerFile[layerIndex]; var oldLayer = SlicerFile[layerIndex];
for (byte i = 0; i < _selectedItem.Modifier; i++) for (byte i = 0; i < _selectedItem.Modifier; i++)
@@ -318,9 +318,8 @@ public sealed class OperationLayerReHeight : Operation
layerIndexes[i] = i * _selectedItem.Modifier; layerIndexes[i] = i * _selectedItem.Modifier;
} }
Parallel.ForEach(layerIndexes, CoreSettings.ParallelOptions, layerIndex => Parallel.ForEach(layerIndexes, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var oldLayer = SlicerFile[layerIndex]; var oldLayer = SlicerFile[layerIndex];
using var matSum = oldLayer.LayerMat; using var matSum = oldLayer.LayerMat;
Mat? matXorSum = null; Mat? matXorSum = null;
@@ -395,8 +394,6 @@ public sealed class OperationLayerReHeight : Operation
}); });
} }
progress.Token.ThrowIfCancellationRequested();
SlicerFile.SuppressRebuildPropertiesWork(() => SlicerFile.SuppressRebuildPropertiesWork(() =>
{ {
SlicerFile.LayerHeight = (float)_selectedItem!.LayerHeight; SlicerFile.LayerHeight = (float)_selectedItem!.LayerHeight;
@@ -203,10 +203,8 @@ public class OperationLightBleedCompensation : Operation
{ {
var dimMats = GetDimMats(); var dimMats = GetDimMats();
if (dimMats.Length == 0) return false; if (dimMats.Length == 0) return false;
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; // Abort operation, user requested cancellation
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
using var mat = layer.LayerMat; using var mat = layer.LayerMat;
using var original = mat.Clone(); using var original = mat.Clone();
+1 -2
View File
@@ -74,9 +74,8 @@ public class OperationMask : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
+1 -2
View File
@@ -176,9 +176,8 @@ public sealed class OperationMorph : Operation
out var maxIteration out var maxIteration
); );
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
int iterations = FileFormat.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex); int iterations = FileFormat.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex);
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
+1 -3
View File
@@ -264,10 +264,8 @@ public class OperationMove : Operation
if (ROI.IsEmpty) ROI = SlicerFile.GetBoundingRectangle(progress); if (ROI.IsEmpty) ROI = SlicerFile.GetBoundingRectangle(progress);
CalculateDstRoi(); CalculateDstRoi();
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = SlicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
+1 -5
View File
@@ -299,10 +299,8 @@ public class OperationPattern : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
using var layerRoi = new Mat(mat, ROI); using var layerRoi = new Mat(mat, ROI);
using var dstLayer = mat.NewBlank(); using var dstLayer = mat.NewBlank();
@@ -321,8 +319,6 @@ public class OperationPattern : Operation
SlicerFile.BoundingRectangle = Rectangle.Empty; SlicerFile.BoundingRectangle = Rectangle.Empty;
progress.Token.ThrowIfCancellationRequested();
if (Anchor == Enumerations.Anchor.None) return true; if (Anchor == Enumerations.Anchor.None) return true;
var operationMove = new OperationMove(SlicerFile, Anchor) var operationMove = new OperationMove(SlicerFile, Anchor)
{ {
@@ -582,9 +582,8 @@ public class OperationPixelArithmetic : Operation
} }
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
using (var mat = layer.LayerMat) using (var mat = layer.LayerMat)
{ {
@@ -650,9 +650,8 @@ public class OperationPixelDimming : Operation
CvInvoke.BitwiseNot(patternMask, patternMask); CvInvoke.BitwiseNot(patternMask, patternMask);
CvInvoke.BitwiseNot(alternatePatternMask, alternatePatternMask); CvInvoke.BitwiseNot(alternatePatternMask, alternatePatternMask);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, patternMask, alternatePatternMask); Execute(mat, layerIndex, patternMask, alternatePatternMask);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
@@ -38,6 +38,7 @@ public sealed class OperationProgress : BindableBase
public CancellationTokenSource TokenSource { get; private set; } = null!; public CancellationTokenSource TokenSource { get; private set; } = null!;
public CancellationToken Token => TokenSource.Token; public CancellationToken Token => TokenSource.Token;
public void ThrowIfCancellationRequested() => TokenSource.Token.ThrowIfCancellationRequested();
private bool _canCancel = true; private bool _canCancel = true;
private string _title = "Operation"; private string _title = "Operation";
@@ -184,7 +184,7 @@ public class OperationRaftRelief : Operation
progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex); progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex);
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++) for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
{ {
if (progress.Token.IsCancellationRequested) return false; progress.ThrowIfCancellationRequested();
progress++; progress++;
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat); supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200); var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200);
@@ -240,9 +240,8 @@ public class OperationRaftRelief : Operation
} }
progress.Reset(ProgressAction, firstSupportLayerIndex - _ignoreFirstLayers); progress.Reset(ProgressAction, firstSupportLayerIndex - _ignoreFirstLayers);
Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, CoreSettings.ParallelOptions, layerIndex => Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
using var original = mat.Clone(); using var original = mat.Clone();
var target = GetRoiOrDefault(mat); var target = GetRoiOrDefault(mat);
@@ -170,9 +170,8 @@ public class OperationRedrawModel : Operation
int startLayerIndex = (int)(SlicerFile.LayerCount - otherFile.LayerCount); int startLayerIndex = (int)(SlicerFile.LayerCount - otherFile.LayerCount);
if (startLayerIndex < 0) return false; if (startLayerIndex < 0) return false;
Parallel.For(0, otherFile.LayerCount, CoreSettings.ParallelOptions, layerIndex => Parallel.For(0, otherFile.LayerCount, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var fullMatLayerIndex = startLayerIndex + layerIndex; var fullMatLayerIndex = startLayerIndex + layerIndex;
using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat; using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat;
using var original = fullMat.Clone(); using var original = fullMat.Clone();
@@ -247,9 +247,8 @@ public class OperationRepairLayers : Operation
if (!issuesGroup.Any()) break; // Nothing to process if (!issuesGroup.Any()) break; // Nothing to process
islandsToRecompute.Clear(); islandsToRecompute.Clear();
Parallel.ForEach(issuesGroup, CoreSettings.ParallelOptions, group => Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = SlicerFile[group.Key]; var layer = SlicerFile[group.Key];
var image = layer.LayerMat; var image = layer.LayerMat;
var bytes = image.GetDataByteSpan(); var bytes = image.GetDataByteSpan();
@@ -300,7 +299,7 @@ public class OperationRepairLayers : Operation
progress.Reset("Attempt to attach islands below", (uint) islandsToProcess!.Count); progress.Reset("Attempt to attach islands below", (uint) islandsToProcess!.Count);
var sync = new object(); var sync = new object();
Parallel.ForEach(issuesGroup, CoreSettings.ParallelOptions, group => Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group =>
{ {
using var mat = SlicerFile[group.Key].LayerMat; using var mat = SlicerFile[group.Key].LayerMat;
var matSpan = mat.GetDataByteSpan(); var matSpan = mat.GetDataByteSpan();
@@ -390,9 +389,8 @@ public class OperationRepairLayers : Operation
progress.Reset(ProgressAction, LayerRangeCount); progress.Reset(ProgressAction, LayerRangeCount);
if (_repairIslands || _repairResinTraps) if (_repairIslands || _repairResinTraps)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var layer = SlicerFile[layerIndex]; var layer = SlicerFile[layerIndex];
Mat? image = null; Mat? image = null;
+1 -2
View File
@@ -157,9 +157,8 @@ public class OperationResize : Operation
decimal xSteps = Math.Abs(100 - _x) / (LayerIndexEnd - LayerIndexStart + 1); decimal xSteps = Math.Abs(100 - _x) / (LayerIndexEnd - LayerIndexStart + 1);
decimal ySteps = Math.Abs(100 - _y) / (LayerIndexEnd - LayerIndexStart + 1); decimal ySteps = Math.Abs(100 - _y) / (LayerIndexEnd - LayerIndexStart + 1);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var newX = _x; var newX = _x;
var newY = _y; var newY = _y;
if (IsFade) if (IsFade)
+1 -2
View File
@@ -95,9 +95,8 @@ public class OperationRotate : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
+25 -4
View File
@@ -32,7 +32,7 @@ public sealed class OperationScripting : Operation
public override bool CanRunInPartialMode => true; public override bool CanRunInPartialMode => true;
public override bool CanHaveProfiles => false; //public override bool CanHaveProfiles => false;
public override string IconClass => "fas fa-code"; public override string IconClass => "fas fa-code";
public override string Title => "Scripting"; public override string Title => "Scripting";
@@ -67,6 +67,13 @@ public sealed class OperationScripting : Operation
return scriptValidation.ReturnValue; return scriptValidation.ReturnValue;
} }
public override string ToString()
{
var result = $"[{Path.GetFileName(_filePath)}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
#endregion #endregion
#region Enums #region Enums
@@ -75,6 +82,7 @@ public sealed class OperationScripting : Operation
#region Properties #region Properties
[XmlIgnore]
public ScriptGlobals? ScriptGlobals { get; private set; } public ScriptGlobals? ScriptGlobals { get; private set; }
public string? FilePath public string? FilePath
@@ -104,10 +112,8 @@ public sealed class OperationScripting : Operation
set => RaiseAndSetIfChanged(ref _scriptText, value); set => RaiseAndSetIfChanged(ref _scriptText, value);
} }
[XmlIgnore]
public bool CanExecute => !string.IsNullOrWhiteSpace(_filePath) && _scriptState is not null && ScriptGlobals is not null && About.Version.CompareTo(ScriptGlobals.Script.MinimumVersionToRun) >= 0; public bool CanExecute => !string.IsNullOrWhiteSpace(_filePath) && _scriptState is not null && ScriptGlobals is not null && About.Version.CompareTo(ScriptGlobals.Script.MinimumVersionToRun) >= 0;
[XmlIgnore]
public bool HaveFile => !string.IsNullOrWhiteSpace(_filePath); public bool HaveFile => !string.IsNullOrWhiteSpace(_filePath);
/*public override string ToString() /*public override string ToString()
@@ -131,7 +137,22 @@ public sealed class OperationScripting : Operation
#endregion #endregion
#region Equality #region Equality
private bool Equals(OperationScripting other)
{
return _filePath == other._filePath;
}
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj) || obj is OperationScripting other && Equals(other);
}
public override int GetHashCode()
{
return (_filePath != null ? _filePath.GetHashCode() : 0);
}
#endregion #endregion
#region Methods #region Methods
+1 -2
View File
@@ -87,9 +87,8 @@ public sealed class OperationSolidify : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
SlicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
@@ -82,9 +82,8 @@ public class OperationThreshold : Operation
protected override bool ExecuteInternally(OperationProgress progress) protected override bool ExecuteInternally(OperationProgress progress)
{ {
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
using (var mat = SlicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
+2 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl> <PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description> <Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>3.0.0</Version> <Version>3.1.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright> <Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon> <PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
@@ -62,6 +62,7 @@
<PackageReference Include="AnimatedGif" Version="1.0.5" /> <PackageReference Include="AnimatedGif" Version="1.0.5" />
<PackageReference Include="BinarySerializer" Version="8.6.2.2" /> <PackageReference Include="BinarySerializer" Version="8.6.2.2" />
<PackageReference Include="Emgu.CV" Version="4.5.5.4823" /> <PackageReference Include="Emgu.CV" Version="4.5.5.4823" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
<PackageReference Include="KdTree" Version="1.4.1" /> <PackageReference Include="KdTree" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" /> <PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
+1 -1
View File
@@ -13,9 +13,9 @@
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" /> <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" />
<MediaTemplate EmbedCab="yes" /> <MediaTemplate EmbedCab="yes" />
<!-- Major Upgrade Rule to disallow downgrades --> <!-- Major Upgrade Rule to disallow downgrades -->
<!-- AllowSameVersionUpgrades="yes" -->
<MajorUpgrade <MajorUpgrade
AllowDowngrades="no" AllowDowngrades="no"
AllowSameVersionUpgrades="yes"
IgnoreRemoveFailure="no" IgnoreRemoveFailure="no"
DowngradeErrorMessage="A newer version of [ProductName] is already installed." DowngradeErrorMessage="A newer version of [ProductName] is already installed."
Schedule="afterInstallInitialize" /> Schedule="afterInstallInitialize" />
+15 -3
View File
@@ -335,9 +335,6 @@
<Component Id="owc79156F385239CEA4DEA3C87C1DA3E1D8" Guid="68380c80-6708-5eb6-415d-10e278417679" Win64="yes"> <Component Id="owc79156F385239CEA4DEA3C87C1DA3E1D8" Guid="68380c80-6708-5eb6-415d-10e278417679" Win64="yes">
<File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" /> <File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b" Win64="yes">
<File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" />
</Component>
<Component Id="owc7BB28EFC52A49429849339DF748B25E7" Guid="ded507d6-fd2b-41f2-bd03-cf489e47df7a" Win64="yes"> <Component Id="owc7BB28EFC52A49429849339DF748B25E7" Guid="ded507d6-fd2b-41f2-bd03-cf489e47df7a" Win64="yes">
<File Id="owf7BB28EFC52A49429849339DF748B25E7" Source="$(var.SourceDir)\runtime_package.dat" KeyPath="yes" /> <File Id="owf7BB28EFC52A49429849339DF748B25E7" Source="$(var.SourceDir)\runtime_package.dat" KeyPath="yes" />
</Component> </Component>
@@ -1449,6 +1446,21 @@
<Component Id="owc9C1F0C0351694913958CEBFB4D988C2D" Guid="9C1F0C03-5169-4913-958C-EBFB4D988C2D"> <Component Id="owc9C1F0C0351694913958CEBFB4D988C2D" Guid="9C1F0C03-5169-4913-958C-EBFB4D988C2D">
<File Id="owf9C1F0C0351694913958CEBFB4D988C2D" Source="$(var.SourceDir)\System.Net.Quic.dll" KeyPath="yes" /> <File Id="owf9C1F0C0351694913958CEBFB4D988C2D" Source="$(var.SourceDir)\System.Net.Quic.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcE9728785ABFF46BBBB650949E58582F6" Guid="E9728785-ABFF-46BB-BB65-0949E58582F6">
<File Id="owfE9728785ABFF46BBBB650949E58582F6" Source="$(var.SourceDir)\AvaloniaEdit.dll" KeyPath="yes" />
</Component>
<Component Id="owc457BCA8E75BC42FFAB4C395A1E488E86" Guid="457BCA8E-75BC-42FF-AB4C-395A1E488E86">
<File Id="owf457BCA8E75BC42FFAB4C395A1E488E86" Source="$(var.SourceDir)\ColorTextBlock.Avalonia.dll" KeyPath="yes" />
</Component>
<Component Id="owcBD9F04FC618C4C23A76BC23A5949C99E" Guid="BD9F04FC-618C-4C23-A76B-C23A5949C99E">
<File Id="owfBD9F04FC618C4C23A76BC23A5949C99E" Source="$(var.SourceDir)\K4os.Compression.LZ4.dll" KeyPath="yes" />
</Component>
<Component Id="owc016FC6E6F2AC48FFA8AA1DF1773755ED" Guid="016FC6E6-F2AC-48FF-A8AA-1DF1773755ED">
<File Id="owf016FC6E6F2AC48FFA8AA1DF1773755ED" Source="$(var.SourceDir)\Markdown.Avalonia.dll" KeyPath="yes" />
</Component>
<Component Id="owc1BDB050EB61B44609ECD990453AC8FB5" Guid="1BDB050E-B61B-4460-9ECD-990453AC8FB5">
<File Id="owf1BDB050EB61B44609ECD990453AC8FB5" Source="$(var.SourceDir)\Markdown.Avalonia.SyntaxHigh.dll" KeyPath="yes" />
</Component>
</Directory> </Directory>
<Directory Id="ProgramMenuFolder"> <Directory Id="ProgramMenuFolder">
<Directory Id="scd220707349D4C8FA275285514283F3E2A" Name="UVtools" /> <Directory Id="scd220707349D4C8FA275285514283F3E2A" Name="UVtools" />
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
@@ -100,7 +100,7 @@ public class ScriptAutomateWorkflowSample : ScriptGlobals
foreach (var operation in operations) // Loop all my created operations to execute them foreach (var operation in operations) // Loop all my created operations to execute them
{ {
Progress.Token.ThrowIfCancellationRequested(); // Abort operation, user requested cancellation Progress.ThrowIfCancellationRequested(); // Abort operation, user requested cancellation
operation.ROI = Operation.ROI; // Copy user selected ROI to my operation operation.ROI = Operation.ROI; // Copy user selected ROI to my operation
operation.MaskPoints = Operation.MaskPoints; // Copy user selected Masks to my operation operation.MaskPoints = Operation.MaskPoints; // Copy user selected Masks to my operation
if (!operation.CanValidate()) continue; // If cant validate don't execute the operation if (!operation.CanValidate()) continue; // If cant validate don't execute the operation
@@ -48,7 +48,7 @@ public class ScriptChangeLayerPropertiesSample : ScriptGlobals
for (uint layerIndex = Operation.LayerIndexStart; layerIndex <= Operation.LayerIndexEnd; layerIndex++) for (uint layerIndex = Operation.LayerIndexStart; layerIndex <= Operation.LayerIndexEnd; layerIndex++)
{ {
Progress.Token.ThrowIfCancellationRequested(); // Abort operation, user requested cancellation Progress.ThrowIfCancellationRequested(); // Abort operation, user requested cancellation
var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use
layer.LiftHeight = random.Next(3, 10); // Random value from 3 to 10 layer.LiftHeight = random.Next(3, 10); // Random value from 3 to 10
+1 -1
View File
@@ -120,7 +120,7 @@ public class ScriptCloneSettings : ScriptGlobals
var results = new List<Tuple<ResultStatus, string, List<string>?>>(); var results = new List<Tuple<ResultStatus, string, List<string>?>>();
foreach (var filePath in filePaths) foreach (var filePath in filePaths)
{ {
if (Progress.Token.IsCancellationRequested) return false; Progress.ThrowIfCancellationRequested();
Tuple<ResultStatus, string, List<string>?> result; Tuple<ResultStatus, string, List<string>?> result;
try try
+1 -3
View File
@@ -93,10 +93,8 @@ public class ScriptInsetSample : ScriptGlobals
// Loop user selected layers in parallel, this will put each core of CPU working here on parallel // Loop user selected layers in parallel, this will put each core of CPU working here on parallel
Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd+1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd+1, CoreSettings.GetParallelOptions(Progress), layerIndex =>
{ {
if (Progress.Token.IsCancellationRequested) return; // Abort operation, user requested cancellation
var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use
using var mat = layer.LayerMat; // Gets this layer mat/image using var mat = layer.LayerMat; // Gets this layer mat/image
var original = mat.Clone(); // Keep a original mat copy var original = mat.Clone(); // Keep a original mat copy
@@ -87,10 +87,8 @@ public class ScriptLightBleedCompensationSample : ScriptGlobals
var brightnesses = Levels; var brightnesses = Levels;
// Loop user selected layers in parallel, this will put each core of CPU working here on parallel // Loop user selected layers in parallel, this will put each core of CPU working here on parallel
Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd+1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd+1, CoreSettings.GetParallelOptions(Progress), layerIndex =>
{ {
if (Progress.Token.IsCancellationRequested) return; // Abort operation, user requested cancellation
var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use var layer = SlicerFile[layerIndex]; // Unpack and expose layer variable for easier use
using var mat = layer.LayerMat; // Gets this layer mat/image using var mat = layer.LayerMat; // Gets this layer mat/image
var original = mat.Clone(); // Keep a original mat copy var original = mat.Clone(); // Keep a original mat copy
@@ -114,7 +114,7 @@ public class ScriptTestPerLayerSettingsSample : ScriptGlobals
CvInvoke.Ellipse(mats[0], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteColor, -1, lineType); CvInvoke.Ellipse(mats[0], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteColor, -1, lineType);
CvInvoke.Ellipse(mats[4], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteColor, -1, lineType); CvInvoke.Ellipse(mats[4], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteColor, -1, lineType);
SlicerFile.AllocateAndSetFromMat(mats); // Replace layers and rebuild properties SlicerFile.AllocateAndSetFromMat(mats, Progress); // Replace layers and rebuild properties
SlicerFile.BottomLayerCount = 1; // Set one bottom layer, the whole face SlicerFile.BottomLayerCount = 1; // Set one bottom layer, the whole face
SlicerFile.BottomExposureTime = 5; // Set exposure to be fixed at 5s SlicerFile.BottomExposureTime = 5; // Set exposure to be fixed at 5s
+1 -1
View File
@@ -53,7 +53,7 @@ public class ScriptChangeLayesrPropertiesSample : ScriptGlobals
public bool ScriptExecute() public bool ScriptExecute()
{ {
var dict = new Dictionary<uint, List<(Point[] points, Rectangle rect)>>(); var dict = new Dictionary<uint, List<(Point[] points, Rectangle rect)>>();
Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex => Parallel.For(Operation.LayerIndexStart, Operation.LayerIndexEnd + 1, CoreSettings.GetParallelOptions(Progress), layerIndex =>
{ {
using var mat = SlicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
using var contours = mat.FindContours(out var hierarchy, RetrType.Tree); using var contours = mat.FindContours(out var hierarchy, RetrType.Tree);
+2 -2
View File
@@ -13,12 +13,12 @@ public static class AppSettings
// These settings eliminate very small zoom factors from the ImageBox default values, // These settings eliminate very small zoom factors from the ImageBox default values,
// while ensuring that 4K/5K build plates can still easily fit on screen. // while ensuring that 4K/5K build plates can still easily fit on screen.
public static readonly int[] ZoomLevels = public static readonly int[] ZoomLevels =
{20, 25, 30, 50, 75, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 3200}; {10, 20, 25, 30, 50, 75, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 3200, 6400};
// Count of the bottom portion of the full zoom range which will be skipped for // Count of the bottom portion of the full zoom range which will be skipped for
// assignable actions such as auto-zoom level, and crosshair fade level. If values // assignable actions such as auto-zoom level, and crosshair fade level. If values
// are added/removed from ZoomLevels above, this value may also need to be adjusted. // are added/removed from ZoomLevels above, this value may also need to be adjusted.
public const byte ZoomLevelSkipCount = 7; // Start at 2x which is index 7. public const byte ZoomLevelSkipCount = 8; // Start at 2x which is index 8.
/// <summary> /// <summary>
/// Returns the zoom level at which the crosshairs will fade and no longer be displayed /// Returns the zoom level at which the crosshairs will fade and no longer be displayed
Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

@@ -20,7 +20,7 @@
<StackPanel Grid.Row="0" Grid.Column="4" <StackPanel Grid.Row="0" Grid.Column="4"
Orientation="Horizontal" Spacing="1"> Orientation="Horizontal" Spacing="1">
<Button <Button
ToolTip.Tip="Loads an script file" ToolTip.Tip="Load script file"
VerticalAlignment="Center" VerticalAlignment="Center"
Command="{Binding LoadScript}" Command="{Binding LoadScript}"
i:Attached.Icon="fas fa-file-import"/> i:Attached.Icon="fas fa-file-import"/>
@@ -1,9 +1,11 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using UVtools.Core; using UVtools.Core;
using UVtools.Core.Operations; using UVtools.Core.Operations;
using UVtools.Core.Scripting; using UVtools.Core.Scripting;
@@ -43,7 +45,10 @@ public class ToolScriptingControl : ToolControl
case ToolWindow.Callbacks.Loaded: case ToolWindow.Callbacks.Loaded:
if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.CanExecute; if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.CanExecute;
ReloadGUI(); ReloadGUI();
ReloadScript(); Dispatcher.UIThread.Post(() =>
{
ReloadScript();
}, DispatcherPriority.Loaded);
Operation.PropertyChanged += (sender, e) => Operation.PropertyChanged += (sender, e) =>
{ {
if (e.PropertyName == nameof(Operation.CanExecute)) if (e.PropertyName == nameof(Operation.CanExecute))
@@ -93,13 +98,13 @@ public class ToolScriptingControl : ToolControl
public void OpenScriptFolder() public void OpenScriptFolder()
{ {
if (!Operation.HaveFile) return; if (!Operation.HaveFile) return;
SystemAware.StartProcess(Path.GetDirectoryName(Operation.FilePath)); SystemAware.SelectFileOnExplorer(Operation.FilePath!);
} }
public void OpenScriptFile() public void OpenScriptFile()
{ {
if (!Operation.HaveFile) return; if (!Operation.HaveFile) return;
SystemAware.StartProcess(Operation.FilePath); SystemAware.StartProcess(Operation.FilePath!);
} }
public void ReloadGUI() public void ReloadGUI()
+24 -10
View File
@@ -18,15 +18,17 @@ namespace UVtools.WPF.Extensions;
public static class WindowExtensions public static class WindowExtensions
{ {
public static async Task<ButtonResult> MessageBoxGeneric(this Window window, string message, string title = null, public static async Task<ButtonResult> MessageBoxGeneric(this Window window, string message, string title = null, string header = null,
ButtonEnum buttons = ButtonEnum.Ok, Icon icon = Icon.None, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner) ButtonEnum buttons = ButtonEnum.Ok, Icon icon = Icon.None, bool markdown = false, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner)
{ {
var messageBoxStandardWindow = MessageBox.Avalonia.MessageBoxManager.GetMessageBoxStandardWindow( var messageBoxStandardWindow = MessageBox.Avalonia.MessageBoxManager.GetMessageBoxStandardWindow(
new MessageBoxStandardParams new MessageBoxStandardParams
{ {
ButtonDefinitions = buttons, ButtonDefinitions = buttons,
ContentTitle = title ?? window.Title, ContentTitle = title ?? window.Title,
ContentHeader = header,
ContentMessage = message, ContentMessage = message,
Markdown = markdown,
Icon = icon, Icon = icon,
WindowIcon = new WindowIcon(App.GetAsset("/Assets/Icons/UVtools.ico")), WindowIcon = new WindowIcon(App.GetAsset("/Assets/Icons/UVtools.ico")),
WindowStartupLocation = location, WindowStartupLocation = location,
@@ -40,17 +42,29 @@ public static class WindowExtensions
return await messageBoxStandardWindow.ShowDialog(window); return await messageBoxStandardWindow.ShowDialog(window);
} }
public static async Task<ButtonResult> MessageBoxInfo(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false) public static async Task<ButtonResult> MessageBoxInfo(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", buttons, Icon.Info, topMost, WindowStartupLocation.CenterOwner); => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", null, buttons, Icon.Info, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxError(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false) public static async Task<ButtonResult> MessageBoxError(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", buttons, Icon.Error, topMost, WindowStartupLocation.CenterOwner); => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", null, buttons, Icon.Error, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxQuestion(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, bool topMost = false) public static async Task<ButtonResult> MessageBoxQuestion(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Setting, topMost, WindowStartupLocation.CenterOwner); => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", null, buttons, Icon.Question, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxWaring(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false) public static async Task<ButtonResult> MessageBoxWaring(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Warning, topMost, WindowStartupLocation.CenterOwner); => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", null, buttons, Icon.Warning, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxWithHeaderInfo(this Window window, string header, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", header, buttons, Icon.Info, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxWithHeaderError(this Window window, string header, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", header, buttons, Icon.Error, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxWithHeaderQuestion(this Window window, string header, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", header, buttons, Icon.Question, markdown, topMost, WindowStartupLocation.CenterOwner);
public static async Task<ButtonResult> MessageBoxWithHeaderWaring(this Window window, string header, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool markdown = false, bool topMost = false)
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", header, buttons, Icon.Warning, markdown, topMost, WindowStartupLocation.CenterOwner);
public static void ShowDialogSync(this Window window, Window parent = null) public static void ShowDialogSync(this Window window, Window parent = null)
+1 -2
View File
@@ -174,9 +174,8 @@ public partial class MainWindow
Progress.Reset("Removing selected issues", (uint)processParallelIssues.Count); Progress.Reset("Removing selected issues", (uint)processParallelIssues.Count);
try try
{ {
Parallel.ForEach(processParallelIssues, CoreSettings.ParallelOptions, layerIssues => Parallel.ForEach(processParallelIssues, CoreSettings.GetParallelOptions(Progress), layerIssues =>
{ {
if (Progress.Token.IsCancellationRequested) return;
using (var image = SlicerFile[layerIssues.Key].LayerMat) using (var image = SlicerFile[layerIssues.Key].LayerMat)
{ {
var bytes = image.GetDataByteSpan(); var bytes = image.GetDataByteSpan();
+44
View File
@@ -844,6 +844,50 @@ public partial class MainWindow
//var imageSpan = LayerCache.Image.GetPixelSpan<byte>(); //var imageSpan = LayerCache.Image.GetPixelSpan<byte>();
//var imageBgrSpan = LayerCache.ImageBgr.GetPixelSpan<byte>(); //var imageBgrSpan = LayerCache.ImageBgr.GetPixelSpan<byte>();
/*var mat = LayerCache.Layer.LayerMat;
var layers = Enum.GetValues<Layer.LayerCompressionMethod>().Select(value => new Layer(mat, SlicerFile, value)).ToList();
const ushort tests = 100;
Debug.WriteLine($"Looping {tests} tests on {SlicerFile.Resolution} resolution");
var sw = Stopwatch.StartNew();
foreach (var layer in layers)
{
Debug.WriteLine($"{layer.CompressionMethod} compressed size: {layer.CompressedBytes.Length} bytes");
sw.Restart();
for (var i = 0; i < tests; i++)
{
using (layer.LayerMat) { }
}
Debug.WriteLine($"Single thread - Decompress: {sw.ElapsedMilliseconds}ms");
sw.Restart();
for (var i = 0; i < tests; i++)
{
layer.LayerMat = mat;
}
Debug.WriteLine($"Single thread - Compress: {sw.ElapsedMilliseconds}ms");
sw.Restart();
Parallel.For(0, tests, i =>
{
using (layer.LayerMat) { }
});
Debug.WriteLine($"Multi thread - Decompress: {sw.ElapsedMilliseconds}ms");
sw.Restart();
Parallel.For(0, tests, i =>
{
layer.LayerMat = mat;
});
Debug.WriteLine($"Multi thread - Compress: {sw.ElapsedMilliseconds}ms");
Debug.WriteLine(string.Empty);
}*/
var imageSpan = LayerCache.ImageSpan; var imageSpan = LayerCache.ImageSpan;
var imageBgrSpan = LayerCache.ImageBgrSpan; var imageBgrSpan = LayerCache.ImageBgrSpan;
+1
View File
@@ -569,6 +569,7 @@
IsReadOnly="{Binding !SlicerFile.SuppressRebuildGCode}" IsReadOnly="{Binding !SlicerFile.SuppressRebuildGCode}"
AcceptsReturn="True" AcceptsReturn="True"
Text="{Binding SlicerFile.GCodeStr}" /> Text="{Binding SlicerFile.GCodeStr}" />
</Grid> </Grid>
</TabItem> </TabItem>
+38 -8
View File
@@ -38,7 +38,6 @@ using UVtools.WPF.Controls.Tools;
using UVtools.WPF.Extensions; using UVtools.WPF.Extensions;
using UVtools.WPF.Structures; using UVtools.WPF.Structures;
using UVtools.WPF.Windows; using UVtools.WPF.Windows;
using Bitmap = Avalonia.Media.Imaging.Bitmap;
using Helpers = UVtools.WPF.Controls.Helpers; using Helpers = UVtools.WPF.Controls.Helpers;
using Path = System.IO.Path; using Path = System.IO.Path;
using Point = Avalonia.Point; using Point = Avalonia.Point;
@@ -1164,6 +1163,7 @@ public partial class MainWindow : WindowEx
public async void MenuFileSettingsClicked() public async void MenuFileSettingsClicked()
{ {
var oldTheme = Settings.General.Theme; var oldTheme = Settings.General.Theme;
var oldLayerCompressionMethod = Settings.General.LayerCompressionMethod;
var settingsWindow = new SettingsWindow(); var settingsWindow = new SettingsWindow();
await settingsWindow.ShowDialog(this); await settingsWindow.ShowDialog(this);
if (settingsWindow.DialogResult == DialogResults.OK) if (settingsWindow.DialogResult == DialogResults.OK)
@@ -1173,6 +1173,33 @@ public partial class MainWindow : WindowEx
App.ApplyTheme(); App.ApplyTheme();
} }
if (oldLayerCompressionMethod != Settings.General.LayerCompressionMethod)
{
IsGUIEnabled = false;
ShowProgressWindow($"Changing layer compression method from {oldLayerCompressionMethod.ToString().ToUpper()} to {Settings.General.LayerCompressionMethod.ToString().ToUpper()}");
await Task.Factory.StartNew(() =>
{
try
{
SlicerFile.ChangeLayersCompressionMethod(Settings.General.LayerCompressionMethod, Progress);
return true;
}
catch (OperationCanceledException)
{
}
catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(exception.ToString(), "Error while converting layers"));
}
return false;
});
IsGUIEnabled = true;
}
_layerNavigationSliderDebounceTimer.Interval = Settings.LayerPreview.LayerSliderDebounce == 0 ? 1 : Settings.LayerPreview.LayerSliderDebounce; _layerNavigationSliderDebounceTimer.Interval = Settings.LayerPreview.LayerSliderDebounce == 0 ? 1 : Settings.LayerPreview.LayerSliderDebounce;
RaisePropertyChanged(nameof(IssuesGridItems)); RaisePropertyChanged(nameof(IssuesGridItems));
} }
@@ -1232,13 +1259,16 @@ public partial class MainWindow : WindowEx
public async void MenuNewVersionClicked() public async void MenuNewVersionClicked()
{ {
var result = var result =
await this.MessageBoxQuestion( await this.MessageBoxWithHeaderQuestion(
$"Do you like to auto-update {About.Software} v{App.VersionStr} to v{VersionChecker.Version}?\n" + $"Do you like to auto-update {About.Software} v{App.VersionStr} to v{VersionChecker.Version}?",
"Yes: Auto update\n" + "Yes: Auto update \n" +
"No: Manual update\n" + "No: Manual update \n" +
"Cancel: No action\n\n" + "Cancel: No action \n\n" +
"Changelog:\n" + "Changelog: \n\n" +
$"{VersionChecker.Changelog}", $"Update UVtools to v{VersionChecker.Version}?", ButtonEnum.YesNoCancel); $"{VersionChecker.Changelog}",
$"Update UVtools to v{VersionChecker.Version}?",
ButtonEnum.YesNoCancel, true);
if (result == ButtonResult.No) if (result == ButtonResult.No)
+22 -20
View File
@@ -12,10 +12,9 @@ using System.IO.Compression;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86; using System.Text.Json.Nodes;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Threading; using Avalonia.Threading;
using Newtonsoft.Json.Linq;
using UVtools.Core; using UVtools.Core;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.Objects; using UVtools.Core.Objects;
@@ -36,33 +35,35 @@ public class AppVersionChecker : BindableBase
{ {
get get
{ {
var file = Path.Combine(App.ApplicationPath, RuntimePackageFile);
if (File.Exists(file))
{
try
{
var package = File.ReadAllText(file);
if (!string.IsNullOrWhiteSpace(package) && (package.EndsWith("-x64") || package.EndsWith("-arm64")))
{
return $"{About.Software}_{package}_v{_version}.zip";
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
return $"{About.Software}_win-x64_v{_version}.msi"; return $"{About.Software}_win-x64_v{_version}.msi";
} }
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{ {
var file = Path.Combine(App.ApplicationPath, RuntimePackageFile);
if (File.Exists(file))
{
try
{
var package = File.ReadAllText(file);
if (!string.IsNullOrWhiteSpace(package) && package.EndsWith("-x64"))
{
return $"{About.Software}_{package}_v{_version}.zip";
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}
return $"{About.Software}_linux-x64_v{_version}.zip"; return $"{About.Software}_linux-x64_v{_version}.zip";
} }
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{ {
if (RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64) return $"{About.Software}_osx-arm64_v{_version}.zip";
return $"{About.Software}_osx-x64_v{_version}.zip"; return $"{About.Software}_osx-x64_v{_version}.zip";
} }
@@ -131,7 +132,8 @@ public class AppVersionChecker : BindableBase
var result= NetworkExtensions.HttpClient.Send(request); var result= NetworkExtensions.HttpClient.Send(request);
var json = JObject.Parse(result.Content.ReadAsStringAsync().Result); var json = JsonNode.Parse(result.Content.ReadAsStream());
string tag_name = json["tag_name"]?.ToString(); string tag_name = json["tag_name"]?.ToString();
if (string.IsNullOrEmpty(tag_name)) return false; if (string.IsNullOrEmpty(tag_name)) return false;
tag_name = tag_name.Trim(' ', 'v', 'V'); tag_name = tag_name.Trim(' ', 'v', 'V');
+7 -1
View File
@@ -5,6 +5,9 @@
* Everyone is permitted to copy and distribute verbatim copies * Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed. * of this license document, but changing it is not allowed.
*/ */
using UVtools.WPF.Windows;
namespace UVtools.WPF.Structures; namespace UVtools.WPF.Structures;
public sealed class BenchmarkTest public sealed class BenchmarkTest
@@ -12,10 +15,11 @@ public sealed class BenchmarkTest
public const string DEVCPU = "Intel® Core™ i9-9900K @ 3.60 GHz"; public const string DEVCPU = "Intel® Core™ i9-9900K @ 3.60 GHz";
public const string DEVRAM = "G.SKILL Trident Z 32GB DDR4-3200MHz CL14"; public const string DEVRAM = "G.SKILL Trident Z 32GB DDR4-3200MHz CL14";
public BenchmarkTest(string name, string functionName, float devSingleThreadResult = 0, float devMultiThreadResult = 0) public BenchmarkTest(string name, string functionName, BenchmarkWindow.BenchmarkResolution resolution, float devSingleThreadResult = 0, float devMultiThreadResult = 0)
{ {
Name = name; Name = name;
FunctionName = functionName; FunctionName = functionName;
Resolution = resolution;
DevSingleThreadResult = devSingleThreadResult; DevSingleThreadResult = devSingleThreadResult;
DevMultiThreadResult = devMultiThreadResult; DevMultiThreadResult = devMultiThreadResult;
} }
@@ -23,6 +27,8 @@ public sealed class BenchmarkTest
public string Name { get; } public string Name { get; }
public string FunctionName { get; } public string FunctionName { get; }
public BenchmarkWindow.BenchmarkResolution Resolution { get; }
public float DevSingleThreadResult { get; } public float DevSingleThreadResult { get; }
public float DevMultiThreadResult { get; } public float DevMultiThreadResult { get; }
@@ -47,6 +47,7 @@ public class OperationProfiles //: IList<Operation>
[XmlElement(typeof(OperationRaiseOnPrintFinish))] [XmlElement(typeof(OperationRaiseOnPrintFinish))]
[XmlElement(typeof(OperationChangeResolution))] [XmlElement(typeof(OperationChangeResolution))]
[XmlElement(typeof(OperationTimelapse))] [XmlElement(typeof(OperationTimelapse))]
[XmlElement(typeof(OperationScripting))]
[XmlElement(typeof(OperationLayerExportGif))] [XmlElement(typeof(OperationLayerExportGif))]
+6 -5
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile> <PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<Version>3.0.0</Version> <Version>3.1.0</Version>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon> <PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
@@ -40,14 +40,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.13" /> <PackageReference Include="Avalonia" Version="0.10.13" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.13" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.13" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.13" /> <PackageReference Include="Avalonia.Desktop" Version="0.10.13" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.13" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.13" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" /> <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
<PackageReference Include="MessageBox.Avalonia" Version="1.8.1-night" /> <PackageReference Include="MessageBox.Avalonia" Version="2.0.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="4.1.0" /> <PackageReference Include="Projektanker.Icons.Avalonia" Version="4.2.1" />
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="4.1.0" /> <PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="4.2.1" />
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="4.2.1" />
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.12" /> <PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.12" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -95,6 +95,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AvaloniaResource> </AvaloniaResource>
<AvaloniaResource Include="Assets\Icons\*" /> <AvaloniaResource Include="Assets\Icons\*" />
<AvaloniaResource Include="Assets\benchmark.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Windows\SuggestionSettingsWindow.axaml.cs"> <Compile Update="Windows\SuggestionSettingsWindow.axaml.cs">
+10
View File
@@ -17,6 +17,7 @@ using JetBrains.Annotations;
using UVtools.Core; using UVtools.Core;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
using UVtools.Core.Layers;
using UVtools.Core.Network; using UVtools.Core.Network;
using UVtools.Core.Objects; using UVtools.Core.Objects;
using Color=UVtools.WPF.Structures.Color; using Color=UVtools.WPF.Structures.Color;
@@ -42,6 +43,7 @@ public sealed class UserSettings : BindableBase
private bool _loadDemoFileOnStartup = true; private bool _loadDemoFileOnStartup = true;
private bool _loadLastRecentFileOnStartup; private bool _loadLastRecentFileOnStartup;
private int _maxDegreeOfParallelism = -1; private int _maxDegreeOfParallelism = -1;
private Layer.LayerCompressionMethod _layerCompressionMethod = CoreSettings.DefaultLayerCompressionMethod;
private bool _windowsCanResize; private bool _windowsCanResize;
private bool _windowsTakeIntoAccountScreenScaling = true; private bool _windowsTakeIntoAccountScreenScaling = true;
@@ -100,6 +102,12 @@ public sealed class UserSettings : BindableBase
set => RaiseAndSetIfChanged(ref _maxDegreeOfParallelism, Math.Min(value, Environment.ProcessorCount)); set => RaiseAndSetIfChanged(ref _maxDegreeOfParallelism, Math.Min(value, Environment.ProcessorCount));
} }
public Layer.LayerCompressionMethod LayerCompressionMethod
{
get => _layerCompressionMethod;
set => RaiseAndSetIfChanged(ref _layerCompressionMethod, value);
}
public bool WindowsCanResize public bool WindowsCanResize
{ {
get => _windowsCanResize; get => _windowsCanResize;
@@ -1633,6 +1641,7 @@ public sealed class UserSettings : BindableBase
} }
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism; CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
if (_instance.Network.RemotePrinters.Count == 0) if (_instance.Network.RemotePrinters.Count == 0)
{ {
@@ -1855,6 +1864,7 @@ public sealed class UserSettings : BindableBase
Instance.SavesCount++; Instance.SavesCount++;
_instance.ModifiedDateTime = DateTime.Now; _instance.ModifiedDateTime = DateTime.Now;
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism; CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
try try
{ {
XmlExtensions.SerializeToFile(_instance, FilePath, XmlExtensions.SettingsIndent); XmlExtensions.SerializeToFile(_instance, FilePath, XmlExtensions.SettingsIndent);
+16 -25
View File
@@ -9,33 +9,28 @@
Icon="/Assets/Icons/UVtools.ico" Icon="/Assets/Icons/UVtools.ico"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
CanResize="False" CanResize="False">
>
<Grid <Grid RowDefinitions="Auto,10,
RowDefinitions="Auto,10,
Auto,10, Auto,10,
Auto,10, Auto,10,
Auto,20, Auto,20,
Auto,10, Auto,10,
Auto,20, Auto,20,
Auto" Auto">
>
<Border <Border
Background="{DynamicResource LightBackground}" Background="{DynamicResource LightBackground}"
Padding="10" Padding="10"
BorderBrush="Black" BorderBrush="Black"
BorderThickness="1" BorderThickness="1">
> <TextBox Classes="TransparentReadOnly" Text="{Binding Description}"/>
<TextBlock Text="{Binding Description}"/>
</Border> </Border>
<Grid <Grid
ColumnDefinitions="Auto,10,*" ColumnDefinitions="Auto,10,*"
Grid.Row="2" Grid.Row="2"
Margin="10" Margin="10">
>
<TextBlock <TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -45,27 +40,25 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
SelectedIndex="{Binding TestSelectedIndex}" SelectedIndex="{Binding TestSelectedIndex}"
Items="{Binding Tests}" Items="{Binding Tests}"
IsEnabled="{Binding !IsRunning}" IsEnabled="{Binding !IsRunning}"/>
/>
</Grid> </Grid>
<TextBlock <TextBlock
Margin="10,0" Margin="10,0"
Grid.Row="4" Grid.Row="4"
FontWeight="Bold" Text="Your results:" /> FontWeight="Bold" Text="Your results:"/>
<Grid <Grid
Grid.Row="6" Grid.Row="6"
ColumnDefinitions="Auto,5,Auto" ColumnDefinitions="Auto,5,Auto"
RowDefinitions="Auto,5,Auto" RowDefinitions="Auto,5,Auto"
Margin="10,0" Margin="10,0">
>
<TextBlock <TextBlock
HorizontalAlignment="Right" HorizontalAlignment="Right"
Text="Single Thread:" /> Text="Single Thread:" />
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="2"
Text="{Binding SingleThreadTDPS}" /> Text="{Binding SingleThreadTDPS}"/>
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -74,13 +67,13 @@
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Text="{Binding MultiThreadTDPS}" /> Text="{Binding MultiThreadTDPS}"/>
</Grid> </Grid>
<TextBlock <TextBlock
Margin="10,0" Margin="10,0"
Grid.Row="8" Grid.Row="8"
FontWeight="Bold" Text="Developer results:" /> FontWeight="Bold" Text="Developer results:"/>
<Grid <Grid
Grid.Row="10" Grid.Row="10"
@@ -93,7 +86,7 @@
Text="Single Thread:" /> Text="Single Thread:" />
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="2"
Text="{Binding DevSingleThreadTDPS}" /> Text="{Binding DevSingleThreadTDPS}"/>
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -102,7 +95,7 @@
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Text="{Binding DevMultiThreadTDPS}" /> Text="{Binding DevMultiThreadTDPS}"/>
</Grid> </Grid>
<Grid <Grid
@@ -112,8 +105,7 @@
<ProgressBar <ProgressBar
IsIndeterminate="{Binding IsRunning}" IsIndeterminate="{Binding IsRunning}"
IsEnabled="{Binding IsRunning}" IsEnabled="{Binding IsRunning}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"/>
/>
<Button <Button
Name="StartStopButton" Name="StartStopButton"
@@ -121,8 +113,7 @@
Padding="40,10" Padding="40,10"
IsDefault="True" IsDefault="True"
Content="{Binding StartStopButtonText}" Content="{Binding StartStopButtonText}"
Command="{Binding StartStop}" Command="{Binding StartStop}"/>
/>
</Grid> </Grid>
+117 -21
View File
@@ -9,6 +9,7 @@ using Avalonia.Threading;
using Emgu.CV; using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.Layers;
using UVtools.WPF.Controls; using UVtools.WPF.Controls;
using UVtools.WPF.Extensions; using UVtools.WPF.Extensions;
using UVtools.WPF.Structures; using UVtools.WPF.Structures;
@@ -24,27 +25,56 @@ public class BenchmarkWindow : WindowEx
private string _devMultiThreadTdps = $"{Tests[0].DevMultiThreadResult} {RunsAbbreviation} ({MultiThreadTests} tests / {Math.Round(MultiThreadTests / Tests[0].DevMultiThreadResult, 2)}s)"; private string _devMultiThreadTdps = $"{Tests[0].DevMultiThreadResult} {RunsAbbreviation} ({MultiThreadTests} tests / {Math.Round(MultiThreadTests / Tests[0].DevMultiThreadResult, 2)}s)";
private bool _isRunning; private bool _isRunning;
private string _startStopButtonText = "Start"; private string _startStopButtonText = "Start";
private const ushort SingleThreadTests = 100; private const ushort SingleThreadTests = 200;
private const ushort MultiThreadTests = 1000; private const ushort MultiThreadTests = 5000;
public const string RunsAbbreviation = "TDPS"; public const string RunsAbbreviation = "TDPS";
public const string StressCPUTestName = "Stress CPU (Run until stop)"; public const string StressCPUTestName = "Stress CPU (Run until stop)";
private readonly Dictionary<BenchmarkResolution, Mat> Mats = new();
//private readonly RNGCryptoServiceProvider _randomProvider = new(); //private readonly RNGCryptoServiceProvider _randomProvider = new();
private CancellationTokenSource _tokenSource; private CancellationTokenSource _tokenSource;
private CancellationToken _token => _tokenSource.Token; private CancellationToken _token => _tokenSource.Token;
public enum BenchmarkResolution
{
Resolution4K,
Resolution8K
}
public static BenchmarkTest[] Tests => public static BenchmarkTest[] Tests =>
new[] new[]
{ {
new BenchmarkTest("4K Random CBBDLP Enconde", "Test4KRandomCBBDLPEncode", 57.14f, 401.61f), new BenchmarkTest("CBBDLP 4K Encode", "TestCBBDLPEncode", BenchmarkResolution.Resolution4K, 108.70f, 912.41f),
new BenchmarkTest("8K Random CBBDLP Enconde", "Test8KRandomCBBDLPEncode", 12.03f, 99.80f), new BenchmarkTest("CBBDLP 8K Encode", "TestCBBDLPEncode", BenchmarkResolution.Resolution8K, 27.47f, 226.76f),
new BenchmarkTest("4K Random CBT Enconde", "Test4KRandomCBTEncode", 19.05f, 124.38f), new BenchmarkTest("CBT 4K Encode", "TestCBTEncode", BenchmarkResolution.Resolution4K, 86.96f, 782.47f),
new BenchmarkTest("8K Random CBT Enconde", "Test8KRandomCBTEncode", 4.03f, 35.64f), new BenchmarkTest("CBT 8K Encode", "TestCBTEncode", BenchmarkResolution.Resolution8K, 21.86f, 196.15f),
new BenchmarkTest("4K Random PW0 Enconde", "Test4KRandomPW0Encode", 18.85f, 103.00f), new BenchmarkTest("PW0 4K Encode", "TestPW0Encode",BenchmarkResolution.Resolution4K, 84.03f, 886.53f),
new BenchmarkTest("8K Random PW0 Enconde", "Test8KRandomPW0Encode", 4.07f, 26.65f), new BenchmarkTest("PW0 8K Encode", "TestPW0Encode", BenchmarkResolution.Resolution8K, 21.05f, 221.63f),
new BenchmarkTest(StressCPUTestName, "Test4KRandomCBTEncode", 0, 0),
new BenchmarkTest("PNG 4K Compress", "TestPNGCompress", BenchmarkResolution.Resolution4K, 55.25f, 501.00f),
//new BenchmarkTest("PNG 4K Decompress", "TestPNGDecompress", BenchmarkResolution.Resolution4K, 4.07f, 26.65f),
new BenchmarkTest("PNG 8K Compress", "TestPNGCompress", BenchmarkResolution.Resolution8K, 14.28f, 124.10f),
//new BenchmarkTest("PNG 8K Decompress", "TestPNGDecompress", BenchmarkResolution.Resolution8K, 4.07f, 26.65f),
new BenchmarkTest("GZip 4K Compress", "TestGZipCompress", BenchmarkResolution.Resolution4K, 169.49f, 1506.02f),
//new BenchmarkTest("GZip 4K Decompress", "TestGZipDecompress", BenchmarkResolution.Resolution4K, 4.07f, 26.65f),
new BenchmarkTest("GZip 8K Compress", "TestGZipCompress", BenchmarkResolution.Resolution8K, 45.77f, 397.47f),
//new BenchmarkTest("GZip 8K Decompress", "TestGZipDecompress", BenchmarkResolution.Resolution8K, 4.07f, 26.65f),
new BenchmarkTest("Deflate 4K Compress", "TestDeflateCompress", BenchmarkResolution.Resolution4K, 170.94f, 1592.36f),
//new BenchmarkTest("Deflate 4K Decompress", "TestDeflateDecompress", BenchmarkResolution.Resolution4K, 4.07f, 26.65f),
new BenchmarkTest("Deflate 8K Compress", "TestDeflateCompress", BenchmarkResolution.Resolution8K, 46.30f, 406.50f),
//new BenchmarkTest("Deflate 8K Decompress", "TestDeflateDecompress", BenchmarkResolution.Resolution8K, 4.07f, 26.65f),
new BenchmarkTest("LZ4 4K Compress", "TestLZ4Compress", BenchmarkResolution.Resolution4K, 665.12f, 2762.43f),
//new BenchmarkTest("LZ4 4K Decompress", "TestLZ4Decompress", BenchmarkResolution.Resolution4K, 4.07f, 26.65f),
new BenchmarkTest("LZ4 8K Compress", "TestLZ4Compress", BenchmarkResolution.Resolution8K, 148.15f, 907.44f),
//new BenchmarkTest("LZ4 8K Decompress", "TestLZ4Decompress", BenchmarkResolution.Resolution8K, 4.07f, 26.65f),
new BenchmarkTest(StressCPUTestName, "TestCBTEncode", BenchmarkResolution.Resolution4K, 0, 0),
}; };
public string Description => "Benchmark your machine against pre-defined tests.\n" + public string Description => "Benchmark your machine against pre-defined tests.\n" +
@@ -112,6 +142,12 @@ public class BenchmarkWindow : WindowEx
InitializeComponent(); InitializeComponent();
DataContext = this; DataContext = this;
foreach (var resolution in Enum.GetValues<BenchmarkResolution>())
{
Mats.Add(resolution, GetBenchmarkMat(resolution));
}
} }
private void InitializeComponent() private void InitializeComponent()
@@ -146,22 +182,18 @@ public class BenchmarkWindow : WindowEx
{ {
while (true) while (true)
{ {
if (_token.IsCancellationRequested) break; Parallel.For(0, MultiThreadTests, new ParallelOptions{CancellationToken = _tokenSource.Token }, i =>
Parallel.For(0, MultiThreadTests, i =>
{ {
if (_token.IsCancellationRequested) return; theMethod.Invoke(this, new object[]{benchmark.Resolution});
theMethod.Invoke(this, null);
}); });
} }
return;
} }
for (int i = 0; i < SingleThreadTests; i++) for (int i = 0; i < SingleThreadTests; i++)
{ {
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested(); if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
theMethod.Invoke(this, null); theMethod.Invoke(this, new object[] { benchmark.Resolution });
} }
sw.Stop(); sw.Stop();
@@ -171,15 +203,13 @@ public class BenchmarkWindow : WindowEx
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested(); if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
sw.Restart(); sw.Restart();
Parallel.For(0, MultiThreadTests, i => Parallel.For(0, MultiThreadTests, new ParallelOptions { CancellationToken = _tokenSource.Token }, i =>
{ {
if (_token.IsCancellationRequested) return; theMethod.Invoke(this, new object[] { benchmark.Resolution });
theMethod.Invoke(this, null);
}); });
sw.Stop(); sw.Stop();
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
var multiMiliseconds = sw.ElapsedMilliseconds; var multiMiliseconds = sw.ElapsedMilliseconds;
Dispatcher.UIThread.InvokeAsync(() => UpdateResults(false, multiMiliseconds)); Dispatcher.UIThread.InvokeAsync(() => UpdateResults(false, multiMiliseconds));
} }
@@ -417,13 +447,32 @@ public class BenchmarkWindow : WindowEx
return rawData.ToArray(); return rawData.ToArray();
} }
public Mat RandomMat(int width, int height) public static Mat RandomMat(int width, int height)
{ {
Mat mat = new(new Size(width, height), DepthType.Cv8U, 1); Mat mat = new(new Size(width, height), DepthType.Cv8U, 1);
CvInvoke.Randu(mat, EmguExtensions.BlackColor, EmguExtensions.WhiteColor); CvInvoke.Randu(mat, EmguExtensions.BlackColor, EmguExtensions.WhiteColor);
return mat; return mat;
} }
public static Mat GetBenchmarkMat(BenchmarkResolution resolution = default)
{
using var stream = App.GetAsset("/Assets/benchmark.png");
var mat4K = new Mat();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.Grayscale, mat4K);
switch (resolution)
{
case BenchmarkResolution.Resolution4K:
return mat4K;
case BenchmarkResolution.Resolution8K:
var mat8K = new Mat();
CvInvoke.Repeat(mat4K, 2, 2, mat8K);
mat4K.Dispose();
return mat8K;
default:
throw new ArgumentOutOfRangeException(nameof(resolution), resolution, null);
}
}
public void Test4KRandomCBBDLPEncode() public void Test4KRandomCBBDLPEncode()
{ {
using var mat = RandomMat(3840, 2160); using var mat = RandomMat(3840, 2160);
@@ -436,6 +485,11 @@ public class BenchmarkWindow : WindowEx
EncodeCbddlpImage(mat); EncodeCbddlpImage(mat);
} }
public void TestCBBDLPEncode(BenchmarkResolution resolution)
{
EncodeCbddlpImage(Mats[resolution]);
}
public void Test4KRandomCBTEncode() public void Test4KRandomCBTEncode()
{ {
using var mat = RandomMat(3840, 2160); using var mat = RandomMat(3840, 2160);
@@ -448,6 +502,11 @@ public class BenchmarkWindow : WindowEx
EncodeCbtImage(mat); EncodeCbtImage(mat);
} }
public void TestCBTEncode(BenchmarkResolution resolution)
{
EncodeCbtImage(Mats[resolution]);
}
public void Test4KRandomPW0Encode() public void Test4KRandomPW0Encode()
{ {
using var mat = RandomMat(3840, 2160); using var mat = RandomMat(3840, 2160);
@@ -460,5 +519,42 @@ public class BenchmarkWindow : WindowEx
EncodePW0Image(mat); EncodePW0Image(mat);
} }
public void TestPW0Encode(BenchmarkResolution resolution)
{
EncodePW0Image(Mats[resolution]);
}
public void TestPNGCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Png);
}
public void TestPNGDecompress(BenchmarkResolution resolution)
{ }
public void TestGZipCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.GZip);
}
public void TestGZipDecompress(BenchmarkResolution resolution)
{ }
public void TestDeflateCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Deflate);
}
public void TestDeflateDecompress(BenchmarkResolution resolution)
{ }
public void TestLZ4Compress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Lz4);
}
public void TestLZ4Decompress(BenchmarkResolution resolution)
{ }
#endregion #endregion
} }
+13 -2
View File
@@ -50,7 +50,7 @@
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<TextBlock Classes="GroupBoxHeader" Text="Tasks"/> <TextBlock Classes="GroupBoxHeader" Text="Tasks"/>
<StackPanel Margin="10" Orientation="Vertical" Spacing="10"> <StackPanel Margin="10" Orientation="Vertical" Spacing="10">
<Grid RowDefinitions="Auto" <Grid RowDefinitions="Auto,10,Auto"
ColumnDefinitions="Auto,10,150,5,Auto,20,Auto,2,Auto,2,Auto,2,Auto,2,Auto,2,Auto,2,Auto"> ColumnDefinitions="Auto,10,150,5,Auto,20,Auto,2,Auto,2,Auto,2,Auto,2,Auto,2,Auto,2,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
@@ -123,7 +123,18 @@
ToolTip.Tip="{Binding MaxProcessorCount, StringFormat=All of the available threads [{0}] (Full performance)}" ToolTip.Tip="{Binding MaxProcessorCount, StringFormat=All of the available threads [{0}] (Full performance)}"
Command="{Binding SetMaxDegreeOfParallelism}" Command="{Binding SetMaxDegreeOfParallelism}"
CommandParameter="{Binding MaxProcessorCount}"/> CommandParameter="{Binding MaxProcessorCount}"/>
<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
ToolTip.Tip="Sets the compression method used to store layer image cache.
&#x0a;The selected method will impact RAM usage and operations speed."
Text="Layer compression:"/>
<ComboBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="17"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Items="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
+2
View File
@@ -603,6 +603,8 @@ public class ToolWindow : WindowEx
ToolControl = toolControl; ToolControl = toolControl;
toolControl.ParentWindow = this; toolControl.ParentWindow = this;
toolControl.Margin = new Thickness(15); toolControl.Margin = new Thickness(15);
ToolControl.BaseOperation.ROI = ROI;
ToolControl.BaseOperation.MaskPoints = Masks;
Title = toolControl.BaseOperation.Title; Title = toolControl.BaseOperation.Title;
//LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None; //LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None;
+1
View File
@@ -1,3 +1,4 @@
#!/bin/bash #!/bin/bash
cd "$(dirname "$0")"
cd .. cd ..
dotnet build dotnet build
+7 -5
View File
@@ -183,7 +183,7 @@ $enableMSI = $true
#$buildOnly = 'osx-x64' #$buildOnly = 'osx-x64'
#$buildOnly = 'osx-arm64' #$buildOnly = 'osx-arm64'
$zipPackages = $true $zipPackages = $true
#$enableNugetPublish = $true $enableNugetPublish = $true
# Profilling # Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
@@ -357,17 +357,19 @@ Building: $runtime"
$macAppFolder = "${software}.app" $macAppFolder = "${software}.app"
$macPublishFolder = "$publishFolder/${macAppFolder}" $macPublishFolder = "$publishFolder/${macAppFolder}"
$macInfoplist = "$platformsFolder/$runtime/Info.plist" $macInfoplist = "$platformsFolder/$runtime/Info.plist"
$macOutputInfoplist = "$macPublishFolder/Contents" $macEntitlements = "$platformsFolder/$runtime/UVtools.entitlements"
$macContents = "$macPublishFolder/Contents"
$macTargetZipLegacy = "$publishFolder/${software}_${runtime}-legacy_v$version.zip" $macTargetZipLegacy = "$publishFolder/${software}_${runtime}-legacy_v$version.zip"
New-Item -ItemType directory -Path "$macPublishFolder" New-Item -ItemType directory -Path $macPublishFolder
New-Item -ItemType directory -Path "$macPublishFolder/Contents" New-Item -ItemType directory -Path "$macPublishFolder/Contents"
New-Item -ItemType directory -Path "$macPublishFolder/Contents/MacOS" New-Item -ItemType directory -Path "$macPublishFolder/Contents/MacOS"
New-Item -ItemType directory -Path "$macPublishFolder/Contents/Resources" New-Item -ItemType directory -Path "$macPublishFolder/Contents/Resources"
Copy-Item "$macIcns" -Destination "$macPublishFolder/Contents/Resources" Copy-Item $macIcns -Destination "$macPublishFolder/Contents/Resources"
((Get-Content -Path "$macInfoplist") -replace '#VERSION',"$version") | Set-Content -Path "$macOutputInfoplist/Info.plist" ((Get-Content -Path $macInfoplist) -replace '#VERSION',"$version") | Set-Content -Path "$macContents/Info.plist"
Copy-Item $macEntitlements -Destination $macContents
wsl cp -a "$publishFolder/$runtime/." "$macPublishFolder/Contents/MacOS" wsl cp -a "$publishFolder/$runtime/." "$macPublishFolder/Contents/MacOS"
wsl chmod +x "$macPublishFolder/Contents/MacOS/UVtools" wsl chmod +x "$macPublishFolder/Contents/MacOS/UVtools"

Some files were not shown because too many files have changed in this diff Show More