diff options
51 files changed, 1852 insertions, 1309 deletions
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 /// <returns></returns> 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 @@ <PackageTags>Advanced image box</PackageTags> <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> <Description>AvaloniaUI Controls</Description> - <Version>1.0.0</Version> + <Version>1.0.1</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> 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<FileHeader>(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<uint>(); @@ -1187,43 +1187,48 @@ namespace UVtools.Core.FileFormats inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin); LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(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<DisplayNameAttribute>().FirstOrDefault(); - if (displayNameAttribute is null) continue; - tw.WriteLine($"{displayNameAttribute.DisplayName.PadRight(24)}= {propertyInfo.GetValue(SliceSettings)}"); - } + var displayNameAttribute = propertyInfo.GetCustomAttributes(false).OfType<DisplayNameAttribute>().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<SlicerInfo>(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<PreLayer>(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<LayerDef>(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<Footer>(inputFile); FooterSettings.Validate(); } - 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; - } - var offset = Helpers.Serializer.SizeOf(HeaderSettings); foreach (var size in ThumbnailsOriginalSize) { diff --git a/UVtools.Core/FileFormats/CXDLPv1File.cs b/UVtools.Core/FileFormats/CXDLPv1File.cs index 24e79d2..f3cc5ef 100644 --- a/UVtools.Core/FileFormats/CXDLPv1File.cs +++ b/UVtools.Core/FileFormats/CXDLPv1File.cs @@ -499,9 +499,9 @@ namespace UVtools.Core.FileFormats #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); if (ResolutionX == 2560 && ResolutionY == 1620) { @@ -628,9 +628,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); HeaderSettings = Helpers.Deserialize<Header>(inputFile); HeaderSettings.Validate(); @@ -654,62 +654,67 @@ namespace UVtools.Core.FileFormats SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(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 range = Enumerable.Range(0, (int)LayerCount); - - var linesBytes = new byte[LayerCount][]; - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - progress.Token.ThrowIfCancellationRequested(); - - foreach (var layerIndex in batch) + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + var linesBytes = new byte[LayerCount][]; + foreach (var batch in BatchLayersIndexes()) { - inputFile.Seek(4, SeekOrigin.Current); - var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); + progress.Token.ThrowIfCancellationRequested(); + + 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); + linesBytes[layerIndex] = new byte[lineCount * 6]; + inputFile.ReadBytes(linesBytes[layerIndex]); + inputFile.Seek(2, SeekOrigin.Current); - progress.Token.ThrowIfCancellationRequested(); - } + progress.Token.ThrowIfCancellationRequested(); + } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => - { - if (progress.Token.IsCancellationRequested) return; - using (var mat = EmguExtensions.InitMat(Resolution)) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { - for (int i = 0; i < linesBytes[layerIndex].Length; i++) + 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(); + }); + } + } + else // Partial read + { + inputFile.Seek(-Helpers.Serializer.SizeOf(FooterSettings), SeekOrigin.End); } progress.Token.ThrowIfCancellationRequested(); @@ -718,24 +723,8 @@ namespace UVtools.Core.FileFormats FooterSettings.Validate(); } - 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; - } - var offset = Helpers.Serializer.SizeOf(HeaderSettings); foreach (var size in ThumbnailsOriginalSize) { diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index 3882ee5..98461fa 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -1775,7 +1775,7 @@ namespace UVtools.Core.FileFormats return true; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { SanitizeMagicVersion(); SanitizeProperties(); @@ -1799,7 +1799,7 @@ namespace UVtools.Core.FileFormats //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings); LayerDefinitions = new LayerDef[HeaderSettings.AntiAliasLevel, HeaderSettings.LayerCount]; - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin); Mat[] thumbnails = {GetThumbnail(true), GetThumbnail(false)}; @@ -1956,16 +1956,16 @@ 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); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header)))); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Magic is not MAGIC_CBDDLP and not MAGIC_CTB and not MAGIC_CTBv4) { - throw new FileLoadException($"Not a valid PHOTON nor CBDDLP nor CTB file! Magic Value: {HeaderSettings.Magic}", fileFullPath); + throw new FileLoadException($"Not a valid PHOTON nor CBDDLP nor CTB file! Magic Value: {HeaderSettings.Magic}", FileFullPath); } if (HeaderSettings.Version == 1 || HeaderSettings.AntiAliasLevel == 0) @@ -1973,8 +1973,6 @@ namespace UVtools.Core.FileFormats HeaderSettings.AntiAliasLevel = 1; } - FileFullPath = fileFullPath; - progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount); Debug.Write("Header -> "); @@ -2031,7 +2029,7 @@ namespace UVtools.Core.FileFormats { throw new FileLoadException( $"Malformed file, PrintParametersV4Address is missing", - fileFullPath); + FileFullPath); } inputFile.Seek(SlicerInfoSettings.PrintParametersV4Address, SeekOrigin.Begin); @@ -2044,7 +2042,7 @@ namespace UVtools.Core.FileFormats throw new FileLoadException( $"Malformed file, PrintParametersV4 found invalid validation values, expected (4, 4) " + $"but got ({PrintParametersV4Settings.Four1}, {PrintParametersV4Settings.Four2})", - fileFullPath); + FileFullPath); } } @@ -2053,8 +2051,7 @@ namespace UVtools.Core.FileFormats uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - progress.Reset(OperationProgress.StatusGatherLayers, - HeaderSettings.AntiAliasLevel * HeaderSettings.LayerCount); + progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.AntiAliasLevel * HeaderSettings.LayerCount); for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) { @@ -2089,65 +2086,52 @@ namespace UVtools.Core.FileFormats } } - LayerManager.Init(HeaderSettings.LayerCount); - - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - foreach (var layerIndex in batch) - { - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) - { - progress.Token.ThrowIfCancellationRequested(); + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin); - LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize); - } - } - - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + foreach (var batch in BatchLayersIndexes()) { - if (progress.Token.IsCancellationRequested) return; - using (var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex)) + foreach (var layerIndex in batch) { - var layer = new Layer((uint)layerIndex, mat, this); - if (layerDefinitionsEx is not null) // CTBv4 - { - layerDefinitionsEx[layerIndex].CopyTo(layer); - } - else // others + for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) { - LayerDefinitions[0, layerIndex].CopyTo(layer); - } + progress.Token.ThrowIfCancellationRequested(); - this[layerIndex] = layer; + inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin); + LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize); + } } - progress.LockAndIncrement(); - }); + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + { + if (progress.Token.IsCancellationRequested) return; + using var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex); + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + + progress.LockAndIncrement(); + }); + } } - } - public override void SaveAs(string filePath = null, OperationProgress progress = null) - { - if (RequireFullEncode) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - if (!string.IsNullOrEmpty(filePath)) + if (layerDefinitionsEx is not null) // CTBv4 + { + layerDefinitionsEx[layerIndex].CopyTo(this[layerIndex]); + } + else // others { - FileFullPath = filePath; + LayerDefinitions[0, layerIndex].CopyTo(this[layerIndex]); } - Encode(FileFullPath, progress); - return; } + } - if (!string.IsNullOrEmpty(filePath)) - { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; - } - + protected override void PartialSaveInternally(OperationProgress progress) + { SanitizeProperties(); using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs index ead0b3e..7cd44d2 100644 --- a/UVtools.Core/FileFormats/ChituboxZipFile.cs +++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs @@ -401,9 +401,9 @@ namespace UVtools.Core.FileFormats return false; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create)) + using (ZipArchive outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create)) { if (Thumbnails.Length > 0 && Thumbnails[0] is not null) { @@ -416,14 +416,10 @@ namespace UVtools.Core.FileFormats if (Thumbnails.Length > 1 && Thumbnails[1] is not null) { - using (Stream stream = outputFile.CreateEntry("preview_cropping.png").Open()) - { - using (var vec = new VectorOfByte()) - { - stream.WriteBytes(Thumbnails[1].GetPngByes()); - stream.Close(); - } - } + using Stream stream = outputFile.CreateEntry("preview_cropping.png").Open(); + using var vec = new VectorOfByte(); + stream.WriteBytes(Thumbnails[1].GetPngByes()); + stream.Close(); } if (!IsPHZZip) @@ -443,7 +439,7 @@ namespace UVtools.Core.FileFormats } } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read)) { @@ -497,24 +493,27 @@ namespace UVtools.Core.FileFormats } } - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); progress.ItemCount = LayerCount; - for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) break; - entry = inputFile.GetEntry($"{layerIndex+1}.png"); - if (entry is null) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - Clear(); - throw new FileLoadException($"Layer {layerIndex+1} not found", fileFullPath); - } + 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, LayerManager); + using var stream = entry.Open(); + this[layerIndex] = new Layer(layerIndex, stream, LayerManager); - progress++; + progress++; + } } if (IsPHZZip) // PHZ file @@ -561,24 +560,8 @@ 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; - } - - if (!string.IsNullOrEmpty(filePath)) - { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; - } - using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".gcode")).ToArray(); foreach (var zipEntry in entriesToRemove) diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs index ec1e414..442bc8e 100644 --- a/UVtools.Core/FileFormats/FDGFile.cs +++ b/UVtools.Core/FileFormats/FDGFile.cs @@ -904,7 +904,7 @@ namespace UVtools.Core.FileFormats LayersDefinitions = null; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { /*if (HeaderSettings.EncryptionKey == 0) { @@ -912,7 +912,7 @@ namespace UVtools.Core.FileFormats HeaderSettings.EncryptionKey = (uint)rnd.Next(short.MaxValue, int.MaxValue); }*/ - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin); for (byte i = 0; i < ThumbnailsCount; i++) @@ -1021,22 +1021,19 @@ 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); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header)))); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Magic != MAGIC) { - throw new FileLoadException("Not a valid FDG file!", fileFullPath); + throw new FileLoadException("Not a valid FDG file!", FileFullPath); } HeaderSettings.AntiAliasLevel = 1; - FileFullPath = fileFullPath; - - progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount); Debug.Write("Header -> "); Debug.WriteLine(HeaderSettings); @@ -1070,7 +1067,7 @@ namespace UVtools.Core.FileFormats HeaderSettings.MachineName = Encoding.ASCII.GetString(buffer); } - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); LayersDefinitions = new LayerDef[HeaderSettings.LayerCount]; progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount); @@ -1087,45 +1084,37 @@ namespace UVtools.Core.FileFormats Debug.Write($"LAYER {layerIndex} -> "); Debug.WriteLine(layerDef); - inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, () => + if (DecodeType == FileDecodeType.Full) { - layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); - }); + inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, + () => { layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); }); + } } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) return; - using (var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex)) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { - var layer = new Layer((uint)layerIndex, mat, this); - LayersDefinitions[layerIndex].CopyTo(layer); - this[layerIndex] = layer; - } - - progress.LockAndIncrement(); - }); - } - } + if (progress.Token.IsCancellationRequested) return; + if (DecodeType == FileDecodeType.Full) + { + using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex); + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + } - public override void SaveAs(string filePath = null, OperationProgress progress = null) - { - if (RequireFullEncode) - { - if (!string.IsNullOrEmpty(filePath)) - { - FileFullPath = filePath; + progress.LockAndIncrement(); + }); } - Encode(FileFullPath, progress); - return; } - if (!string.IsNullOrEmpty(filePath)) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; + LayersDefinitions[layerIndex].CopyTo(this[layerIndex]); } + } + protected override void PartialSaveInternally(OperationProgress progress) + { using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 5ded9f6..cfe695d 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -121,6 +121,19 @@ namespace UVtools.Core.FileFormats Small = 0, Large } + + public enum FileDecodeType : byte + { + /// <summary> + /// Decodes all the file information and caches layer images + /// </summary> + Full, + + /// <summary> + /// Decodes only the information in the file and thumbnails, no layer image is read nor cached, fast + /// </summary> + Partial, + } #endregion #region Sub Classes @@ -441,6 +454,17 @@ namespace UVtools.Core.FileFormats return PathExtensions.GetFileNameStripExtensions(filepath, AllFileExtensionsString.OrderByDescending(s => s.Length).ToList(), out strippedExtension); } + public static FileFormat Open(string fileFullPath, FileDecodeType decodeType, OperationProgress progress = null) + { + var slicerFile = FindByExtensionOrFilePath(fileFullPath, true); + if (slicerFile is null) return null; + slicerFile.Decode(fileFullPath, decodeType, progress); + return slicerFile; + } + + public static FileFormat Open(string fileFullPath, OperationProgress progress = null) => + Open(fileFullPath, FileDecodeType.Full, progress); + public static byte[] EncodeImage(string dataType, Mat mat) { @@ -762,6 +786,8 @@ namespace UVtools.Core.FileFormats /// </summary> public abstract FileExtension[] FileExtensions { get; } + public FileDecodeType DecodeType { get; private set; } = FileDecodeType.Full; + /// <summary> /// Gets the available <see cref="PrintParameterModifier"/> /// </summary> @@ -847,6 +873,7 @@ namespace UVtools.Core.FileFormats /// </summary> public string FileFullPath { get; set; } + public string FileDirectoryPath => Path.GetDirectoryName(FileFullPath); public string Filename => Path.GetFileName(FileFullPath); public string FileExtension => Path.GetExtension(FileFullPath); public string FilenameNoExt => GetFileNameStripExtensions(FileFullPath); @@ -2520,9 +2547,8 @@ namespace UVtools.Core.FileFormats /// <summary> /// Encode to an output file /// </summary> - /// <param name="fileFullPath">Output file</param> /// <param name="progress"></param> - protected abstract void EncodeInternally(string fileFullPath, OperationProgress progress); + protected abstract void EncodeInternally(OperationProgress progress); /// <summary> /// Encode to an output file @@ -2531,6 +2557,11 @@ namespace UVtools.Core.FileFormats /// <param name="progress"></param> public void Encode(string fileFullPath, OperationProgress progress = null) { + if (DecodeType == FileDecodeType.Partial) + { + throw new InvalidOperationException("File was partial decoded, a full encode is not possible."); + } + progress ??= new OperationProgress(); progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount); @@ -2543,12 +2574,9 @@ namespace UVtools.Core.FileFormats LayerManager.Sanitize(); - FileFullPath = fileFullPath; + if (File.Exists(fileFullPath)) File.Delete(fileFullPath); - if (File.Exists(fileFullPath)) - { - File.Delete(fileFullPath); - } + FileFullPath = fileFullPath; for (var i = 0; i < Thumbnails.Length; i++) { @@ -2557,7 +2585,7 @@ namespace UVtools.Core.FileFormats CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height)); } - EncodeInternally(fileFullPath, progress); + EncodeInternally(progress); LayerManager.SetAllIsModified(false); RequireFullEncode = false; @@ -2566,24 +2594,32 @@ namespace UVtools.Core.FileFormats /// <summary> /// Decode a slicer file /// </summary> + /// <param name="progress"></param> + protected abstract void DecodeInternally(OperationProgress progress); + + /// <summary> + /// Decode a slicer file + /// </summary> /// <param name="fileFullPath"></param> /// <param name="progress"></param> - protected abstract void DecodeInternally(string fileFullPath, OperationProgress progress); + public void Decode(string fileFullPath, OperationProgress progress = null) => Decode(fileFullPath, FileDecodeType.Full, progress); /// <summary> /// Decode a slicer file /// </summary> /// <param name="fileFullPath"></param> + /// <param name="fileDecodeType"></param> /// <param name="progress"></param> - public void Decode(string fileFullPath, OperationProgress progress = null) + public void Decode(string fileFullPath, FileDecodeType fileDecodeType, OperationProgress progress = null) { Clear(); FileValidation(fileFullPath); FileFullPath = fileFullPath; + DecodeType = fileDecodeType; progress ??= new OperationProgress(); progress.Reset(OperationProgress.StatusGatherLayers, LayerCount); - DecodeInternally(fileFullPath, progress); + DecodeInternally(progress); progress.Token.ThrowIfCancellationRequested(); @@ -2745,20 +2781,15 @@ namespace UVtools.Core.FileFormats } } - if (LayerCount > 0) + if (LayerCount > 0 && DecodeType == FileDecodeType.Full) { Parallel.ForEach(this, CoreSettings.ParallelOptions, layer => { if (progress.Token.IsCancellationRequested) return; var byteArr = layer.CompressedBytes; - using var stream = File.Create(Path.Combine(path, layer.Filename), - byteArr.Length); + 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); - stream.Close(); - - //using var mat = layer.LayerMat; - //mat.Save(Path.Combine(path, $"{layer.Filename}.jpg")); - progress.LockAndIncrement(); }); } @@ -3343,7 +3374,34 @@ namespace UVtools.Core.FileFormats /// </summary> /// <param name="filePath">File path to save copy as, use null to overwrite active file (Same as <see cref="Save"/>)</param> /// <param name="progress"></param> - public abstract void SaveAs(string filePath = null, OperationProgress progress = null); + public void SaveAs(string filePath = null, OperationProgress progress = null) + { + if (RequireFullEncode) + { + if (!string.IsNullOrEmpty(filePath)) + { + FileFullPath = filePath; + } + Encode(FileFullPath, progress); + return; + } + + if (!string.IsNullOrEmpty(filePath)) + { + File.Copy(FileFullPath, filePath, true); + FileFullPath = filePath; + + } + + PartialSaveInternally(progress); + } + + /// <summary> + /// Partial save of the file, this is the file information only. + /// When this function is called it's already ready to save to file + /// </summary> + /// <param name="progress"></param> + protected abstract void PartialSaveInternally(OperationProgress progress); /// <summary> /// Triggers when a conversion is valid and before start converting values diff --git a/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs b/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs index 3e3190c..0583caf 100644 --- a/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs +++ b/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs @@ -446,17 +446,17 @@ namespace UVtools.Core.FileFormats #endregion #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { if (SVGDocument.PrintParameters.ResolutionX == 0 || SVGDocument.PrintParameters.ResolutionY == 0 || SVGDocument.PrintParameters.DisplayWidth == 0 || SVGDocument.PrintParameters.DisplayHeight == 0) { throw new FileLoadException("This file does not contain a resolution and/or display size information needed to generate the layer images.\n" + "Note that FlashDLPrint slicer is unable to output files with the required information to load in here.\n" + - "Please use other compatible slicer capable of output the correct information to load the file in here.", fileFullPath); + "Please use other compatible slicer capable of output the correct information to load the file in here.", FileFullPath); } - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin); HeaderSettings.Preview1Address = 0; @@ -594,13 +594,13 @@ 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); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Identifier != Header.IdentifierText) { - throw new FileLoadException("Not a valid Flashforge SVGX file!", fileFullPath); + throw new FileLoadException("Not a valid Flashforge SVGX file!", FileFullPath); } progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount); @@ -644,15 +644,16 @@ namespace UVtools.Core.FileFormats { throw new FileLoadException("This file does not contain a resolution and/or display size information needed to generate the layer images.\n" + "Note that FlashDLPrint slicer is unable to output files with the required information to load in here.\n" + - "Please use other compatible slicer capable of output the correct information to load the file in here.", fileFullPath); + "Please use other compatible slicer capable of output the correct information to load the file in here.", FileFullPath); } var halfDisplay = Display.Half(); var ppmm = Ppmm; - LayerManager.Init(SVGDocument.PrintParameters.LayerCount); - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + LayerManager.Init(SVGDocument.PrintParameters.LayerCount, DecodeType == FileDecodeType.Partial); + if (DecodeType != FileDecodeType.Full) return; + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex => { if (progress.Token.IsCancellationRequested) return; @@ -661,14 +662,15 @@ namespace UVtools.Core.FileFormats var group = SVGDocument.Groups.FirstOrDefault(g => g.Id == $"layer-{layerIndex}"); - if (group is not null) + if (@group is not null) { var pointsOfPoints = new List<Point[]>(); var points = new List<Point>(); - foreach (var path in group.Paths) + foreach (var path in @group.Paths) { if (progress.Token.IsCancellationRequested) break; - var spaceSplit = path.Value.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + var spaceSplit = path.Value.Split(' ', + StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < spaceSplit.Length; i++) { @@ -679,8 +681,10 @@ namespace UVtools.Core.FileFormats pointsOfPoints.Add(points.ToArray()); points.Clear(); } + continue; } + if (spaceSplit[i] == "Z") { if (points.Count > 0) @@ -688,9 +692,12 @@ namespace UVtools.Core.FileFormats pointsOfPoints.Add(points.ToArray()); points.Clear(); } + continue; } - if (spaceSplit[i].Length == 1 && !char.IsDigit(spaceSplit[i][0])) continue; // Ignore any other not processed 1 char that's not a digit (L) + + if (spaceSplit[i].Length == 1 && !char.IsDigit(spaceSplit[i][0])) + continue; // Ignore any other not processed 1 char that's not a digit (L) if (i + 1 >= spaceSplit.Length) break; // No more to see @@ -730,24 +737,8 @@ namespace UVtools.Core.FileFormats }); } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(HeaderSettings.SVGDocumentAddress, SeekOrigin.Begin); outputFile.SetLength(outputFile.Position); diff --git a/UVtools.Core/FileFormats/GR1File.cs b/UVtools.Core/FileFormats/GR1File.cs index 808b588..c55167e 100644 --- a/UVtools.Core/FileFormats/GR1File.cs +++ b/UVtools.Core/FileFormats/GR1File.cs @@ -354,9 +354,9 @@ namespace UVtools.Core.FileFormats #endregion #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); var pageBreak = PageBreak.Bytes; Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); @@ -465,13 +465,13 @@ 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); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.HeaderValue != Header.HEADER_VALUE) { - throw new FileLoadException("Not a valid Makerbase file!", fileFullPath); + throw new FileLoadException("Not a valid Makerbase file!", FileFullPath); } byte[][] previews = new byte[ThumbnailsOriginalSize.Length][]; @@ -491,77 +491,65 @@ namespace UVtools.Core.FileFormats SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(inputFile); - LayerManager.Init(SlicerInfoSettings.LayerCount); + LayerManager.Init(SlicerInfoSettings.LayerCount, DecodeType == FileDecodeType.Partial); - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - - var range = Enumerable.Range(0, (int)LayerCount); - - var linesBytes = new byte[LayerCount][]; - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - progress.Token.ThrowIfCancellationRequested(); - - foreach (var layerIndex in batch) + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + var linesBytes = new byte[LayerCount][]; + foreach (var batch in BatchLayersIndexes()) { - var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); + progress.Token.ThrowIfCancellationRequested(); - linesBytes[layerIndex] = new byte[lineCount * 6]; - inputFile.ReadBytes(linesBytes[layerIndex]); - inputFile.Seek(2, SeekOrigin.Current); + foreach (var layerIndex in batch) + { + var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); - progress.Token.ThrowIfCancellationRequested(); - } + linesBytes[layerIndex] = new byte[lineCount * 6]; + inputFile.ReadBytes(linesBytes[layerIndex]); + inputFile.Seek(2, SeekOrigin.Current); - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => - { - if (progress.Token.IsCancellationRequested) return; - using var mat = EmguExtensions.InitMat(Resolution); + progress.Token.ThrowIfCancellationRequested(); + } - for (int i = 0; i < linesBytes[layerIndex].Length; i++) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { - var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); - var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); - var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]); + if (progress.Token.IsCancellationRequested) return; + using var mat = EmguExtensions.InitMat(Resolution); - CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), EmguExtensions.WhiteColor); - } + for (int i = 0; i < linesBytes[layerIndex].Length; i++) + { + var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); + var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); + var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]); - linesBytes[layerIndex] = null; + CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), + EmguExtensions.WhiteColor); + } - this[layerIndex] = new Layer((uint)layerIndex, mat, this); + linesBytes[layerIndex] = null; - progress.LockAndIncrement(); - }); + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + + progress.LockAndIncrement(); + }); + } + } + else // Partial read + { + inputFile.Seek(-Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.End); } HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.HeaderValue != Header.HEADER_VALUE) { - throw new FileLoadException("Not a valid Makerbase file!", fileFullPath); + throw new FileLoadException("Not a valid Makerbase file!", FileFullPath); } } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(SlicerInfoAddress, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings); diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs index 6057155..f80b8f1 100644 --- a/UVtools.Core/FileFormats/ImageFile.cs +++ b/UVtools.Core/FileFormats/ImageFile.cs @@ -77,14 +77,14 @@ namespace UVtools.Core.FileFormats private Mat ImageMat { get; set; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - throw new NotSupportedException(); + this[0].LayerMat.Save(FileFullPath); } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { - ImageMat = CvInvoke.Imread(fileFullPath, ImreadModes.Grayscale); + ImageMat = CvInvoke.Imread(FileFullPath, ImreadModes.Grayscale); const byte startDivisor = 2; for (int i = 0; i < ThumbnailsCount; i++) { @@ -102,9 +102,9 @@ namespace UVtools.Core.FileFormats this[0] = new Layer(0, ImageMat, LayerManager); } - public override void SaveAs(string filePath = null, OperationProgress progress = null) + protected override void PartialSaveInternally(OperationProgress progress) { - this[0].LayerMat.Save(filePath ?? FileFullPath); + this[0].LayerMat.Save(FileFullPath); } public override FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null) diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs index 5ce2820..492c438 100644 --- a/UVtools.Core/FileFormats/LGSFile.cs +++ b/UVtools.Core/FileFormats/LGSFile.cs @@ -487,7 +487,7 @@ namespace UVtools.Core.FileFormats #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { if (FileEndsWith(".lgs")) // Longer Orange 10 { @@ -511,7 +511,7 @@ namespace UVtools.Core.FileFormats } //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings); - using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write)) + using (var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write)) { outputFile.WriteSerialize(HeaderSettings); outputFile.WriteBytes(EncodeImage(DATATYPE_RGB565_BE, Thumbnails[0])); @@ -566,13 +566,13 @@ 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); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Name != Header.NameValue) { - throw new FileLoadException("Not a valid LGS file!", fileFullPath); + throw new FileLoadException("Not a valid LGS file!", FileFullPath); } //if (HeaderSettings.PrinterModel is 10 or 30 or 120) @@ -594,54 +594,38 @@ namespace UVtools.Core.FileFormats } - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); var layerData = new LayerDef[LayerCount]; - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - foreach (var layerIndex in batch) + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + foreach (var batch in BatchLayersIndexes()) { - progress.Token.ThrowIfCancellationRequested(); + foreach (var layerIndex in batch) + { + progress.Token.ThrowIfCancellationRequested(); - layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); - layerData[layerIndex].Parent = this; - } + layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile); + layerData[layerIndex].Parent = this; + } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => - { - if (progress.Token.IsCancellationRequested) return; - using (var mat = layerData[layerIndex].Decode()) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { + if (progress.Token.IsCancellationRequested) return; + using var mat = layerData[layerIndex].Decode(); this[layerIndex] = new Layer((uint)layerIndex, mat, this); - } - progress.LockAndIncrement(); - }); + progress.LockAndIncrement(); + }); + } } LayerManager.RebuildLayersProperties(); } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); diff --git a/UVtools.Core/FileFormats/MDLPFile.cs b/UVtools.Core/FileFormats/MDLPFile.cs index 10d14e7..7736634 100644 --- a/UVtools.Core/FileFormats/MDLPFile.cs +++ b/UVtools.Core/FileFormats/MDLPFile.cs @@ -315,9 +315,9 @@ namespace UVtools.Core.FileFormats #endregion #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); var pageBreak = PageBreak.Bytes; Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); @@ -425,9 +425,9 @@ 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); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header)))); HeaderSettings = Helpers.Deserialize<Header>(inputFile); @@ -450,76 +450,62 @@ namespace UVtools.Core.FileFormats SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(inputFile); - LayerManager.Init(SlicerInfoSettings.LayerCount); + LayerManager.Init(SlicerInfoSettings.LayerCount, DecodeType == FileDecodeType.Partial); - - progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); - - var range = Enumerable.Range(0, (int)LayerCount); - - var linesBytes = new byte[LayerCount][]; - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - progress.Token.ThrowIfCancellationRequested(); - - foreach (var layerIndex in batch) + progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); + var linesBytes = new byte[LayerCount][]; + foreach (var batch in BatchLayersIndexes()) { - 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) { + var lineCount = BitExtensions.ToUIntBigEndian(inputFile.ReadBytes(4)); + + linesBytes[layerIndex] = new byte[lineCount * 6]; + inputFile.ReadBytes(linesBytes[layerIndex]); + inputFile.Seek(2, SeekOrigin.Current); - for (int i = 0; i < linesBytes[layerIndex].Length; i++) + progress.Token.ThrowIfCancellationRequested(); + } + + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + { + if (progress.Token.IsCancellationRequested) return; + using (var mat = EmguExtensions.InitMat(Resolution)) { - var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); - var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); - var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]); - CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), EmguExtensions.WhiteColor); - } + for (int i = 0; i < linesBytes[layerIndex].Length; i++) + { + var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); + var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]); + var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]); - linesBytes[layerIndex] = null; + CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), EmguExtensions.WhiteColor); + } - this[layerIndex] = new Layer((uint)layerIndex, mat, this); - } + linesBytes[layerIndex] = null; - progress.LockAndIncrement(); - }); + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + } + + progress.LockAndIncrement(); + }); + } + } + else // Partial read + { + inputFile.Seek(-Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.End); } HeaderSettings = Helpers.Deserialize<Header>(inputFile); HeaderSettings.Validate(); } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(SlicerInfoAddress, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings); diff --git a/UVtools.Core/FileFormats/OSLAFile.cs b/UVtools.Core/FileFormats/OSLAFile.cs index c80f680..8d487ab 100644 --- a/UVtools.Core/FileFormats/OSLAFile.cs +++ b/UVtools.Core/FileFormats/OSLAFile.cs @@ -465,9 +465,9 @@ namespace UVtools.Core.FileFormats Previews = null; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); FileSettings.Update(); var fileDefSize = Helpers.SerializeWriteFileStream(outputFile, FileSettings); HeaderSettings.TableSize = (uint)Helpers.Serializer.SizeOf(HeaderSettings); @@ -598,9 +598,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); FileSettings = Helpers.Deserialize<FileDef>(inputFile); Debug.Write("File -> "); Debug.WriteLine(FileSettings); @@ -646,7 +646,7 @@ namespace UVtools.Core.FileFormats inputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin); - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); var layerDef = new LayerDef[LayerCount]; @@ -672,34 +672,37 @@ namespace UVtools.Core.FileFormats } - - progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount); - foreach (var batch in BatchLayersIndexes()) + if (DecodeType == FileDecodeType.Full) { - var layerBytes = new byte[LayerCount][]; - - foreach (var layerIndex in batch) + progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount); + foreach (var batch in BatchLayersIndexes()) { - progress.Token.ThrowIfCancellationRequested(); + var layerBytes = new byte[LayerCount][]; - inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin); - layerBytes[layerIndex] = inputFile.ReadBytes(inputFile.ReadUIntLittleEndian()); - } + foreach (var layerIndex in batch) + { + progress.Token.ThrowIfCancellationRequested(); - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => - { - if (progress.Token.IsCancellationRequested) return; - using (var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution)) + inputFile.Seek(layerDataAddresses[layerIndex], SeekOrigin.Begin); + layerBytes[layerIndex] = inputFile.ReadBytes(inputFile.ReadUIntLittleEndian()); + } + + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { + if (progress.Token.IsCancellationRequested) return; + using var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution); layerBytes[layerIndex] = null; // Clean - var layer = new Layer((uint)layerIndex, mat, this); - layerDef[layerIndex].CopyTo(layer); - this[layerIndex] = layer; - } + this[layerIndex] = new Layer((uint)layerIndex, mat, this); - progress.LockAndIncrement(); - }); + progress.LockAndIncrement(); + }); + } + } + + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + { + layerDef[layerIndex].CopyTo(this[layerIndex]); } progress.Reset(OperationProgress.StatusDecodeGcode); @@ -711,24 +714,8 @@ namespace UVtools.Core.FileFormats UpdateGlobalPropertiesFromLayers(); } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); FileSettings.Update(); diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs index b69bf5f..8fc1c4b 100644 --- a/UVtools.Core/FileFormats/PHZFile.cs +++ b/UVtools.Core/FileFormats/PHZFile.cs @@ -927,7 +927,7 @@ namespace UVtools.Core.FileFormats LayersDefinitions = null; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { /*if (HeaderSettings.EncryptionKey == 0) { @@ -936,7 +936,7 @@ namespace UVtools.Core.FileFormats }*/ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount]; - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin); for (byte i = 0; i < ThumbnailsCount; i++) @@ -1046,15 +1046,15 @@ 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); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header)))); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Magic != MAGIC_PHZ) { - throw new FileLoadException("Not a valid PHZ file!", fileFullPath); + throw new FileLoadException("Not a valid PHZ file!", FileFullPath); } HeaderSettings.AntiAliasLevel = 1; @@ -1093,7 +1093,7 @@ namespace UVtools.Core.FileFormats } - LayerManager.Init(HeaderSettings.LayerCount); + LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); LayersDefinitions = new LayerDef[HeaderSettings.LayerCount]; progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount); @@ -1110,45 +1110,34 @@ namespace UVtools.Core.FileFormats Debug.Write($"LAYER {layerIndex} -> "); Debug.WriteLine(layerDef); - inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, () => + if (DecodeType == FileDecodeType.Full) { - layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); - }); + inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, + () => { layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); }); + } } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) return; - using (var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex)) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { - var layer = new Layer((uint)layerIndex, mat, this); - LayersDefinitions[layerIndex].CopyTo(layer); - this[layerIndex] = layer; - } - - progress.LockAndIncrement(); - }); - } - } + if (progress.Token.IsCancellationRequested) return; - public override void SaveAs(string filePath = null, OperationProgress progress = null) - { - if (RequireFullEncode) - { - if (!string.IsNullOrEmpty(filePath)) - { - FileFullPath = filePath; + using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex); + this[layerIndex] = new Layer((uint)layerIndex, mat, this); + progress.LockAndIncrement(); + }); } - Encode(FileFullPath, progress); - return; } - if (!string.IsNullOrEmpty(filePath)) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; + LayersDefinitions[layerIndex].CopyTo(this[layerIndex]); } + } + protected override void PartialSaveInternally(OperationProgress progress) + { using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs index 87c4368..d054234 100644 --- a/UVtools.Core/FileFormats/PhotonSFile.cs +++ b/UVtools.Core/FileFormats/PhotonSFile.cs @@ -434,10 +434,10 @@ namespace UVtools.Core.FileFormats #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { //throw new NotSupportedException("PhotonS is read-only format, please use pws instead!"); - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.WriteSerialize(HeaderSettings); outputFile.WriteBytes(EncodeImage(DATATYPE_BGR565, Thumbnails[0])); outputFile.WriteSerialize(LayerSettings); @@ -474,13 +474,13 @@ 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); HeaderSettings = Helpers.Deserialize<Header>(inputFile); if (HeaderSettings.Tag1 != Header.TAG1 || HeaderSettings.Tag2 != Header.TAG2) { - throw new FileLoadException("Not a valid PHOTONS file! TAGs doesn't match", fileFullPath); + throw new FileLoadException("Not a valid PHOTONS file! TAGs doesn't match", FileFullPath); } int previewSize = (int) (HeaderSettings.PreviewResolutionX * HeaderSettings.PreviewResolutionY * 2); @@ -495,7 +495,7 @@ namespace UVtools.Core.FileFormats Debug.WriteLine(LayerSettings); - LayerManager.Init(LayerSettings.LayerCount); + LayerManager.Init(LayerSettings.LayerCount, DecodeType == FileDecodeType.Partial); var layersDefinitions = new LayerDef[LayerSettings.LayerCount]; progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); @@ -508,7 +508,8 @@ namespace UVtools.Core.FileFormats var layerDef = Helpers.Deserialize<LayerDef>(inputFile); layersDefinitions[layerIndex] = layerDef; - layerDef.EncodedRle = inputFile.ReadBytes(layerDef.RleDataSize); + if (DecodeType == FileDecodeType.Full) layerDef.EncodedRle = inputFile.ReadBytes(layerDef.RleDataSize); + else inputFile.Seek(layerDef.RleDataSize, SeekOrigin.Current); Debug.Write($"LAYER {layerIndex} -> "); Debug.WriteLine(layerDef); @@ -521,40 +522,23 @@ namespace UVtools.Core.FileFormats } } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) return; - using (var mat = layersDefinitions[layerIndex].Decode()) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { + if (progress.Token.IsCancellationRequested) return; + using var mat = layersDefinitions[layerIndex].Decode(); this[layerIndex] = new Layer((uint)layerIndex, mat, this); - } - - progress.LockAndIncrement(); - }); + progress.LockAndIncrement(); + }); + } } LayerManager.RebuildLayersProperties(); } - 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; - } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(0, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index 33176aa..246d6b2 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -1256,7 +1256,7 @@ namespace UVtools.Core.FileFormats LayersDefinition = null; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { HeaderSettings.PixelSizeUm = PixelSizeMicronsMax; @@ -1277,7 +1277,7 @@ namespace UVtools.Core.FileFormats FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings); - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.Write); outputFile.Seek((int)FileMarkSettings.HeaderAddress, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); @@ -1348,9 +1348,9 @@ namespace UVtools.Core.FileFormats Helpers.SerializeWriteFileStream(outputFile, FileMarkSettings); } - 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); FileMarkSettings = Helpers.Deserialize<FileMark>(inputFile); Debug.Write("FileMark -> "); @@ -1359,17 +1359,14 @@ namespace UVtools.Core.FileFormats if (!FileMarkSettings.Mark.Equals(FileMark.SectionMarkFile)) { throw new FileLoadException( - $"Invalid Filemark {FileMarkSettings.Mark}, expected {FileMark.SectionMarkFile}", fileFullPath); + $"Invalid Filemark {FileMarkSettings.Mark}, expected {FileMark.SectionMarkFile}", FileFullPath); } if (FileMarkSettings.Version is not VERSION_1 and not VERSION_515) { - throw new FileLoadException($"Invalid Version {FileMarkSettings.Version}, expected {VERSION_1} or {VERSION_515}", - fileFullPath); + throw new FileLoadException($"Invalid Version {FileMarkSettings.Version}, expected {VERSION_1} or {VERSION_515}", FileFullPath); } - FileFullPath = fileFullPath; - inputFile.Seek(FileMarkSettings.HeaderAddress, SeekOrigin.Begin); HeaderSettings = Helpers.Deserialize<Header>(inputFile); @@ -1402,7 +1399,7 @@ namespace UVtools.Core.FileFormats Debug.Write("LayersDefinition -> "); Debug.WriteLine(LayersDefinition); - LayerManager.Init(LayersDefinition.LayerCount); + LayerManager.Init(LayersDefinition.LayerCount, DecodeType == FileDecodeType.Partial); LayersDefinition.Layers = new LayerDef[LayerCount]; LayersDefinition.Validate(); @@ -1418,52 +1415,43 @@ namespace UVtools.Core.FileFormats LayersDefinition[layerIndex].Parent = this; Debug.WriteLine($"Layer {layerIndex}: {LayersDefinition[layerIndex]}"); - - inputFile.SeekDoWorkAndRewind(LayersDefinition[layerIndex].DataAddress, () => + if (DecodeType == FileDecodeType.Full) { - LayersDefinition[layerIndex].EncodedRle = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength); - }); + inputFile.SeekDoWorkAndRewind(LayersDefinition[layerIndex].DataAddress, + () => + { + LayersDefinition[layerIndex].EncodedRle = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength); + }); + } } - Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => + if (DecodeType == FileDecodeType.Full) { - if (progress.Token.IsCancellationRequested) return; - using (var mat = LayersDefinition[layerIndex].Decode()) + Parallel.ForEach(batch, CoreSettings.ParallelOptions, layerIndex => { - var layer = new Layer((uint)layerIndex, mat, this) + if (progress.Token.IsCancellationRequested) return; + + using var mat = LayersDefinition[layerIndex].Decode(); + this[layerIndex] = new Layer((uint)layerIndex, mat, this) { PositionZ = LayersDefinition.Layers .Where((_, i) => i <= layerIndex) .Sum(def => def.LayerHeight), }; - LayersDefinition[layerIndex].CopyTo(layer); - this[layerIndex] = layer; - } - - progress.LockAndIncrement(); - }); - } - } - public override void SaveAs(string filePath = null, OperationProgress progress = null) - { - if (RequireFullEncode) - { - if (!string.IsNullOrEmpty(filePath)) - { - FileFullPath = filePath; + progress.LockAndIncrement(); + }); } - Encode(FileFullPath, progress); - return; } - - if (!string.IsNullOrEmpty(filePath)) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; + LayersDefinition[layerIndex].CopyTo(this[layerIndex]); } + } + protected override void PartialSaveInternally(OperationProgress progress) + { HeaderSettings.PerLayerOverride = LayerManager.AllLayersAreUsingGlobalParameters ? 0 : 1u; using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs index feac9dd..34fc91c 100644 --- a/UVtools.Core/FileFormats/SL1File.cs +++ b/UVtools.Core/FileFormats/SL1File.cs @@ -533,13 +533,13 @@ namespace UVtools.Core.FileFormats Statistics.Clear(); } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - var filename = fileFullPath; + var filename = FileFullPath; if (filename.EndsWith(TemporaryFileAppend)) filename = Path.GetFileNameWithoutExtension(filename); // tmp filename = Path.GetFileNameWithoutExtension(filename); // sl1 OutputConfigSettings.JobDir = filename; - using ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); + using ZipArchive outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); var entry = outputFile.CreateEntry("config.ini"); using (TextWriter tw = new StreamWriter(entry.Open())) { @@ -596,7 +596,7 @@ namespace UVtools.Core.FileFormats } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { PrinterSettings = new Printer(); MaterialSettings = new Material(); @@ -605,7 +605,7 @@ namespace UVtools.Core.FileFormats Statistics.ExecutionTime.Restart(); - using (var inputFile = ZipFile.OpenRead(fileFullPath)) + using (var inputFile = ZipFile.OpenRead(FileFullPath)) { List<string> iniFiles = new(); foreach (ZipArchiveEntry entity in inputFile.Entries) @@ -689,7 +689,7 @@ namespace UVtools.Core.FileFormats LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM); }); - LayerManager.Init(OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast); + LayerManager.Init(OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast, DecodeType == FileDecodeType.Partial); progress.ItemCount = LayerCount; @@ -698,7 +698,7 @@ namespace UVtools.Core.FileFormats if (!entity.Name.EndsWith(".png")) continue; if (entity.Name.StartsWith("thumbnail")) { - using Stream stream = entity.Open(); + using var stream = entity.Open(); Mat image = new(); CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image); byte thumbnailIndex = @@ -707,17 +707,21 @@ namespace UVtools.Core.FileFormats ? FileThumbnailSize.Small : FileThumbnailSize.Large); Thumbnails[thumbnailIndex] = image; - stream.Close(); //thumbnailIndex++; continue; } - - // - .png - 5 numbers - string layerStr = entity.Name.Substring(entity.Name.Length - 4 - 5, 5); - uint iLayer = uint.Parse(layerStr); - this[iLayer] = new Layer(iLayer, entity.Open(), LayerManager); + + 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, LayerManager); + } + progress.ProcessedItems++; } } @@ -729,26 +733,8 @@ namespace UVtools.Core.FileFormats Debug.WriteLine(Statistics); } - 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; - - } - using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); //InputFile.CreateEntry("Modified"); using (TextWriter tw = new StreamWriter(outputFile.PutFileContent("config.ini", string.Empty, ZipArchiveMode.Update).Open())) diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs index 913fc8c..9fabb76 100644 --- a/UVtools.Core/FileFormats/UVJFile.cs +++ b/UVtools.Core/FileFormats/UVJFile.cs @@ -467,7 +467,7 @@ namespace UVtools.Core.FileFormats JsonSettings.Layers = new List<LayerDef>(); } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { // Redo layer data if (JsonSettings.Layers is null) @@ -484,7 +484,7 @@ namespace UVtools.Core.FileFormats JsonSettings.Layers.Add(new LayerDef(this[layerIndex])); } - using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); outputFile.PutFileContent(FileConfigName, JsonConvert.SerializeObject(JsonSettings, Formatting.Indented), ZipArchiveMode.Create); if (CreatedThumbnailsCount > 0) @@ -514,20 +514,20 @@ namespace UVtools.Core.FileFormats } } - 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(FileConfigName); if (entry is null) { Clear(); - throw new FileLoadException($"{FileConfigName} not found", fileFullPath); + throw new FileLoadException($"{FileConfigName} not found", FileFullPath); } JsonSettings = Helpers.JsonDeserializeObject<Settings>(entry.Open()); - LayerManager.Init(JsonSettings.Properties.Size.Layers); + LayerManager.Init(JsonSettings.Properties.Size.Layers, DecodeType == FileDecodeType.Partial); entry = inputFile.GetEntry(FilePreviewTinyName); if (entry is not null) @@ -554,15 +554,16 @@ namespace UVtools.Core.FileFormats entry = inputFile.GetEntry($"{FolderImageName}/{layerIndex:D8}.png"); if (entry is null) continue; - using var stream = entry.Open(); - var layer = new Layer(layerIndex, stream, LayerManager); + if (DecodeType == FileDecodeType.Full) + { + using var stream = entry.Open(); + this[layerIndex] = new Layer(layerIndex, stream, LayerManager); + } if (JsonSettings.Layers?.Count > layerIndex) { - JsonSettings.Layers[(int)layerIndex].CopyTo(layer); + JsonSettings.Layers[(int)layerIndex].CopyTo(this[layerIndex]); } - - this[layerIndex] = layer; } progress.ProcessedItems++; @@ -571,25 +572,8 @@ namespace UVtools.Core.FileFormats LayerManager.GetBoundingRectangle(progress); } - 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; - - } - if (JsonSettings.Layers is null) { JsonSettings.Layers = new List<LayerDef>(); diff --git a/UVtools.Core/FileFormats/VDAFile.cs b/UVtools.Core/FileFormats/VDAFile.cs index f8353ed..8f83d41 100644 --- a/UVtools.Core/FileFormats/VDAFile.cs +++ b/UVtools.Core/FileFormats/VDAFile.cs @@ -302,10 +302,10 @@ namespace UVtools.Core.FileFormats return false; } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); - var manifestFilename = Path.GetFileName(fileFullPath). + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); + var manifestFilename = Filename. Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml"). Replace($".{FileExtensions[0].Extension}", ".xml"); @@ -328,7 +328,7 @@ namespace UVtools.Core.FileFormats serializer.Serialize(stream, ManifestFile, ns); } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read)) { @@ -336,7 +336,7 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException($".xml manifest not found", fileFullPath); + throw new FileLoadException($".xml manifest not found", FileFullPath); } try @@ -348,11 +348,11 @@ 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); } - LayerManager.Init(ManifestFile.Slices.LayerCount); + LayerManager.Init(ManifestFile.Slices.LayerCount, DecodeType == FileDecodeType.Partial); progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); @@ -364,11 +364,14 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException($"Layer {filename} not found", fileFullPath); + throw new FileLoadException($"Layer {filename} not found", FileFullPath); } - using var stream = entry.Open(); - this[layerIndex] = new Layer(layerIndex, stream, LayerManager); + if (DecodeType == FileDecodeType.Full) + { + using var stream = entry.Open(); + this[layerIndex] = new Layer(layerIndex, stream, LayerManager); + } progress++; } @@ -377,24 +380,8 @@ namespace UVtools.Core.FileFormats LayerManager.GetBoundingRectangle(progress); } - 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; - } - using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); bool deleted; diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs index 7d725e3..db5fe12 100644 --- a/UVtools.Core/FileFormats/VDTFile.cs +++ b/UVtools.Core/FileFormats/VDTFile.cs @@ -149,6 +149,42 @@ namespace UVtools.Core.FileFormats [JsonProperty("retract_distance2")] public float RetractHeight2 { get; set; } = DefaultRetractHeight2; [JsonProperty("retract_speed2")] public float RetractSpeed2 { get; set; } = DefaultRetractSpeed2; [JsonProperty("light_pwm")] public byte LightPWM { get; set; } = DefaultLightPWM; + + public void SetFrom(Layer layer) + { + PositionZ = layer.PositionZ; + LightOffDelay = layer.LightOffDelay; + WaitTimeBeforeCure = layer.WaitTimeBeforeCure; + ExposureTime = layer.ExposureTime; + WaitTimeAfterCure = layer.WaitTimeAfterCure; + LiftHeight = layer.LiftHeight; + LiftSpeed = layer.LiftSpeed; + LiftHeight2 = layer.LiftHeight2; + LiftSpeed2 = layer.LiftSpeed2; + WaitTimeAfterLift = layer.WaitTimeAfterLift; + RetractSpeed = layer.RetractSpeed; + RetractHeight2 = layer.RetractHeight2; + RetractSpeed2 = layer.RetractSpeed2; + LightPWM = layer.LightPWM; + } + + public void CopyTo(Layer layer) + { + layer.PositionZ = PositionZ; + layer.LightOffDelay = LightOffDelay; + layer.WaitTimeBeforeCure = WaitTimeBeforeCure; + layer.ExposureTime = ExposureTime; + layer.WaitTimeAfterCure = WaitTimeAfterCure; + layer.LiftHeight = LiftHeight; + layer.LiftSpeed = LiftSpeed; + layer.LiftHeight2 = LiftHeight2; + layer.LiftSpeed2 = LiftSpeed2; + layer.WaitTimeAfterLift = WaitTimeAfterLift; + layer.RetractSpeed = RetractSpeed; + layer.RetractHeight2 = RetractHeight2; + layer.RetractSpeed2 = RetractSpeed2; + layer.LightPWM = LightPWM; + } } #endregion @@ -566,12 +602,12 @@ namespace UVtools.Core.FileFormats } } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { // Redo layer data RebuildVDTLayers(); - using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); outputFile.PutFileContent(FileManifestName, JsonConvert.SerializeObject(ManifestFile, Formatting.Indented), ZipArchiveMode.Create); if (CreatedThumbnailsCount > 0) @@ -598,20 +634,20 @@ namespace UVtools.Core.FileFormats } } - 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(FileManifestName); if (entry is null) { Clear(); - throw new FileLoadException($"{FileManifestName} not found", fileFullPath); + throw new FileLoadException($"{FileManifestName} not found", FileFullPath); } ManifestFile = Helpers.JsonDeserializeObject<VDTManifest>(entry.Open()); - LayerManager.Init((uint) ManifestFile.Layers.Length); + LayerManager.Init((uint) ManifestFile.Layers.Length, DecodeType == FileDecodeType.Partial); for (int i = 0; i < FilePreviewNames.Length; i++) { @@ -631,24 +667,14 @@ namespace UVtools.Core.FileFormats var manifestLayer = ManifestFile.Layers[layerIndex]; entry = inputFile.GetEntry($"{layerIndex}.png"); if (entry is null) continue; - using var stream = entry.Open(); - this[layerIndex] = new Layer(layerIndex, stream, LayerManager) + + if (DecodeType == FileDecodeType.Full) { - PositionZ = manifestLayer.PositionZ, - LightOffDelay = manifestLayer.LightOffDelay, - WaitTimeBeforeCure = manifestLayer.WaitTimeBeforeCure, - ExposureTime = manifestLayer.ExposureTime, - WaitTimeAfterCure = manifestLayer.WaitTimeAfterCure, - LiftHeight = manifestLayer.LiftHeight, - LiftSpeed = manifestLayer.LiftSpeed, - LiftHeight2 = manifestLayer.LiftHeight2, - LiftSpeed2 = manifestLayer.LiftSpeed2, - WaitTimeAfterLift = manifestLayer.WaitTimeAfterLift, - RetractSpeed = manifestLayer.RetractSpeed, - RetractHeight2 = manifestLayer.RetractHeight2, - RetractSpeed2 = manifestLayer.RetractSpeed2, - LightPWM = manifestLayer.LightPWM, - }; + using var stream = entry.Open(); + this[layerIndex] = new Layer(layerIndex, stream, LayerManager); + } + + manifestLayer.CopyTo(this[layerIndex]); } progress.ProcessedItems++; @@ -657,25 +683,8 @@ namespace UVtools.Core.FileFormats LayerManager.GetBoundingRectangle(progress); } - 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; - - } - RebuildVDTLayers(); using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); outputFile.PutFileContent(FileManifestName, JsonConvert.SerializeObject(ManifestFile, Formatting.Indented), ZipArchiveMode.Update); diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs index cb4710a..37728c9 100644 --- a/UVtools.Core/FileFormats/ZCodeFile.cs +++ b/UVtools.Core/FileFormats/ZCodeFile.cs @@ -467,9 +467,9 @@ namespace UVtools.Core.FileFormats #region Methods - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { - using ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); if (Thumbnails.Length > 0 && Thumbnails[0] is not null) { using var thumbnailsStream = outputFile.CreateEntry(PreviewFilename).Open(); @@ -497,14 +497,14 @@ namespace UVtools.Core.FileFormats outputFile.PutFileContent(GCodeFilename, EncryptGCode(progress), ZipArchiveMode.Create); } - protected override void DecodeInternally(string fileFullPath, OperationProgress progress) + protected override void DecodeInternally(OperationProgress progress) { using var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read); var entry = inputFile.GetEntry(ManifestFilename); if (entry is null) { Clear(); - throw new FileLoadException($"{ManifestFilename} not found", fileFullPath); + throw new FileLoadException($"{ManifestFilename} not found", FileFullPath); } try @@ -516,14 +516,14 @@ 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); } entry = inputFile.GetEntry(GCodeFilename); if (entry is null) { Clear(); - throw new FileLoadException($"{GCodeFilename} not found", fileFullPath); + throw new FileLoadException($"{GCodeFilename} not found", FileFullPath); } var encryptEngine = new RsaEngine(); @@ -551,7 +551,7 @@ namespace UVtools.Core.FileFormats tr.Close(); } - LayerManager.Init(ManifestFile.Job.LayerCount); + LayerManager.Init(ManifestFile.Job.LayerCount, DecodeType == FileDecodeType.Partial); progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount); //var gcode = GCode.ToString(); @@ -564,12 +564,15 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException($"Layer {layerIndex+1} not found", fileFullPath); + throw new FileLoadException($"Layer {layerIndex+1} not found", FileFullPath); } - using var stream = entry.Open(); - this[layerIndex] = new Layer(layerIndex, stream, LayerManager); - + if (DecodeType == FileDecodeType.Full) + { + using var stream = entry.Open(); + this[layerIndex] = new Layer(layerIndex, stream, LayerManager); + } + progress++; } @@ -585,24 +588,8 @@ namespace UVtools.Core.FileFormats LayerManager.GetBoundingRectangle(progress); } - 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; - } - using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".gcode") || zipEntry.Name.EndsWith(".xml")).ToArray(); diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs index 34f3839..e8d7eaf 100644 --- a/UVtools.Core/FileFormats/ZCodexFile.cs +++ b/UVtools.Core/FileFormats/ZCodexFile.cs @@ -374,7 +374,7 @@ namespace UVtools.Core.FileFormats LayersSettings.Clear(); } - protected override void EncodeInternally(string fileFullPath, OperationProgress progress) + protected override void EncodeInternally(OperationProgress progress) { float usedMaterial = MaterialMilliliters / LayerCount; ResinMetadataSettings.Layers.Clear(); @@ -387,87 +387,83 @@ namespace UVtools.Core.FileFormats }); } - using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create)) - { - outputFile.PutFileContent("ResinMetadata", JsonConvert.SerializeObject(ResinMetadataSettings, Formatting.Indented), ZipArchiveMode.Create); - outputFile.PutFileContent("UserSettingsData", JsonConvert.SerializeObject(UserSettings, Formatting.Indented), ZipArchiveMode.Create); - outputFile.PutFileContent("ZCodeMetadata", JsonConvert.SerializeObject(ZCodeMetadataSettings, Formatting.Indented), ZipArchiveMode.Create); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Create); + outputFile.PutFileContent("ResinMetadata", JsonConvert.SerializeObject(ResinMetadataSettings, Formatting.Indented), ZipArchiveMode.Create); + outputFile.PutFileContent("UserSettingsData", JsonConvert.SerializeObject(UserSettings, Formatting.Indented), ZipArchiveMode.Create); + outputFile.PutFileContent("ZCodeMetadata", JsonConvert.SerializeObject(ZCodeMetadataSettings, Formatting.Indented), ZipArchiveMode.Create); - if (CreatedThumbnailsCount > 0) - { - using (var stream = outputFile.CreateEntry("Preview.png").Open()) - { - stream.WriteBytes(Thumbnails[0].GetPngByes()); - stream.Close(); - } - } + if (CreatedThumbnailsCount > 0) + { + using var stream = outputFile.CreateEntry("Preview.png").Open(); + stream.WriteBytes(Thumbnails[0].GetPngByes()); + stream.Close(); + } - GCode.Clear(); + GCode.Clear(); - float lastZPosition = 0; - for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) - { - progress.Token.ThrowIfCancellationRequested(); + float lastZPosition = 0; + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + { + progress.Token.ThrowIfCancellationRequested(); - Layer layer = this[layerIndex]; - GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}"); + var layer = this[layerIndex]; + GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}"); - if (lastZPosition != layer.PositionZ) + if (lastZPosition != layer.PositionZ) + { + if (layer.LiftHeight > 0) { - if (layer.LiftHeight > 0) - { - GCode.AppendLine($"G1 Z{layer.LiftHeight} F{layer.LiftSpeed}"); - GCode.AppendLine($"G1 Z-{Layer.RoundHeight(layer.LiftHeight - layer.PositionZ + lastZPosition)} F{layer.RetractSpeed}"); - } - else - { - GCode.AppendLine($"G1 Z{Layer.RoundHeight(layer.PositionZ- lastZPosition)} F{layer.LiftSpeed}"); - } + GCode.AppendLine($"G1 Z{layer.LiftHeight} F{layer.LiftSpeed}"); + GCode.AppendLine($"G1 Z-{Layer.RoundHeight(layer.LiftHeight - layer.PositionZ + lastZPosition)} F{layer.RetractSpeed}"); } - /*else + else + { + GCode.AppendLine($"G1 Z{Layer.RoundHeight(layer.PositionZ- lastZPosition)} F{layer.LiftSpeed}"); + } + } + /*else { //GCode.AppendLine($";G1 Z{LiftHeight} F{LiftSpeed}; Already here"); //GCode.AppendLine($";G1 Z-{LiftHeight - layer.PositionZ + lastZPosition} F{RetractSpeed}; Already here"); }*/ - //GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}"); - //GCode.AppendLine($"G1 Z-{LiftHeight - LayerHeight} F{RetractSpeed}"); - GCode.AppendLine(GCodeKeywordDelayBlank); - GCode.AppendLine("M106 S255"); - GCode.AppendLine(GCodeKeywordDelayModel); - GCode.AppendLine("M106 S0"); - - - var layerimagePath = $"{FolderImages}/{FolderImageName}{layerIndex:D5}.png"; - using (Stream stream = outputFile.CreateEntry(layerimagePath).Open()) - { - //image.Save(stream, Helpers.PngEncoder); - var byteArr = this[layerIndex].CompressedBytes; - stream.Write(byteArr, 0, byteArr.Length); - stream.Close(); - } + //GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}"); + //GCode.AppendLine($"G1 Z-{LiftHeight - LayerHeight} F{RetractSpeed}"); + GCode.AppendLine(GCodeKeywordDelayBlank); + GCode.AppendLine("M106 S255"); + GCode.AppendLine(GCodeKeywordDelayModel); + GCode.AppendLine("M106 S0"); - lastZPosition = layer.PositionZ; - progress++; + 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(); } - GCode.AppendLine($"G1 Z40.0 F{UserSettings.ZLiftFeedRate}"); - GCode.AppendLine("M18"); + lastZPosition = layer.PositionZ; - outputFile.PutFileContent("ResinGCodeData", GCode.ToString(), ZipArchiveMode.Create); + progress++; } + + GCode.AppendLine($"G1 Z40.0 F{UserSettings.ZLiftFeedRate}"); + GCode.AppendLine("M18"); + + outputFile.PutFileContent("ResinGCodeData", GCode.ToString(), 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("ResinMetadata"); if (entry is null) { Clear(); - throw new FileLoadException("ResinMetadata not found", fileFullPath); + throw new FileLoadException("ResinMetadata not found", FileFullPath); } ResinMetadataSettings = Helpers.JsonDeserializeObject<ResinMetadata>(entry.Open()); @@ -476,7 +472,7 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException("UserSettingsData not found", fileFullPath); + throw new FileLoadException("UserSettingsData not found", FileFullPath); } UserSettings = Helpers.JsonDeserializeObject<UserSettingsdata>(entry.Open()); @@ -485,7 +481,7 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException("ZCodeMetadata not found", fileFullPath); + throw new FileLoadException("ZCodeMetadata not found", FileFullPath); } ZCodeMetadataSettings = Helpers.JsonDeserializeObject<ZCodeMetadata>(entry.Open()); @@ -494,10 +490,10 @@ namespace UVtools.Core.FileFormats if (entry is null) { Clear(); - throw new FileLoadException("ResinGCodeData not found", fileFullPath); + throw new FileLoadException("ResinGCodeData not found", FileFullPath); } - LayerManager.Init(ResinMetadataSettings.TotalLayersCount); + LayerManager.Init(ResinMetadataSettings.TotalLayersCount, DecodeType == FileDecodeType.Partial); GCode.Clear(); using (TextReader tr = new StreamReader(entry.Open())) { @@ -577,14 +573,18 @@ M106 S0 LayersSettings[layerIndex].LayerFileIndex = layerFileIndex; LayersSettings[layerIndex].LayerEntry = inputFile.GetEntry(layerimagePath); - this[layerIndex] = new Layer((uint) layerIndex, LayersSettings[layerIndex].LayerEntry.Open(), LayerManager) + + if (DecodeType == FileDecodeType.Full) { - PositionZ = currentHeight, - LiftHeight = liftHeight, - LiftSpeed = liftSpeed, - RetractSpeed = retractSpeed, - LightPWM = pwm - }; + using var stream = LayersSettings[layerIndex].LayerEntry.Open(); + this[layerIndex] = new Layer((uint)layerIndex, stream, LayerManager); + } + + this[layerIndex].PositionZ = currentHeight; + this[layerIndex].LiftHeight = liftHeight; + this[layerIndex].LiftSpeed = liftSpeed; + this[layerIndex].RetractSpeed = retractSpeed; + this[layerIndex].LightPWM = pwm; layerIndex++; progress++; @@ -595,9 +595,9 @@ M106 S0 } entry = inputFile.GetEntry("Preview.png"); - if (!ReferenceEquals(entry, null)) + if (entry is not null) { - using Stream stream = entry.Open(); + using var stream = entry.Open(); CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[0]); stream.Close(); } @@ -622,36 +622,15 @@ M106 S0 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; - } - - if (!string.IsNullOrEmpty(filePath)) - { - File.Copy(FileFullPath, filePath, true); - FileFullPath = filePath; - - } - - using (var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update)) - { - outputFile.PutFileContent("ResinMetadata", JsonConvert.SerializeObject(ResinMetadataSettings, Formatting.Indented), ZipArchiveMode.Update); - outputFile.PutFileContent("UserSettingsData", JsonConvert.SerializeObject(UserSettings, Formatting.Indented), ZipArchiveMode.Update); - outputFile.PutFileContent("ZCodeMetadata", JsonConvert.SerializeObject(ZCodeMetadataSettings, Formatting.Indented), ZipArchiveMode.Update); - outputFile.PutFileContent("ResinGCodeData", GCodeStr, ZipArchiveMode.Update); - } - - //Decode(FileFullPath, progress); + using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update); + outputFile.PutFileContent("ResinMetadata", JsonConvert.SerializeObject(ResinMetadataSettings, Formatting.Indented), ZipArchiveMode.Update); + outputFile.PutFileContent("UserSettingsData", JsonConvert.SerializeObject(UserSettings, Formatting.Indented), ZipArchiveMode.Update); + outputFile.PutFileContent("ZCodeMetadata", JsonConvert.SerializeObject(ZCodeMetadataSettings, Formatting.Indented), ZipArchiveMode.Update); + outputFile.PutFileContent("ResinGCodeData", GCodeStr, ZipArchiveMode.Update); } - #endregion + #endregion } } diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs index 7f425c3..055d888 100644 --- a/UVtools.Core/Layers/Layer.cs +++ b/UVtools.Core/Layers/Layer.cs @@ -479,6 +479,7 @@ namespace UVtools.Core.Layers { get { + if (!HaveImage) return null; Mat mat = new(); CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat); return mat; @@ -604,6 +605,8 @@ namespace UVtools.Core.Layers _lightPWM = SlicerFile.GetBottomOrNormalValue(this, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); } + public Layer(uint index, FileFormat slicerFile) : this(index, slicerFile.LayerManager) {} + public Layer(uint index, byte[] compressedBytes, LayerManager parentLayerManager) : this(index, parentLayerManager) { CompressedBytes = compressedBytes; @@ -625,8 +628,8 @@ namespace UVtools.Core.Layers public Layer(uint index, Mat layerMat, FileFormat slicerFile) : this(index, layerMat, slicerFile.LayerManager) { } - public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream.ToArray(), parentLayerManager) { } - public Layer(uint index, Stream stream, FileFormat slicerFile) : this(index, stream.ToArray(), slicerFile.LayerManager) { } + public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream?.ToArray(), parentLayerManager) { } + public Layer(uint index, Stream stream, FileFormat slicerFile) : this(index, stream?.ToArray(), slicerFile.LayerManager) { } #endregion #region Equatables @@ -671,7 +674,7 @@ namespace UVtools.Core.Layers if (other is null) return false; if (ReferenceEquals(this, other)) return true; if (_index != other._index) return false; - if (_compressedBytes.Length != other._compressedBytes.Length) return false; + if (_compressedBytes?.Length != other._compressedBytes?.Length) return false; return _compressedBytes.AsSpan().SequenceEqual(other._compressedBytes.AsSpan()); //return Equals(_compressedBytes, other._compressedBytes); } @@ -1112,7 +1115,7 @@ namespace UVtools.Core.Layers //layer.CompressedBytes = _compressedBytes.ToArray(); //Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes)); //return layer; - return new (_index, CompressedBytes.ToArray(), ParentLayerManager) + return new (_index, CompressedBytes?.ToArray(), ParentLayerManager) { _positionZ = _positionZ, _lightOffDelay = _lightOffDelay, diff --git a/UVtools.Core/Layers/LayerManager.cs b/UVtools.Core/Layers/LayerManager.cs index 4e551ff..2b1a1bc 100644 --- a/UVtools.Core/Layers/LayerManager.cs +++ b/UVtools.Core/Layers/LayerManager.cs @@ -176,9 +176,14 @@ namespace UVtools.Core } } - public void Init(uint layerCount) + public void Init(uint layerCount, bool initializeLayers = false) { _layers = new Layer[layerCount]; + if (!initializeLayers) return; + for (uint layerIndex = 0; layerIndex < layerCount; layerIndex++) + { + this[layerIndex] = new Layer(layerIndex, this); + } } public void Init(Layer[] layers) @@ -672,9 +677,10 @@ namespace UVtools.Core public Rectangle GetBoundingRectangle(OperationProgress progress = null) { - if (!_boundingRectangle.IsEmpty || LayerCount == 0 || this[0] is null) return _boundingRectangle; + var firstLayer = FirstLayer; + if (!_boundingRectangle.IsEmpty || LayerCount == 0 || firstLayer is null || !firstLayer.HaveImage) return _boundingRectangle; progress ??= new OperationProgress(OperationProgress.StatusOptimizingBounds, LayerCount - 1); - _boundingRectangle = this[0].BoundingRectangle; + _boundingRectangle = firstLayer.BoundingRectangle; if (_boundingRectangle.IsEmpty) // Safe checking { progress.Reset(OperationProgress.StatusOptimizingBounds, LayerCount-1); @@ -687,9 +693,9 @@ namespace UVtools.Core if (progress is null) return; progress.LockAndIncrement(); }); - _boundingRectangle = this[0].BoundingRectangle; + _boundingRectangle = firstLayer.BoundingRectangle; - if (progress is not null && progress.Token.IsCancellationRequested) + if (progress.Token.IsCancellationRequested) { _boundingRectangle = Rectangle.Empty; progress.Token.ThrowIfCancellationRequested(); diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs index 07a363f..7c5de4b 100644 --- a/UVtools.Core/Managers/ClipboardManager.cs +++ b/UVtools.Core/Managers/ClipboardManager.cs @@ -275,11 +275,11 @@ namespace UVtools.Core.Managers /// <param name="slicerFile"></param> public void Init(FileFormat slicerFile) { + Clear(); + SlicerFile = slicerFile; + if (slicerFile is null || slicerFile.DecodeType == FileFormat.FileDecodeType.Partial) return; SuppressRestoreWork(() => { - Clear(); - SlicerFile = slicerFile; - if (slicerFile is null) return; var clip = new ClipboardItem(SlicerFile, "Original layers", true); clip.AddRange(SlicerFile.LayerManager.CloneLayers()); Add(clip); diff --git a/UVtools.Core/Managers/IssueManager.cs b/UVtools.Core/Managers/IssueManager.cs index da771a0..48079d2 100644 --- a/UVtools.Core/Managers/IssueManager.cs +++ b/UVtools.Core/Managers/IssueManager.cs @@ -124,6 +124,8 @@ namespace UVtools.Core.Managers bool emptyLayersConfig = true, OperationProgress progress = null) { + if (SlicerFile.DecodeType == FileFormat.FileDecodeType.Partial) return null; + islandConfig ??= new IslandDetectionConfiguration(); overhangConfig ??= new OverhangDetectionConfiguration(); resinTrapConfig ??= new ResinTrapDetectionConfiguration(); diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs index f635df7..8bc2db6 100644 --- a/UVtools.Core/Operations/Operation.cs +++ b/UVtools.Core/Operations/Operation.cs @@ -7,15 +7,12 @@ */ using System; -using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Xml.Serialization; using Emgu.CV; -using Emgu.CV.Cuda; -using Emgu.CV.Util; using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Layers; @@ -121,6 +118,11 @@ namespace UVtools.Core.Operations public virtual bool PassActualLayerIndex => false; /// <summary> + /// Gets if this operation can run in a file open as partial mode + /// </summary> + public virtual bool CanRunInPartialMode => false; + + /// <summary> /// Gets if this operation can make use of ROI /// </summary> public virtual bool CanROI => true; @@ -502,6 +504,7 @@ namespace UVtools.Core.Operations public bool Execute(OperationProgress progress = null) { if (_slicerFile is null) throw new InvalidOperationException($"{Title} can't execute due the lacking of a file parent."); + if (_slicerFile.DecodeType == FileFormat.FileDecodeType.Partial && !CanRunInPartialMode) throw new InvalidOperationException($"The file was open in partial mode and the tool \"{Title}\" is unable to run in this mode.\nPlease reload the file in full mode in order to use this tool."); if (!IsValidated) { var msg = Validate(); diff --git a/UVtools.Core/Operations/OperationCalculator.cs b/UVtools.Core/Operations/OperationCalculator.cs index 9f50071..779272e 100644 --- a/UVtools.Core/Operations/OperationCalculator.cs +++ b/UVtools.Core/Operations/OperationCalculator.cs @@ -18,6 +18,9 @@ namespace UVtools.Core.Operations public class OperationCalculator : Operation { #region Overrides + + public override bool CanRunInPartialMode => true; + public override string Title => "Calculator"; public override string Description => null; diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs index d772222..53d4f6d 100644 --- a/UVtools.Core/Operations/OperationDynamicLifts.cs +++ b/UVtools.Core/Operations/OperationDynamicLifts.cs @@ -65,6 +65,8 @@ namespace UVtools.Core.Operations #region Overrides + public override bool CanRunInPartialMode => true; + public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal; public override string Title => "Dynamic lifts"; diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs index de8d37f..7e6e8f3 100644 --- a/UVtools.Core/Operations/OperationEditParameters.cs +++ b/UVtools.Core/Operations/OperationEditParameters.cs @@ -9,10 +9,8 @@ using System; using System.Linq; using System.Text; -using System.Threading.Tasks; using System.Xml.Serialization; using UVtools.Core.FileFormats; -using UVtools.Core.Objects; namespace UVtools.Core.Operations { @@ -29,6 +27,8 @@ namespace UVtools.Core.Operations #endregion #region Overrides + + public override bool CanRunInPartialMode => true; public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None; public override bool CanROI => false; diff --git a/UVtools.Core/Operations/OperationFadeExposureTime.cs b/UVtools.Core/Operations/OperationFadeExposureTime.cs index 6a9ffd9..328ea66 100644 --- a/UVtools.Core/Operations/OperationFadeExposureTime.cs +++ b/UVtools.Core/Operations/OperationFadeExposureTime.cs @@ -25,6 +25,7 @@ namespace UVtools.Core.Operations #endregion #region Overrides + public override bool CanRunInPartialMode => true; public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal; public override bool LayerIndexEndEnabled => false; public override string Title => "Fade exposure time"; diff --git a/UVtools.Core/Operations/OperationIPrintedThisFile.cs b/UVtools.Core/Operations/OperationIPrintedThisFile.cs index 36aec90..c36faeb 100644 --- a/UVtools.Core/Operations/OperationIPrintedThisFile.cs +++ b/UVtools.Core/Operations/OperationIPrintedThisFile.cs @@ -27,6 +27,8 @@ namespace UVtools.Core.Operations #region Overrides + public override bool CanRunInPartialMode => true; + public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None; public override bool CanROI => false; diff --git a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs index 7b378ad..387b43c 100644 --- a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs +++ b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs @@ -29,6 +29,9 @@ namespace UVtools.Core.Operations #endregion #region Overrides + + public override bool CanRunInPartialMode => true; + public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None; public override string Title => "Raise platform on print finish"; diff --git a/UVtools.Core/Operations/OperationScripting.cs b/UVtools.Core/Operations/OperationScripting.cs index a54326c..4ca04a1 100644 --- a/UVtools.Core/Operations/OperationScripting.cs +++ b/UVtools.Core/Operations/OperationScripting.cs @@ -30,6 +30,8 @@ namespace UVtools.Core.Operations #region Overrides + public override bool CanRunInPartialMode => true; + public override bool CanHaveProfiles => false; public override string Title => "Scripting"; diff --git a/UVtools.Core/Scripting/ScriptFileDialogInput.cs b/UVtools.Core/Scripting/ScriptFileDialogInput.cs new file mode 100644 index 0000000..a8b4aef --- /dev/null +++ b/UVtools.Core/Scripting/ScriptFileDialogInput.cs @@ -0,0 +1,41 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +using System.Collections.Generic; + +namespace UVtools.Core.Scripting +{ + public abstract class ScriptFileDialogInput : ScriptBaseInput<string> + { + public class ScriptFileDialogFilter + { + public string Name { get; set; } + public List<string> Extensions { get; set; } = new(); + } + + /// <summary> + /// Gets or sets the title for the dialog + /// </summary> + public string Title { get; set; } + + /// <summary> + /// Gets or sets the default directory to open the dialog in + /// </summary> + public string Directory { get; set; } + + /// <summary> + /// Gets or sets the initial filename to be on the dialog + /// </summary> + public string InitialFilename { get; set; } + + /// <summary> + /// Gets or sets the file filters on the dropdown list + /// </summary> + public List<ScriptFileDialogFilter> Filters { get; set; } + } +} diff --git a/UVtools.Core/Scripting/ScriptOpenFileDialogInput.cs b/UVtools.Core/Scripting/ScriptOpenFileDialogInput.cs new file mode 100644 index 0000000..209b0c5 --- /dev/null +++ b/UVtools.Core/Scripting/ScriptOpenFileDialogInput.cs @@ -0,0 +1,23 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +namespace UVtools.Core.Scripting +{ + public class ScriptOpenFileDialogInput : ScriptFileDialogInput + { + /// <summary> + /// Gets or sets if allow multiple file selection + /// </summary> + public bool AllowMultiple { get; set; } + + /// <summary> + /// Gets or sets the selected files + /// </summary> + public string[] Files {get; set; } + } +} diff --git a/UVtools.Core/Scripting/ScriptOpenFolderDialogInput.cs b/UVtools.Core/Scripting/ScriptOpenFolderDialogInput.cs new file mode 100644 index 0000000..5baa2f1 --- /dev/null +++ b/UVtools.Core/Scripting/ScriptOpenFolderDialogInput.cs @@ -0,0 +1,18 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +namespace UVtools.Core.Scripting +{ + public class ScriptOpenFolderDialogInput : ScriptBaseInput<string> + { + /// <summary> + /// Gets the title for the dialog + /// </summary> + public string Title { get; set; } + } +} diff --git a/UVtools.Core/Scripting/ScriptSaveFileDialogInput.cs b/UVtools.Core/Scripting/ScriptSaveFileDialogInput.cs new file mode 100644 index 0000000..e2d64c8 --- /dev/null +++ b/UVtools.Core/Scripting/ScriptSaveFileDialogInput.cs @@ -0,0 +1,18 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +namespace UVtools.Core.Scripting +{ + public class ScriptSaveFileDialogInput : ScriptFileDialogInput + { + /// <summary> + /// Gets or sets the default extension for the dialog + /// </summary> + public string DefaultExtension { get; set; } + } +} diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index dc66e2b..3d59718 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -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>2.24.4</Version> + <Version>2.25.0</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.ScriptSample/ScriptCloneSettings.cs b/UVtools.ScriptSample/ScriptCloneSettings.cs new file mode 100644 index 0000000..70a7704 --- /dev/null +++ b/UVtools.ScriptSample/ScriptCloneSettings.cs @@ -0,0 +1,427 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +using System; +using UVtools.Core.Scripting; +using System.IO; +using System.Collections.Generic; +using UVtools.Core.FileFormats; +using System.Threading.Tasks; +using UVtools.Core; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Linq; + +namespace UVtools.ScriptSample +{ + /// <summary> + /// Performs a black inset around objects + /// </summary> + public class ScriptCloneSettings : ScriptGlobals + { + ScriptCheckBoxInput Recursive = new() + { + Label = "Recursive", + ToolTip = "If unchecked, only files in the same folder are modified; if checked, files in all sub-folders are modified too", + Value = true + }; + + ScriptCheckBoxInput Report = new() + { + Label = "Generate report file", + ToolTip = "Optionally generate a report file in the same directory as the open file", + Value = true + }; + + ScriptCheckBoxInput OpenReport = new() + { + Label = "Open report file", + ToolTip = "Optionally open the result file when completed", + Value = true + }; + + ScriptOpenFolderDialogInput FolderPath = new() + { + Label = "Folder path", + ToolTip = "The folder path to process", + }; + + private enum ResultStatus + { + Exception, + UnknownFileType, + DifferentMachineTypes, + Success, + Unchanged, + } + + /// <summary> + /// Set configurations here, this function trigger just after load a script + /// </summary> + public void ScriptInit() + { + Script.Name = "Clone Settings"; + Script.Description = "Copies the print settings from the current file to all files in the same directory and, optionally, recursively below it"; + Script.Author = "Gina Venolia"; + Script.Version = new Version(0, 2); + Script.UserInputs.Add(Recursive); + Script.UserInputs.Add(Report); + Script.UserInputs.Add(OpenReport); + Script.UserInputs.Add(FolderPath); + FolderPath.Value = SlicerFile.FileDirectoryPath; + } + + /// <summary> + /// Validate user inputs here, this function trigger when user click on execute + /// </summary> + /// <returns>A error message, empty or null if validation passes.</returns> + public string ScriptValidate() + { + return null; + } + + /// <summary> + /// Execute the script, this function trigger when when user click on execute and validation passes + /// </summary> + /// <returns>True if executes successfully to the end, otherwise false.</returns> + public bool ScriptExecute() + { + Progress.CanCancel = true; + + // Gather the list of directories to operate on + Progress.Reset("Processing files..."); + + var directoryPaths = new List<string>(); + directoryPaths.Add(Path.GetDirectoryName(SlicerFile.FileFullPath)); + + if (Recursive.Value) + { + for (var i = 0; i < directoryPaths.Count; i++) + { + directoryPaths.AddRange(Directory.EnumerateDirectories(directoryPaths[i])); + } + } + + // Gather the list of files to operate on + var filePaths = new List<string>(); + foreach (var directoryPath in directoryPaths) + { + filePaths.AddRange(Directory.EnumerateFiles(directoryPath)); + } + + // Except for the file we started with + var normalizedFilePath = Path.GetFullPath(SlicerFile.FileFullPath); + filePaths.RemoveAll(x => Path.GetFullPath(x) == normalizedFilePath); + + // Process the files + Progress.Reset("Processing files...", (uint)filePaths.Count, 0); + + var results = new List<Tuple<ResultStatus, string, List<string>>>(); + foreach (var filePath in filePaths) + { + if (Progress.Token.IsCancellationRequested) return false; + + Tuple<ResultStatus, string, List<string>> result; + try + { + result = ProcessFile(filePath); + } + catch (Exception ex) + { + var deets = new List<string>(); + deets.Add(ex.GetType().Name); + deets.Add(ex.Message); + result = new Tuple<ResultStatus, string, List<string>>(ResultStatus.Exception, filePath, deets); + } + + results.Add(result); + + Progress++; + } + + // Generate the report + if (Report.Value) + { + var reportDirectory = Path.GetDirectoryName(SlicerFile.FileFullPath); + var reportFilePath = Path.Combine(reportDirectory, "CloneSettingsReport.txt"); + using (var writer = new StreamWriter(reportFilePath)) + { + writer.WriteLine(Script.Name + " " + Script.Version.ToString() + " by " + Script.Author); + writer.WriteLine("Source file: " + SlicerFile.FileFullPath); + writer.WriteLine(DateTime.Now.ToLongDateString() + ", " + DateTime.Now.ToLongTimeString()); + writer.WriteLine("Recursive: " + Recursive.Value.ToString()); + writer.WriteLine("Directories: " + directoryPaths.Count); + writer.WriteLine("Files: " + filePaths.Count); + writer.WriteLine(); + + foreach (var statusGroup in results.GroupBy(x => x.Item1)) + { + writer.WriteLine(statusGroup.Key.ToString()); + foreach (var result in statusGroup.OrderBy(x => x.Item2)) + { + writer.WriteLine("\t" + result.Item2); + if (result.Item3 is not null) + { + foreach (var detail in result.Item3) + { + writer.WriteLine("\t\t" + detail); + } + } + } + } + } + + if (OpenReport.Value) + { + var startInfo = new ProcessStartInfo(reportFilePath) + { + UseShellExecute = true + }; + Process.Start(startInfo); + } + } + + // return true if not cancelled by user + return true; + } + + private Tuple<ResultStatus, string, List<string>> ProcessFile(string filePath) + { + // Determine the type of file + var file = FileFormat.FindByExtensionOrFilePath(filePath, true); + if (file is null) + { + return new Tuple<ResultStatus, string, List<string>>(ResultStatus.UnknownFileType, filePath, null); + } + + // Load the file + file.Decode(filePath); + if (string.Compare(file.MachineName, SlicerFile.MachineName, true) != 0) + { + var deets = new List<string>(); + deets.Add("Source machine type: " + SlicerFile.MachineName); + deets.Add("Destination machine type: " + file.MachineName); + return new Tuple<ResultStatus, string, List<string>>(ResultStatus.DifferentMachineTypes, filePath, deets); + } + + // TODO: Validate that some parameters are the same in both files? + + // Change the parameters + var changed = false; + var details = new List<string>(); + + if (file.CanUseBottomLayerCount && file.BottomLayerCount != SlicerFile.BottomLayerCount) + { + details.Add($"Bottom Layer Count: {file.BottomLayerCount} to {SlicerFile.BottomLayerCount}"); + file.BottomLayerCount = SlicerFile.BottomLayerCount; + changed = true; + } + + if (file.CanUseBottomLightOffDelay && file.BottomLightOffDelay != SlicerFile.BottomLightOffDelay) + { + details.Add($"Bottom Light Off Delay: {file.BottomLightOffDelay} to {SlicerFile.BottomLightOffDelay}"); + file.BottomLightOffDelay = SlicerFile.BottomLightOffDelay; + changed = true; + } + + if (file.CanUseLightOffDelay && file.LightOffDelay != SlicerFile.LightOffDelay) + { + details.Add($"Light Off Delay: {file.LightOffDelay} to {SlicerFile.LightOffDelay}"); + file.LightOffDelay = SlicerFile.LightOffDelay; + changed = true; + } + + if (file.CanUseBottomWaitTimeBeforeCure && file.BottomWaitTimeBeforeCure != SlicerFile.BottomWaitTimeBeforeCure) + { + details.Add($"Bottom Wait Time Before Cure: {file.BottomWaitTimeBeforeCure} to {SlicerFile.BottomWaitTimeBeforeCure}"); + file.BottomWaitTimeBeforeCure = SlicerFile.BottomWaitTimeBeforeCure; + changed = true; + } + + if (file.CanUseWaitTimeBeforeCure && file.WaitTimeBeforeCure != SlicerFile.WaitTimeBeforeCure) + { + details.Add($"Wait Time Before Cure: {file.WaitTimeBeforeCure} to {SlicerFile.WaitTimeBeforeCure}"); + file.WaitTimeBeforeCure = SlicerFile.WaitTimeBeforeCure; + changed = true; + } + + if (file.CanUseBottomExposureTime && file.BottomExposureTime != SlicerFile.BottomExposureTime) + { + details.Add($"Bottom Exposure Time: {file.BottomExposureTime} to {SlicerFile.BottomExposureTime}"); + file.BottomExposureTime = SlicerFile.BottomExposureTime; + changed = true; + } + + if (file.CanUseExposureTime && file.ExposureTime != SlicerFile.ExposureTime) + { + details.Add($"Exposure Time: {file.ExposureTime} to {SlicerFile.ExposureTime}"); + file.ExposureTime = SlicerFile.ExposureTime; + changed = true; + } + + if (file.CanUseBottomWaitTimeAfterCure && file.BottomWaitTimeAfterCure != SlicerFile.BottomWaitTimeAfterCure) + { + details.Add($"Bottom Wait Time After Cure: {file.BottomWaitTimeAfterCure} to {SlicerFile.BottomWaitTimeAfterCure}"); + file.BottomWaitTimeAfterCure = SlicerFile.BottomWaitTimeAfterCure; + changed = true; + } + + if (file.CanUseWaitTimeAfterCure && file.WaitTimeAfterCure != SlicerFile.WaitTimeAfterCure) + { + details.Add($"Wait Time After Cure: {file.WaitTimeAfterCure} to {SlicerFile.WaitTimeAfterCure}"); + file.WaitTimeAfterCure = SlicerFile.WaitTimeAfterCure; + changed = true; + } + + if (file.CanUseBottomLiftHeight && file.BottomLiftHeight != SlicerFile.BottomLiftHeight) + { + details.Add($"Bottom Lift Height: {file.BottomLiftHeight} to {SlicerFile.BottomLiftHeight}"); + file.BottomLiftHeight = SlicerFile.BottomLiftHeight; + changed = true; + } + + if (file.CanUseBottomLiftSpeed && file.BottomLiftSpeed != SlicerFile.BottomLiftSpeed) + { + details.Add($"Bottom Lift Speed: {file.BottomLiftSpeed} to {SlicerFile.BottomLiftSpeed}"); + file.BottomLiftSpeed = SlicerFile.BottomLiftSpeed; + changed = true; + } + + if (file.CanUseLiftHeight && file.LiftHeight != SlicerFile.LiftHeight) + { + details.Add($"Lift Height: {file.LiftHeight} to {SlicerFile.LiftHeight}"); + file.LiftHeight = SlicerFile.LiftHeight; + changed = true; + } + + if (file.CanUseLiftSpeed && file.LiftSpeed != SlicerFile.LiftSpeed) + { + details.Add($"Lift Speed: {file.LiftSpeed} to {SlicerFile.LiftSpeed}"); + file.LiftSpeed = SlicerFile.LiftSpeed; + changed = true; + } + + if (file.CanUseBottomLiftHeight2 && file.BottomLiftHeight2 != SlicerFile.BottomLiftHeight2) + { + details.Add($"Bottom Lift Height 2: {file.BottomLiftHeight2} to {SlicerFile.BottomLiftHeight2}"); + file.BottomLiftHeight2 = SlicerFile.BottomLiftHeight2; + changed = true; + } + + if (file.CanUseBottomLiftSpeed2 && file.BottomLiftSpeed2 != SlicerFile.BottomLiftSpeed2) + { + details.Add($"Bottom Lift Speed2: {file.BottomLiftSpeed2} to {SlicerFile.BottomLiftSpeed2}"); + file.BottomLiftSpeed2 = SlicerFile.BottomLiftSpeed2; + changed = true; + } + + if (file.CanUseLiftHeight2 && file.LiftHeight2 != SlicerFile.LiftHeight2) + { + details.Add($"Lift Height 2: {file.LiftHeight2} to {SlicerFile.LiftHeight2}"); + file.LiftHeight2 = SlicerFile.LiftHeight2; + changed = true; + } + + if (file.CanUseLiftSpeed2 && file.LiftSpeed2 != SlicerFile.LiftSpeed2) + { + details.Add($"Lift Speed 2: {file.LiftSpeed2} to {SlicerFile.LiftSpeed2}"); + file.LiftSpeed2 = SlicerFile.LiftSpeed2; + changed = true; + } + + if (file.CanUseBottomWaitTimeAfterLift && file.BottomWaitTimeAfterLift != SlicerFile.BottomWaitTimeAfterLift) + { + details.Add($"Bottom Wait Time After Lift: {file.BottomWaitTimeAfterLift} to {SlicerFile.BottomWaitTimeAfterLift}"); + file.BottomWaitTimeAfterLift = SlicerFile.BottomWaitTimeAfterLift; + changed = true; + } + + if (file.CanUseWaitTimeAfterLift && file.WaitTimeAfterLift != SlicerFile.WaitTimeAfterLift) + { + details.Add($"Wait Time After Lift: {file.WaitTimeAfterLift} to {SlicerFile.WaitTimeAfterLift}"); + file.WaitTimeAfterLift = SlicerFile.WaitTimeAfterLift; + changed = true; + } + + if (file.CanUseBottomRetractSpeed && file.BottomRetractSpeed != SlicerFile.BottomRetractSpeed) + { + details.Add($"Bottom Retract Speed: {file.BottomRetractSpeed} to {SlicerFile.BottomRetractSpeed}"); + file.BottomRetractSpeed = SlicerFile.BottomRetractSpeed; + changed = true; + } + + if (file.CanUseRetractSpeed && file.RetractSpeed != SlicerFile.RetractSpeed) + { + details.Add($"Retract Speed: {file.RetractSpeed} to {SlicerFile.RetractSpeed}"); + file.RetractSpeed = SlicerFile.RetractSpeed; + changed = true; + } + + if (file.CanUseBottomRetractHeight2 && file.BottomRetractHeight2 != SlicerFile.BottomRetractHeight2) + { + details.Add($"Bottom Retract Height 2: {file.BottomRetractHeight2} to {SlicerFile.BottomRetractHeight2}"); + file.BottomRetractHeight2 = SlicerFile.BottomRetractHeight2; + changed = true; + } + + if (file.CanUseBottomRetractSpeed2 && file.BottomRetractSpeed2 != SlicerFile.BottomRetractSpeed2) + { + details.Add($"Bottom Retract Speed2: {file.BottomRetractSpeed2} to {SlicerFile.BottomRetractSpeed2}"); + file.BottomRetractSpeed2 = SlicerFile.BottomRetractSpeed2; + changed = true; + } + + if (file.CanUseRetractHeight2 && file.RetractHeight2 != SlicerFile.RetractHeight2) + { + details.Add($"Retract Height 2: {file.RetractHeight2} to {SlicerFile.RetractHeight2}"); + file.RetractHeight2 = SlicerFile.RetractHeight2; + changed = true; + } + + if (file.CanUseRetractSpeed2 && file.RetractSpeed2 != SlicerFile.RetractSpeed2) + { + details.Add($"Retract Speed 2: {file.RetractSpeed2} to {SlicerFile.RetractSpeed2}"); + file.RetractSpeed2 = SlicerFile.RetractSpeed2; + changed = true; + } + + if (file.CanUseBottomLightPWM && file.BottomLightPWM != SlicerFile.BottomLightPWM) + { + details.Add($"Bottom Light PWM: {file.BottomLightPWM} to {SlicerFile.BottomLightPWM}"); + file.BottomLightPWM = SlicerFile.BottomLightPWM; + changed = true; + } + + if (file.CanUseLightPWM && file.LightPWM != SlicerFile.LightPWM) + { + details.Add($"Light PWM: {file.LightPWM} to {SlicerFile.LightPWM}"); + file.LightPWM = SlicerFile.LightPWM; + changed = true; + } + + // if (file.CanUseXXX && file.XXX != SlicerFile.XXX) + // { + // details.Add($"XXX: {file.XXX} to {SlicerFile.XXX}"); + // file.XXX = SlicerFile.XXX; + // changed = true; + // } + + // Bail out if not changed + if (!changed) + { + return new Tuple<ResultStatus, string, List<string>>(ResultStatus.Unchanged, filePath, null); + } + + // Save the changed file + file.Save(); + + return new Tuple<ResultStatus, string, List<string>>(ResultStatus.Success, filePath, details); + } + + } +} diff --git a/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs index a786ac5..720d020 100644 --- a/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Avalonia; using Avalonia.Controls; @@ -39,7 +40,7 @@ namespace UVtools.WPF.Controls.Tools { case ToolWindow.Callbacks.Init: case ToolWindow.Callbacks.Loaded: - ParentWindow.ButtonOkEnabled = Operation.CanExecute; + if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.CanExecute; ReloadGUI(); Operation.PropertyChanged += (sender, e) => { @@ -183,309 +184,309 @@ namespace UVtools.WPF.Controls.Tools switch (variable) { case ScriptNumericalInput<sbyte> numSBYTE: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numSBYTE.Minimum, - Maximum = numSBYTE.Maximum, - Value = numSBYTE.Value, - Increment = numSBYTE.Increment, - MinWidth = 150 - }; + Minimum = numSBYTE.Minimum, + Maximum = numSBYTE.Maximum, + Value = numSBYTE.Value, + Increment = numSBYTE.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numSBYTE.Value = (sbyte)value; - control.Value = numSBYTE.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numSBYTE.Value = (sbyte)value; + control.Value = numSBYTE.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<byte> numBYTE: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numBYTE.Minimum, - Maximum = numBYTE.Maximum, - Value = numBYTE.Value, - Increment = numBYTE.Increment, - MinWidth = 150 - }; + Minimum = numBYTE.Minimum, + Maximum = numBYTE.Maximum, + Value = numBYTE.Value, + Increment = numBYTE.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numBYTE.Value = (byte)value; - control.Value = numBYTE.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numBYTE.Value = (byte)value; + control.Value = numBYTE.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<short> numSHORT: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numSHORT.Minimum, - Maximum = numSHORT.Maximum, - Value = numSHORT.Value, - Increment = numSHORT.Increment, - MinWidth = 150 - }; + Minimum = numSHORT.Minimum, + Maximum = numSHORT.Maximum, + Value = numSHORT.Value, + Increment = numSHORT.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numSHORT.Value = (short)value; - control.Value = numSHORT.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numSHORT.Value = (short)value; + control.Value = numSHORT.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<ushort> numUSHORT: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numUSHORT.Minimum, - Maximum = numUSHORT.Maximum, - Value = numUSHORT.Value, - Increment = numUSHORT.Increment, - MinWidth = 150 - }; + Minimum = numUSHORT.Minimum, + Maximum = numUSHORT.Maximum, + Value = numUSHORT.Value, + Increment = numUSHORT.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numUSHORT.Value = (ushort)value; - control.Value = numUSHORT.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numUSHORT.Value = (ushort)value; + control.Value = numUSHORT.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<int> numINT: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numINT.Minimum, - Maximum = numINT.Maximum, - Value = numINT.Value, - Increment = numINT.Increment, - MinWidth = 150 - }; + Minimum = numINT.Minimum, + Maximum = numINT.Maximum, + Value = numINT.Value, + Increment = numINT.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numINT.Value = (int)value; - control.Value = numINT.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numINT.Value = (int)value; + control.Value = numINT.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<uint> numUINT: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numUINT.Minimum, - Maximum = numUINT.Maximum, - Value = numUINT.Value, - Increment = numUINT.Increment, - MinWidth = 150 - }; + Minimum = numUINT.Minimum, + Maximum = numUINT.Maximum, + Value = numUINT.Value, + Increment = numUINT.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numUINT.Value = (uint)value; - control.Value = numUINT.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numUINT.Value = (uint)value; + control.Value = numUINT.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<long> numLONG: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numLONG.Minimum, - Maximum = numLONG.Maximum, - Value = numLONG.Value, - Increment = numLONG.Increment, - MinWidth = 150 - }; + Minimum = numLONG.Minimum, + Maximum = numLONG.Maximum, + Value = numLONG.Value, + Increment = numLONG.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numLONG.Value = (long)value; - control.Value = numLONG.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numLONG.Value = (long)value; + control.Value = numLONG.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<ulong> numULONG: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numULONG.Minimum, - Maximum = numULONG.Maximum, - Value = numULONG.Value, - Increment = numULONG.Increment, - MinWidth = 150 - }; + Minimum = numULONG.Minimum, + Maximum = numULONG.Maximum, + Value = numULONG.Value, + Increment = numULONG.Increment, + MinWidth = 150 + }; - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numULONG.Value = (ulong)value; - control.Value = numULONG.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numULONG.Value = (ulong)value; + control.Value = numULONG.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<float> numFLOAT: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numFLOAT.Minimum, - Maximum = numFLOAT.Maximum, - Value = numFLOAT.Value, - Increment = numFLOAT.Increment, - MinWidth = 150 - }; + Minimum = numFLOAT.Minimum, + Maximum = numFLOAT.Maximum, + Value = numFLOAT.Value, + Increment = numFLOAT.Increment, + MinWidth = 150 + }; - if (numFLOAT.DecimalPlates > 0) - { - control.FormatString = $"F{numFLOAT.DecimalPlates}"; - } + if (numFLOAT.DecimalPlates > 0) + { + control.FormatString = $"F{numFLOAT.DecimalPlates}"; + } - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numFLOAT.Value = (float) Math.Round(value, numFLOAT.DecimalPlates); - control.Value = numFLOAT.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numFLOAT.Value = (float) Math.Round(value, numFLOAT.DecimalPlates); + control.Value = numFLOAT.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<double> numDOUBLE: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = numDOUBLE.Minimum, - Maximum = numDOUBLE.Maximum, - Value = numDOUBLE.Value, - Increment = numDOUBLE.Increment, - MinWidth = 150 - }; + Minimum = numDOUBLE.Minimum, + Maximum = numDOUBLE.Maximum, + Value = numDOUBLE.Value, + Increment = numDOUBLE.Increment, + MinWidth = 150 + }; - if (numDOUBLE.DecimalPlates > 0) - { - control.FormatString = $"F{numDOUBLE.DecimalPlates}"; - } + if (numDOUBLE.DecimalPlates > 0) + { + control.FormatString = $"F{numDOUBLE.DecimalPlates}"; + } - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numDOUBLE.Value = Math.Round(value, numDOUBLE.DecimalPlates); - control.Value = numDOUBLE.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numDOUBLE.Value = Math.Round(value, numDOUBLE.DecimalPlates); + control.Value = numDOUBLE.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptNumericalInput<decimal> numDECIMAL: + { + NumericUpDown control = new() { - NumericUpDown control = new() - { - Minimum = (double)numDECIMAL.Minimum, - Maximum = (double)numDECIMAL.Maximum, - Value = (double)numDECIMAL.Value, - Increment = (double)numDECIMAL.Increment, - MinWidth = 150 - }; + Minimum = (double)numDECIMAL.Minimum, + Maximum = (double)numDECIMAL.Maximum, + Value = (double)numDECIMAL.Value, + Increment = (double)numDECIMAL.Increment, + MinWidth = 150 + }; - if (numDECIMAL.DecimalPlates > 0) - { - control.FormatString = $"F{numDECIMAL.DecimalPlates}"; - } + if (numDECIMAL.DecimalPlates > 0) + { + control.FormatString = $"F{numDECIMAL.DecimalPlates}"; + } - var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); - valueProperty.Subscribe(value => - { - numDECIMAL.Value = (decimal)Math.Round(value, numDECIMAL.DecimalPlates); - control.Value = (double)numDECIMAL.Value; - }); + var valueProperty = control.GetObservable(NumericUpDown.ValueProperty); + valueProperty.Subscribe(value => + { + numDECIMAL.Value = (decimal)Math.Round(value, numDECIMAL.DecimalPlates); + control.Value = (double)numDECIMAL.Value; + }); - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; - } + continue; + } case ScriptCheckBoxInput inputCheckBox: + { + var control = new CheckBox { - CheckBox control = new() - { - Content = variable.Label, - IsChecked = inputCheckBox.Value - }; - - var valueProperty = control.GetObservable(CheckBox.IsCheckedProperty); - valueProperty.Subscribe(value => - { - if (value != null) inputCheckBox.Value = value.Value; - }); + Content = variable.Label, + IsChecked = inputCheckBox.Value + }; - _scriptVariablesGrid.Children.Add(control); - Grid.SetRow(control, i * 2); - Grid.SetColumn(control, 2); + var valueProperty = control.GetObservable(CheckBox.IsCheckedProperty); + valueProperty.Subscribe(value => + { + if (value != null) inputCheckBox.Value = value.Value; + }); - if (!string.IsNullOrWhiteSpace(variable.ToolTip)) - { - ToolTip.SetTip(control, variable.ToolTip); - } + _scriptVariablesGrid.Children.Add(control); + Grid.SetRow(control, i * 2); + Grid.SetColumn(control, 2); - continue; + if (!string.IsNullOrWhiteSpace(variable.ToolTip)) + { + ToolTip.SetTip(control, variable.ToolTip); } + + continue; + } case ScriptTextBoxInput inputTextBox: { TextBox control = new() @@ -506,10 +507,169 @@ namespace UVtools.WPF.Controls.Tools continue; } + case ScriptOpenFolderDialogInput inputOpenFolder: + { + var panel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 5 + }; + + var control = new TextBox + { + IsReadOnly = true, + Text = inputOpenFolder.Value, + }; + + var button = new Button + { + Content = "Select", + }; + + button.Click += async (sender, args) => + { + var dialog = new OpenFolderDialog + { + Directory = inputOpenFolder.Value, + Title = inputOpenFolder.Title + }; + var result = await dialog.ShowAsync(ParentWindow); + if (!string.IsNullOrWhiteSpace(result)) + { + inputOpenFolder.Value = result; + control.Text = result; + } + }; + + panel.Children.Add(control); + panel.Children.Add(button); + + _scriptVariablesGrid.Children.Add(panel); + Grid.SetRow(panel, i * 2); + Grid.SetColumn(panel, 2); + + continue; + } + case ScriptSaveFileDialogInput inputSaveFile: + { + var panel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 5 + }; + + var control = new TextBox + { + IsReadOnly = true, + Text = inputSaveFile.Value, + }; + + var button = new Button + { + Content = "Select", + }; + + button.Click += async (sender, args) => + { + var dialog = new SaveFileDialog + { + Directory = inputSaveFile.Value, + Title = inputSaveFile.Title, + DefaultExtension = inputSaveFile.DefaultExtension, + InitialFileName = inputSaveFile.InitialFilename + }; + + if (inputSaveFile.Filters is not null) + { + foreach (var filter in inputSaveFile.Filters) + { + dialog.Filters.Add(new FileDialogFilter + { + Extensions = filter.Extensions, + Name = filter.Name + }); + } + } + + var result = await dialog.ShowAsync(ParentWindow); + if (!string.IsNullOrWhiteSpace(result)) + { + inputSaveFile.Value = result; + control.Text = result; + } + }; + + panel.Children.Add(control); + panel.Children.Add(button); + + _scriptVariablesGrid.Children.Add(panel); + Grid.SetRow(panel, i * 2); + Grid.SetColumn(panel, 2); + + continue; + } + case ScriptOpenFileDialogInput inputOpenFile: + { + var panel = new StackPanel + { + Orientation = Orientation.Horizontal, + Spacing = 5 + }; + + var control = new TextBox + { + IsReadOnly = true, + Text = inputOpenFile.Value, + AcceptsReturn = true, + }; + + var button = new Button + { + Content = "Select", + }; + + button.Click += async (sender, args) => + { + var dialog = new OpenFileDialog + { + Directory = inputOpenFile.Value, + Title = inputOpenFile.Title, + AllowMultiple = inputOpenFile.AllowMultiple, + InitialFileName = inputOpenFile.InitialFilename + }; + + if (inputOpenFile.Filters is not null) + { + foreach (var filter in inputOpenFile.Filters) + { + dialog.Filters.Add(new FileDialogFilter + { + Extensions = filter.Extensions, + Name = filter.Name + }); + } + } + + var result = await dialog.ShowAsync(ParentWindow); + if (result is null || result.Length == 0) return; + inputOpenFile.Value = result[0]; + inputOpenFile.Files = result; + control.Text = string.Join('\n', result); + }; + + panel.Children.Add(control); + panel.Children.Add(button); + + _scriptVariablesGrid.Children.Add(panel); + Grid.SetRow(panel, i * 2); + Grid.SetColumn(panel, 2); + + continue; + } } } - ParentWindow.FitToSize(); + ParentWindow?.FitToSize(); } } } diff --git a/UVtools.WPF/LayerCache.cs b/UVtools.WPF/LayerCache.cs index 4c5f1b8..b8c84bc 100644 --- a/UVtools.WPF/LayerCache.cs +++ b/UVtools.WPF/LayerCache.cs @@ -36,6 +36,7 @@ namespace UVtools.WPF Clear(); _layer = value; Image = _layer.LayerMat; + if (Image is null) return; ImageBgr = new Mat(); CvInvoke.CvtColor(Image, ImageBgr, ColorConversion.Gray2Bgr); diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs index 6cc6122..88bce1f 100644 --- a/UVtools.WPF/MainWindow.Issues.cs +++ b/UVtools.WPF/MainWindow.Issues.cs @@ -24,6 +24,7 @@ using MoreLinq; using UVtools.Core; using UVtools.Core.EmguCV; using UVtools.Core.Extensions; +using UVtools.Core.FileFormats; using UVtools.Core.Layers; using UVtools.Core.Operations; using UVtools.WPF.Extensions; @@ -467,6 +468,13 @@ namespace UVtools.WPF public async Task OnClickDetectIssues() { if (!IsFileLoaded) return; + if (SlicerFile.DecodeType == FileFormat.FileDecodeType.Partial) + { + await this.MessageBoxError("The file was open in partial mode and the detect issues is unable to run in this mode.\n" + + "Please reload the file in full mode in order to use detect issues.", "Unable to run in partial mode"); + return; + + } await ComputeIssues( GetIslandDetectionConfiguration(), GetOverhangDetectionConfiguration(), diff --git a/UVtools.WPF/MainWindow.LayerPreview.cs b/UVtools.WPF/MainWindow.LayerPreview.cs index a6844f8..e369695 100644 --- a/UVtools.WPF/MainWindow.LayerPreview.cs +++ b/UVtools.WPF/MainWindow.LayerPreview.cs @@ -799,7 +799,11 @@ namespace UVtools.WPF var watch = Stopwatch.StartNew(); LayerCache.Layer = SlicerFile[_actualLayer]; - + if (LayerCache.Image is null) + { + RefreshCurrentLayerData(); + return; + } try { //var imageSpan = LayerCache.Image.GetPixelSpan<byte>(); @@ -1304,9 +1308,6 @@ namespace UVtools.WPF CvInvoke.Rotate(LayerCache.ImageBgr, LayerCache.ImageBgr, _showLayerImageRotateCcwDirection ? RotateFlags.Rotate90CounterClockwise : RotateFlags.Rotate90Clockwise); } - - - LayerImageBox.Image = LayerCache.Bitmap = LayerCache.ImageBgr.ToBitmap(); RefreshCurrentLayerData(); diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml index e825817..f76687c 100644 --- a/UVtools.WPF/MainWindow.axaml +++ b/UVtools.WPF/MainWindow.axaml @@ -43,6 +43,13 @@ <Image Source="\Assets\Icons\file-import-16x16.png"/> </MenuItem.Icon> </MenuItem> + <MenuItem Name="MainMenu.File.OpenInPartialMode" Header="Open in partial mode" Command="{Binding MenuFileOpenInPartialModeClicked}" + ToolTip.Tip="Open a file only to see and/or edit properties. +
Layer images won't be loaded and most tools won't run in this mode."> + <MenuItem.Icon> + <Image Source="\Assets\Icons\file-import-16x16.png"/> + </MenuItem.Icon> + </MenuItem> <MenuItem Name="MainMenu.File.Reload" Header="_Reload" diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 131f48e..1364e12 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -584,8 +584,7 @@ namespace UVtools.WPF menuTool.Click += async (sender, args) => await ShowRunOperation(operation.GetType()); } } - - + /*LayerSlider.PropertyChanged += (sender, args) => { Debug.WriteLine(args.Property.Name); @@ -1146,6 +1145,7 @@ namespace UVtools.WPF public void MenuFileOpenClicked() => OpenFile(); public void MenuFileOpenNewWindowClicked() => OpenFile(true); + public void MenuFileOpenInPartialModeClicked() => OpenFile(false, FileFormat.FileDecodeType.Partial); public void MenuFileOpenCurrentFileFolderClicked() { @@ -1196,7 +1196,7 @@ namespace UVtools.WPF await SaveFile(file); } - public async void OpenFile(bool newWindow = false) + public async void OpenFile(bool newWindow = false, FileFormat.FileDecodeType fileDecodeType = FileFormat.FileDecodeType.Full) { var filters = Helpers.ToAvaloniaFileFilter(FileFormat.AllFileFiltersAvalonia); var orderedFilters = new List<FileDialogFilter> {filters[Settings.General.DefaultOpenFileExtensionIndex]}; @@ -1213,7 +1213,7 @@ namespace UVtools.WPF Directory = Settings.General.DefaultDirectoryOpenFile }; var files = await dialog.ShowAsync(this); - ProcessFiles(files, newWindow); + ProcessFiles(files, newWindow, fileDecodeType); } public async void OnMenuFileCloseFile() @@ -1386,19 +1386,36 @@ namespace UVtools.WPF private void UpdateTitle() { - Title = SlicerFile is null - ? $"{About.Software} Version: {App.VersionStr}" - : $"{About.Software} File: {Path.GetFileName(SlicerFile.FileFullPath)} ({Math.Round(LastStopWatch.ElapsedMilliseconds / 1000m, 2)}s) Version: {App.VersionStr}" - ; + var title = $"{About.Software} "; + + if (IsFileLoaded) + { + title += $"File: {Path.GetFileName(SlicerFile.FileFullPath)} ({Math.Round(LastStopWatch.ElapsedMilliseconds / 1000m, 2)}s) "; + } - Title += $" RAM: {SizeExtensions.SizeSuffix(Environment.WorkingSet)}"; + title += $"Version: {App.VersionStr} RAM: {SizeExtensions.SizeSuffix(Environment.WorkingSet)}"; + + if (IsFileLoaded) + { + if (CanSave) + { + title += " [UNSAVED]"; + } + + if (SlicerFile.DecodeType == FileFormat.FileDecodeType.Partial) + { + title += " [PARTIAL MODE]"; + } + } #if DEBUG - Title += " [DEBUG]"; + title += " [DEBUG]"; #endif + + Title = title; } - public async void ProcessFiles(string[] files, bool openNewWindow = false) + public async void ProcessFiles(string[] files, bool openNewWindow = false, FileFormat.FileDecodeType fileDecodeType = FileFormat.FileDecodeType.Full) { if (files is null || files.Length == 0) return; @@ -1436,7 +1453,7 @@ namespace UVtools.WPF if (i == 0 && !openNewWindow && (_globalModifiers & KeyModifiers.Shift) == 0) { - ProcessFile(files[i]); + ProcessFile(files[i], fileDecodeType); continue; } @@ -1450,10 +1467,11 @@ namespace UVtools.WPF void ReloadFile(uint actualLayer) { if (App.SlicerFile is null) return; - ProcessFile(SlicerFile.FileFullPath, _actualLayer); + ProcessFile(SlicerFile.FileFullPath, SlicerFile.DecodeType, _actualLayer); } - async void ProcessFile(string fileName, uint actualLayer = 0) + void ProcessFile(string fileName, uint actualLayer = 0) => ProcessFile(fileName, FileFormat.FileDecodeType.Full, actualLayer); + async void ProcessFile(string fileName, FileFormat.FileDecodeType fileDecodeType, uint actualLayer = 0) { if (!File.Exists(fileName)) return; CloseFile(); @@ -1468,7 +1486,7 @@ namespace UVtools.WPF { try { - SlicerFile.Decode(fileName, Progress); + SlicerFile.Decode(fileName, fileDecodeType, Progress); return true; } catch (OperationCanceledException) @@ -1507,7 +1525,7 @@ namespace UVtools.WPF return; } - if (Settings.Automations.AutoConvertFiles) + if (Settings.Automations.AutoConvertFiles && SlicerFile.DecodeType == FileFormat.FileDecodeType.Full) { string convertFileExtension = SlicerFile switch { @@ -1626,7 +1644,7 @@ namespace UVtools.WPF Clipboard.Init(SlicerFile); - if (SlicerFile is not ImageFile) + if (SlicerFile is not ImageFile && SlicerFile.DecodeType == FileFormat.FileDecodeType.Full) { List<MenuItem> menuItems = new(); foreach (var fileFormat in FileFormat.AvailableFormats) @@ -1664,7 +1682,7 @@ namespace UVtools.WPF MenuFileConvertItems = menuItems.ToArray(); } - using var mat = SlicerFile[0].LayerMat; + using var mat = SlicerFile.FirstLayer?.LayerMat; VisibleThumbnailIndex = 1; @@ -1672,7 +1690,6 @@ namespace UVtools.WPF UpdateTitle(); - if (mat is not null) { if (Settings.LayerPreview.AutoRotateLayerBestView) @@ -1726,7 +1743,7 @@ namespace UVtools.WPF "Incorrect image ratio detected"); } - if (mat.Size != SlicerFile.Resolution) + if (mat is not null && mat.Size != SlicerFile.Resolution) { var result = await this.MessageBoxWaring($"Layer image resolution of {mat.Size} mismatch with printer resolution of {SlicerFile.Resolution}.\n" + "1) Printing this file can lead to problems or malformed model, please verify your slicer printer settings;\n" + @@ -1747,29 +1764,32 @@ namespace UVtools.WPF UpdateLayerTrackerHighlightIssues(); }; - if (Settings.Issues.ComputeIssuesOnLoad) + if (SlicerFile.DecodeType == FileFormat.FileDecodeType.Full) { - _firstTimeOnIssues = false; - await OnClickDetectIssues(); - if (SlicerFile.IssueManager.Count > 0) + if (Settings.Issues.ComputeIssuesOnLoad) { - SelectedTabItem = TabIssues; - if(Settings.Issues.AutoRepairIssuesOnLoad) - await RunOperation(ToolRepairLayersControl.GetOperationRepairLayers()); + _firstTimeOnIssues = false; + await OnClickDetectIssues(); + if (SlicerFile.IssueManager.Count > 0) + { + SelectedTabItem = TabIssues; + if (Settings.Issues.AutoRepairIssuesOnLoad) + await RunOperation(ToolRepairLayersControl.GetOperationRepairLayers()); + } } - } - else - { - await ComputeIssues( - GetIslandDetectionConfiguration(false), - GetOverhangDetectionConfiguration(false), - GetResinTrapDetectionConfiguration(false), - GetTouchingBoundsDetectionConfiguration(false), - GetPrintHeightDetectionConfiguration(true), - true); - if (SlicerFile.IssueManager.Count > 0) + else { - SelectedTabItem = TabIssues; + await ComputeIssues( + GetIslandDetectionConfiguration(false), + GetOverhangDetectionConfiguration(false), + GetResinTrapDetectionConfiguration(false), + GetTouchingBoundsDetectionConfiguration(false), + GetPrintHeightDetectionConfiguration(true), + true); + if (SlicerFile.IssueManager.Count > 0) + { + SelectedTabItem = TabIssues; + } } } @@ -2066,6 +2086,13 @@ namespace UVtools.WPF return null; } + if (SlicerFile.DecodeType == FileFormat.FileDecodeType.Partial && !control.BaseOperation.CanRunInPartialMode) + { + await this.MessageBoxError($"The file was open in partial mode and the tool \"{control.BaseOperation.Title}\" is unable to run in this mode.\n" + + "Please reload the file in full mode in order to use this tool.", "Unable to run in partial mode"); + return null; + } + if (removeContent) { control.IsVisible = false; diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 38e0b02..f231c37 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ <PackageLicenseFile>LICENSE</PackageLicenseFile> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryType>Git</RepositoryType> - <Version>2.24.4</Version> + <Version>2.25.0</Version> <Platforms>AnyCPU;x64</Platforms> </PropertyGroup> |