mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
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
This commit is contained in:
@@ -1,5 +1,35 @@
|
||||
# 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
|
||||
|
||||
- **(Add) Suggestions:**
|
||||
|
||||
+3
-1
@@ -70,4 +70,6 @@
|
||||
- Tim Anderson
|
||||
- Sakari Toivonen
|
||||
- Ed Wagaman
|
||||
- Marcin Chomiczuk
|
||||
- Marcin Chomiczuk
|
||||
- Patrick Hofmann
|
||||
- Ajilus
|
||||
@@ -113,7 +113,7 @@ public class AdvancedImageBox : UserControl
|
||||
/// </summary>
|
||||
public static ZoomLevelCollection Default =>
|
||||
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
|
||||
@@ -276,32 +276,28 @@ public class AdvancedImageBox : UserControl
|
||||
/// Returns the next increased zoom level for the given current zoom.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public int NextZoom(int zoomLevel)
|
||||
public int NextZoom(int zoomLevel, int constrainZoomLevel = 0)
|
||||
{
|
||||
var index = IndexOf(FindNearest(zoomLevel));
|
||||
if (index < Count - 1)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
if (index < Count - 1) index++;
|
||||
|
||||
return this[index];
|
||||
return constrainZoomLevel > 0 && this[index] >= constrainZoomLevel ? constrainZoomLevel : this[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the next decreased zoom level for the given current zoom.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public int PreviousZoom(int zoomLevel)
|
||||
public int PreviousZoom(int zoomLevel, int constrainZoomLevel = 0)
|
||||
{
|
||||
var index = IndexOf(FindNearest(zoomLevel));
|
||||
if (index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
if (index > 0) index--;
|
||||
|
||||
return this[index];
|
||||
return constrainZoomLevel > 0 && this[index] <= constrainZoomLevel ? constrainZoomLevel : this[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -842,7 +838,7 @@ public class AdvancedImageBox : UserControl
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<int> MaxZoomProperty =
|
||||
AvaloniaProperty.Register<AdvancedImageBox, int>(nameof(MaxZoom), 3500);
|
||||
AvaloniaProperty.Register<AdvancedImageBox, int>(nameof(MaxZoom), 6400);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum possible zoom.
|
||||
@@ -854,6 +850,18 @@ public class AdvancedImageBox : UserControl
|
||||
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 =
|
||||
AvaloniaProperty.RegisterDirect<AdvancedImageBox, int>(
|
||||
@@ -884,12 +892,14 @@ public class AdvancedImageBox : UserControl
|
||||
get => GetValue(ZoomProperty);
|
||||
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;
|
||||
if (previousZoom == newZoom) return;
|
||||
OldZoom = previousZoom;
|
||||
SetValue(ZoomProperty, value);
|
||||
SetValue(ZoomProperty, newZoom);
|
||||
|
||||
UpdateViewPort();
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zoom factor, the zoom / 100
|
||||
/// Gets the zoom factor, the zoom / 100.0
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets the width of the scaled image.
|
||||
/// </summary>
|
||||
@@ -1442,36 +1497,8 @@ public class AdvancedImageBox : UserControl
|
||||
/// </summary>
|
||||
public void ZoomToFit()
|
||||
{
|
||||
var image = Image;
|
||||
if (image is null) return;
|
||||
|
||||
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;
|
||||
if (!IsImageLoaded) return;
|
||||
Zoom = ZoomLevelToFit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
<PackageIconUrl />
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools/tree/master/UVtools.AvaloniaControls</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageTags>Advanced image box</PackageTags>
|
||||
<PackageTags>Advanced image box; Avalonia</PackageTags>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Description>AvaloniaUI Controls</Description>
|
||||
<Version>1.0.1</Version>
|
||||
<Description>AvaloniaUI Controls
|
||||
- AdvancedImageBox: Pan, zoom, cursor, pixel grid and selections image box</Description>
|
||||
<Version>2.0.0</Version>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
@@ -49,4 +52,11 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -10,7 +10,10 @@ using Emgu.CV.Cuda;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UVtools.Core.Layers;
|
||||
using UVtools.Core.Operations;
|
||||
|
||||
namespace UVtools.Core;
|
||||
|
||||
@@ -40,6 +43,21 @@ public static class CoreSettings
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets or sets if operations run via CUDA when possible
|
||||
/// </summary>
|
||||
@@ -50,6 +68,11 @@ public static class CoreSettings
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets the default folder to save the settings
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,15 @@ namespace UVtools.Core;
|
||||
|
||||
public class Enumerations
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets index start number
|
||||
/// </summary>
|
||||
public enum IndexStartNumber : byte
|
||||
{
|
||||
Zero,
|
||||
One
|
||||
}
|
||||
|
||||
public enum LayerRangeSelection : byte
|
||||
{
|
||||
None,
|
||||
|
||||
@@ -60,4 +60,9 @@ public static class StreamExtensions
|
||||
{
|
||||
await CopyToAsync(source, destination, DefaultCopyBufferSize, progress, cancellationToken);
|
||||
}
|
||||
|
||||
public static MemoryStream ToStream(this byte[] arr)
|
||||
{
|
||||
return new MemoryStream(arr);
|
||||
}
|
||||
}
|
||||
@@ -103,16 +103,12 @@ public static class ZipArchiveExtensions
|
||||
{
|
||||
//Gets the complete path for the destination file, including any
|
||||
//relative paths that were in the zip file
|
||||
string destinationFileName = Path.Combine(destinationPath, file.FullName);
|
||||
|
||||
//Gets just the new path, minus the file name so we can create the
|
||||
//directory if it does not exist
|
||||
string? destinationFilePath = Path.GetDirectoryName(destinationFileName);
|
||||
|
||||
destinationFilePath ??= string.Empty;
|
||||
var destFileName = Path.Combine(destinationPath, file.FullName);
|
||||
var fullDestDirPath = Path.GetFullPath(destinationPath + Path.DirectorySeparatorChar);
|
||||
if (!destFileName.StartsWith(fullDestDirPath)) return; // Entry is outside the target dir
|
||||
|
||||
//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
|
||||
//method of overwriting chosen
|
||||
@@ -120,26 +116,28 @@ public static class ZipArchiveExtensions
|
||||
{
|
||||
case Overwrite.Always:
|
||||
//Just put the file in and overwrite anything that is found
|
||||
file.ExtractToFile(destinationFileName, true);
|
||||
file.ExtractToFile(destFileName, true);
|
||||
break;
|
||||
case Overwrite.IfNewer:
|
||||
//Checks to see if the file exists, and if so, if it should
|
||||
//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
|
||||
//we will extract it and overwrite any existing file
|
||||
file.ExtractToFile(destinationFileName, true);
|
||||
file.ExtractToFile(destFileName, true);
|
||||
}
|
||||
break;
|
||||
case Overwrite.Never:
|
||||
//Put the file in if it is new but ignores the
|
||||
//file if it already exists
|
||||
if (!File.Exists(destinationFileName))
|
||||
if (!File.Exists(destFileName))
|
||||
{
|
||||
file.ExtractToFile(destinationFileName);
|
||||
file.ExtractToFile(destFileName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(overwriteMethod), overwriteMethod, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +192,7 @@ public static class ZipArchiveExtensions
|
||||
//Throws an error if the file exists
|
||||
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;
|
||||
case ArchiveAction.Ignore:
|
||||
|
||||
@@ -1169,7 +1169,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
LayersPointer = new LayerPointer[Settings.LayerCount];
|
||||
for (uint layerIndex = 0; layerIndex < Settings.LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
LayersPointer[layerIndex] = Helpers.Deserialize<LayerPointer>(inputFile);
|
||||
Debug.WriteLine($"pointer[{layerIndex}]: {LayersPointer[layerIndex]}");
|
||||
progress++;
|
||||
@@ -1184,7 +1184,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
|
||||
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
@@ -1195,10 +1195,8 @@ public class CTBEncryptedFile : FileFormat
|
||||
|
||||
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];
|
||||
|
||||
|
||||
@@ -1359,9 +1357,8 @@ public class CTBEncryptedFile : FileFormat
|
||||
outputFile.Seek(outputFile.Position + layerTableSize, SeekOrigin.Begin);
|
||||
|
||||
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]);
|
||||
using (var mat = this[layerIndex].LayerMat)
|
||||
{
|
||||
@@ -1375,6 +1372,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var layerDef = LayersDefinition[layerIndex];
|
||||
LayersPointer[layerIndex] = new LayerPointer((uint)outputFile.Position);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using UVtools.Core.Extensions;
|
||||
@@ -624,7 +625,7 @@ public class CWSFile : FileFormat
|
||||
|
||||
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);
|
||||
@@ -659,16 +660,27 @@ public class CWSFile : FileFormat
|
||||
|
||||
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 },
|
||||
layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
|
||||
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);
|
||||
var span = mat.GetDataByteSpan();
|
||||
var spanEncode = matEncode.GetDataByteSpan();
|
||||
@@ -683,18 +695,11 @@ public class CWSFile : FileFormat
|
||||
outputFile.PutFileContent(layerImagePath, bytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
});
|
||||
});*/
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
var layer = this[layerIndex];
|
||||
var layerImagePath = layer.FormatFileName(filename);
|
||||
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, filename, LayerDigits, Enumerations.IndexStartNumber.Zero, progress);
|
||||
}
|
||||
|
||||
RebuildGCode();
|
||||
@@ -822,70 +827,65 @@ public class CWSFile : FileFormat
|
||||
|
||||
Init(OutputSettings.LayersNum, DecodeType == FileDecodeType.Partial);
|
||||
|
||||
progress.ItemCount = OutputSettings.LayersNum;
|
||||
|
||||
if(LayerCount > 0)
|
||||
if (LayerCount <= 0) return;
|
||||
|
||||
// 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)!;
|
||||
foreach (var pngEntry in inputFile.Entries)
|
||||
{
|
||||
if (!pngEntry.Name.EndsWith(".png")) 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);
|
||||
}
|
||||
}
|
||||
if (!pngEntry.Name.EndsWith(".png")) continue;
|
||||
var match = Regex.Match(pngEntry.Name, @"(\d+).png");
|
||||
if (!match.Success || match.Groups.Count < 2) continue;
|
||||
if (!uint.TryParse(match.Groups[1].Value, out var layerIndex)) continue;
|
||||
|
||||
GCode.ParseLayersFromGCode(this);
|
||||
/*var filename = Path.GetFileNameWithoutExtension(pngEntry.Name).Replace(inputFilename, string.Empty, StringComparison.Ordinal);
|
||||
|
||||
var firstLayer = FirstLayer;
|
||||
if (firstLayer is not null && DecodeType == FileDecodeType.Full)
|
||||
{
|
||||
if (Printer == PrinterType.Unknown)
|
||||
var layerIndexStr = string.Empty;
|
||||
var layerStr = filename;
|
||||
for (int i = layerStr.Length - 1; i >= 0; i--)
|
||||
{
|
||||
using Mat mat = new ();
|
||||
CvInvoke.Imdecode(firstLayer.CompressedBytes, ImreadModes.AnyColor, mat);
|
||||
Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono;
|
||||
if (layerStr[i] < '0' || layerStr[i] > '9') break;
|
||||
layerIndexStr = $"{layerStr[i]}{layerIndexStr}";
|
||||
}
|
||||
|
||||
if (Printer == PrinterType.BeneMono)
|
||||
{
|
||||
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
var layer = this[layerIndex];
|
||||
using Mat mat = new();
|
||||
CvInvoke.Imdecode(layer.CompressedBytes, ImreadModes.Color, mat);
|
||||
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();
|
||||
});
|
||||
}
|
||||
if (string.IsNullOrEmpty(layerIndexStr)) continue;
|
||||
if (!uint.TryParse(layerIndexStr, out var layerIndex)) continue;*/
|
||||
|
||||
using var stream = pngEntry.Open();
|
||||
using var mat = new Mat();
|
||||
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, mat);
|
||||
Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -657,9 +657,8 @@ public class CXDLPFile : FileFormat
|
||||
var previews = new byte[ThumbnailsOriginalSize!.Length][];
|
||||
|
||||
// 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;
|
||||
if (Thumbnails[previewIndex] is null)
|
||||
{
|
||||
@@ -707,11 +706,8 @@ public class CXDLPFile : FileFormat
|
||||
var layerBytes = new List<byte>[LayerCount];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
|
||||
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
var layer = this[layerIndex];
|
||||
using (var mat = layer.LayerMat)
|
||||
{
|
||||
@@ -762,8 +758,6 @@ public class CXDLPFile : FileFormat
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
|
||||
@@ -892,7 +886,7 @@ public class CXDLPFile : FileFormat
|
||||
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]);
|
||||
previews[previewIndex] = null!;
|
||||
@@ -919,23 +913,20 @@ public class CXDLPFile : FileFormat
|
||||
var linesBytes = new byte[LayerCount][];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(4, SeekOrigin.Current);
|
||||
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
|
||||
|
||||
linesBytes[layerIndex] = new byte[lineCount * 6];
|
||||
inputFile.ReadBytes(linesBytes[layerIndex]);
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -973,10 +964,6 @@ public class CXDLPFile : FileFormat
|
||||
inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End);
|
||||
}
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
|
||||
|
||||
FooterSettings = Helpers.Deserialize<Footer>(inputFile);
|
||||
FooterSettings.Validate();
|
||||
}
|
||||
|
||||
@@ -519,9 +519,8 @@ public class CXDLPv1File : FileFormat
|
||||
var previews = new byte[ThumbnailsOriginalSize!.Length][];
|
||||
|
||||
// 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;
|
||||
if (Thumbnails[previewIndex] is null)
|
||||
{
|
||||
@@ -557,11 +556,8 @@ public class CXDLPv1File : FileFormat
|
||||
var layerBytes = new List<byte>[LayerCount];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
|
||||
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
var layer = this[layerIndex];
|
||||
using (var mat = layer.LayerMat)
|
||||
{
|
||||
@@ -610,8 +606,6 @@ public class CXDLPv1File : FileFormat
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
|
||||
@@ -644,7 +638,7 @@ public class CXDLPv1File : FileFormat
|
||||
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]);
|
||||
previews[previewIndex] = null!;
|
||||
@@ -664,10 +658,10 @@ public class CXDLPv1File : FileFormat
|
||||
var linesBytes = new byte[LayerCount][];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(4, SeekOrigin.Current);
|
||||
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
|
||||
|
||||
@@ -675,12 +669,10 @@ public class CXDLPv1File : FileFormat
|
||||
inputFile.ReadBytes(linesBytes[layerIndex]);
|
||||
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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
FooterSettings = Helpers.Deserialize<Footer>(inputFile);
|
||||
FooterSettings.Validate();
|
||||
}
|
||||
|
||||
@@ -1914,9 +1914,8 @@ public class ChituboxFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
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]);
|
||||
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = LayerDefinitions[aaIndex, layerIndex];
|
||||
LayerDef? layerDefHash = null;
|
||||
@@ -2098,7 +2097,7 @@ public class ChituboxFile : FileFormat
|
||||
Debug.WriteLine($"-Image GROUP {aaIndex}-");
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
inputFile.Seek(layerOffset, SeekOrigin.Begin);
|
||||
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
layerDef.Parent = this;
|
||||
@@ -2136,16 +2135,15 @@ public class ChituboxFile : FileFormat
|
||||
{
|
||||
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
|
||||
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);
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
||||
|
||||
|
||||
@@ -426,116 +426,87 @@ public class ChituboxZipFile : FileFormat
|
||||
outputFile.PutFileContent(GCodeFilename, GCodeStr, ZipArchiveMode.Create);
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
var layer = this[layerIndex];
|
||||
outputFile.PutFileContent($"{layerIndex + 1}.png", layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, 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);
|
||||
if (entry is not null)
|
||||
//Clear();
|
||||
//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();
|
||||
//throw new FileLoadException("run.gcode not found", fileFullPath);
|
||||
using TextReader tr = new StreamReader(entry.Open());
|
||||
string? line;
|
||||
GCode!.Clear();
|
||||
while ((line = tr.ReadLine()) != null)
|
||||
GCode.AppendLine(line);
|
||||
if (string.IsNullOrEmpty(line)) continue;
|
||||
|
||||
if (line[0] != ';')
|
||||
{
|
||||
GCode.AppendLine(line);
|
||||
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());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
tr.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsPHZZip = true;
|
||||
}
|
||||
|
||||
if (HeaderSettings.LayerCount == 0)
|
||||
{
|
||||
foreach (var zipEntry in inputFile.Entries)
|
||||
var splitLine = line.Split(':');
|
||||
if (splitLine.Length < 2) continue;
|
||||
|
||||
foreach (var propertyInfo in HeaderSettings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
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;
|
||||
HeaderSettings.LayerCount = Math.Max(HeaderSettings.LayerCount, layerIndex);
|
||||
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;
|
||||
}
|
||||
|
||||
Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial);
|
||||
|
||||
progress.ItemCount = LayerCount;
|
||||
|
||||
if (DecodeType == FileDecodeType.Full)
|
||||
if (HeaderSettings.LayerCount == 0)
|
||||
{
|
||||
foreach (var zipEntry in inputFile.Entries)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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]);
|
||||
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;
|
||||
HeaderSettings.LayerCount = Math.Max(HeaderSettings.LayerCount, layerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -976,9 +976,8 @@ public class FDGFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
|
||||
@@ -989,7 +988,7 @@ public class FDGFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = LayersDefinitions[layerIndex];
|
||||
LayerDef? layerDefHash = null;
|
||||
@@ -1089,7 +1088,7 @@ public class FDGFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
layerDef.Parent = this;
|
||||
@@ -1107,9 +1106,8 @@ public class FDGFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
|
||||
|
||||
@@ -19,8 +19,10 @@ using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using UVtools.Core.EmguCV;
|
||||
@@ -3229,7 +3231,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
|
||||
DecodeInternally(progress);
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerHeightDigits = LayerHeight.DecimalDigits();
|
||||
if (layerHeightDigits > Layer.HeightPrecision)
|
||||
@@ -3243,8 +3245,128 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
{
|
||||
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>
|
||||
/// Extract contents to a folder
|
||||
/// </summary>
|
||||
@@ -3389,10 +3511,9 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
|
||||
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.CompressedBytes;
|
||||
var byteArr = layer.CompressedPngBytes;
|
||||
if (byteArr is null) return;
|
||||
using var stream = new FileStream(Path.Combine(path, layer.Filename), FileMode.Create, FileAccess.Write);
|
||||
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)
|
||||
=> 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>
|
||||
/// Validate AntiAlias Level
|
||||
/// </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
|
||||
{
|
||||
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();
|
||||
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
if (progress.Token.IsCancellationRequested)
|
||||
{
|
||||
_boundingRectangle = Rectangle.Empty;
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
FindFirstBoundingRectangle();
|
||||
}
|
||||
|
||||
@@ -4960,10 +5089,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
/// </summary>
|
||||
/// <param name="mats"></param>
|
||||
/// <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];
|
||||
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);
|
||||
});
|
||||
@@ -4976,9 +5106,9 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
/// </summary>
|
||||
/// <param name="mats"></param>
|
||||
/// /// <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;
|
||||
return layers;
|
||||
}
|
||||
@@ -5349,7 +5479,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
}
|
||||
|
||||
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;
|
||||
modifiedLayer.Value.Dispose();
|
||||
|
||||
@@ -503,10 +503,8 @@ public class FlashForgeSVGXFile : FileFormat
|
||||
SVGDocument.Groups = new List<FlashForgeSVGXSvgGroup> { new("background") };
|
||||
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}");
|
||||
|
||||
using var mat = this[layerIndex].LayerMat;
|
||||
@@ -651,10 +649,8 @@ public class FlashForgeSVGXFile : FileFormat
|
||||
|
||||
if (DecodeType != FileDecodeType.Full) return;
|
||||
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 group = SVGDocument.Groups.FirstOrDefault(g => g.Id == $"layer-{layerIndex}");
|
||||
@@ -665,7 +661,7 @@ public class FlashForgeSVGXFile : FileFormat
|
||||
var points = new List<Point>();
|
||||
foreach (var path in @group.Paths)
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) break;
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var spaceSplit = path.Value.Split(' ',
|
||||
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
@@ -727,8 +723,6 @@ public class FlashForgeSVGXFile : FileFormat
|
||||
|
||||
}
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
@@ -364,9 +364,8 @@ public class GR1File : FileFormat
|
||||
var previews = new byte[ThumbnailsOriginalSize!.Length][];
|
||||
|
||||
// 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;
|
||||
if (Thumbnails[previewIndex] is null)
|
||||
{
|
||||
@@ -396,11 +395,8 @@ public class GR1File : FileFormat
|
||||
var layerBytes = new List<byte>[LayerCount];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
|
||||
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
var layer = this[layerIndex];
|
||||
using (var mat = layer.LayerMat)
|
||||
{
|
||||
@@ -446,8 +442,6 @@ public class GR1File : FileFormat
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
|
||||
@@ -482,7 +476,7 @@ public class GR1File : FileFormat
|
||||
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]);
|
||||
previews[previewIndex] = null!;
|
||||
@@ -500,22 +494,18 @@ public class GR1File : FileFormat
|
||||
var linesBytes = new byte[LayerCount][];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
|
||||
|
||||
linesBytes[layerIndex] = new byte[lineCount * 6];
|
||||
inputFile.ReadBytes(linesBytes[layerIndex]);
|
||||
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);
|
||||
|
||||
for (int i = 0; i < linesBytes[layerIndex].Length; i++)
|
||||
|
||||
@@ -167,6 +167,7 @@ public class GenericZIPFile : FileFormat
|
||||
{
|
||||
if (entry.Name == ManifestFileName) return true;
|
||||
if (entry.Name.EndsWith(".gcode")) return false;
|
||||
if (entry.Name.EndsWith(".xml")) return false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -201,14 +202,7 @@ public class GenericZIPFile : FileFormat
|
||||
}
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
var layer = this[layerIndex];
|
||||
var filename = $"{layerIndex + 1}.png";
|
||||
outputFile.PutFileContent(filename, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
|
||||
|
||||
ManifestFile.Update();
|
||||
|
||||
@@ -219,81 +213,56 @@ public class GenericZIPFile : FileFormat
|
||||
|
||||
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);
|
||||
if (entry is not null)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
using var stream = entry.Open();
|
||||
ManifestFile = XmlExtensions.DeserializeFromStream<GenericZipManifest>(stream);
|
||||
}
|
||||
|
||||
uint layerCount = 0;
|
||||
foreach (var zipEntry in inputFile.Entries)
|
||||
catch (Exception)
|
||||
{
|
||||
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);
|
||||
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]);
|
||||
// Not required
|
||||
//Clear();
|
||||
//throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -530,9 +530,8 @@ public class LGSFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
layerData[layerIndex] = new LayerDef(this);
|
||||
@@ -543,7 +542,7 @@ public class LGSFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
outputFile.WriteSerialize(layerData[layerIndex]);
|
||||
layerData[layerIndex].EncodedRle = null!; // Free this
|
||||
}
|
||||
@@ -555,7 +554,7 @@ public class LGSFile : FileFormat
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
outputFile.WriteSerialize(layerData[layerIndex]);
|
||||
progress++;
|
||||
}
|
||||
@@ -604,15 +603,14 @@ public class LGSFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
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();
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
||||
|
||||
|
||||
@@ -323,9 +323,8 @@ public class MDLPFile : FileFormat
|
||||
var previews = new byte[ThumbnailsOriginalSize!.Length][];
|
||||
|
||||
// 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;
|
||||
if (Thumbnails[previewIndex] is null)
|
||||
{
|
||||
@@ -355,11 +354,8 @@ public class MDLPFile : FileFormat
|
||||
var layerBytes = new List<byte>[LayerCount];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex =>
|
||||
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
var layer = this[layerIndex];
|
||||
using (var mat = layer.LayerMat)
|
||||
{
|
||||
@@ -405,8 +401,6 @@ public class MDLPFile : FileFormat
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
outputFile.WriteBytes(layerBytes[layerIndex].ToArray());
|
||||
@@ -439,7 +433,7 @@ public class MDLPFile : FileFormat
|
||||
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]);
|
||||
previews[previewIndex] = null!;
|
||||
@@ -456,22 +450,19 @@ public class MDLPFile : FileFormat
|
||||
var linesBytes = new byte[LayerCount][];
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4));
|
||||
|
||||
linesBytes[layerIndex] = new byte[lineCount * 6];
|
||||
inputFile.ReadBytes(linesBytes[layerIndex]);
|
||||
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))
|
||||
{
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ public class OSLAFile : FileFormat
|
||||
var image = Thumbnails[i];
|
||||
if(image is null) continue;
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var bytes = EncodeImage(HeaderSettings.PreviewDataType, image);
|
||||
if (bytes.Length == 0) continue;
|
||||
@@ -517,9 +517,8 @@ public class OSLAFile : FileFormat
|
||||
{
|
||||
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)
|
||||
{
|
||||
layerBytes[layerIndex] = EncodeImage(HeaderSettings.LayerDataType, mat);
|
||||
@@ -530,7 +529,7 @@ public class OSLAFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
// Try to reuse layers
|
||||
var hash = CryptExtensions.ComputeSHA1Hash(layerBytes[layerIndex]);
|
||||
@@ -556,7 +555,7 @@ public class OSLAFile : FileFormat
|
||||
outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
|
||||
for (int layerIndex = 0; layerIndex < layerDataAddresses.Length; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layer = this[layerIndex];
|
||||
var layerdef = new LayerDef(layer);
|
||||
@@ -615,7 +614,7 @@ public class OSLAFile : FileFormat
|
||||
|
||||
for (byte i = 0; i < HeaderSettings.PreviewCount; i++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var preview = Helpers.Deserialize<Preview>(inputFile);
|
||||
|
||||
Debug.Write($"Preview {i} -> ");
|
||||
@@ -644,7 +643,7 @@ public class OSLAFile : FileFormat
|
||||
uint layerTableSize = 0;
|
||||
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
layerDataAddresses[layerIndex] = inputFile.ReadUIntLittleEndian();
|
||||
|
||||
layerDef[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
@@ -670,15 +669,14 @@ public class OSLAFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin);
|
||||
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);
|
||||
layerBytes[layerIndex] = null!; // Clean
|
||||
|
||||
|
||||
@@ -1002,9 +1002,8 @@ public class PHZFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
|
||||
@@ -1015,7 +1014,7 @@ public class PHZFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = LayersDefinitions[layerIndex];
|
||||
LayerDef? layerDefHash = null;
|
||||
@@ -1116,7 +1115,7 @@ public class PHZFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
layerDef.Parent = this;
|
||||
@@ -1134,10 +1133,8 @@ public class PHZFile : FileFormat
|
||||
|
||||
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);
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
||||
progress.LockAndIncrement();
|
||||
|
||||
@@ -447,9 +447,8 @@ public class PhotonSFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
layerData[layerIndex] = new LayerDef(mat);
|
||||
@@ -460,7 +459,7 @@ public class PhotonSFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
outputFile.WriteSerialize(layerData[layerIndex]);
|
||||
outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
|
||||
@@ -503,7 +502,7 @@ public class PhotonSFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
layersDefinitions[layerIndex] = layerDef;
|
||||
@@ -524,9 +523,8 @@ public class PhotonSFile : FileFormat
|
||||
|
||||
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();
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
||||
progress.LockAndIncrement();
|
||||
|
||||
@@ -1695,9 +1695,8 @@ public class PhotonWorkshopFile : FileFormat
|
||||
|
||||
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)
|
||||
{
|
||||
LayersDefinition.Layers[layerIndex] = new LayerDef(this, this[layerIndex]);
|
||||
@@ -1708,7 +1707,7 @@ public class PhotonWorkshopFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layerDef = LayersDefinition.Layers[layerIndex];
|
||||
|
||||
@@ -1822,7 +1821,7 @@ public class PhotonWorkshopFile : FileFormat
|
||||
{
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
LayersDefinition[layerIndex].Parent = this;
|
||||
@@ -1840,10 +1839,8 @@ public class PhotonWorkshopFile : FileFormat
|
||||
|
||||
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();
|
||||
this[layerIndex] = new Layer((uint)layerIndex, mat, this)
|
||||
{
|
||||
|
||||
@@ -614,15 +614,7 @@ public class SL1File : FileFormat
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
Layer layer = this[layerIndex];
|
||||
var layerImagePath = $"{filename}{layerIndex:D5}.png";
|
||||
//layer.Filename = layerImagePath;
|
||||
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, filename, 5, Enumerations.IndexStartNumber.Zero, progress);
|
||||
}
|
||||
|
||||
|
||||
@@ -635,135 +627,118 @@ public class SL1File : FileFormat
|
||||
|
||||
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();
|
||||
foreach (ZipArchiveEntry entity in inputFile.Entries)
|
||||
if (!entity.Name.EndsWith(".ini")) continue;
|
||||
iniFiles.Add(entity.Name);
|
||||
using StreamReader streamReader = new(entity.Open());
|
||||
string? line;
|
||||
while ((line = streamReader.ReadLine()) != null)
|
||||
{
|
||||
if (!entity.Name.EndsWith(".ini")) continue;
|
||||
iniFiles.Add(entity.Name);
|
||||
using StreamReader streamReader = new(entity.Open());
|
||||
string? line;
|
||||
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();
|
||||
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]);
|
||||
bool foundMember = false;
|
||||
var fieldName = IniKeyToMemberName(keyValue[0]);
|
||||
bool foundMember = false;
|
||||
|
||||
|
||||
foreach (var obj in Configs)
|
||||
{
|
||||
var attribute = obj.GetType().GetProperty(fieldName);
|
||||
if (attribute is null || !attribute.CanWrite) continue;
|
||||
//Debug.WriteLine(attribute.Name);
|
||||
Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
|
||||
foreach (var obj in Configs)
|
||||
{
|
||||
var attribute = obj.GetType().GetProperty(fieldName);
|
||||
if (attribute is null || !attribute.CanWrite) continue;
|
||||
//Debug.WriteLine(attribute.Name);
|
||||
Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
|
||||
|
||||
Statistics.ImplementedKeys.Add(keyValue[0]);
|
||||
foundMember = true;
|
||||
}
|
||||
Statistics.ImplementedKeys.Add(keyValue[0]);
|
||||
foundMember = true;
|
||||
}
|
||||
|
||||
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"))
|
||||
if (!foundMember)
|
||||
{
|
||||
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++;
|
||||
|
||||
continue;
|
||||
Statistics.MissingKeys.Add(keyValue[0]);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SetTransitionLayers(TransitionLayerCount, false);
|
||||
}
|
||||
|
||||
GetBoundingRectangle(progress);
|
||||
|
||||
Statistics.ExecutionTime.Stop();
|
||||
|
||||
Debug.WriteLine(Statistics);
|
||||
|
||||
@@ -502,75 +502,52 @@ public class UVJFile : FileFormat
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Layer layer = this[layerIndex];
|
||||
|
||||
var layerimagePath = $"{FolderImageName}/{layerIndex:D8}.png";
|
||||
outputFile.PutFileContent(layerimagePath, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, 8, Enumerations.IndexStartNumber.Zero, progress, FolderImageName);
|
||||
}
|
||||
|
||||
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);
|
||||
if (entry is null)
|
||||
{
|
||||
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++;
|
||||
Clear();
|
||||
throw new FileLoadException($"{FileConfigName} not found", FileFullPath);
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -309,15 +309,8 @@ public class VDAFile : FileFormat
|
||||
Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml").
|
||||
Replace($".{FileExtensions[0].Extension}", ".xml");
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
var layer = this[layerIndex];
|
||||
var filename = $"{layerIndex + 1}".PadLeft(4, '0') + ".png";
|
||||
outputFile.PutFileContent(filename, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
|
||||
EncodeLayersInZip(outputFile, 4, Enumerations.IndexStartNumber.One, progress);
|
||||
|
||||
UpdateManifest();
|
||||
|
||||
var entry = outputFile.CreateEntry(manifestFilename);
|
||||
@@ -327,53 +320,28 @@ public class VDAFile : FileFormat
|
||||
|
||||
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"));
|
||||
if (entry is null)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
Clear();
|
||||
throw new FileLoadException($".xml manifest not found", FileFullPath);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -413,7 +381,7 @@ public class VDAFile : FileFormat
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; 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
|
||||
|
||||
@@ -651,64 +651,45 @@ public class VDTFile : FileFormat
|
||||
}
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
var layer = this[layerIndex];
|
||||
var layerImagePath = $"{layerIndex}.png";
|
||||
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, 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);
|
||||
if (entry is null)
|
||||
{
|
||||
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++;
|
||||
Clear();
|
||||
throw new FileLoadException($"{FileManifestName} not found", FileFullPath);
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -13,11 +13,13 @@ using Org.BouncyCastle.Crypto.Engines;
|
||||
using Org.BouncyCastle.OpenSsl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.GCode;
|
||||
@@ -477,13 +479,7 @@ public class ZCodeFile : FileFormat
|
||||
thumbnailsStream.Close();
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
var layer = this[layerIndex];
|
||||
outputFile.PutFileContent($"{layerIndex + 1}.png", layer.CompressedBytes, ZipArchiveMode.Create);
|
||||
progress++;
|
||||
}
|
||||
EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
|
||||
|
||||
var entry = outputFile.CreateEntry(ManifestFilename);
|
||||
using (var stream = entry.Open())
|
||||
@@ -549,29 +545,8 @@ public class ZCodeFile : FileFormat
|
||||
}
|
||||
|
||||
Init(ManifestFile.Job.LayerCount, DecodeType == FileDecodeType.Partial);
|
||||
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
|
||||
|
||||
//var gcode = GCode.ToString();
|
||||
//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++;
|
||||
}
|
||||
DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
|
||||
|
||||
GCode!.ParseLayersFromGCode(this);
|
||||
|
||||
@@ -581,8 +556,6 @@ public class ZCodeFile : FileFormat
|
||||
Thumbnails[0] = new Mat();
|
||||
CvInvoke.Imdecode(entry.Open().ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
|
||||
}
|
||||
|
||||
GetBoundingRectangle(progress);
|
||||
}
|
||||
|
||||
protected override void PartialSaveInternally(OperationProgress progress)
|
||||
|
||||
@@ -401,12 +401,14 @@ public class ZCodexFile : FileFormat
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
EncodeLayersInZip(outputFile, FolderImageName, 5, Enumerations.IndexStartNumber.Zero, progress, FolderImages);
|
||||
|
||||
GCode!.Clear();
|
||||
|
||||
float lastZPosition = 0;
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var layer = this[layerIndex];
|
||||
GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}");
|
||||
@@ -436,19 +438,7 @@ public class ZCodexFile : FileFormat
|
||||
GCode.AppendLine(GCodeKeywordDelayModel);
|
||||
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;
|
||||
|
||||
progress++;
|
||||
}
|
||||
|
||||
GCode.AppendLine($"G1 Z40.0 F{UserSettings.ZLiftFeedRate}");
|
||||
@@ -496,6 +486,8 @@ public class ZCodexFile : FileFormat
|
||||
}
|
||||
|
||||
Init(ResinMetadataSettings.TotalLayersCount, DecodeType == FileDecodeType.Partial);
|
||||
DecodeLayersFromZip(inputFile, FolderImageName, Enumerations.IndexStartNumber.Zero, progress);
|
||||
|
||||
GCode!.Clear();
|
||||
using (TextReader tr = new StreamReader(entry.Open()))
|
||||
{
|
||||
@@ -576,11 +568,11 @@ M106 S0
|
||||
LayersSettings[layerIndex].LayerFileIndex = layerFileIndex;
|
||||
LayersSettings[layerIndex].LayerEntry = inputFile.GetEntry(layerimagePath);
|
||||
|
||||
if (DecodeType == FileDecodeType.Full)
|
||||
/*if (DecodeType == FileDecodeType.Full)
|
||||
{
|
||||
using var stream = LayersSettings[layerIndex].LayerEntry!.Open();
|
||||
this[layerIndex] = new Layer((uint)layerIndex, stream, this);
|
||||
}
|
||||
}*/
|
||||
|
||||
this[layerIndex].PositionZ = currentHeight;
|
||||
this[layerIndex].LiftHeight = liftHeight;
|
||||
@@ -588,8 +580,6 @@ M106 S0
|
||||
this[layerIndex].RetractSpeed = retractSpeed;
|
||||
this[layerIndex].LightPWM = pwm;
|
||||
layerIndex++;
|
||||
|
||||
progress++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,7 +596,6 @@ M106 S0
|
||||
}
|
||||
|
||||
BottomRetractSpeed = RetractSpeed; // Compability
|
||||
GetBoundingRectangle(progress);
|
||||
}
|
||||
|
||||
public override void RebuildGCode()
|
||||
|
||||
+214
-25
@@ -10,9 +10,12 @@ using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using K4os.Compression.LZ4;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.FileFormats;
|
||||
using UVtools.Core.Objects;
|
||||
@@ -25,6 +28,24 @@ namespace UVtools.Core.Layers;
|
||||
/// </summary>
|
||||
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
|
||||
public const byte HeightPrecision = 3;
|
||||
public const decimal HeightPrecisionIncrement = 0.001M;
|
||||
@@ -35,6 +56,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
#region Members
|
||||
|
||||
public object Mutex = new();
|
||||
private LayerCompressionMethod _compressionMethod;
|
||||
private byte[]? _compressedBytes;
|
||||
private uint _nonZeroPixelCount;
|
||||
private Rectangle _boundingRectangle = Rectangle.Empty;
|
||||
@@ -55,6 +77,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
private float _retractSpeed2 = FileFormat.DefaultRetractSpeed2;
|
||||
private byte _lightPWM = FileFormat.DefaultLightPWM;
|
||||
private float _materialMilliliters;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
@@ -567,6 +590,29 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets or sets layer image compressed data
|
||||
/// </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>
|
||||
/// True if this layer have an valid initialized image, otherwise false
|
||||
/// </summary>
|
||||
@@ -596,13 +654,70 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
get
|
||||
{
|
||||
if (!HaveImage) return null!;
|
||||
Mat mat = new();
|
||||
CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat);
|
||||
return mat;
|
||||
|
||||
Mat 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
|
||||
{
|
||||
CompressedBytes = value?.GetPngByes();
|
||||
if (value is not null)
|
||||
{
|
||||
CompressedBytes = CompressMat(value, _compressionMethod);
|
||||
}
|
||||
|
||||
GetBoundingRectangle(value, true);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
@@ -627,7 +742,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
/// <summary>
|
||||
/// Gets a computed layer filename, padding zeros are equal to layer count digits
|
||||
/// </summary>
|
||||
public string Filename => FormatFileName("layer");
|
||||
public string Filename => FormatFileNameWithLayerDigits("layer");
|
||||
|
||||
/// <summary>
|
||||
/// Gets if layer image has been modified
|
||||
@@ -700,29 +815,55 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
|
||||
#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;
|
||||
_index = index;
|
||||
|
||||
|
||||
//if (slicerFile is null) return;
|
||||
_positionZ = SlicerFile.GetHeightFromLayer(index);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
_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
|
||||
|
||||
#region Equatables
|
||||
@@ -946,22 +1087,22 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
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;
|
||||
if (!layerIndexZeroStarted)
|
||||
if (layerIndexStartNumber == Enumerations.IndexStartNumber.One)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
return $"{prepend}{index.ToString().PadLeft(padDigits, '0')}{appendExt}";
|
||||
}
|
||||
|
||||
public string FormatFileName(string prepend = "", bool layerIndexZeroStarted = true, string appendExt = ".png")
|
||||
=> FormatFileName(prepend, SlicerFile.LayerDigits, layerIndexZeroStarted, appendExt);
|
||||
|
||||
public string FormatFileName(byte padDigits, bool layerIndexZeroStarted = true, string appendExt = ".png")
|
||||
=> FormatFileName(string.Empty, padDigits, layerIndexZeroStarted, appendExt);
|
||||
|
||||
public string FormatFileName(byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
|
||||
=> FormatFileName(string.Empty, padDigits, layerIndexStartNumber, appendExt);
|
||||
|
||||
public string FormatFileNameWithLayerDigits(string prepend = "", Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
|
||||
=> FormatFileName(prepend, SlicerFile.LayerDigits, layerIndexStartNumber, appendExt);
|
||||
|
||||
|
||||
public Rectangle GetBoundingRectangle(Mat? mat = null, bool reCalculate = false)
|
||||
{
|
||||
@@ -1314,12 +1455,13 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
|
||||
public Layer Clone()
|
||||
{
|
||||
//var layer = (Layer)MemberwiseClone();
|
||||
//layer.CompressedBytes = _compressedBytes.ToArray();
|
||||
var layer = (Layer)MemberwiseClone();
|
||||
layer._compressedBytes = _compressedBytes?.ToArray();
|
||||
//Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes));
|
||||
//return layer;
|
||||
return new (_index, CompressedBytes?.ToArray()!, SlicerFile)
|
||||
return layer;
|
||||
/*return new (_index, CompressedBytes?.ToArray()!, SlicerFile)
|
||||
{
|
||||
_compressionMethod = _compressionMethod,
|
||||
_positionZ = _positionZ,
|
||||
_lightOffDelay = _lightOffDelay,
|
||||
_waitTimeBeforeCure = _waitTimeBeforeCure,
|
||||
@@ -1337,8 +1479,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
_boundingRectangle = _boundingRectangle,
|
||||
_nonZeroPixelCount = _nonZeroPixelCount,
|
||||
_isModified = _isModified,
|
||||
_materialMilliliters = _materialMilliliters
|
||||
};
|
||||
_materialMilliliters = _materialMilliliters,
|
||||
};*/
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -1362,5 +1504,52 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
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
|
||||
}
|
||||
@@ -553,7 +553,7 @@ public abstract class Operation : BindableBase, IDisposable
|
||||
|
||||
var result = ExecuteInternally(progress);
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,9 +130,8 @@ public sealed class OperationBlur : Operation
|
||||
|
||||
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)
|
||||
{
|
||||
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();
|
||||
SlicerFile.BottomLayerCount = _bottomLayers;
|
||||
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];
|
||||
using var mat = layer.LayerMat;
|
||||
var matRoi = new Mat(mat, boundingRectangle);
|
||||
@@ -1964,7 +1963,6 @@ public sealed class OperationCalibrateExposureFinder : Operation
|
||||
}
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
if (parallelLayers.IsEmpty) return false;
|
||||
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];
|
||||
for (var layerIndex = 1; layerIndex < layers.Count; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
progress++;
|
||||
var layer = layers[layerIndex];
|
||||
if (currentLayer.PositionZ != layer.PositionZ ||
|
||||
@@ -2206,7 +2204,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
|
||||
currentHeight = Layer.RoundHeight(currentHeight);
|
||||
for (decimal layerHeight = _layerHeight; layerHeight <= endLayerHeight; layerHeight += _multipleLayerHeightStep)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
layerHeight = Layer.RoundHeight(layerHeight);
|
||||
|
||||
if (_multipleExposures)
|
||||
|
||||
@@ -418,7 +418,7 @@ public sealed class OperationCalibrateStressTower : Operation
|
||||
|
||||
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};
|
||||
layers[layerIndex].Dispose();
|
||||
|
||||
@@ -729,7 +729,7 @@ public sealed class OperationCalibrateTolerance : Operation
|
||||
|
||||
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};
|
||||
layers[layerIndex].Dispose();
|
||||
|
||||
@@ -205,10 +205,8 @@ public sealed class OperationChangeResolution : Operation
|
||||
|
||||
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;
|
||||
|
||||
if (mat.Size != newSize)
|
||||
@@ -230,8 +228,6 @@ public sealed class OperationChangeResolution : Operation
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
SlicerFile.ResolutionX = NewResolutionX;
|
||||
SlicerFile.ResolutionY = NewResolutionY;
|
||||
|
||||
|
||||
@@ -283,10 +283,8 @@ public class OperationDoubleExposure : Operation
|
||||
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 secondLayer = firstLayer.Clone();
|
||||
var isBottomLayer = firstLayer.IsBottomLayer;
|
||||
|
||||
@@ -669,7 +669,7 @@ public sealed class OperationDynamicLayerHeight : Operation
|
||||
|
||||
while (true) // In a stack
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
progress.ProcessedItems = layerIndex - LayerIndexStart;
|
||||
|
||||
if (currentLayerHeight >= (float)_maximumLayerHeight || layerIndex == LayerIndexEnd)
|
||||
|
||||
@@ -325,7 +325,7 @@ public sealed class OperationDynamicLifts : Operation
|
||||
|
||||
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var layer = SlicerFile[layerIndex];
|
||||
|
||||
// Height
|
||||
|
||||
@@ -191,7 +191,7 @@ public class OperationFadeExposureTime : Operation
|
||||
var exposure = _fromExposureTime;
|
||||
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
exposure += increment;
|
||||
SlicerFile[layerIndex].ExposureTime = (float)exposure;
|
||||
}
|
||||
|
||||
@@ -101,9 +101,8 @@ public class OperationFlip : Operation
|
||||
#region Methods
|
||||
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;
|
||||
Execute(mat);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -135,10 +135,8 @@ public sealed class OperationInfill : Operation
|
||||
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;
|
||||
Execute(mat, layerIndex, mask!);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -253,7 +253,7 @@ public class OperationLayerArithmetic : Operation
|
||||
progress.ItemCount = (uint) Operations.Count;
|
||||
for (int i = 1; i < Operations.Count; i++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
using var image = SlicerFile[Operations[i].LayerIndex].LayerMat;
|
||||
var imageRoi = GetRoiOrDefault(image);
|
||||
|
||||
@@ -289,9 +289,8 @@ public class OperationLayerArithmetic : Operation
|
||||
}
|
||||
|
||||
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();
|
||||
if (Operations.Count == 1 || HaveROIorMask)
|
||||
{
|
||||
|
||||
@@ -224,9 +224,8 @@ public sealed class OperationLayerExportGif : Operation
|
||||
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));
|
||||
var layer = SlicerFile[layerIndex];
|
||||
using var mat = layer.LayerMat;
|
||||
@@ -270,8 +269,8 @@ public sealed class OperationLayerExportGif : Operation
|
||||
progress.ResetNameAndProcessed("Packed layers");
|
||||
foreach (var buffer in layerBuffer)
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) break;
|
||||
using Stream stream = new MemoryStream(buffer);
|
||||
progress.ThrowIfCancellationRequested();
|
||||
using var stream = new MemoryStream(buffer);
|
||||
using var img = Image.FromStream(stream);
|
||||
gif.AddFrame(img, -1, GifQuality.Bit8);
|
||||
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
|
||||
? SlicerFile.GetMergedMatForSequentialPositionedLayers(layer.Index)
|
||||
: 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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
return !progress.Token.IsCancellationRequested;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,10 +180,8 @@ public sealed class OperationLayerExportImage : Operation
|
||||
|
||||
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;
|
||||
var matRoi = mat;
|
||||
if (_cropByRoi && HaveROI)
|
||||
@@ -201,7 +199,7 @@ public sealed class OperationLayerExportImage : Operation
|
||||
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()}");
|
||||
|
||||
if (_imageType != LayerExportImageTypes.SVG)
|
||||
|
||||
@@ -274,7 +274,7 @@ public sealed class OperationLayerExportMesh : Operation
|
||||
var voxelSpan = voxelLayer.GetBytePointer();
|
||||
|
||||
/* 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 */
|
||||
var threadDict = new Dictionary<Voxelizer.FaceOrientation, List<Point>>();
|
||||
@@ -477,10 +477,8 @@ public sealed class OperationLayerExportMesh : Operation
|
||||
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. */
|
||||
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 */
|
||||
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);
|
||||
|
||||
|
||||
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;
|
||||
var matRoi = GetRoiOrDefault(mat);
|
||||
using var skeletonRoi = matRoi.Skeletonize();
|
||||
@@ -104,17 +102,14 @@ public sealed class OperationLayerExportSkeleton : Operation
|
||||
progress++;
|
||||
}
|
||||
});
|
||||
|
||||
if (!progress.Token.IsCancellationRequested)
|
||||
|
||||
if (_cropByRoi && HaveROI)
|
||||
{
|
||||
if (_cropByRoi && HaveROI)
|
||||
{
|
||||
skeletonSumRoi.Save(_filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
skeletonSum.Save(_filePath);
|
||||
}
|
||||
skeletonSumRoi.Save(_filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
skeletonSum.Save(_filePath);
|
||||
}
|
||||
|
||||
return !progress.Token.IsCancellationRequested;
|
||||
|
||||
@@ -255,9 +255,8 @@ public sealed class OperationLayerImport : Operation
|
||||
SL1File format = new();
|
||||
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);
|
||||
if (pair.Key == 0) format.Resolution = mat.Size;
|
||||
format[pair.Key] = new Layer(pair.Key, mat, format);
|
||||
@@ -265,7 +264,6 @@ public sealed class OperationLayerImport : Operation
|
||||
progress.LockAndIncrement();
|
||||
});
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
fileFormats.Add(format);
|
||||
}
|
||||
|
||||
@@ -284,7 +282,7 @@ public sealed class OperationLayerImport : Operation
|
||||
fileFormats.Add(fileFormat);
|
||||
}
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
if (fileFormats.Count == 0) return false;
|
||||
|
||||
@@ -379,9 +377,8 @@ public sealed class OperationLayerImport : Operation
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
switch (_importType)
|
||||
@@ -503,7 +500,6 @@ public sealed class OperationLayerImport : Operation
|
||||
});
|
||||
|
||||
fileFormat.Dispose();
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
if (_importType == ImportTypes.Stack)
|
||||
|
||||
@@ -296,7 +296,7 @@ public sealed class OperationLayerReHeight : Operation
|
||||
uint newLayerIndex = 0;
|
||||
for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
|
||||
{
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
var oldLayer = SlicerFile[layerIndex];
|
||||
for (byte i = 0; i < _selectedItem.Modifier; i++)
|
||||
@@ -318,9 +318,8 @@ public sealed class OperationLayerReHeight : Operation
|
||||
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];
|
||||
using var matSum = oldLayer.LayerMat;
|
||||
Mat? matXorSum = null;
|
||||
@@ -395,8 +394,6 @@ public sealed class OperationLayerReHeight : Operation
|
||||
});
|
||||
}
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
SlicerFile.SuppressRebuildPropertiesWork(() =>
|
||||
{
|
||||
SlicerFile.LayerHeight = (float)_selectedItem!.LayerHeight;
|
||||
|
||||
@@ -203,10 +203,8 @@ public class OperationLightBleedCompensation : Operation
|
||||
{
|
||||
var dimMats = GetDimMats();
|
||||
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];
|
||||
using var mat = layer.LayerMat;
|
||||
using var original = mat.Clone();
|
||||
|
||||
@@ -74,9 +74,8 @@ public class OperationMask : Operation
|
||||
|
||||
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;
|
||||
Execute(mat);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -176,9 +176,8 @@ public sealed class OperationMorph : Operation
|
||||
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);
|
||||
|
||||
using var mat = SlicerFile[layerIndex].LayerMat;
|
||||
|
||||
@@ -264,10 +264,8 @@ public class OperationMove : Operation
|
||||
if (ROI.IsEmpty) ROI = SlicerFile.GetBoundingRectangle(progress);
|
||||
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)
|
||||
{
|
||||
Execute(mat);
|
||||
|
||||
@@ -299,10 +299,8 @@ public class OperationPattern : Operation
|
||||
|
||||
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 layerRoi = new Mat(mat, ROI);
|
||||
using var dstLayer = mat.NewBlank();
|
||||
@@ -321,8 +319,6 @@ public class OperationPattern : Operation
|
||||
|
||||
SlicerFile.BoundingRectangle = Rectangle.Empty;
|
||||
|
||||
progress.Token.ThrowIfCancellationRequested();
|
||||
|
||||
if (Anchor == Enumerations.Anchor.None) return true;
|
||||
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];
|
||||
using (var mat = layer.LayerMat)
|
||||
{
|
||||
|
||||
@@ -650,9 +650,8 @@ public class OperationPixelDimming : Operation
|
||||
CvInvoke.BitwiseNot(patternMask, patternMask);
|
||||
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;
|
||||
Execute(mat, layerIndex, patternMask, alternatePatternMask);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -38,6 +38,7 @@ public sealed class OperationProgress : BindableBase
|
||||
|
||||
public CancellationTokenSource TokenSource { get; private set; } = null!;
|
||||
public CancellationToken Token => TokenSource.Token;
|
||||
public void ThrowIfCancellationRequested() => TokenSource.Token.ThrowIfCancellationRequested();
|
||||
|
||||
private bool _canCancel = true;
|
||||
private string _title = "Operation";
|
||||
|
||||
@@ -184,7 +184,7 @@ public class OperationRaftRelief : Operation
|
||||
progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex);
|
||||
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return false;
|
||||
progress.ThrowIfCancellationRequested();
|
||||
progress++;
|
||||
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
|
||||
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);
|
||||
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 original = mat.Clone();
|
||||
var target = GetRoiOrDefault(mat);
|
||||
|
||||
@@ -170,9 +170,8 @@ public class OperationRedrawModel : Operation
|
||||
|
||||
int startLayerIndex = (int)(SlicerFile.LayerCount - otherFile.LayerCount);
|
||||
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;
|
||||
using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat;
|
||||
using var original = fullMat.Clone();
|
||||
|
||||
@@ -247,9 +247,8 @@ public class OperationRepairLayers : Operation
|
||||
if (!issuesGroup.Any()) break; // Nothing to process
|
||||
|
||||
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 image = layer.LayerMat;
|
||||
var bytes = image.GetDataByteSpan();
|
||||
@@ -300,7 +299,7 @@ public class OperationRepairLayers : Operation
|
||||
|
||||
progress.Reset("Attempt to attach islands below", (uint) islandsToProcess!.Count);
|
||||
var sync = new object();
|
||||
Parallel.ForEach(issuesGroup, CoreSettings.ParallelOptions, group =>
|
||||
Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group =>
|
||||
{
|
||||
using var mat = SlicerFile[group.Key].LayerMat;
|
||||
var matSpan = mat.GetDataByteSpan();
|
||||
@@ -390,9 +389,8 @@ public class OperationRepairLayers : Operation
|
||||
progress.Reset(ProgressAction, LayerRangeCount);
|
||||
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];
|
||||
Mat? image = null;
|
||||
|
||||
|
||||
@@ -157,9 +157,8 @@ public class OperationResize : Operation
|
||||
decimal xSteps = Math.Abs(100 - _x) / (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 newY = _y;
|
||||
if (IsFade)
|
||||
|
||||
@@ -95,9 +95,8 @@ public class OperationRotate : Operation
|
||||
|
||||
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;
|
||||
Execute(mat);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class OperationScripting : Operation
|
||||
|
||||
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 Title => "Scripting";
|
||||
|
||||
@@ -67,6 +67,13 @@ public sealed class OperationScripting : Operation
|
||||
return scriptValidation.ReturnValue;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var result = $"[{Path.GetFileName(_filePath)}]" + LayerRangeString;
|
||||
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enums
|
||||
@@ -75,6 +82,7 @@ public sealed class OperationScripting : Operation
|
||||
|
||||
#region Properties
|
||||
|
||||
[XmlIgnore]
|
||||
public ScriptGlobals? ScriptGlobals { get; private set; }
|
||||
|
||||
public string? FilePath
|
||||
@@ -104,10 +112,8 @@ public sealed class OperationScripting : Operation
|
||||
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;
|
||||
|
||||
[XmlIgnore]
|
||||
public bool HaveFile => !string.IsNullOrWhiteSpace(_filePath);
|
||||
|
||||
/*public override string ToString()
|
||||
@@ -131,7 +137,22 @@ public sealed class OperationScripting : Operation
|
||||
#endregion
|
||||
|
||||
#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
|
||||
|
||||
#region Methods
|
||||
|
||||
@@ -87,9 +87,8 @@ public sealed class OperationSolidify : Operation
|
||||
|
||||
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;
|
||||
Execute(mat);
|
||||
SlicerFile[layerIndex].LayerMat = mat;
|
||||
|
||||
@@ -82,9 +82,8 @@ public class OperationThreshold : Operation
|
||||
|
||||
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)
|
||||
{
|
||||
Execute(mat);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.1.0</Version>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
@@ -62,6 +62,7 @@
|
||||
<PackageReference Include="AnimatedGif" Version="1.0.5" />
|
||||
<PackageReference Include="BinarySerializer" Version="8.6.2.2" />
|
||||
<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="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" Platform="x64" />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
<!-- Major Upgrade Rule to disallow downgrades -->
|
||||
<!-- AllowSameVersionUpgrades="yes" -->
|
||||
<MajorUpgrade
|
||||
AllowDowngrades="no"
|
||||
AllowSameVersionUpgrades="yes"
|
||||
IgnoreRemoveFailure="no"
|
||||
DowngradeErrorMessage="A newer version of [ProductName] is already installed."
|
||||
Schedule="afterInstallInitialize" />
|
||||
|
||||
@@ -335,9 +335,6 @@
|
||||
<Component Id="owc79156F385239CEA4DEA3C87C1DA3E1D8" Guid="68380c80-6708-5eb6-415d-10e278417679" Win64="yes">
|
||||
<File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" />
|
||||
</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">
|
||||
<File Id="owf7BB28EFC52A49429849339DF748B25E7" Source="$(var.SourceDir)\runtime_package.dat" KeyPath="yes" />
|
||||
</Component>
|
||||
@@ -1449,6 +1446,21 @@
|
||||
<Component Id="owc9C1F0C0351694913958CEBFB4D988C2D" Guid="9C1F0C03-5169-4913-958C-EBFB4D988C2D">
|
||||
<File Id="owf9C1F0C0351694913958CEBFB4D988C2D" Source="$(var.SourceDir)\System.Net.Quic.dll" KeyPath="yes" />
|
||||
</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 Id="ProgramMenuFolder">
|
||||
<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
|
||||
{
|
||||
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.MaskPoints = Operation.MaskPoints; // Copy user selected Masks to my 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++)
|
||||
{
|
||||
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
|
||||
|
||||
layer.LiftHeight = random.Next(3, 10); // Random value from 3 to 10
|
||||
|
||||
@@ -120,7 +120,7 @@ public class ScriptCloneSettings : ScriptGlobals
|
||||
var results = new List<Tuple<ResultStatus, string, List<string>?>>();
|
||||
foreach (var filePath in filePaths)
|
||||
{
|
||||
if (Progress.Token.IsCancellationRequested) return false;
|
||||
Progress.ThrowIfCancellationRequested();
|
||||
|
||||
Tuple<ResultStatus, string, List<string>?> result;
|
||||
try
|
||||
|
||||
@@ -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
|
||||
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
|
||||
using var mat = layer.LayerMat; // Gets this layer mat/image
|
||||
var original = mat.Clone(); // Keep a original mat copy
|
||||
|
||||
@@ -87,10 +87,8 @@ public class ScriptLightBleedCompensationSample : ScriptGlobals
|
||||
var brightnesses = Levels;
|
||||
|
||||
// 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
|
||||
using var mat = layer.LayerMat; // Gets this layer mat/image
|
||||
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[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.BottomExposureTime = 5; // Set exposure to be fixed at 5s
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ScriptChangeLayesrPropertiesSample : ScriptGlobals
|
||||
public bool ScriptExecute()
|
||||
{
|
||||
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 contours = mat.FindContours(out var hierarchy, RetrType.Tree);
|
||||
|
||||
@@ -13,12 +13,12 @@ public static class AppSettings
|
||||
// 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.
|
||||
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
|
||||
// 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.
|
||||
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>
|
||||
/// 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"
|
||||
Orientation="Horizontal" Spacing="1">
|
||||
<Button
|
||||
ToolTip.Tip="Loads an script file"
|
||||
ToolTip.Tip="Load script file"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding LoadScript}"
|
||||
i:Attached.Icon="fas fa-file-import"/>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Operations;
|
||||
using UVtools.Core.Scripting;
|
||||
@@ -43,7 +45,10 @@ public class ToolScriptingControl : ToolControl
|
||||
case ToolWindow.Callbacks.Loaded:
|
||||
if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.CanExecute;
|
||||
ReloadGUI();
|
||||
ReloadScript();
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
ReloadScript();
|
||||
}, DispatcherPriority.Loaded);
|
||||
Operation.PropertyChanged += (sender, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Operation.CanExecute))
|
||||
@@ -93,13 +98,13 @@ public class ToolScriptingControl : ToolControl
|
||||
public void OpenScriptFolder()
|
||||
{
|
||||
if (!Operation.HaveFile) return;
|
||||
SystemAware.StartProcess(Path.GetDirectoryName(Operation.FilePath));
|
||||
SystemAware.SelectFileOnExplorer(Operation.FilePath!);
|
||||
}
|
||||
|
||||
public void OpenScriptFile()
|
||||
{
|
||||
if (!Operation.HaveFile) return;
|
||||
SystemAware.StartProcess(Operation.FilePath);
|
||||
SystemAware.StartProcess(Operation.FilePath!);
|
||||
}
|
||||
|
||||
public void ReloadGUI()
|
||||
|
||||
@@ -18,15 +18,17 @@ namespace UVtools.WPF.Extensions;
|
||||
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static async Task<ButtonResult> MessageBoxGeneric(this Window window, string message, string title = null,
|
||||
ButtonEnum buttons = ButtonEnum.Ok, Icon icon = Icon.None, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner)
|
||||
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 markdown = false, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner)
|
||||
{
|
||||
var messageBoxStandardWindow = MessageBox.Avalonia.MessageBoxManager.GetMessageBoxStandardWindow(
|
||||
new MessageBoxStandardParams
|
||||
{
|
||||
ButtonDefinitions = buttons,
|
||||
ContentTitle = title ?? window.Title,
|
||||
ContentHeader = header,
|
||||
ContentMessage = message,
|
||||
Markdown = markdown,
|
||||
Icon = icon,
|
||||
WindowIcon = new WindowIcon(App.GetAsset("/Assets/Icons/UVtools.ico")),
|
||||
WindowStartupLocation = location,
|
||||
@@ -40,17 +42,29 @@ public static class WindowExtensions
|
||||
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)
|
||||
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", buttons, Icon.Info, topMost, WindowStartupLocation.CenterOwner);
|
||||
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", 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)
|
||||
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", buttons, Icon.Error, topMost, WindowStartupLocation.CenterOwner);
|
||||
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", 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)
|
||||
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Setting, topMost, WindowStartupLocation.CenterOwner);
|
||||
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", 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)
|
||||
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Warning, topMost, WindowStartupLocation.CenterOwner);
|
||||
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", 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)
|
||||
|
||||
@@ -174,9 +174,8 @@ public partial class MainWindow
|
||||
Progress.Reset("Removing selected issues", (uint)processParallelIssues.Count);
|
||||
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)
|
||||
{
|
||||
var bytes = image.GetDataByteSpan();
|
||||
|
||||
@@ -844,6 +844,50 @@ public partial class MainWindow
|
||||
//var imageSpan = LayerCache.Image.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 imageBgrSpan = LayerCache.ImageBgrSpan;
|
||||
|
||||
|
||||
@@ -569,6 +569,7 @@
|
||||
IsReadOnly="{Binding !SlicerFile.SuppressRebuildGCode}"
|
||||
AcceptsReturn="True"
|
||||
Text="{Binding SlicerFile.GCodeStr}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -38,7 +38,6 @@ using UVtools.WPF.Controls.Tools;
|
||||
using UVtools.WPF.Extensions;
|
||||
using UVtools.WPF.Structures;
|
||||
using UVtools.WPF.Windows;
|
||||
using Bitmap = Avalonia.Media.Imaging.Bitmap;
|
||||
using Helpers = UVtools.WPF.Controls.Helpers;
|
||||
using Path = System.IO.Path;
|
||||
using Point = Avalonia.Point;
|
||||
@@ -1164,6 +1163,7 @@ public partial class MainWindow : WindowEx
|
||||
public async void MenuFileSettingsClicked()
|
||||
{
|
||||
var oldTheme = Settings.General.Theme;
|
||||
var oldLayerCompressionMethod = Settings.General.LayerCompressionMethod;
|
||||
var settingsWindow = new SettingsWindow();
|
||||
await settingsWindow.ShowDialog(this);
|
||||
if (settingsWindow.DialogResult == DialogResults.OK)
|
||||
@@ -1173,6 +1173,33 @@ public partial class MainWindow : WindowEx
|
||||
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;
|
||||
RaisePropertyChanged(nameof(IssuesGridItems));
|
||||
}
|
||||
@@ -1232,13 +1259,16 @@ public partial class MainWindow : WindowEx
|
||||
public async void MenuNewVersionClicked()
|
||||
{
|
||||
var result =
|
||||
await this.MessageBoxQuestion(
|
||||
$"Do you like to auto-update {About.Software} v{App.VersionStr} to v{VersionChecker.Version}?\n" +
|
||||
"Yes: Auto update\n" +
|
||||
"No: Manual update\n" +
|
||||
"Cancel: No action\n\n" +
|
||||
"Changelog:\n" +
|
||||
$"{VersionChecker.Changelog}", $"Update UVtools to v{VersionChecker.Version}?", ButtonEnum.YesNoCancel);
|
||||
await this.MessageBoxWithHeaderQuestion(
|
||||
$"Do you like to auto-update {About.Software} v{App.VersionStr} to v{VersionChecker.Version}?",
|
||||
"Yes: Auto update \n" +
|
||||
"No: Manual update \n" +
|
||||
"Cancel: No action \n\n" +
|
||||
"Changelog: \n\n" +
|
||||
$"{VersionChecker.Changelog}",
|
||||
$"Update UVtools to v{VersionChecker.Version}?",
|
||||
|
||||
ButtonEnum.YesNoCancel, true);
|
||||
|
||||
|
||||
if (result == ButtonResult.No)
|
||||
|
||||
@@ -12,10 +12,9 @@ using System.IO.Compression;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Objects;
|
||||
@@ -36,33 +35,35 @@ public class AppVersionChecker : BindableBase
|
||||
{
|
||||
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))
|
||||
{
|
||||
return $"{About.Software}_win-x64_v{_version}.msi";
|
||||
}
|
||||
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";
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -131,7 +132,8 @@ public class AppVersionChecker : BindableBase
|
||||
|
||||
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();
|
||||
if (string.IsNullOrEmpty(tag_name)) return false;
|
||||
tag_name = tag_name.Trim(' ', 'v', 'V');
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using UVtools.WPF.Windows;
|
||||
|
||||
namespace UVtools.WPF.Structures;
|
||||
|
||||
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 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;
|
||||
FunctionName = functionName;
|
||||
Resolution = resolution;
|
||||
DevSingleThreadResult = devSingleThreadResult;
|
||||
DevMultiThreadResult = devMultiThreadResult;
|
||||
}
|
||||
@@ -23,6 +27,8 @@ public sealed class BenchmarkTest
|
||||
public string Name { get; }
|
||||
public string FunctionName { get; }
|
||||
|
||||
public BenchmarkWindow.BenchmarkResolution Resolution { get; }
|
||||
|
||||
public float DevSingleThreadResult { get; }
|
||||
public float DevMultiThreadResult { get; }
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public class OperationProfiles //: IList<Operation>
|
||||
[XmlElement(typeof(OperationRaiseOnPrintFinish))]
|
||||
[XmlElement(typeof(OperationChangeResolution))]
|
||||
[XmlElement(typeof(OperationTimelapse))]
|
||||
[XmlElement(typeof(OperationScripting))]
|
||||
|
||||
[XmlElement(typeof(OperationLayerExportGif))]
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<Version>3.0.0</Version>
|
||||
<Version>3.1.0</Version>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
@@ -40,14 +40,14 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<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.Desktop" 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="MessageBox.Avalonia" Version="1.8.1-night" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="4.1.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="4.1.0" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="2.0.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia" Version="4.2.1" />
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -95,6 +95,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
</AvaloniaResource>
|
||||
<AvaloniaResource Include="Assets\Icons\*" />
|
||||
<AvaloniaResource Include="Assets\benchmark.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Windows\SuggestionSettingsWindow.axaml.cs">
|
||||
|
||||
@@ -17,6 +17,7 @@ using JetBrains.Annotations;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.FileFormats;
|
||||
using UVtools.Core.Layers;
|
||||
using UVtools.Core.Network;
|
||||
using UVtools.Core.Objects;
|
||||
using Color=UVtools.WPF.Structures.Color;
|
||||
@@ -42,6 +43,7 @@ public sealed class UserSettings : BindableBase
|
||||
private bool _loadDemoFileOnStartup = true;
|
||||
private bool _loadLastRecentFileOnStartup;
|
||||
private int _maxDegreeOfParallelism = -1;
|
||||
private Layer.LayerCompressionMethod _layerCompressionMethod = CoreSettings.DefaultLayerCompressionMethod;
|
||||
|
||||
private bool _windowsCanResize;
|
||||
private bool _windowsTakeIntoAccountScreenScaling = true;
|
||||
@@ -100,6 +102,12 @@ public sealed class UserSettings : BindableBase
|
||||
set => RaiseAndSetIfChanged(ref _maxDegreeOfParallelism, Math.Min(value, Environment.ProcessorCount));
|
||||
}
|
||||
|
||||
public Layer.LayerCompressionMethod LayerCompressionMethod
|
||||
{
|
||||
get => _layerCompressionMethod;
|
||||
set => RaiseAndSetIfChanged(ref _layerCompressionMethod, value);
|
||||
}
|
||||
|
||||
public bool WindowsCanResize
|
||||
{
|
||||
get => _windowsCanResize;
|
||||
@@ -1633,6 +1641,7 @@ public sealed class UserSettings : BindableBase
|
||||
}
|
||||
|
||||
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
|
||||
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
|
||||
|
||||
if (_instance.Network.RemotePrinters.Count == 0)
|
||||
{
|
||||
@@ -1855,6 +1864,7 @@ public sealed class UserSettings : BindableBase
|
||||
Instance.SavesCount++;
|
||||
_instance.ModifiedDateTime = DateTime.Now;
|
||||
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
|
||||
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
|
||||
try
|
||||
{
|
||||
XmlExtensions.SerializeToFile(_instance, FilePath, XmlExtensions.SettingsIndent);
|
||||
|
||||
@@ -9,33 +9,28 @@
|
||||
Icon="/Assets/Icons/UVtools.ico"
|
||||
SizeToContent="WidthAndHeight"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
>
|
||||
CanResize="False">
|
||||
|
||||
<Grid
|
||||
RowDefinitions="Auto,10,
|
||||
<Grid RowDefinitions="Auto,10,
|
||||
Auto,10,
|
||||
Auto,10,
|
||||
Auto,20,
|
||||
Auto,10,
|
||||
Auto,20,
|
||||
Auto"
|
||||
>
|
||||
Auto">
|
||||
<Border
|
||||
Background="{DynamicResource LightBackground}"
|
||||
Padding="10"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1"
|
||||
>
|
||||
<TextBlock Text="{Binding Description}"/>
|
||||
BorderThickness="1">
|
||||
<TextBox Classes="TransparentReadOnly" Text="{Binding Description}"/>
|
||||
|
||||
</Border>
|
||||
|
||||
<Grid
|
||||
ColumnDefinitions="Auto,10,*"
|
||||
Grid.Row="2"
|
||||
Margin="10"
|
||||
>
|
||||
Margin="10">
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
@@ -45,27 +40,25 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectedIndex="{Binding TestSelectedIndex}"
|
||||
Items="{Binding Tests}"
|
||||
IsEnabled="{Binding !IsRunning}"
|
||||
/>
|
||||
IsEnabled="{Binding !IsRunning}"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
Grid.Row="4"
|
||||
FontWeight="Bold" Text="Your results:" />
|
||||
FontWeight="Bold" Text="Your results:"/>
|
||||
|
||||
<Grid
|
||||
Grid.Row="6"
|
||||
ColumnDefinitions="Auto,5,Auto"
|
||||
RowDefinitions="Auto,5,Auto"
|
||||
Margin="10,0"
|
||||
>
|
||||
Margin="10,0">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
Text="Single Thread:" />
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Text="{Binding SingleThreadTDPS}" />
|
||||
Text="{Binding SingleThreadTDPS}"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -74,13 +67,13 @@
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Text="{Binding MultiThreadTDPS}" />
|
||||
Text="{Binding MultiThreadTDPS}"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0"
|
||||
Grid.Row="8"
|
||||
FontWeight="Bold" Text="Developer results:" />
|
||||
FontWeight="Bold" Text="Developer results:"/>
|
||||
|
||||
<Grid
|
||||
Grid.Row="10"
|
||||
@@ -93,7 +86,7 @@
|
||||
Text="Single Thread:" />
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Text="{Binding DevSingleThreadTDPS}" />
|
||||
Text="{Binding DevSingleThreadTDPS}"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -102,7 +95,7 @@
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Text="{Binding DevMultiThreadTDPS}" />
|
||||
Text="{Binding DevMultiThreadTDPS}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
@@ -112,8 +105,7 @@
|
||||
<ProgressBar
|
||||
IsIndeterminate="{Binding IsRunning}"
|
||||
IsEnabled="{Binding IsRunning}"
|
||||
VerticalAlignment="Stretch"
|
||||
/>
|
||||
VerticalAlignment="Stretch"/>
|
||||
|
||||
<Button
|
||||
Name="StartStopButton"
|
||||
@@ -121,8 +113,7 @@
|
||||
Padding="40,10"
|
||||
IsDefault="True"
|
||||
Content="{Binding StartStopButtonText}"
|
||||
Command="{Binding StartStop}"
|
||||
/>
|
||||
Command="{Binding StartStop}"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Avalonia.Threading;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Layers;
|
||||
using UVtools.WPF.Controls;
|
||||
using UVtools.WPF.Extensions;
|
||||
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 bool _isRunning;
|
||||
private string _startStopButtonText = "Start";
|
||||
private const ushort SingleThreadTests = 100;
|
||||
private const ushort MultiThreadTests = 1000;
|
||||
private const ushort SingleThreadTests = 200;
|
||||
private const ushort MultiThreadTests = 5000;
|
||||
|
||||
public const string RunsAbbreviation = "TDPS";
|
||||
public const string StressCPUTestName = "Stress CPU (Run until stop)";
|
||||
|
||||
private readonly Dictionary<BenchmarkResolution, Mat> Mats = new();
|
||||
|
||||
//private readonly RNGCryptoServiceProvider _randomProvider = new();
|
||||
|
||||
private CancellationTokenSource _tokenSource;
|
||||
private CancellationToken _token => _tokenSource.Token;
|
||||
|
||||
public enum BenchmarkResolution
|
||||
{
|
||||
Resolution4K,
|
||||
Resolution8K
|
||||
}
|
||||
|
||||
public static BenchmarkTest[] Tests =>
|
||||
new[]
|
||||
{
|
||||
new BenchmarkTest("4K Random CBBDLP Enconde", "Test4KRandomCBBDLPEncode", 57.14f, 401.61f),
|
||||
new BenchmarkTest("8K Random CBBDLP Enconde", "Test8KRandomCBBDLPEncode", 12.03f, 99.80f),
|
||||
new BenchmarkTest("4K Random CBT Enconde", "Test4KRandomCBTEncode", 19.05f, 124.38f),
|
||||
new BenchmarkTest("8K Random CBT Enconde", "Test8KRandomCBTEncode", 4.03f, 35.64f),
|
||||
new BenchmarkTest("4K Random PW0 Enconde", "Test4KRandomPW0Encode", 18.85f, 103.00f),
|
||||
new BenchmarkTest("8K Random PW0 Enconde", "Test8KRandomPW0Encode", 4.07f, 26.65f),
|
||||
new BenchmarkTest(StressCPUTestName, "Test4KRandomCBTEncode", 0, 0),
|
||||
new BenchmarkTest("CBBDLP 4K Encode", "TestCBBDLPEncode", BenchmarkResolution.Resolution4K, 108.70f, 912.41f),
|
||||
new BenchmarkTest("CBBDLP 8K Encode", "TestCBBDLPEncode", BenchmarkResolution.Resolution8K, 27.47f, 226.76f),
|
||||
new BenchmarkTest("CBT 4K Encode", "TestCBTEncode", BenchmarkResolution.Resolution4K, 86.96f, 782.47f),
|
||||
new BenchmarkTest("CBT 8K Encode", "TestCBTEncode", BenchmarkResolution.Resolution8K, 21.86f, 196.15f),
|
||||
new BenchmarkTest("PW0 4K Encode", "TestPW0Encode",BenchmarkResolution.Resolution4K, 84.03f, 886.53f),
|
||||
new BenchmarkTest("PW0 8K Encode", "TestPW0Encode", BenchmarkResolution.Resolution8K, 21.05f, 221.63f),
|
||||
|
||||
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" +
|
||||
@@ -112,6 +142,12 @@ public class BenchmarkWindow : WindowEx
|
||||
InitializeComponent();
|
||||
|
||||
DataContext = this;
|
||||
|
||||
|
||||
foreach (var resolution in Enum.GetValues<BenchmarkResolution>())
|
||||
{
|
||||
Mats.Add(resolution, GetBenchmarkMat(resolution));
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
@@ -146,22 +182,18 @@ public class BenchmarkWindow : WindowEx
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_token.IsCancellationRequested) break;
|
||||
Parallel.For(0, MultiThreadTests, i =>
|
||||
Parallel.For(0, MultiThreadTests, new ParallelOptions{CancellationToken = _tokenSource.Token }, i =>
|
||||
{
|
||||
if (_token.IsCancellationRequested) return;
|
||||
theMethod.Invoke(this, null);
|
||||
theMethod.Invoke(this, new object[]{benchmark.Resolution});
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < SingleThreadTests; i++)
|
||||
{
|
||||
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
|
||||
theMethod.Invoke(this, null);
|
||||
theMethod.Invoke(this, new object[] { benchmark.Resolution });
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
@@ -171,15 +203,13 @@ public class BenchmarkWindow : WindowEx
|
||||
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
|
||||
|
||||
sw.Restart();
|
||||
Parallel.For(0, MultiThreadTests, i =>
|
||||
Parallel.For(0, MultiThreadTests, new ParallelOptions { CancellationToken = _tokenSource.Token }, i =>
|
||||
{
|
||||
if (_token.IsCancellationRequested) return;
|
||||
theMethod.Invoke(this, null);
|
||||
theMethod.Invoke(this, new object[] { benchmark.Resolution });
|
||||
});
|
||||
|
||||
sw.Stop();
|
||||
|
||||
if (_token.IsCancellationRequested) _token.ThrowIfCancellationRequested();
|
||||
var multiMiliseconds = sw.ElapsedMilliseconds;
|
||||
Dispatcher.UIThread.InvokeAsync(() => UpdateResults(false, multiMiliseconds));
|
||||
}
|
||||
@@ -417,13 +447,32 @@ public class BenchmarkWindow : WindowEx
|
||||
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);
|
||||
CvInvoke.Randu(mat, EmguExtensions.BlackColor, EmguExtensions.WhiteColor);
|
||||
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()
|
||||
{
|
||||
using var mat = RandomMat(3840, 2160);
|
||||
@@ -436,6 +485,11 @@ public class BenchmarkWindow : WindowEx
|
||||
EncodeCbddlpImage(mat);
|
||||
}
|
||||
|
||||
public void TestCBBDLPEncode(BenchmarkResolution resolution)
|
||||
{
|
||||
EncodeCbddlpImage(Mats[resolution]);
|
||||
}
|
||||
|
||||
public void Test4KRandomCBTEncode()
|
||||
{
|
||||
using var mat = RandomMat(3840, 2160);
|
||||
@@ -448,6 +502,11 @@ public class BenchmarkWindow : WindowEx
|
||||
EncodeCbtImage(mat);
|
||||
}
|
||||
|
||||
public void TestCBTEncode(BenchmarkResolution resolution)
|
||||
{
|
||||
EncodeCbtImage(Mats[resolution]);
|
||||
}
|
||||
|
||||
public void Test4KRandomPW0Encode()
|
||||
{
|
||||
using var mat = RandomMat(3840, 2160);
|
||||
@@ -460,5 +519,42 @@ public class BenchmarkWindow : WindowEx
|
||||
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
|
||||
}
|
||||
@@ -50,7 +50,7 @@
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Classes="GroupBoxHeader" Text="Tasks"/>
|
||||
<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">
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
@@ -123,7 +123,18 @@
|
||||
ToolTip.Tip="{Binding MaxProcessorCount, StringFormat=All of the available threads [{0}] (Full performance)}"
|
||||
Command="{Binding SetMaxDegreeOfParallelism}"
|
||||
CommandParameter="{Binding MaxProcessorCount}"/>
|
||||
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip.Tip="Sets the compression method used to store layer image cache.
|
||||

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>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -603,6 +603,8 @@ public class ToolWindow : WindowEx
|
||||
ToolControl = toolControl;
|
||||
toolControl.ParentWindow = this;
|
||||
toolControl.Margin = new Thickness(15);
|
||||
ToolControl.BaseOperation.ROI = ROI;
|
||||
ToolControl.BaseOperation.MaskPoints = Masks;
|
||||
|
||||
Title = toolControl.BaseOperation.Title;
|
||||
//LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")"
|
||||
cd ..
|
||||
dotnet build
|
||||
@@ -183,7 +183,7 @@ $enableMSI = $true
|
||||
#$buildOnly = 'osx-x64'
|
||||
#$buildOnly = 'osx-arm64'
|
||||
$zipPackages = $true
|
||||
#$enableNugetPublish = $true
|
||||
$enableNugetPublish = $true
|
||||
|
||||
# Profilling
|
||||
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
|
||||
@@ -357,17 +357,19 @@ Building: $runtime"
|
||||
$macAppFolder = "${software}.app"
|
||||
$macPublishFolder = "$publishFolder/${macAppFolder}"
|
||||
$macInfoplist = "$platformsFolder/$runtime/Info.plist"
|
||||
$macOutputInfoplist = "$macPublishFolder/Contents"
|
||||
$macEntitlements = "$platformsFolder/$runtime/UVtools.entitlements"
|
||||
$macContents = "$macPublishFolder/Contents"
|
||||
$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/MacOS"
|
||||
New-Item -ItemType directory -Path "$macPublishFolder/Contents/Resources"
|
||||
|
||||
|
||||
Copy-Item "$macIcns" -Destination "$macPublishFolder/Contents/Resources"
|
||||
((Get-Content -Path "$macInfoplist") -replace '#VERSION',"$version") | Set-Content -Path "$macOutputInfoplist/Info.plist"
|
||||
Copy-Item $macIcns -Destination "$macPublishFolder/Contents/Resources"
|
||||
((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 chmod +x "$macPublishFolder/Contents/MacOS/UVtools"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user