From 32ccf55d42787d7d6274aa31a424f3205df562fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sat, 3 Jun 2023 03:13:54 +0100 Subject: [PATCH] v3.14.1 - (Improvement) File formats: When full encoding make sure thumbnails are all set according to file, otherwise clone/create them - (Fix) Encrypted CTB: Files are getting read/write without thumbnails making invalid files --- CHANGELOG.md | 7 +- RELEASE_NOTES.md | 24 +---- UVtools.Core/FileFormats/CTBEncryptedFile.cs | 31 +++---- UVtools.Core/FileFormats/FileFormat.cs | 37 +++++--- .../FileFormats/PhotonWorkshopFile.cs | 90 +++++++++++++------ UVtools.Core/UVtools.Core.csproj | 2 +- UVtools.WPF/UVtools.WPF.csproj | 2 +- documentation/UVtools.Core.xml | 23 ++++- 8 files changed, 130 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1bbc755..a1d38249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 03/06/2023 - v3.14.1 + +- (Improvement) File formats: When full encoding make sure thumbnails are all set according to file, otherwise clone/create them +- (Fix) Encrypted CTB: Files are getting read/write without thumbnails making invalid files + ## 31/05/2023 - v3.14.0 - **File formats:** @@ -9,9 +14,9 @@ - (Add) Support for Photon Mono M5 (.pm5) and corresponding PrusaSlicer printer - (Add) Support for Photon Mono M5s (.pm5s) and corresponding PrusaSlicer printer - (Improvement) Better tables validation and data structures - - (Improvement) Ensure the correct number of thumbnails are created when converting between files with different thumbnail count - (Add) PRZ file format and corresponding PrusaSlicer printer Phrozen Sonic Mini 8K S (#705) - (Improvement) When encoding a file with wait time before cure set but file does not support it, attempt to set light-off delay with that extra time if supported + - (Improvement) Ensure the correct number of thumbnails are created when converting between files with different thumbnail count - (Improvement) Minor code cleanup and improve some types to not nullable - **PrusaSlicer printers:** - (Add) Elegoo Mars 4 Max diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ed0bd4c3..3d25f72e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,23 +1,3 @@ -- **File formats:** - - **Anycubic:** - - (Add) Support for version 518 of the file format - - (Add) Support for Photon Mono X 6Ks (.px6s) and corresponding PrusaSlicer printer - - (Add) Support for Photon Mono M5 (.pm5) and corresponding PrusaSlicer printer - - (Add) Support for Photon Mono M5s (.pm5s) and corresponding PrusaSlicer printer - - (Improvement) Better tables validation and data structures - - (Improvement) Ensure the correct number of thumbnails are created when converting between files with different thumbnail count - - (Add) PRZ file format and corresponding PrusaSlicer printer Phrozen Sonic Mini 8K S (#705) - - (Improvement) When encoding a file with wait time before cure set but file does not support it, attempt to set light-off delay with that extra time if supported - - (Improvement) Minor code cleanup and improve some types to not nullable -- **PrusaSlicer printers:** - - (Add) Elegoo Mars 4 Max - - (Add) Peopoly Phenom XXL V2 - - (Add) Nova3D Bene6 -- (Improvement) Suggestion - Wait time before cure: Create the empty layer only to file formats that we know who require it -- (Improvement) Disable suggestions for image file formats -- (Improvement) After file load, if version is outside the supported range for the printer and format it will prompt to change for the latest supported version -- (Improvement) Pixel size information on status bar: If pixel width is not equal to pixel height, show both -- (Fix) Tool - Timelapse: The informative number of additional lifts not respecting the selected layer range and get calculated for whole model height -- (Fix) Tool - Change resolution: Allow image file types to run this tool without error (#716) -- (Fix) Menu - Open recent file: Filenames with underscore (_) are not shown correctly +- (Improvement) File formats: When full encoding make sure thumbnails are all set according to file, otherwise clone/create them +- (Fix) Encrypted CTB: Files are getting read/write without thumbnails making invalid files diff --git a/UVtools.Core/FileFormats/CTBEncryptedFile.cs b/UVtools.Core/FileFormats/CTBEncryptedFile.cs index 3d147d59..f5d4d34e 100644 --- a/UVtools.Core/FileFormats/CTBEncryptedFile.cs +++ b/UVtools.Core/FileFormats/CTBEncryptedFile.cs @@ -1119,28 +1119,25 @@ protected override void DecodeInternally(OperationProgress progress) progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount); - if (HaveThumbnails) + for (byte i = 0; i < ThumbnailsCount; i++) { - for (byte i = 0; i < ThumbnailsCount; i++) - { - uint offsetAddress = i == 0 - ? Settings.LargePreviewOffset - : Settings.SmallPreviewOffset; - if (offsetAddress == 0) continue; + uint offsetAddress = i == 0 + ? Settings.LargePreviewOffset + : Settings.SmallPreviewOffset; + if (offsetAddress == 0) continue; - inputFile.Seek(offsetAddress, SeekOrigin.Begin); - Previews[i] = Helpers.Deserialize(inputFile); + inputFile.Seek(offsetAddress, SeekOrigin.Begin); + Previews[i] = Helpers.Deserialize(inputFile); - Debug.Write($"Preview {i} -> "); - Debug.WriteLine(Previews[i]); + Debug.Write($"Preview {i} -> "); + Debug.WriteLine(Previews[i]); - inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin); - byte[] rawImageData = new byte[Previews[i].ImageLength]; - inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength); + inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin); + byte[] rawImageData = new byte[Previews[i].ImageLength]; + inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength); - Thumbnails[i] = Previews[i].Decode(rawImageData); - progress++; - } + Thumbnails[i] = Previews[i].Decode(rawImageData); + progress++; } /* Read the settings and disclaimer */ diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 947018cd..6abe3d3d 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -1243,14 +1243,14 @@ public virtual uint Version public virtual Size[] ThumbnailsOriginalSize => Array.Empty(); /// - /// Gets if this file have any valid thumbnail + /// Gets the thumbnails count present in this file format /// - public bool HaveThumbnails => Thumbnails.Any(thumbnail => thumbnail is not null); + public byte ThumbnailsCount => (byte)ThumbnailsOriginalSize.Length; /// - /// Gets the thumbnails count present in this file format + /// Gets if this file have any valid thumbnail /// - public byte ThumbnailsCount => (byte)ThumbnailsOriginalSize.Length; + public bool HaveThumbnails => Thumbnails.Any(thumbnail => thumbnail is not null && !thumbnail.IsEmpty); /// /// Gets the number of created thumbnails @@ -3430,11 +3430,14 @@ public bool SetThumbnails(Mat?[] images, bool generateImagesIfEmpty = false) images = images.Where(mat => mat is not null && !mat.IsEmpty).ToArray(); + int count = 0; + if (images.Length == 0) { if (!generateImagesIfEmpty) return false; - using var mat = FirstLayer?.BrgMat; - if (mat is null || mat.IsEmpty) + count = Thumbnails.Length; + using var matRoi = FirstLayer?.LayerMatModelBoundingRectangle; + if (matRoi is null || matRoi.SourceMat.IsEmpty) { using var genMat = EmguExtensions.InitMat(new Size(200, 100), 3); CvInvoke.PutText(genMat, About.Software, new Point(40, 60), FontFace.HersheyDuplex, 1, EmguExtensions.WhiteColor, 2); @@ -3451,7 +3454,8 @@ public bool SetThumbnails(Mat?[] images, bool generateImagesIfEmpty = false) { Thumbnails[i]?.Dispose(); Thumbnails[i] = new Mat(); - CvInvoke.Resize(mat, Thumbnails[i], ThumbnailsOriginalSize[i]); + CvInvoke.CvtColor(matRoi.RoiMat, Thumbnails[i], ColorConversion.Gray2Bgr); + CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]); } } } @@ -3468,9 +3472,13 @@ public bool SetThumbnails(Mat?[] images, bool generateImagesIfEmpty = false) { CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]); } + + count++; } } + if (count == 0) return false; + RaisePropertyChanged(nameof(Thumbnails)); RequireFullEncode = true; return true; @@ -3607,16 +3615,21 @@ public void Encode(string? fileFullPath, OperationProgress? progress = null) } } - OnBeforeEncode(false); - BeforeEncode(); + // Make sure thumbnails are all set, otherwise clone/create them + SetThumbnails(Thumbnails, true); + // Make sure thumbnails are in right size for (var i = 0; i < Thumbnails.Length; i++) { if (Thumbnails[i] is null || Thumbnails[i]!.IsEmpty) continue; if(Thumbnails[i]!.Size == ThumbnailsOriginalSize[i]) continue; - CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height)); + CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]); } + OnBeforeEncode(false); + BeforeEncode(); + + bool success; try { EncodeInternally(progress); @@ -3627,7 +3640,7 @@ public void Encode(string? fileFullPath, OperationProgress? progress = null) IsModified = false; RequireFullEncode = false; - OnAfterEncode(false); + success = true; } catch (Exception) { @@ -3636,6 +3649,8 @@ public void Encode(string? fileFullPath, OperationProgress? progress = null) if (File.Exists(tempFile)) File.Delete(tempFile); throw; } + + if (success) OnAfterEncode(false); } public void Encode(OperationProgress progress) => Encode(null, progress); diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index fdf83ecd..937f374d 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -447,19 +447,45 @@ public override string ToString() public void ResetData() => Data = null!; } - public sealed class Preview2 : Preview + public sealed class Preview2 : AnycubicNamedTable { protected override string DefaultTableName => "PREVIEW2"; protected override bool IncludeBaseTableLength => true; + /// + /// Gets the image width, in pixels. + /// + [FieldOrder(0)] public uint ResolutionX { get; set; } = 320; + + /// + /// Gets the operation mark 'x' + /// + [FieldOrder(1)] public ushort BackgroundColor1 { get; set; } = 4293; + [FieldOrder(2)] public ushort BackgroundColor2 { get; set; } + + /// + /// Gets the image height, in pixels. + /// + [FieldOrder(3)] public uint ResolutionY { get; set; } = 190; + + [Ignore] public uint DataSize => ResolutionX * ResolutionY * 2; + + [Ignore] public byte[] Data { get; set; } = null!; + public Preview2() { - ResolutionX = 320; - ResolutionY = 190; } - public Preview2(uint resolutionX, uint resolutionY) : base(resolutionX, resolutionY) + public Preview2(uint resolutionX, uint resolutionY) + { + ResolutionX = resolutionX; + ResolutionY = resolutionY; + TableLength += DataSize; + } + + public void ResetData() { + Data = null!; } } @@ -532,7 +558,7 @@ public class Machine : AnycubicNamedTable [FieldOrder(0)][FieldLength(96)][SerializeAs(SerializedType.TerminatedString)] public string MachineName { get; set; } = null!; [FieldOrder(1)][FieldLength(16)][SerializeAs(SerializedType.TerminatedString)] public string LayerImageFormat { get; set; } = "pw0img"; [FieldOrder(2)] public uint MaxAntialiasingLevel { get; set; } = 16; - [FieldOrder(3)] public uint PropertyFields { get; set; } + [FieldOrder(3)] public uint PropertyFields { get; set; } = 7; [FieldOrder(4)] public float DisplayWidth { get; set; } [FieldOrder(5)] public float DisplayHeight { get; set; } [FieldOrder(6)] public float MachineZ { get; set; } @@ -540,26 +566,26 @@ public class Machine : AnycubicNamedTable [FieldOrder(8)] public uint MachineBackground { get; set; } = 6506241; [FieldOrder(9)] [SerializeWhen(nameof(TableLength), 160, ComparisonOperator.GreaterThanOrEqual)] public float PixelWidthUm { get; set; } [FieldOrder(10)] [SerializeWhen(nameof(TableLength), 164, ComparisonOperator.GreaterThanOrEqual)] public float PixelHeightUm { get; set; } - [FieldOrder(11)] [SerializeWhen(nameof(TableLength), 168, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown1 { get; set; } - [FieldOrder(12)] [SerializeWhen(nameof(TableLength), 172, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown2 { get; set; } - [FieldOrder(13)] [SerializeWhen(nameof(TableLength), 176, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown3 { get; set; } - [FieldOrder(14)] [SerializeWhen(nameof(TableLength), 180, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown4 { get; set; } - [FieldOrder(15)] [SerializeWhen(nameof(TableLength), 184, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown5 { get; set; } - [FieldOrder(16)] [SerializeWhen(nameof(TableLength), 188, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown6 { get; set; } - [FieldOrder(17)] [SerializeWhen(nameof(TableLength), 192, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown7 { get; set; } - [FieldOrder(18)] [SerializeWhen(nameof(TableLength), 196, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown8 { get; set; } - [FieldOrder(19)] [SerializeWhen(nameof(TableLength), 200, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown9 { get; set; } = 1; - [FieldOrder(20)] [SerializeWhen(nameof(TableLength), 204, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown10 { get; set; } + [FieldOrder(11)] [SerializeWhen(nameof(TableLength), 168, ComparisonOperator.GreaterThanOrEqual)] public uint Padding1 { get; set; } + [FieldOrder(12)] [SerializeWhen(nameof(TableLength), 172, ComparisonOperator.GreaterThanOrEqual)] public uint Padding2 { get; set; } + [FieldOrder(13)] [SerializeWhen(nameof(TableLength), 176, ComparisonOperator.GreaterThanOrEqual)] public uint Padding3 { get; set; } + [FieldOrder(14)] [SerializeWhen(nameof(TableLength), 180, ComparisonOperator.GreaterThanOrEqual)] public uint Padding4 { get; set; } + [FieldOrder(15)] [SerializeWhen(nameof(TableLength), 184, ComparisonOperator.GreaterThanOrEqual)] public uint Padding5 { get; set; } + [FieldOrder(16)] [SerializeWhen(nameof(TableLength), 188, ComparisonOperator.GreaterThanOrEqual)] public uint Padding6 { get; set; } + [FieldOrder(17)] [SerializeWhen(nameof(TableLength), 192, ComparisonOperator.GreaterThanOrEqual)] public uint Padding7 { get; set; } + [FieldOrder(18)] [SerializeWhen(nameof(TableLength), 196, ComparisonOperator.GreaterThanOrEqual)] public uint Padding8 { get; set; } + [FieldOrder(19)] [SerializeWhen(nameof(TableLength), 200, ComparisonOperator.GreaterThanOrEqual)] public uint DisplayCount { get; set; } = 1; + [FieldOrder(20)] [SerializeWhen(nameof(TableLength), 204, ComparisonOperator.GreaterThanOrEqual)] public uint Padding9 { get; set; } [FieldOrder(21)] [SerializeWhen(nameof(TableLength), 206, ComparisonOperator.GreaterThanOrEqual)] public ushort ResolutionX { get; set; } [FieldOrder(22)] [SerializeWhen(nameof(TableLength), 208, ComparisonOperator.GreaterThanOrEqual)] public ushort ResolutionY { get; set; } - [FieldOrder(23)][SerializeWhen(nameof(TableLength), 212, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown11 { get; set; } - [FieldOrder(24)][SerializeWhen(nameof(TableLength), 216, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown12 { get; set; } - [FieldOrder(25)][SerializeWhen(nameof(TableLength), 220, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown13 { get; set; } - [FieldOrder(26)][SerializeWhen(nameof(TableLength), 224, ComparisonOperator.GreaterThanOrEqual)] public uint Unknown14 { get; set; } + [FieldOrder(23)] [SerializeWhen(nameof(TableLength), 212, ComparisonOperator.GreaterThanOrEqual)] public uint Padding10 { get; set; } + [FieldOrder(24)] [SerializeWhen(nameof(TableLength), 216, ComparisonOperator.GreaterThanOrEqual)] public uint Padding11 { get; set; } + [FieldOrder(25)] [SerializeWhen(nameof(TableLength), 220, ComparisonOperator.GreaterThanOrEqual)] public uint Padding12 { get; set; } + [FieldOrder(26)] [SerializeWhen(nameof(TableLength), 224, ComparisonOperator.GreaterThanOrEqual)] public uint Padding13 { get; set; } public override string ToString() { - return $"{base.ToString()}, {nameof(MachineName)}: {MachineName}, {nameof(LayerImageFormat)}: {LayerImageFormat}, {nameof(MaxAntialiasingLevel)}: {MaxAntialiasingLevel}, {nameof(PropertyFields)}: {PropertyFields}, {nameof(DisplayWidth)}: {DisplayWidth}, {nameof(DisplayHeight)}: {DisplayHeight}, {nameof(MachineZ)}: {MachineZ}, {nameof(MaxFileVersion)}: {MaxFileVersion}, {nameof(MachineBackground)}: {MachineBackground}, {nameof(PixelWidthUm)}: {PixelWidthUm}, {nameof(PixelHeightUm)}: {PixelHeightUm}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}, {nameof(Unknown5)}: {Unknown5}, {nameof(Unknown6)}: {Unknown6}, {nameof(Unknown7)}: {Unknown7}, {nameof(Unknown8)}: {Unknown8}, {nameof(Unknown9)}: {Unknown9}, {nameof(Unknown10)}: {Unknown10}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Unknown11)}: {Unknown11}, {nameof(Unknown12)}: {Unknown12}, {nameof(Unknown13)}: {Unknown13}, {nameof(Unknown14)}: {Unknown14}"; + return $"{base.ToString()}, {nameof(MachineName)}: {MachineName}, {nameof(LayerImageFormat)}: {LayerImageFormat}, {nameof(MaxAntialiasingLevel)}: {MaxAntialiasingLevel}, {nameof(PropertyFields)}: {PropertyFields}, {nameof(DisplayWidth)}: {DisplayWidth}, {nameof(DisplayHeight)}: {DisplayHeight}, {nameof(MachineZ)}: {MachineZ}, {nameof(MaxFileVersion)}: {MaxFileVersion}, {nameof(MachineBackground)}: {MachineBackground}, {nameof(PixelWidthUm)}: {PixelWidthUm}, {nameof(PixelHeightUm)}: {PixelHeightUm}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(Padding4)}: {Padding4}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(Padding7)}: {Padding7}, {nameof(Padding8)}: {Padding8}, {nameof(DisplayCount)}: {DisplayCount}, {nameof(Padding9)}: {Padding9}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Padding10)}: {Padding10}, {nameof(Padding11)}: {Padding11}, {nameof(Padding12)}: {Padding12}, {nameof(Padding13)}: {Padding13}"; } } #endregion @@ -1003,18 +1029,18 @@ public sealed class SubLayerDef [FieldOrder(2)] public uint NonZeroPixelCount { get; set; } - [FieldOrder(3)] public float Unknown1 { get; set; } - [FieldOrder(4)] public float Unknown2 { get; set; } - [FieldOrder(5)] public float Unknown3 { get; set; } - [FieldOrder(6)] public float Unknown4 { get; set; } - [FieldOrder(7)] public float Unknown5 { get; set; } - [FieldOrder(8)] public float Unknown6 { get; set; } - [FieldOrder(9)] public float Unknown7 { get; set; } - [FieldOrder(10)] public float Unknown8 { get; set; } + [FieldOrder(3)] public float Padding1 { get; set; } + [FieldOrder(4)] public float Padding2 { get; set; } + [FieldOrder(5)] public float Padding3 { get; set; } + [FieldOrder(6)] public float Padding4 { get; set; } + [FieldOrder(7)] public float Padding5 { get; set; } + [FieldOrder(8)] public float Padding6 { get; set; } + [FieldOrder(9)] public float Padding7 { get; set; } + [FieldOrder(10)] public float Padding8 { get; set; } public override string ToString() { - return $"{nameof(DataAddress)}: {DataAddress}, {nameof(DataLength)}: {DataLength}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}, {nameof(Unknown5)}: {Unknown5}, {nameof(Unknown6)}: {Unknown6}, {nameof(Unknown7)}: {Unknown7}, {nameof(Unknown8)}: {Unknown8}"; + return $"{nameof(DataAddress)}: {DataAddress}, {nameof(DataLength)}: {DataLength}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(Padding4)}: {Padding4}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(Padding7)}: {Padding7}, {nameof(Padding8)}: {Padding8}"; } public void SetFrom(LayerDef layerDef) @@ -1894,6 +1920,12 @@ protected override void EncodeInternally(OperationProgress progress) _ => 156 }; + MachineSettings.PropertyFields = Version switch + { + >= VERSION_518 => 15, + _ => 7 + }; + HeaderSettings.PixelSizeUm = PixelSizeMicronsMax; MachineSettings.PixelWidthUm = PixelWidthMicrons; MachineSettings.PixelHeightUm = PixelHeightMicrons; diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 47786ae4..b4e559f2 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 3.14.0 + 3.14.1 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 0f88d3a4..88ee6304 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ LICENSE https://github.com/sn4k3/UVtools Git - 3.14.0 + 3.14.1 AnyCPU;x64 UVtools.png README.md diff --git a/documentation/UVtools.Core.xml b/documentation/UVtools.Core.xml index 81afe6ed..90b93700 100644 --- a/documentation/UVtools.Core.xml +++ b/documentation/UVtools.Core.xml @@ -2601,14 +2601,14 @@ Gets the original thumbnail sizes - + - Gets if this file have any valid thumbnail + Gets the thumbnails count present in this file format - + - Gets the thumbnails count present in this file format + Gets if this file have any valid thumbnail @@ -4356,6 +4356,21 @@ Gets the image height, in pixels. + + + Gets the image width, in pixels. + + + + + Gets the operation mark 'x' + + + + + Gets the image height, in pixels. + + Gets the layer image offset to encoded layer data, and its length in bytes.