added UVtools patch

This commit is contained in:
cpu
2026-06-14 11:38:45 +02:00
parent f5eca9efa4
commit 9bcea25f78
14 changed files with 577 additions and 840 deletions

173
UVtools/pcb-expose.patch Normal file
View File

@@ -0,0 +1,173 @@
diff --git a/UVtools.Cmd/Program.cs b/UVtools.Cmd/Program.cs
index 6d2d1ff..38da048 100644
--- a/UVtools.Cmd/Program.cs
+++ b/UVtools.Cmd/Program.cs
@@ -45,6 +45,7 @@ public static async Task<int> Main(params string[] args)
ExtractCommand.CreateCommand(),
CopyParametersCommand.CreateCommand(),
SetThumbnailCommand.CreateCommand(),
+ PcbExposeCommand.CreateCommand(),
CompareCommand.CreateCommand(),
diff --git a/UVtools.Cmd/Symbols/PcbExposeCommand.cs b/UVtools.Cmd/Symbols/PcbExposeCommand.cs
new file mode 100644
index 0000000..e67e876
--- /dev/null
+++ b/UVtools.Cmd/Symbols/PcbExposeCommand.cs
@@ -0,0 +1,155 @@
+/*
+ * 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 System.CommandLine;
+using System.IO;
+using UVtools.Core.FileFormats;
+using UVtools.Core.Operations;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class PcbExposeCommand
+{
+ internal static Command CreateCommand()
+ {
+ var gerberArgument = new Argument<FileInfo[]>("gerber-files")
+ {
+ Description = "One or more Gerber/drill files (.gbr .gtl .gbl .gts .gbs .drl etc.)",
+ };
+
+ var exposureOption = new Option<decimal>("-e", "--exposure")
+ {
+ Description = "Exposure time in seconds (0 = keep value from input file)",
+ DefaultValueFactory = _ => 0m,
+ };
+
+ var invertOption = new Option<bool>("-i", "--invert")
+ {
+ Description = "Invert image color",
+ };
+
+ var mirrorOption = new Option<bool>("-m", "--mirror")
+ {
+ Description = "Mirror the image horizontally",
+ };
+
+ var mergeOption = new Option<bool>("--merge")
+ {
+ Description = "Merge all gerber files into a single layer",
+ };
+
+ var invertPolarityOption = new Option<bool>("--invert-polarity")
+ {
+ Description = "Invert Gerber drawing polarity for all supplied files",
+ };
+
+ var antiAliasingOption = new Option<bool>("--aa")
+ {
+ Description = "Enable anti-aliasing",
+ };
+
+ var offsetXOption = new Option<decimal>("--offset-x")
+ {
+ Description = "X offset in mm",
+ DefaultValueFactory = _ => 0m,
+ };
+
+ var offsetYOption = new Option<decimal>("--offset-y")
+ {
+ Description = "Y offset in mm",
+ DefaultValueFactory = _ => 0m,
+ };
+
+ var command = new Command("pcb-expose", "Inject a Gerber file into a slicer file for PCB UV exposure")
+ {
+ GlobalArguments.InputFileArgument,
+ gerberArgument,
+
+ exposureOption,
+ invertOption,
+ mirrorOption,
+ mergeOption,
+ invertPolarityOption,
+ antiAliasingOption,
+ offsetXOption,
+ offsetYOption,
+ GlobalOptions.OutputFile,
+ };
+
+ command.SetAction(result =>
+ {
+ var inputFile = result.GetRequiredValue(GlobalArguments.InputFileArgument);
+ var gerbers = result.GetRequiredValue(gerberArgument);
+ var exposure = result.GetValue(exposureOption);
+ var invert = result.GetValue(invertOption);
+ var mirror = result.GetValue(mirrorOption);
+ var merge = result.GetValue(mergeOption);
+ var invertPolarity = result.GetValue(invertPolarityOption);
+ var aa = result.GetValue(antiAliasingOption);
+ var offsetX = result.GetValue(offsetXOption);
+ var offsetY = result.GetValue(offsetYOption);
+ var outputFile = result.GetValue(GlobalOptions.OutputFile);
+
+ if (gerbers.Length == 0)
+ {
+ Program.WriteLineError("Specify at least one gerber file.");
+ return;
+ }
+
+ foreach (var g in gerbers)
+ {
+ if (!g.Exists)
+ {
+ Program.WriteLineError($"Gerber file not found: {g.FullName}");
+ return;
+ }
+ }
+
+ var slicerFile = Program.OpenInputFile(inputFile);
+
+ var op = new OperationPCBExposure(slicerFile)
+ {
+ MergeFiles = merge,
+ Mirror = mirror,
+ InvertColor = invert,
+ EnableAntiAliasing = aa,
+ OffsetX = offsetX,
+ OffsetY = offsetY,
+ };
+
+ if (exposure > 0)
+ op.ExposureTime = exposure;
+
+ foreach (var g in gerbers)
+ op.Files.Add(new OperationPCBExposure.PCBExposureFile(g.FullName, invertPolarity));
+
+ var spawnError = op.ValidateSpawn();
+ if (!string.IsNullOrWhiteSpace(spawnError))
+ {
+ Program.WriteLineError(spawnError);
+ return;
+ }
+
+ var validationError = op.ValidateInternally();
+ if (!string.IsNullOrWhiteSpace(validationError))
+ {
+ Program.WriteLineError(validationError.TrimEnd());
+ return;
+ }
+
+ Program.ProgressBarWork(
+ $"PCB exposure: {string.Join(", ", Array.ConvertAll(gerbers, g => g.Name))}",
+ () => op.Execute(Program.Progress));
+
+ Program.SaveFile(slicerFile, outputFile);
+ });
+
+ return command;
+ }
+}