diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d68c05..f1dc8d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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:**
diff --git a/CREDITS.md b/CREDITS.md
index 7f9976e..3f78f2d 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -70,4 +70,6 @@
- Tim Anderson
- Sakari Toivonen
- Ed Wagaman
-- Marcin Chomiczuk
\ No newline at end of file
+- Marcin Chomiczuk
+- Patrick Hofmann
+- Ajilus
\ No newline at end of file
diff --git a/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs b/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs
index f8c88c2..71d8ed8 100644
--- a/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs
+++ b/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs
@@ -113,7 +113,7 @@ public class AdvancedImageBox : UserControl
///
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.
///
/// The current zoom level.
+ /// When positive, constrain maximum zoom to this value
/// The next matching increased zoom level for the given current zoom if applicable, otherwise the nearest zoom.
- 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];
}
///
/// Returns the next decreased zoom level for the given current zoom.
///
/// The current zoom level.
+ /// When positive, constrain minimum zoom to this value
/// The next matching decreased zoom level for the given current zoom if applicable, otherwise the nearest zoom.
- 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];
}
///
@@ -842,7 +838,7 @@ public class AdvancedImageBox : UserControl
}
public static readonly StyledProperty MaxZoomProperty =
- AvaloniaProperty.Register(nameof(MaxZoom), 3500);
+ AvaloniaProperty.Register(nameof(MaxZoom), 6400);
///
/// Gets or sets the maximum possible zoom.
@@ -854,6 +850,18 @@ public class AdvancedImageBox : UserControl
set => SetValue(MaxZoomProperty, value);
}
+ public static readonly StyledProperty ConstrainZoomOutToFitLevelProperty =
+ AvaloniaProperty.Register(nameof(ConstrainZoomOutToFitLevel), true);
+
+ ///
+ /// Gets or sets if the zoom out should constrain to fit image as the lowest zoom level.
+ ///
+ public bool ConstrainZoomOutToFitLevel
+ {
+ get => GetValue(ConstrainZoomOutToFitLevelProperty);
+ set => SetValue(ConstrainZoomOutToFitLevelProperty, value);
+ }
+
public static readonly DirectProperty OldZoomProperty =
AvaloniaProperty.RegisterDirect(
@@ -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
}
}
+ ///
+ /// Gets if the image have zoom.
+ /// True if zoomed in or out
+ /// False if no zoom applied
+ ///
public bool IsActualSize => Zoom == 100;
///
- /// Gets the zoom factor, the zoom / 100
+ /// Gets the zoom factor, the zoom / 100.0
///
public double ZoomFactor => Zoom / 100.0;
+ ///
+ /// Gets the zoom to fit level which shows all the image
+ ///
+ 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;
+ }
+ }
+
///
/// Gets the width of the scaled image.
///
@@ -1442,36 +1497,8 @@ public class AdvancedImageBox : UserControl
///
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;
}
///
diff --git a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
index 5974565..5a23b57 100644
--- a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
+++ b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
@@ -10,11 +10,14 @@
https://github.com/sn4k3/UVtools/tree/master/UVtools.AvaloniaControls
Git
- Advanced image box
+ Advanced image box; Avalonia
true
- AvaloniaUI Controls
- 1.0.1
+ AvaloniaUI Controls
+- AdvancedImageBox: Pan, zoom, cursor, pixel grid and selections image box
+ 2.0.0
enable
+ https://github.com/sn4k3/UVtools
+ README.md
@@ -49,4 +52,11 @@
+
+
+ True
+ \
+
+
+
diff --git a/UVtools.Core/CoreSettings.cs b/UVtools.Core/CoreSettings.cs
index e7b54fb..d6ef78a 100644
--- a/UVtools.Core/CoreSettings.cs
+++ b/UVtools.Core/CoreSettings.cs
@@ -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
///
public static ParallelOptions ParallelOptions => new() {MaxDegreeOfParallelism = _maxDegreeOfParallelism};
+ ///
+ /// Gets the ParallelOptions with and the set
+ ///
+ public static ParallelOptions GetParallelOptions(CancellationToken token = default)
+ {
+ var options = ParallelOptions;
+ options.CancellationToken = token;
+ return options;
+ }
+
+ ///
+ /// Gets the ParallelOptions with and the set
+ ///
+ public static ParallelOptions GetParallelOptions(OperationProgress progress) => GetParallelOptions(progress.Token);
+
///
/// Gets or sets if operations run via CUDA when possible
///
@@ -50,6 +68,11 @@ public static class CoreSettings
///
public static bool CanUseCuda => EnableCuda && CudaInvoke.HasCuda;
+ ///
+ /// Gets or sets the default compression type for layers
+ ///
+ public static Layer.LayerCompressionMethod DefaultLayerCompressionMethod { get; set; } = Layer.LayerCompressionMethod.Png;
+
///
/// Gets the default folder to save the settings
///
diff --git a/UVtools.Core/Enumerations.cs b/UVtools.Core/Enumerations.cs
index c7b9a96..d82c942 100644
--- a/UVtools.Core/Enumerations.cs
+++ b/UVtools.Core/Enumerations.cs
@@ -14,6 +14,15 @@ namespace UVtools.Core;
public class Enumerations
{
+ ///
+ /// Gets index start number
+ ///
+ public enum IndexStartNumber : byte
+ {
+ Zero,
+ One
+ }
+
public enum LayerRangeSelection : byte
{
None,
diff --git a/UVtools.Core/Extensions/StreamExtensions.cs b/UVtools.Core/Extensions/StreamExtensions.cs
index d55a6a3..d8b6e7f 100644
--- a/UVtools.Core/Extensions/StreamExtensions.cs
+++ b/UVtools.Core/Extensions/StreamExtensions.cs
@@ -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);
+ }
}
\ No newline at end of file
diff --git a/UVtools.Core/Extensions/ZipArchiveExtensions.cs b/UVtools.Core/Extensions/ZipArchiveExtensions.cs
index 8446283..c021783 100644
--- a/UVtools.Core/Extensions/ZipArchiveExtensions.cs
+++ b/UVtools.Core/Extensions/ZipArchiveExtensions.cs
@@ -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:
diff --git a/UVtools.Core/FileFormats/CTBEncryptedFile.cs b/UVtools.Core/FileFormats/CTBEncryptedFile.cs
index c1b9b2a..b86a406 100644
--- a/UVtools.Core/FileFormats/CTBEncryptedFile.cs
+++ b/UVtools.Core/FileFormats/CTBEncryptedFile.cs
@@ -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(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(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);
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index 3bb3d99..bd7622c 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -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()
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
index ecd7fd6..e92316a 100644
--- a/UVtools.Core/FileFormats/CXDLPFile.cs
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -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[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