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 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. + * 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("gerber-files") + { + Description = "One or more Gerber/drill files (.gbr .gtl .gbl .gts .gbs .drl etc.)", + }; + + var exposureOption = new Option("-e", "--exposure") + { + Description = "Exposure time in seconds (0 = keep value from input file)", + DefaultValueFactory = _ => 0m, + }; + + var invertOption = new Option("-i", "--invert") + { + Description = "Invert image color", + }; + + var mirrorOption = new Option("-m", "--mirror") + { + Description = "Mirror the image horizontally", + }; + + var mergeOption = new Option("--merge") + { + Description = "Merge all gerber files into a single layer", + }; + + var invertPolarityOption = new Option("--invert-polarity") + { + Description = "Invert Gerber drawing polarity for all supplied files", + }; + + var antiAliasingOption = new Option("--aa") + { + Description = "Enable anti-aliasing", + }; + + var offsetXOption = new Option("--offset-x") + { + Description = "X offset in mm", + DefaultValueFactory = _ => 0m, + }; + + var offsetYOption = new Option("--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; + } +}