From c968eaedf961a6809d571b02528bf823b34e625b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Thu, 18 Nov 2021 03:29:08 +0000 Subject: v2.25.0 - **File formats:** - (Add) Allow to partial open the files for read and/or change properties, the layer images won't be read nor cached (Fast) - (Add) More abstraction on partial save - **Scripting:** - (Add) ScriptOpenFolderDialogInput - Selects a folder path - (Add) ScriptOpenFileDialogInput - Selectes a file to open - (Add) ScriptSaveFileDialogInput - Selects a file to save - (Add) [UNSAVED] tag to the title bar when there are unsaved changes on the current session - (Improvement) Better handling of empty images on the UI --- CHANGELOG.md | 12 + UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs | 2 +- .../UVtools.AvaloniaControls.csproj | 2 +- UVtools.Core/FileFormats/CTBEncryptedFile.cs | 99 ++-- UVtools.Core/FileFormats/CWSFile.cs | 117 ++-- UVtools.Core/FileFormats/CXDLPFile.cs | 145 ++--- UVtools.Core/FileFormats/CXDLPv1File.cs | 113 ++-- UVtools.Core/FileFormats/ChituboxFile.cs | 90 ++- UVtools.Core/FileFormats/ChituboxZipFile.cs | 61 +- UVtools.Core/FileFormats/FDGFile.cs | 61 +- UVtools.Core/FileFormats/FileFormat.cs | 98 +++- UVtools.Core/FileFormats/FlashForgeSVGXFile.cs | 51 +- UVtools.Core/FileFormats/GR1File.cs | 96 ++- UVtools.Core/FileFormats/ImageFile.cs | 12 +- UVtools.Core/FileFormats/LGSFile.cs | 60 +- UVtools.Core/FileFormats/MDLPFile.cs | 96 ++- UVtools.Core/FileFormats/OSLAFile.cs | 71 +-- UVtools.Core/FileFormats/PHZFile.cs | 55 +- UVtools.Core/FileFormats/PhotonSFile.cs | 48 +- UVtools.Core/FileFormats/PhotonWorkshopFile.cs | 66 +-- UVtools.Core/FileFormats/SL1File.cs | 50 +- UVtools.Core/FileFormats/UVJFile.cs | 42 +- UVtools.Core/FileFormats/VDAFile.cs | 41 +- UVtools.Core/FileFormats/VDTFile.cs | 91 +-- UVtools.Core/FileFormats/ZCodeFile.cs | 43 +- UVtools.Core/FileFormats/ZCodexFile.cs | 173 +++--- UVtools.Core/Layers/Layer.cs | 11 +- UVtools.Core/Layers/LayerManager.cs | 16 +- UVtools.Core/Managers/ClipboardManager.cs | 6 +- UVtools.Core/Managers/IssueManager.cs | 2 + UVtools.Core/Operations/Operation.cs | 9 +- UVtools.Core/Operations/OperationCalculator.cs | 3 + UVtools.Core/Operations/OperationDynamicLifts.cs | 2 + UVtools.Core/Operations/OperationEditParameters.cs | 4 +- .../Operations/OperationFadeExposureTime.cs | 1 + .../Operations/OperationIPrintedThisFile.cs | 2 + .../Operations/OperationRaiseOnPrintFinish.cs | 3 + UVtools.Core/Operations/OperationScripting.cs | 2 + UVtools.Core/Scripting/ScriptFileDialogInput.cs | 41 ++ .../Scripting/ScriptOpenFileDialogInput.cs | 23 + .../Scripting/ScriptOpenFolderDialogInput.cs | 18 + .../Scripting/ScriptSaveFileDialogInput.cs | 18 + UVtools.Core/UVtools.Core.csproj | 2 +- UVtools.ScriptSample/ScriptCloneSettings.cs | 427 ++++++++++++++ .../Controls/Tools/ToolScriptingControl.axaml.cs | 644 +++++++++++++-------- UVtools.WPF/LayerCache.cs | 1 + UVtools.WPF/MainWindow.Issues.cs | 8 + UVtools.WPF/MainWindow.LayerPreview.cs | 9 +- UVtools.WPF/MainWindow.axaml | 7 + UVtools.WPF/MainWindow.axaml.cs | 105 ++-- UVtools.WPF/UVtools.WPF.csproj | 2 +- 51 files changed, 1852 insertions(+), 1309 deletions(-) create mode 100644 UVtools.Core/Scripting/ScriptFileDialogInput.cs create mode 100644 UVtools.Core/Scripting/ScriptOpenFileDialogInput.cs create mode 100644 UVtools.Core/Scripting/ScriptOpenFolderDialogInput.cs create mode 100644 UVtools.Core/Scripting/ScriptSaveFileDialogInput.cs create mode 100644 UVtools.ScriptSample/ScriptCloneSettings.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 86f9dec..f682326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 18/11/2021 - v2.25.0 + +- **File formats:** + - (Add) Allow to partial open the files for read and/or change properties, the layer images won't be read nor cached (Fast) + - (Add) More abstraction on partial save +- **Scripting:** + - (Add) ScriptOpenFolderDialogInput - Selects a folder path + - (Add) ScriptOpenFileDialogInput - Selectes a file to open + - (Add) ScriptSaveFileDialogInput - Selects a file to save +- (Add) [UNSAVED] tag to the title bar when there are unsaved changes on the current session +- (Improvement) Better handling of empty images on the UI + ## 14/11/2021 - v2.24.4 - **File - Send to - Device** diff --git a/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs b/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs index 7791193..6ff899d 100644 --- a/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs +++ b/UVtools.AvaloniaControls/AdvancedImageBox.axaml.cs @@ -2117,7 +2117,7 @@ namespace UVtools.AvaloniaControls /// public Rect GetImageViewPort() { - if (ViewPortSize.Width == 0 && ViewPortSize.Height == 0) return Rect.Empty; + if (!IsImageLoaded || (ViewPortSize.Width == 0 && ViewPortSize.Height == 0)) return Rect.Empty; double xOffset = 0; double yOffset = 0; diff --git a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj index e7ba28e..977d10a 100644 --- a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj +++ b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj @@ -13,7 +13,7 @@ Advanced image box true AvaloniaUI Controls - 1.0.0 + 1.0.1 diff --git a/UVtools.Core/FileFormats/CTBEncryptedFile.cs b/UVtools.Core/FileFormats/CTBEncryptedFile.cs index 680a445..efa7fab 100644 --- a/UVtools.Core/FileFormats/CTBEncryptedFile.cs +++ b/UVtools.Core/FileFormats/CTBEncryptedFile.cs @@ -1097,15 +1097,15 @@ namespace UVtools.Core.FileFormats } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { - using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read); + using var inputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Read); Header = Helpers.Deserialize(inputFile); Debug.WriteLine($"Header: {Header}"); if (Header.Magic is not MAGIC_CBT_ENCRYPTED) { - throw new FileLoadException($"Not a valid CTB encrypted file! Magic Value: {Header.Magic}", fileFullPath); + throw new FileLoadException($"Not a valid CTB encrypted file! Magic Value: {Header.Magic}", FileFullPath); } inputFile.Seek(Header.SettingsOffset, SeekOrigin.Begin); @@ -1127,7 +1127,7 @@ namespace UVtools.Core.FileFormats var hash = inputFile.ReadBytes(HASH_LENGTH); if (!hash.SequenceEqual(encryptedHash)) { - throw new FileLoadException("The file checksum does not match, malformed file.", fileFullPath); + throw new FileLoadException("The file checksum does not match, malformed file.", FileFullPath); } progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount); @@ -1174,7 +1174,7 @@ namespace UVtools.Core.FileFormats } progress.Reset(OperationProgress.StatusDecodeLayers, Settings.LayerCount); - LayerManager.Init(Settings.LayerCount); + LayerManager.Init(Settings.LayerCount, DecodeType == FileDecodeType.Partial); LayersDefinition = new LayerDef[LayerCount]; var buggyLayers = new ConcurrentBag(); @@ -1187,43 +1187,48 @@ namespace UVtools.Core.FileFormats inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin); LayersDefinition[layerIndex] = Helpers.Deserialize(inputFile); LayersDefinition[layerIndex].Parent = this; - LayersDefinition[layerIndex].RLEData = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength); + if (DecodeType == FileDecodeType.Full) LayersDefinition[layerIndex].RLEData = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength); Debug.WriteLine($"layer[{layerIndex}]: {LayersDefinition[layerIndex]}"); } - - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) return; + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + { + if (progress.Token.IsCancellationRequested) return; - var layerDef = LayersDefinition[layerIndex]; + var layerDef = LayersDefinition[layerIndex]; - if (layerDef.EncryptedDataLength > 0) - { - /* Decrypt RLE data here */ - var byteBuffer = new byte[layerDef.EncryptedDataLength]; - Array.Copy(layerDef.RLEData, (int)layerDef.EncryptedDataOffset, byteBuffer, 0, (int)layerDef.EncryptedDataLength); + if (layerDef.EncryptedDataLength > 0) + { + /* Decrypt RLE data here */ - byteBuffer = CryptExtensions.AesCryptBytes(byteBuffer, Bigfoot, CipherMode.CBC, PaddingMode.None, false, CookieMonster); - Array.Copy(byteBuffer, 0, layerDef.RLEData, layerDef.EncryptedDataOffset, layerDef.EncryptedDataLength); - } + var byteBuffer = new byte[layerDef.EncryptedDataLength]; + Array.Copy(layerDef.RLEData, (int)layerDef.EncryptedDataOffset, byteBuffer, 0, + (int)layerDef.EncryptedDataLength); - bool isBugged = false; - /* bug fix for Chitubox when a small layer RLE data is encrypted */ - if (layerDef.EncryptedDataLength > 0 && layerDef.RLEData.Length < RLEEncryptedMinimumLength && layerDef.RLEData.Length % 16 != 0) - { - buggyLayers.Add((uint)layerIndex); - isBugged = true; - layerDef.RLEData = null; /* clean up RLE data */ - } + byteBuffer = CryptExtensions.AesCryptBytes(byteBuffer, Bigfoot, CipherMode.CBC, + PaddingMode.None, false, CookieMonster); + Array.Copy(byteBuffer, 0, layerDef.RLEData, layerDef.EncryptedDataOffset, + layerDef.EncryptedDataLength); + } - var layer = new Layer((uint)layerIndex, isBugged ? null : layerDef.DecodeImage((uint)layerIndex), this); - layerDef.CopyTo(layer); - this[layerIndex] = layer; - - progress.LockAndIncrement(); - }); + bool isBugged = false; + /* bug fix for Chitubox when a small layer RLE data is encrypted */ + if (layerDef.EncryptedDataLength > 0 && layerDef.RLEData.Length < RLEEncryptedMinimumLength && + layerDef.RLEData.Length % 16 != 0) + { + buggyLayers.Add((uint)layerIndex); + isBugged = true; + layerDef.RLEData = null; /* clean up RLE data */ + } + + this[layerIndex] = new Layer((uint)layerIndex, isBugged ? null : layerDef.DecodeImage((uint)layerIndex), this); + + progress.LockAndIncrement(); + }); + } } if (buggyLayers.Count == LayerCount) @@ -1231,7 +1236,12 @@ namespace UVtools.Core.FileFormats throw new FileLoadException("Unable to load this file due to Chitubox bug affecting every layer." + "Please increase the portion of the plate in use and reslice the file."); } - + + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + { + LayersDefinition[layerIndex].CopyTo(this[layerIndex]); + } + if (!buggyLayers.IsEmpty) { var sortedLayerIndexes = buggyLayers.ToArray(); @@ -1267,13 +1277,13 @@ namespace UVtools.Core.FileFormats //inputFile.ReadBytes(HashLength); } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { #if !DEBUG throw new NotSupportedException(Preamble); #endif - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); //uint currentOffset = 0; /* Create the file header and fill out what we can. SignatureOffset will have to be populated later @@ -1401,25 +1411,8 @@ namespace UVtools.Core.FileFormats Helpers.SerializeWriteFileStream(outputFile, Header); } - public override void SaveAs(string filePath = null, OperationProgress progress = null) + protected override void PartialSaveInternally(OperationProgress progress) { - if (RequireFullEncode) - { - if (!string.IsNullOrEmpty(filePath)) - { - FileFullPath = filePath; - } - Encode(FileFullPath, progress); - return; - } - - - if (!string.IsNullOrEmpty(filePath)) - { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; - } - SanitizeProperties(); using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs index 97b9f8f..d7f1c6b 100644 --- a/UVtools.Core/FileFormats/CWSFile.cs +++ b/UVtools.Core/FileFormats/CWSFile.cs @@ -575,7 +575,7 @@ namespace UVtools.Core.FileFormats #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { //var filename = fileFullPath.EndsWith(TemporaryFileAppend) ? Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(fileFullPath)) : Path.GetFileNameWithoutExtension(fileFullPath); @@ -610,7 +610,7 @@ namespace UVtools.Core.FileFormats throw new InvalidOperationException($"Filename for this format should not end with a digit: {filename}"); } - using ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); if (Printer == PrinterType.Wanhao) { var manifest = new CWSManifest @@ -703,9 +703,9 @@ namespace UVtools.Core.FileFormats outputFile.PutFileContent($"{filename}.gcode", GCodeStr, ZipArchiveMode.Create); } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { - using var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read); + using var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read); var entry = inputFile.GetEntry("manifest.xml"); if (entry is not null) // Wanhao { @@ -722,7 +722,7 @@ namespace UVtools.Core.FileFormats catch (Exception e) { Clear(); - throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", fileFullPath); + throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath); } @@ -741,7 +741,7 @@ namespace UVtools.Core.FileFormats catch (Exception e) { Clear(); - throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", fileFullPath); + throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath); } } } @@ -751,7 +751,7 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException("slice.conf not found", fileFullPath); + throw new FileLoadException("slice.conf not found", FileFullPath); } using TextReader tr = new StreamReader(entry.Open()); @@ -780,8 +780,7 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException("Unable to find .gcode file", - fileFullPath); + throw new FileLoadException("Unable to find .gcode file", FileFullPath); } using (TextReader tr = new StreamReader(entry.Open())) @@ -821,32 +820,36 @@ namespace UVtools.Core.FileFormats tr.Close(); } - LayerManager.Init(OutputSettings.LayersNum); + LayerManager.Init(OutputSettings.LayersNum, DecodeType == FileDecodeType.Partial); progress.ItemCount = OutputSettings.LayersNum; if(LayerCount > 0) { - var inputFilename = Path.GetFileNameWithoutExtension(fileFullPath); - foreach (var pngEntry in inputFile.Entries) + if (DecodeType == FileDecodeType.Full) { - 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--) + var inputFilename = Path.GetFileNameWithoutExtension(FileFullPath); + foreach (var pngEntry in inputFile.Entries) { - if (layerStr[i] < '0' || layerStr[i] > '9') break; - layerIndexStr = $"{layerStr[i]}{layerIndexStr}"; - } + if (!pngEntry.Name.EndsWith(".png")) continue; + var filename = Path.GetFileNameWithoutExtension(pngEntry.Name) + .Replace(inputFilename, string.Empty, StringComparison.Ordinal); - if (string.IsNullOrEmpty(layerIndexStr)) continue; - if (!uint.TryParse(layerIndexStr, out var layerIndex)) continue; - using var stream = pngEntry.Open(); - this[layerIndex] = new Layer(layerIndex, stream, LayerManager); - } + 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, LayerManager); + } + } + GCode.ParseLayersFromGCode(this); var firstLayer = FirstLayer; @@ -993,61 +996,43 @@ namespace UVtools.Core.FileFormats RaisePropertyChanged(nameof(GCodeStr)); } - public override void SaveAs(string filePath = null, OperationProgress progress = null) + protected override void PartialSaveInternally(OperationProgress progress) { - if (RequireFullEncode) - { - if (!string.IsNullOrEmpty(filePath)) - { - FileFullPath = filePath; - } - Encode(FileFullPath, progress); - return; - } + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); + var arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; + var entry = outputFile.GetPutFile("slice.conf"); + var stream = entry.Open(); + stream.SetLength(0); - if (!string.IsNullOrEmpty(filePath)) + using (TextWriter tw = new StreamWriter(stream)) { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; - } - using (var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update)) - { - string arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; - var entry = outputFile.GetPutFile("slice.conf"); - var stream = entry.Open(); - stream.SetLength(0); + tw.WriteLine($"# {About.Website} {About.Software} {Assembly.GetExecutingAssembly().GetName().Version} {arch} {DateTime.UtcNow}"); + tw.WriteLine("# conf version 1.0"); + tw.WriteLine(""); - using (TextWriter tw = new StreamWriter(stream)) + foreach (var propertyInfo in SliceSettings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - - tw.WriteLine($"# {About.Website} {About.Software} {Assembly.GetExecutingAssembly().GetName().Version} {arch} {DateTime.UtcNow}"); - tw.WriteLine("# conf version 1.0"); - tw.WriteLine(""); - - foreach (var propertyInfo in SliceSettings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - var displayNameAttribute = propertyInfo.GetCustomAttributes(false).OfType().FirstOrDefault(); - if (displayNameAttribute is null) continue; - tw.WriteLine($"{displayNameAttribute.DisplayName.PadRight(24)}= {propertyInfo.GetValue(SliceSettings)}"); - } + var displayNameAttribute = propertyInfo.GetCustomAttributes(false).OfType().FirstOrDefault(); + if (displayNameAttribute is null) continue; + tw.WriteLine($"{displayNameAttribute.DisplayName.PadRight(24)}= {propertyInfo.GetValue(SliceSettings)}"); } + } - var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".gcode")).ToArray(); - foreach (var zipEntry in entriesToRemove) - { - zipEntry.Delete(); - } + var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".gcode")).ToArray(); + foreach (var zipEntry in entriesToRemove) + { + zipEntry.Delete(); + } - outputFile.PutFileContent($"{About.Software}.gcode", GCodeStr, ZipArchiveMode.Update); + outputFile.PutFileContent($"{About.Software}.gcode", GCodeStr, ZipArchiveMode.Update); - /*foreach (var layer in this) + /*foreach (var layer in this) { if (!layer.IsModified) continue; outputFile.PutFileContent(layer.Filename, layer.CompressedBytes, ZipArchiveMode.Update); layer.IsModified = false; }*/ - } //Decode(FileFullPath, progress); } diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs index 705567f..ff39673 100644 --- a/UVtools.Core/FileFormats/CXDLPFile.cs +++ b/UVtools.Core/FileFormats/CXDLPFile.cs @@ -17,7 +17,6 @@ using System.Text; using System.Threading.Tasks; using BinarySerialization; using Emgu.CV; -using Emgu.CV.CvEnum; using Emgu.CV.Structure; using MoreLinq; using UVtools.Core.Extensions; @@ -571,9 +570,9 @@ namespace UVtools.Core.FileFormats SlicerInfoSettings.WaitTimeBeforeCure = (ushort)Math.Max(1, WaitTimeBeforeCure); } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.ReadWrite); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.ReadWrite); if (ResolutionX == 1620 && ResolutionY == 2560) { @@ -790,9 +789,9 @@ namespace UVtools.Core.FileFormats Debug.WriteLine("-End-"); } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { - using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read); + using var inputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Read); inputFile.Seek(0, SeekOrigin.Begin); @@ -812,10 +811,10 @@ namespace UVtools.Core.FileFormats if (expectedCheckSum != checkSum) { throw new FileLoadException($"Checksum fails, expecting: {expectedCheckSum} but got: {checkSum}.\n" + - $"Try to reslice the file.", fileFullPath); + $"Try to reslice the file.", FileFullPath); } - byte[][] previews = new byte[ThumbnailsOriginalSize.Length][]; + var previews = new byte[ThumbnailsOriginalSize.Length][]; for (int i = 0; i < ThumbnailsOriginalSize.Length; i++) { previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2]; @@ -833,116 +832,80 @@ namespace UVtools.Core.FileFormats SlicerInfoSettings = Helpers.Deserialize(inputFile); Debug.WriteLine(SlicerInfoSettings); - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); inputFile.Seek(LayerCount * 4 + 2, SeekOrigin.Current); // Skip pre layers - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - /*var preLayers = new PreLayer[LayerCount]; - for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++) - { - progress.Token.ThrowIfCancellationRequested(); - preLayers[layerIndex] = Helpers.Deserialize(inputFile); - progress++; - }*/ - - //inputFile.Seek(2, SeekOrigin.Current); - var linesBytes = new byte[LayerCount][]; - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - progress.Token.ThrowIfCancellationRequested(); + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - foreach (var layerIndex in batch) + var linesBytes = new byte[LayerCount][]; + foreach (var batch in BatchLayersIndexes()) { - 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 => - { - if (progress.Token.IsCancellationRequested) return; - using (var mat = EmguExtensions.InitMat(Resolution)) + foreach (var layerIndex in batch) { + 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(); + } - for (int i = 0; i < linesBytes[layerIndex].Length; i++) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + { + if (progress.Token.IsCancellationRequested) return; + using (var mat = EmguExtensions.InitMat(Resolution)) { - LayerLine line = new() + + for (int i = 0; i < linesBytes[layerIndex].Length; i++) { - Coordinates = + LayerLine line = new() { - [0] = linesBytes[layerIndex][i++], - [1] = linesBytes[layerIndex][i++], - [2] = linesBytes[layerIndex][i++], - [3] = linesBytes[layerIndex][i++], - [4] = linesBytes[layerIndex][i++] - }, - Gray = linesBytes[layerIndex][i] - }; - - CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY), - new MCvScalar(line.Gray)); - } + Coordinates = + { + [0] = linesBytes[layerIndex][i++], + [1] = linesBytes[layerIndex][i++], + [2] = linesBytes[layerIndex][i++], + [3] = linesBytes[layerIndex][i++], + [4] = linesBytes[layerIndex][i++] + }, + Gray = linesBytes[layerIndex][i] + }; + + CvInvoke.Line(mat, new Point(line.StartX, line.StartY), + new Point(line.StartX, line.EndY), + new MCvScalar(line.Gray)); + } - linesBytes[layerIndex] = null; + linesBytes[layerIndex] = null; - this[layerIndex] = new Layer((uint)layerIndex, mat, this); - } + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + } - progress.LockAndIncrement(); - }); + progress.LockAndIncrement(); + }); + } } - - progress.Token.ThrowIfCancellationRequested(); - - /*var layerDefs = new LayerDef[LayerCount]; - for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++) + else // Partial read { - progress.Token.ThrowIfCancellationRequested(); - layerDefs[layerIndex] = Helpers.Deserialize(inputFile); - progress++; + inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End); } - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => - { - if (progress.Token.IsCancellationRequested) return; - using var mat = EmguExtensions.InitMat(Resolution); - foreach (var line in layerDefs[layerIndex].Lines) - { - CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY), new MCvScalar(line.Gray)); - } + progress.Token.ThrowIfCancellationRequested(); + - this[layerIndex] = new Layer((uint)layerIndex, mat, this); - progress.LockAndIncrement(); - });*/ FooterSettings = Helpers.Deserialize