diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c621e2..e07e1b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 22/03/2023 - v3.12.1 + +- **File formats:** + - (Improvement) Does not set `PerLayerSettings` flag when found different exposure times on transition layers, this fixes the issue where users can't edit settings on printer menu when having transition layers (#507) + - (Fix) CTB for UniFormation GKtwo: Unable to show nor print files (#673) + - (Fix) CBDDLP corruption when downgrade version (#675) +- **PCB exposure:** + - (Add) EagleCAD XLN drill format (#676) + - (Add) Allow to re-order gerbers up and down on the grid + - (Change) Drill files do not require G05 to do the holes (#676) + - (Fix) Infinite loop on refresh preview when selecting drl files + - (Fix) Unable to individual invert drl files +- (Upgrade) .NET from 6.0.14 to 6.0.15 + ## 27/02/2023 - v3.12.0 - (Add) Allow to pause and resume operations (#654) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a4b8684..70a1bd1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,12 +1,12 @@ -- (Add) Allow to pause and resume operations (#654) -- (Add) `Layer.FirstTransitionLayer` -- (Add) `Layer.LastTransitionLayer` -- (Add) File format: Elegoo GOO -- (Add) PrusaSlicer Printer: Elegoo Mars 4 -- (Improvement) Allocate maximum GPU memory for Skia up to 256 MB -- (Improvement) Set and sanitize transition layers exposure time from last bottom layer and first normal layer instead of global times (#659) -- (Change) CXDLP: Default version from 2 to 3 -- (Fix) UI was not rendering with GPU (ANGLE) -- (Fix) `Layer.IsTransitionLayer` was returning the wrong value -- (Upgrade) .NET from 6.0.13 to 6.0.14 +- **File formats:** + - (Improvement) Does not set `PerLayerSettings` flag when found different exposure times on transition layers, this fix the issue where users can't edit settings on printer menu when having transition layers (#507) + - (Fix) CTB for UniFormation GKtwo: Unable to show nor print files (#673) + - (Fix) CBDDLP corruption when downgrade version (#675) +- **PCB exposure:** + - (Add) EagleCAD XLN drill format (#676) + - (Add) Allow to re-order gerbers up and down on the grid + - (Change) Drill files does not require G05 to do the holes (#676) + - (Fix) Infinite loop on refresh preview when selecting drl files + - (Fix) Unable to individual invert drl files +- (Upgrade) .NET from 6.0.14 to 6.0.15 diff --git a/Scripts/010 Editor/ctb_decrypted.bt b/Scripts/010 Editor/ctb_decrypted.bt index 40dd92f..44805ff 100644 --- a/Scripts/010 Editor/ctb_decrypted.bt +++ b/Scripts/010 Editor/ctb_decrypted.bt @@ -7,6 +7,8 @@ // Purpose: CTB File Format //-------------------------------------- +LittleEndian(); + struct HEADER { uint Magic ; uint HeaderSize ; diff --git a/Scripts/010 Editor/ctb_encrypted.bt b/Scripts/010 Editor/ctb_encrypted.bt index df1063e..84562fc 100644 --- a/Scripts/010 Editor/ctb_encrypted.bt +++ b/Scripts/010 Editor/ctb_encrypted.bt @@ -7,6 +7,8 @@ // Purpose: CTB File Format //-------------------------------------- +LittleEndian(); + struct HEADER { uint Magic ; uint EncryptedHeaderSize ; diff --git a/UVtools.Core/Excellon/ExcellonDrillFormat.cs b/UVtools.Core/Excellon/ExcellonDrillFormat.cs index 1c3dd00..2a2bd0f 100644 --- a/UVtools.Core/Excellon/ExcellonDrillFormat.cs +++ b/UVtools.Core/Excellon/ExcellonDrillFormat.cs @@ -102,7 +102,8 @@ public class ExcellonDrillFormat #endregion #region Constants - public const string Extension = "drl"; + + public static readonly string[] Extensions = {"drl", "xln"}; /// /// Indicates the start of the header. should always be the first line in the header @@ -183,7 +184,7 @@ public class ExcellonDrillFormat Drills.Clear(); bool endOfHeader = false; - bool drillMode = false; + bool drillMode = true; uint selectedToolIndex = 0; float x = 0, y = 0; @@ -192,11 +193,12 @@ public class ExcellonDrillFormat { if (line.Length == 0) continue; + if (line is "M30") break; // End + if (line.StartsWith("FMAT,")) { var split = line.Split(',', StringSplitOptions.TrimEntries); FormatVersion = uint.Parse(split[1]); - continue; } @@ -222,7 +224,7 @@ public class ExcellonDrillFormat continue; } - if (line == "ICI") + if (line is "ICI" or "ICI,ON") { throw new NotImplementedException("ICI (Incremental input of program coordinates) is not yet implemented, please use absolute coordinate system."); } @@ -233,7 +235,7 @@ public class ExcellonDrillFormat continue; } - if (line == "G05") + if (line is "G81" or "G05") { drillMode = true; continue; diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index d6c1a6d..2ab86a3 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -48,6 +48,10 @@ public sealed class ChituboxFile : FileFormat private const string CTBv4_DISCLAIMER = "Layout and record format for the ctb and cbddlp file types are the copyrighted programs or codes of CBD Technology (China) Inc..The Customer or User shall not in any manner reproduce, distribute, modify, decompile, disassemble, decrypt, extract, reverse engineer, lease, assign, or sublicense the said programs or codes."; private const ushort CTBv4_DISCLAIMER_SIZE = 320; + + private const string CTBv4_GKtwo_DISCLAIMER = "Layout and record format for the jxs,ctb and cbddlp file types are the copyrighted programs or codes of CBD Technology (China) Inc.The Customer or User shall not in any manner reproduce, distribute, modify, decompile, disassemble, decrypt, extract, reverse engineer, lease, assign, or sublicense the said programs or codes."; + private const ushort CTBv4_GKtwo_DISCLAIMER_SIZE = 323; + private const ushort CTBv4_RESERVED_SIZE = 384; public const long PageSize = 4_294_967_296L; // Page-size for layers, limited to 4GB @@ -1695,6 +1699,7 @@ public sealed class ChituboxFile : FileFormat public bool IsCbddlpFile => HeaderSettings.Magic == MAGIC_CBDDLP; public bool IsCtbFile => HeaderSettings.Magic is MAGIC_CTB or MAGIC_CTBv4 or MAGIC_CTBv4_GKtwo; + public bool IsGkTwoFile => HeaderSettings.Magic is MAGIC_CTBv4_GKtwo; public bool IsMagicValid => IsValidKnownMagic(HeaderSettings.Magic); @@ -1803,7 +1808,7 @@ public sealed class ChituboxFile : FileFormat SlicerInfoSettings.PerLayerSettings = AllLayersAreUsingGlobalParameters ? PERLAYER_SETTINGS_DISALLOW - : (byte)(Version * 16); // 0x10, 0x20, 0x30, 0x40, 0x50, ... + : (byte)(Version * 0x10); // 0x10, 0x20, 0x30, 0x40, 0x50, ... SlicerInfoSettings.ModifiedTimestampMinutes = (uint)DateTimeExtensions.TimestampMinutes; } @@ -1813,7 +1818,7 @@ public sealed class ChituboxFile : FileFormat SanitizeMagicVersion(); HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings); - + if (IsCtbFile) { if (HeaderSettings.EncryptionKey == 0) @@ -1821,10 +1826,12 @@ public sealed class ChituboxFile : FileFormat HeaderSettings.EncryptionKey = (uint)new Random().Next(byte.MaxValue, int.MaxValue); } } - else + else // IsCbddlp { //HeaderSettings.Version = 2; HeaderSettings.EncryptionKey = 0; // Force disable encryption + HeaderSettings.SlicerOffset = 0; // Force remove SlicerInfo for cbddlp + HeaderSettings.SlicerSize = 0; } //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings); @@ -1880,16 +1887,26 @@ public sealed class ChituboxFile : FileFormat if (HeaderSettings.Version >= 4) { - SlicerInfoSettings.PrintParametersV4Address = (uint) (HeaderSettings.SlicerOffset + Helpers.Serializer.SizeOf(SlicerInfoSettings) + CTBv4_DISCLAIMER_SIZE); + SlicerInfoSettings.PrintParametersV4Address = (uint) (HeaderSettings.SlicerOffset + + Helpers.Serializer.SizeOf(SlicerInfoSettings) + + (IsGkTwoFile ? CTBv4_GKtwo_DISCLAIMER_SIZE : CTBv4_DISCLAIMER_SIZE)); } outputFile.WriteSerialize(SlicerInfoSettings); if (HeaderSettings.Version >= 4) { - PrintParametersV4Settings.DisclaimerAddress = (uint) outputFile.Position; - PrintParametersV4Settings.DisclaimerLength = (uint) CTBv4_DISCLAIMER.Length; - outputFile.WriteBytes(Encoding.UTF8.GetBytes(CTBv4_DISCLAIMER)); + PrintParametersV4Settings.DisclaimerAddress = (uint)outputFile.Position; + + if (IsGkTwoFile) + { + PrintParametersV4Settings.DisclaimerLength = outputFile.WriteBytes(Encoding.UTF8.GetBytes(CTBv4_GKtwo_DISCLAIMER)); + } + else + { + PrintParametersV4Settings.DisclaimerLength = outputFile.WriteBytes(Encoding.UTF8.GetBytes(CTBv4_DISCLAIMER)); + } + outputFile.WriteSerialize(PrintParametersV4Settings); } } diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs index 08fc726..0ce23b2 100644 --- a/UVtools.Core/Layers/Layer.cs +++ b/UVtools.Core/Layers/Layer.cs @@ -1018,7 +1018,8 @@ public class Layer : BindableBase, IEquatable, IEquatable _positionZ != RoundHeight(SlicerFile.LayerHeight * Number) || _lightOffDelay != SlicerFile.LightOffDelay || _waitTimeBeforeCure != SlicerFile.WaitTimeBeforeCure || - _exposureTime != SlicerFile.ExposureTime || + (!IsTransitionLayer && _exposureTime != SlicerFile.ExposureTime) || // Fix for can't edit settings on menu https://github.com/sn4k3/UVtools/issues/507 + //_exposureTime != SlicerFile.ExposureTime || _waitTimeAfterCure != SlicerFile.WaitTimeAfterCure || _liftHeight != SlicerFile.LiftHeight || _liftSpeed != SlicerFile.LiftSpeed || diff --git a/UVtools.Core/Operations/OperationPCBExposure.cs b/UVtools.Core/Operations/OperationPCBExposure.cs index 7a3236e..d7647f0 100644 --- a/UVtools.Core/Operations/OperationPCBExposure.cs +++ b/UVtools.Core/Operations/OperationPCBExposure.cs @@ -32,8 +32,8 @@ public class OperationPCBExposure : Operation public sealed class PCBExposureFile : GenericFileRepresentation { - private bool _invertPolarity; - private double _sizeScale = 1; + public bool _invertPolarity; + public double _sizeScale = 1; /// /// Gets or sets to invert the polarity when drawing @@ -76,7 +76,8 @@ public class OperationPCBExposure : Operation "gbo", // Bottom silkscreen layer "gbs", // Bottom solder mask layer "gml", // Mechanical layer - "drl" // Drill holes + "drl", // Drill holes + "xln" // Eagle drill holes }; #endregion @@ -293,14 +294,6 @@ public class OperationPCBExposure : Operation var file = new PCBExposureFile(filePath); if (_files.Contains(file)) return; _files.Add(file); - - /*var drlFiles = _files.Where(exposureFile => exposureFile.FileExtension == ".drl"); - var drlArray = drlFiles.ToArray(); - if (drlArray.Length > 0) - { - _files.RemoveRange(drlArray); - _files.AddRange(drlArray); - }*/ } public void AddFiles(string[] files, bool handleZipFiles = true) @@ -324,7 +317,8 @@ public class OperationPCBExposure : Operation { if (!file.Exists) return; - if (file.IsExtension("drl")) + + if (ExcellonDrillFormat.Extensions.Any(file.IsExtension)) { ExcellonDrillFormat.ParseAndDraw(file, mat, SlicerFile.Ppmm, _sizeMidpointRounding, new SizeF((float)OffsetX, (float)OffsetY), _enableAntiAliasing); } @@ -355,7 +349,8 @@ public class OperationPCBExposure : Operation using var mergeMat = SlicerFile.CreateMat(); progress.ItemCount = FileCount; - var orderFiles = _files.OrderBy(file => file.IsExtension(".drl")).ToArray(); + //var orderFiles = _files.OrderBy(file => file.IsExtension(".drl") || file.IsExtension(".xln")).ToArray(); + var orderFiles = _files.OrderBy(file => ExcellonDrillFormat.Extensions.Any(file.IsExtension)).ToArray(); for (var i = 0; i < orderFiles.Length; i++) { diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 8501c6e..77c2f73 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.12.0 + 3.12.1 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 diff --git a/UVtools.Installer/Code/HeatGeneratedFileList.wxs b/UVtools.Installer/Code/HeatGeneratedFileList.wxs index 2a0428b..a4fb346 100644 --- a/UVtools.Installer/Code/HeatGeneratedFileList.wxs +++ b/UVtools.Installer/Code/HeatGeneratedFileList.wxs @@ -323,8 +323,8 @@ - - + + @@ -1700,7 +1700,7 @@ - + diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index e4f88ce..191bc80 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -400,9 +400,10 @@ public class App : Application public static Bitmap GetBitmapFromAsset(string url) => new(GetAsset(url)); - public static string? GetPrusaSlicerDirectory(bool isSuperSlicer = false) + public static string? GetPrusaSlicerDirectory(bool isSuperSlicer = false, bool isAlpha = false) { var slicerFolder = isSuperSlicer ? "SuperSlicer" : "PrusaSlicer"; + if (isAlpha) slicerFolder += "-alpha"; if (OperatingSystem.IsWindows()) { return Path.Combine( diff --git a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml index 45edb74..8260de4 100644 --- a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml @@ -12,47 +12,76 @@ - - + + + - + - + + + + + + + + + + + + - - - - - - - + + + + + + + diff --git a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs index ff2452d..4d03e65 100644 --- a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Timers; +using UVtools.Core.Excellon; using UVtools.Core.Extensions; using UVtools.Core.Operations; using UVtools.WPF.Extensions; @@ -70,7 +71,10 @@ namespace UVtools.WPF.Controls.Tools { AutoReset = false }; - _timer.Elapsed += (sender, e) => Dispatcher.UIThread.InvokeAsync(UpdatePreview); + _timer.Elapsed += (sender, e) => + { + Dispatcher.UIThread.InvokeAsync(UpdatePreview); + }; } private void InitializeComponent() @@ -125,7 +129,7 @@ namespace UVtools.WPF.Controls.Tools if (!OperationPCBExposure.ValidExtensions.Any(extension => _selectedFile.IsExtension(extension)) || !_selectedFile.Exists) return; var file = (OperationPCBExposure.PCBExposureFile)_selectedFile.Clone(); - file.InvertPolarity = file.IsExtension(".drl"); + file._invertPolarity = ExcellonDrillFormat.Extensions.Any(extension => file.IsExtension(extension)); _previewImage?.Dispose(); using var mat = Operation.GetMat(file); @@ -186,6 +190,49 @@ namespace UVtools.WPF.Controls.Tools Operation.Files.RemoveRange(FilesDataGrid.SelectedItems.OfType()); } + public void MoveFileTop() + { + if (FilesDataGrid.SelectedIndex <= 0) return; + var selectedFile = SelectedFile; + Operation.Files.RemoveAt(FilesDataGrid.SelectedIndex); + Operation.Files.Insert(0, selectedFile); + FilesDataGrid.SelectedIndex = 0; + FilesDataGrid.ScrollIntoView(selectedFile, FilesDataGrid.Columns[0]); + } + + public void MoveFileUp() + { + if (FilesDataGrid.SelectedIndex <= 0) return; + var selectedFile = SelectedFile; + var newIndex = FilesDataGrid.SelectedIndex - 1; + Operation.Files.RemoveAt(FilesDataGrid.SelectedIndex); + Operation.Files.Insert(newIndex, selectedFile); + FilesDataGrid.SelectedIndex = newIndex; + FilesDataGrid.ScrollIntoView(selectedFile, FilesDataGrid.Columns[0]); + } + + public void MoveFileDown() + { + if (FilesDataGrid.SelectedIndex == -1 || FilesDataGrid.SelectedIndex == Operation.FileCount - 1) return; + var selectedFile = SelectedFile; + var newIndex = FilesDataGrid.SelectedIndex + 1; + Operation.Files.RemoveAt(FilesDataGrid.SelectedIndex); + Operation.Files.Insert(newIndex, selectedFile); + FilesDataGrid.SelectedIndex = newIndex; + FilesDataGrid.ScrollIntoView(selectedFile, FilesDataGrid.Columns[0]); + } + + public void MoveFileBottom() + { + var lastIndex = Operation.Files.Count - 1; + if (FilesDataGrid.SelectedIndex == -1 || FilesDataGrid.SelectedIndex == lastIndex) return; + var selectedFile = SelectedFile; + Operation.Files.RemoveAt(FilesDataGrid.SelectedIndex); + Operation.Files.Insert(lastIndex, selectedFile); + FilesDataGrid.SelectedIndex = lastIndex; + FilesDataGrid.ScrollIntoView(selectedFile, FilesDataGrid.Columns[0]); + } + public void ClearFiles() { Operation.Files.Clear(); diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs index d3ad780..957e87b 100644 --- a/UVtools.WPF/Program.cs +++ b/UVtools.WPF/Program.cs @@ -54,13 +54,6 @@ public static class Program Console.WriteLine(e); return; } - - /*foreach (var s in FileFormat.AllFileExtensions.Where(extension => !extension.Extension.Contains('.')).DistinctBy(extension => extension.Extension)) - { - Debug.WriteLine($"- {s.Extension}"); - } - Debug.WriteLine(FileFormat.AllFileExtensions.Where(extension => !extension.Extension.Contains('.')).DistinctBy(extension => extension.Extension).Count()); - return;*/ if (Args.Length >= 1) { @@ -75,7 +68,6 @@ public static class Program } } - /*using var mat = CvInvoke.Imread(@"D:\layer0.png", ImreadModes.Grayscale); var contours = mat.FindContours(out var hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxTc89Kcos); diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 6a2f013..76fac1f 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.12.0 + 3.12.1 AnyCPU;x64 UVtools.png README.md @@ -48,9 +48,9 @@ - - - + + +