- **Benchmark:**
   - (Add) PNG, GZip, Deflate and LZ4 compress tests
   - (Change) Test against a known image instead of random noise
   - (Change) Single-thread tests from 100 to 200 and multi-thread tests from 1000 to 5000
   - (Improvement) Same image instance is shared between tests instead of create new per test
   - (Fix) Encode typo
- **Core:**
   - (Add) Layer compression method: Allow to choose the compression method for layer image
      - **PNG:** Compression=High Speed=Slow (Use with low RAM)
      - **GZip:** Compression=Medium Speed=Medium (Optimal)
      - **Deflate:** Compression=Medium Speed=Medium (Optimal)
      - **LZ4:** Compression=Low Speed=Fast (Use with high RAM)
   - (Improvement) Better handling on cancel operations and more immediate response
   - (Fix) Extract: Zip Slip Vulnerability (CWE-22)
- **File formats:**
   - (Improvement) Better handling of encode/decoding layers from zip files
   - (Fix) ZCode: Canceling the file load can trigger an error
   - (Fix) VDA: Unable to open vda zip files
- **Tools:**
   - (Improvement) Allow operations to be aware of ROI and Masks before execution (#436)
   - (Improvement) Scripting: Allow save and load profiles (#436)
   - (Fix) Adjust layer height: When using the Offset type the last layer in the range was not taken in account (#435)
- **UI:**
   - (Improvement) Allow layer zoom levels of 0.1x and 64x but constrain minimum zoom to the level of image fit
   - (Improvement) Update change log now shows with markdown style and more readable
   - (Fix) Windows MSI upgrade to this version (#432)
   - (Fix) Auto-updater for Mac ARM, was downloading x64 instead
This commit is contained in:
Tiago Conceição
2022-03-17 23:50:47 +00:00
parent 4a0c4adfc3
commit 22897ea389
101 changed files with 1455 additions and 1069 deletions
+30
View File
@@ -1,5 +1,35 @@
# Changelog
## 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
View File
@@ -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>
+23
View File
@@ -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>
+9
View File
@@ -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);
}
}
+12 -14
View File
@@ -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:
+5 -7
View File
@@ -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);
+69 -69
View File
@@ -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()
+6 -19
View File
@@ -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();
}
+6 -16
View File
@@ -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();
}
+5 -7
View File
@@ -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);
+64 -93
View File
@@ -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()
+4 -6
View File
@@ -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);
+149 -19
View File
@@ -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();
});
+5 -15
View File
@@ -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++)
+45 -76
View File
@@ -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)
+5 -7
View File
@@ -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);
+6 -15
View File
@@ -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))
{
+8 -10
View File
@@ -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
+4 -7
View File
@@ -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();
+4 -6
View File
@@ -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)
{
+96 -121
View File
@@ -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);
+39 -62
View File
@@ -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)
+22 -54
View File
@@ -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
+32 -51
View File
@@ -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)
+4 -31
View File
@@ -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)
+7 -18
View File
@@ -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
View File
@@ -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
}
+1 -1
View File
@@ -553,7 +553,7 @@ public abstract class Operation : BindableBase, IDisposable
var result = ExecuteInternally(progress);
progress.Token.ThrowIfCancellationRequested();
progress.ThrowIfCancellationRequested();
return result;
}
+1 -2
View File
@@ -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;
}
+1 -2
View File
@@ -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;
+1 -3
View File
@@ -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();
+1 -2
View File
@@ -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;
+1 -2
View File
@@ -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;
+1 -3
View File
@@ -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);
+1 -5
View File
@@ -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;
+1 -2
View File
@@ -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)
+1 -2
View File
@@ -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;
+25 -4
View File
@@ -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
+1 -2
View File
@@ -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);
+2 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>3.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" />
+1 -1
View File
@@ -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" />
+15 -3
View File
@@ -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
+1 -1
View File
@@ -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
+1 -3
View File
@@ -93,10 +93,8 @@ public class ScriptInsetSample : ScriptGlobals
// Loop user selected layers in parallel, this will put each core of CPU working here on parallel
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
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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()
+24 -10
View File
@@ -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)
+1 -2
View File
@@ -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();
+44
View File
@@ -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;
+1
View File
@@ -569,6 +569,7 @@
IsReadOnly="{Binding !SlicerFile.SuppressRebuildGCode}"
AcceptsReturn="True"
Text="{Binding SlicerFile.GCodeStr}" />
</Grid>
</TabItem>
+38 -8
View File
@@ -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)
+22 -20
View File
@@ -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');
+7 -1
View File
@@ -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))]
+6 -5
View File
@@ -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">
+10
View File
@@ -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);
+16 -25
View File
@@ -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>
+117 -21
View File
@@ -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
}
+13 -2
View File
@@ -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.
&#x0a;The selected method will impact RAM usage and operations speed."
Text="Layer compression:"/>
<ComboBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="17"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Items="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
</Grid>
</StackPanel>
+2
View File
@@ -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
View File
@@ -1,3 +1,4 @@
#!/bin/bash
cd "$(dirname "$0")"
cd ..
dotnet build
+7 -5
View File
@@ -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