Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2022-03-26 06:38:39 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2022-03-26 06:38:39 +0300
commit57b8a9dc8411da7b008025f8ef20a945373ccee9 (patch)
tree076f87dee73368cd55fa29aea6f48720fd3d067e
parent1d23048c2a12c7830ad27d9cfa4788c097b08c2c (diff)
v3.2.0v3.2.0
- **Core:** - (Add) Machine presets and able to load machine collection from PrusaSlicer - (Improvement) Core: Reference EmguCV runtimes into core instead of the UI project - **File formats:** - **CXDLP:** - (Add) Detection support for Halot One Pro - (Add) Detection support for Halot One Plus - (Add) Detection support for Halot Sky Plus - (Add) Detection support for Halot Lite - (Improvement) Better handling and detection of printer model when converting - (Improvement) Discovered more fields meanings on format - (Fix) Exposure time in format is `round(time * 10, 1)` - (Fix) Speeds in format are in mm/s, was using mm/min before - (Add) JXS format for Uniformation GKone [Zip+GCode] - (Improvement) Saving and converting files now handle the file backup on Core instead on the UI, which prevents scripts and other projects lose the original file in case of error while saving - (Fix) After load files they was flagged as requiring a full encode, preventing fast save a fresh file - **UVtoolsCmd:** - Bring back the commandline project - Consult README to see the available commands and syntax - Old terminal commands on UVtools still works for now, but consider switch to UVtoolsCmd or redirect the command using `UVtools --cmd "commands"` - **Tools:** - **Change print resolution:** - (Add) Allow to change the display size to match the new printer - (Add) Machine presets to help set both resolution and display size to a correct printer and auto set fix pixel ratio - (Improvement) Real pixel pitch fixer due new display size information, this allow full transfers between different printers "without" invalidating the model size - (Improvement) Better arrangement of the layout - (Add) Infill: Option "Reinforce infill if possible", it was always on before, now default is off and configurable - (Improvement) Always allow to export settings from tools - **GCode:** - (Improvement) After print the last layer, do one lift with the same layer settings before attempt a fast move to top - (Improvement) Use the highest defined speed to send the build plate to top after finish print - (Improvement) Append a wait sync command in the end of gcode if needed - (Fix) When lift without a retract it still output the motor sync delay for the retract time and the wait time after retract - **PrusaSlicer:** - (Add) Printer: Creality Halot One Pro CL-70 - (Add) Printer: Creality Halot One Plus CL-79 - (Add) Printer: Creality Halot Sky Plus CL-92 - (Add) Printer: Creality Halot Lite CL-89L - (Add) Printer: Creality Halot Lite CL-89L - (Add) Printer: Creality CT133 Pro - (Add) Printer: Creality CT-005 Pro - (Add) Printer: Uniformation GKone - (Add) Printer: FlashForge Foto 8.9S - (Add) Printer: Elegoo Mars 2 - (Improvement) Rename all Creality printers - (Fix) Creality model in print notes
-rw-r--r--CHANGELOG.md50
-rw-r--r--README.md42
-rw-r--r--Scripts/010 Editor/cxdlp.bt21
-rw-r--r--Scripts/ImportPrusaSlicerData.ps1206
-rw-r--r--UVtools.Cmd/Program.cs442
-rw-r--r--UVtools.Cmd/ProgressBar.cs126
-rw-r--r--UVtools.Cmd/Symbols/ConvertCommand.cs93
-rw-r--r--UVtools.Cmd/Symbols/CopyParametersCommand.cs53
-rw-r--r--UVtools.Cmd/Symbols/ExtractCommand.cs50
-rw-r--r--UVtools.Cmd/Symbols/GlobalArguments.cs19
-rw-r--r--UVtools.Cmd/Symbols/GlobalOptions.cs21
-rw-r--r--UVtools.Cmd/Symbols/PrintGCodeCommand.cs42
-rw-r--r--UVtools.Cmd/Symbols/PrintLayersCommand.cs106
-rw-r--r--UVtools.Cmd/Symbols/PrintMachines.cs53
-rw-r--r--UVtools.Cmd/Symbols/PrintPropertiesCommand.cs101
-rw-r--r--UVtools.Cmd/Symbols/RunCommand.cs95
-rw-r--r--UVtools.Cmd/UVtools.Cmd.csproj7
-rw-r--r--UVtools.Cmd/UVtools.icobin124548 -> 128964 bytes
-rw-r--r--UVtools.Core/About.cs4
-rw-r--r--UVtools.Core/Converters/SpeedConverter.cs56
-rw-r--r--UVtools.Core/Converters/TimeConverter.cs (renamed from UVtools.Core/Extensions/TimeExtensions.cs)4
-rw-r--r--UVtools.Core/Enumerations.cs144
-rw-r--r--UVtools.Core/Extensions/JsonExtensions.cs9
-rw-r--r--UVtools.Core/Extensions/TypeExtensions.cs9
-rw-r--r--UVtools.Core/FileFormats/CTBEncryptedFile.cs18
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs69
-rw-r--r--UVtools.Core/FileFormats/CXDLPFile.cs112
-rw-r--r--UVtools.Core/FileFormats/CXDLPv1File.cs6
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs16
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs20
-rw-r--r--UVtools.Core/FileFormats/FDGFile.cs12
-rw-r--r--UVtools.Core/FileFormats/FileExtension.cs10
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs221
-rw-r--r--UVtools.Core/FileFormats/FlashForgeSVGXFile.cs10
-rw-r--r--UVtools.Core/FileFormats/GR1File.cs8
-rw-r--r--UVtools.Core/FileFormats/GenericZIPFile.cs12
-rw-r--r--UVtools.Core/FileFormats/ImageFile.cs4
-rw-r--r--UVtools.Core/FileFormats/JXSFile.cs698
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs27
-rw-r--r--UVtools.Core/FileFormats/MDLPFile.cs8
-rw-r--r--UVtools.Core/FileFormats/OSLAFile.cs10
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs12
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs10
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs10
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs26
-rw-r--r--UVtools.Core/FileFormats/UVJFile.cs8
-rw-r--r--UVtools.Core/FileFormats/VDAFile.cs14
-rw-r--r--UVtools.Core/FileFormats/VDTFile.cs18
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs33
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs29
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs120
-rw-r--r--UVtools.Core/GCode/GCodeLayer.cs2
-rw-r--r--UVtools.Core/Layers/Layer.cs14
-rw-r--r--UVtools.Core/Managers/MatCacheManager.cs8
-rw-r--r--UVtools.Core/Operations/Operation.cs40
-rw-r--r--UVtools.Core/Operations/OperationCalculator.cs2
-rw-r--r--UVtools.Core/Operations/OperationCalibrateElephantFoot.cs6
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs6
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExternalTests.cs2
-rw-r--r--UVtools.Core/Operations/OperationCalibrateGrayscale.cs6
-rw-r--r--UVtools.Core/Operations/OperationCalibrateLiftHeight.cs2
-rw-r--r--UVtools.Core/Operations/OperationCalibrateStressTower.cs6
-rw-r--r--UVtools.Core/Operations/OperationCalibrateTolerance.cs6
-rw-r--r--UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs6
-rw-r--r--UVtools.Core/Operations/OperationChangeResolution.cs97
-rw-r--r--UVtools.Core/Operations/OperationDoubleExposure.cs2
-rw-r--r--UVtools.Core/Operations/OperationDynamicLifts.cs2
-rw-r--r--UVtools.Core/Operations/OperationEditParameters.cs2
-rw-r--r--UVtools.Core/Operations/OperationFadeExposureTime.cs2
-rw-r--r--UVtools.Core/Operations/OperationIPrintedThisFile.cs2
-rw-r--r--UVtools.Core/Operations/OperationInfill.cs67
-rw-r--r--UVtools.Core/Operations/OperationLayerArithmetic.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerClone.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerExportGif.cs12
-rw-r--r--UVtools.Core/Operations/OperationLayerExportHeatMap.cs12
-rw-r--r--UVtools.Core/Operations/OperationLayerExportImage.cs14
-rw-r--r--UVtools.Core/Operations/OperationLayerExportMesh.cs16
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs4
-rw-r--r--UVtools.Core/Operations/OperationLayerReHeight.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerRemove.cs2
-rw-r--r--UVtools.Core/Operations/OperationLightBleedCompensation.cs2
-rw-r--r--UVtools.Core/Operations/OperationMove.cs34
-rw-r--r--UVtools.Core/Operations/OperationPattern.cs8
-rw-r--r--UVtools.Core/Operations/OperationRaftRelief.cs4
-rw-r--r--UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs2
-rw-r--r--UVtools.Core/Operations/OperationRedrawModel.cs2
-rw-r--r--UVtools.Core/Operations/OperationTimelapse.cs2
-rw-r--r--UVtools.Core/Printer/Machine.cs409
-rw-r--r--UVtools.Core/Printer/PrinterBrand.cs31
-rw-r--r--UVtools.Core/SystemOS/SystemAware.cs5
-rw-r--r--UVtools.Core/UVtools.Core.csproj4
-rw-r--r--UVtools.InstallerMM/UVtools.InstallerMM.wxs110
-rw-r--r--UVtools.WPF/App.axaml.cs3
-rw-r--r--UVtools.WPF/ConsoleArguments.cs8
-rw-r--r--UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml100
-rw-r--r--UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs37
-rw-r--r--UVtools.WPF/Controls/Tools/ToolInfillControl.axaml25
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs51
-rw-r--r--UVtools.WPF/Program.cs38
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj4
-rw-r--r--UVtools.WPF/UserSettings.cs2
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml2
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml.cs46
-rw-r--r--UVtools.sln18
104 files changed, 3556 insertions, 1031 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39fabf8..e860122 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,55 @@
# Changelog
+## 26/03/2022 - v3.2.0
+
+- **Core:**
+ - (Add) Machine presets and able to load machine collection from PrusaSlicer
+ - (Improvement) Core: Reference EmguCV runtimes into core instead of the UI project
+- **File formats:**
+ - **CXDLP:**
+ - (Add) Detection support for Halot One Pro
+ - (Add) Detection support for Halot One Plus
+ - (Add) Detection support for Halot Sky Plus
+ - (Add) Detection support for Halot Lite
+ - (Improvement) Better handling and detection of printer model when converting
+ - (Improvement) Discovered more fields meanings on format
+ - (Fix) Exposure time in format is `round(time * 10, 1)`
+ - (Fix) Speeds in format are in mm/s, was using mm/min before
+ - (Add) JXS format for Uniformation GKone [Zip+GCode]
+ - (Improvement) Saving and converting files now handle the file backup on Core instead on the UI, which prevents scripts and other projects lose the original file in case of error while saving
+ - (Improvement) When saving files the .tmp extension is no longer shown on `FileFullPath`, which now `TemporaryOutputFileFullPath` is who holds the file.tmp
+ - (Fix) After load files they was flagged as requiring a full encode, preventing fast save a fresh file
+- **UVtoolsCmd:**
+ - Bring back the commandline project
+ - Consult README to see the available commands and syntax
+ - Old terminal commands on UVtools still works for now, but consider switch to UVtoolsCmd or redirect the command using `UVtools --cmd "commands"`
+- **Tools:**
+ - **Change print resolution:**
+ - (Add) Allow to change the display size to match the new printer
+ - (Add) Machine presets to help set both resolution and display size to a correct printer and auto set fix pixel ratio
+ - (Improvement) Real pixel pitch fixer due new display size information, this allow full transfers between different printers "without" invalidating the model size
+ - (Improvement) Better arrangement of the layout
+ - (Add) Infill: Option "Reinforce infill if possible", it was always on before, now default is off and configurable
+ - (Improvement) Always allow to export settings from tools
+- **GCode:**
+ - (Improvement) After print the last layer, do one lift with the same layer settings before attempt a fast move to top
+ - (Improvement) Use the highest defined speed to send the build plate to top after finish print
+ - (Improvement) Append a wait sync command in the end of gcode if needed
+ - (Fix) When lift without a retract it still output the motor sync delay for the retract time and the wait time after retract
+- **PrusaSlicer:**
+ - (Add) Printer: Creality Halot One Pro CL-70
+ - (Add) Printer: Creality Halot One Plus CL-79
+ - (Add) Printer: Creality Halot Sky Plus CL-92
+ - (Add) Printer: Creality Halot Lite CL-89L
+ - (Add) Printer: Creality Halot Lite CL-89L
+ - (Add) Printer: Creality CT133 Pro
+ - (Add) Printer: Creality CT-005 Pro
+ - (Add) Printer: Uniformation GKone
+ - (Add) Printer: FlashForge Foto 8.9S
+ - (Add) Printer: Elegoo Mars 2
+ - (Improvement) Rename all Creality printers
+ - (Fix) Creality model in print notes
+
## 21/03/2022 - v3.1.1
- (Add) Raft relief: Tabs type - Creates tabs around the raft to easily insert a tool under it and detach the raft from build plate
diff --git a/README.md b/README.md
index 304e31f..004d66c 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,7 @@ But also, i need victims for test subject. Proceed at your own risk!
- PWMX (Photon Workshop)
- PWMB (Photon Workshop)
- PWSQ (Photon Workshop)
+- JXS (GKone Slicer)
- ZCode (UnizMaker)
- ZCodex (Z-Suite)
- CWS (NovaMaker)
@@ -146,15 +147,52 @@ Replace the "xxx" by your desired value in the correct units
https://github.com/sn4k3/UVtools/wiki/Sliced-File-Conversion
-# Command-line arguments
+# Command-line
-The UVtools executable allow to set some arguments to do special functions:
+## UVtoolsCmd (Console) executable
+
+```bash
+Usage:
+ UVtoolsCmd [command] [options]
+
+Options:
+ -q, --quiet Make output silent but exceptions error will still show
+ --no-progress Show no progress
+ --core-version Show core version information
+ --version Show version information
+ -?, -h, --help Show help and usage information
+
+Commands:
+ run <input-file> <files> Run operations and/or scripts
+ convert <input-file> <target-type/ext> <output-file> Convert input file into a output file format by a known type or
+ extension []
+ extract <input-file> <output-folder> Extract file contents to a folder []
+ copy-parameters <input-file> <target-files> Copy print parameters from one file to another
+ print-properties <input-file> Prints available properties
+ print-layers <input-file> Prints layer(s) properties
+ print-gcode <input-file> Prints the gcode of the file if available
+ print-machines Prints machine settings
+```
+
+Note: On each command you can use -? to see specific command help and extra options
+
+## UVtools (UI) executable
- **Open file(s):**
- **Syntax:** UVtools \<file1\> [file2] [file3] ...
- **Example 1:** UVtools C:\model.osla
- **Example 2:** UVtools C:\model.zip D:\other_model.osla
- **Note:** When a invalid file is pass, the program will open as default.
+- **Redirect a command to UVtoolsCmd:**
+ - **Syntax:** UVtools --cmd \<commands ...\>
+ - **Example 1:** UVtools --cmd convert C:\model.osla zip
+ - **Note:** This can be used when UVtoolsCmd is not directly exposed, for example if you are running via a .AppImage.
+ All commands will be redirected to `UVtoolsCmd` and the UI will not run. It still shows the terminal window.
+
+### Legacy
+
+The following commands are the old way and commands under the UI executable, they will be removed in near future, try to not use them, please prefer **UVtoolsCmd**.
+
- **Convert a file into another type(s)**
- **Syntax:** UVtools -c/--convert \<input_file\> \<output_file1_or_ext\> [output_file2_or_ext] ...
- **Example 1:** UVtools -c model.zip osla
diff --git a/Scripts/010 Editor/cxdlp.bt b/Scripts/010 Editor/cxdlp.bt
index 2512246..6d82510 100644
--- a/Scripts/010 Editor/cxdlp.bt
+++ b/Scripts/010 Editor/cxdlp.bt
@@ -100,15 +100,18 @@ if(header.Version >= 3){
char SoftwareName[SoftwareNameSize];
uint32 MaterialNameSize;
char MaterialName[MaterialNameSize];
- //ubyte offset[67-SoftwareNameSize-MaterialNameSize];
- //ubyte offset[20];
- uint Unknown;
- uint Unknown;
- uint Unknown;
- uint Unknown;
- ubyte Unknown;
- ubyte LightPWM;
- ushort Unknown;
+ ubyte DistortionCompensationEnabled;
+ uint DistortionCompensationThickness;
+ uint DistortionCompensationFocalLength;
+ ubyte XYAxisProfileCompensationEnabled;
+ ushort XYAxisProfileCompensation;
+ ubyte ZPenetrationCompensationEnabled;
+ ushort ZPenetrationCompensationLevel;
+ ubyte AntiAliasEnabled;
+ ubyte AntiAliasGreyMinValue;
+ ubyte AntiAliasGreyMaxValue;
+ ubyte ImageBlurEnabled;
+ ubyte ImageBlurLevel;
ubyte rn0[2] <fgcolor=cBlack, bgcolor=cRed>;
} slicerInfoV3;
}
diff --git a/Scripts/ImportPrusaSlicerData.ps1 b/Scripts/ImportPrusaSlicerData.ps1
index 2d492bb..3ef558e 100644
--- a/Scripts/ImportPrusaSlicerData.ps1
+++ b/Scripts/ImportPrusaSlicerData.ps1
@@ -5,111 +5,121 @@ $output_dir = 'PrusaSlicer'
$print_dir = 'sla_print'
$printer_dir = 'printer'
-$printers =
- 'UVtools Prusa SL1.ini',
- 'UVtools Prusa SL1S Speed.ini',
- 'EPAX E6 Mono.ini',
- 'EPAX E10 Mono.ini',
- 'EPAX E10 5K.ini',
- 'EPAX E10 8K.ini',
- 'EPAX X10 8K.ini',
- 'EPAX X1.ini',
- 'EPAX X1 4KS.ini',
- 'EPAX X1K 2K Mono.ini',
- 'EPAX X10.ini',
- 'EPAX X10 4K Mono.ini',
- 'EPAX X10 5K.ini',
- 'EPAX X133 4K Mono.ini',
- 'EPAX X133 6K.ini',
- 'EPAX X156 4K Color.ini',
- 'EPAX DX1 Pro.ini',
- 'EPAX DX10 Pro 5K.ini',
- 'EPAX DX10 Pro 8K.ini',
- 'Zortrax Inkspire.ini',
- 'Nova3D Elfin.ini',
- 'Nova3D Elfin2.ini',
- 'Nova3D Elfin2 Mono SE.ini',
- 'Nova3D Elfin3 Mini.ini',
- 'Nova3D Bene4.ini',
- 'Nova3D Bene4 Mono.ini',
- 'Nova3D Bene5.ini',
- 'Nova3D Whale.ini',
- 'Nova3D Whale2.ini',
- 'AnyCubic Photon.ini',
- 'AnyCubic Photon S.ini',
- 'AnyCubic Photon Zero.ini',
- 'AnyCubic Photon X.ini',
- 'AnyCubic Photon Ultra.ini',
- 'AnyCubic Photon Mono.ini',
- 'AnyCubic Photon Mono 4K.ini',
- 'AnyCubic Photon Mono SE.ini',
- 'AnyCubic Photon Mono X.ini',
- 'AnyCubic Photon Mono X 6K.ini',
- 'AnyCubic Photon Mono SQ.ini',
- 'Elegoo Mars.ini',
- 'Elegoo Mars 2 Pro.ini',
- 'Elegoo Mars 3.ini',
- 'Elegoo Mars C.ini',
- 'Elegoo Saturn.ini',
- 'Elegoo Jupiter.ini',
- 'Peopoly Phenom.ini',
- 'Peopoly Phenom L.ini',
- 'Peopoly Phenom Noir.ini',
- 'Peopoly Phenom XXL.ini',
- 'QIDI Shadow5.5.ini',
- 'QIDI Shadow6.0 Pro.ini',
- 'QIDI S-Box.ini',
- 'QIDI I-Box Mono.ini',
- 'Phrozen Shuffle.ini',
- 'Phrozen Shuffle Lite.ini',
- 'Phrozen Shuffle XL.ini',
- 'Phrozen Shuffle XL Lite.ini',
- 'Phrozen Shuffle 16.ini',
- 'Phrozen Shuffle 4K.ini',
- 'Phrozen Sonic.ini',
- 'Phrozen Sonic 4K.ini',
- 'Phrozen Sonic Mighty 4K.ini',
- 'Phrozen Sonic Mini.ini',
- 'Phrozen Sonic Mini 4K.ini',
- 'Phrozen Sonic Mini 8K.ini',
- 'Phrozen Transform.ini',
- 'Phrozen Sonic Mega 8K.ini',
- 'Kelant S400.ini',
- 'Wanhao D7.ini',
- 'Wanhao D8.ini',
- 'Wanhao CGR Mini Mono.ini',
- 'Wanhao CGR Mono.ini',
- 'Creality LD-002R.ini',
- 'Creality LD-002H.ini',
- 'Creality LD-006.ini',
- 'Creality HALOT-ONE CL-60.ini',
- 'Creality HALOT-SKY CL-89.ini',
- 'Creality HALOT-MAX CL-133.ini',
- 'Voxelab Polaris 5.5.ini',
- 'Voxelab Proxima 6.ini',
- 'Voxelab Ceres 8.9.ini',
- 'Longer Orange 10.ini',
- 'Longer Orange 30.ini',
- 'Longer Orange 120.ini',
- 'Longer Orange 4K.ini',
- 'Uniz IBEE.ini',
- 'FlashForge Explorer MAX.ini',
- 'FlashForge Focus 8.9.ini',
- 'FlashForge Focus 13.3.ini',
- 'FlashForge Foto 6.0.ini',
- 'FlashForge Foto 8.9.ini',
- 'FlashForge Foto 13.3.ini',
- 'FlashForge Hunter.ini'
-;
+#$printers =
+# 'UVtools Prusa SL1.ini',
+# 'UVtools Prusa SL1S Speed.ini',
+# 'EPAX E6 Mono.ini',
+# 'EPAX E10 Mono.ini',
+# 'EPAX E10 5K.ini',
+# 'EPAX E10 8K.ini',
+# 'EPAX X10 8K.ini',
+# 'EPAX X1.ini',
+# 'EPAX X1 4KS.ini',
+# 'EPAX X1K 2K Mono.ini',
+# 'EPAX X10.ini',
+# 'EPAX X10 4K Mono.ini',
+# 'EPAX X10 5K.ini',
+# 'EPAX X133 4K Mono.ini',
+# 'EPAX X133 6K.ini',
+# 'EPAX X156 4K Color.ini',
+# 'EPAX DX1 Pro.ini',
+# 'EPAX DX10 Pro 5K.ini',
+# 'EPAX DX10 Pro 8K.ini',
+# 'Zortrax Inkspire.ini',
+# 'Nova3D Elfin.ini',
+# 'Nova3D Elfin2.ini',
+# 'Nova3D Elfin2 Mono SE.ini',
+# 'Nova3D Elfin3 Mini.ini',
+# 'Nova3D Bene4.ini',
+# 'Nova3D Bene4 Mono.ini',
+# 'Nova3D Bene5.ini',
+# 'Nova3D Whale.ini',
+# 'Nova3D Whale2.ini',
+# 'AnyCubic Photon.ini',
+# 'AnyCubic Photon S.ini',
+# 'AnyCubic Photon Zero.ini',
+# 'AnyCubic Photon X.ini',
+# 'AnyCubic Photon Ultra.ini',
+# 'AnyCubic Photon Mono.ini',
+# 'AnyCubic Photon Mono 4K.ini',
+# 'AnyCubic Photon Mono SE.ini',
+# 'AnyCubic Photon Mono X.ini',
+# 'AnyCubic Photon Mono X 6K.ini',
+# 'AnyCubic Photon Mono SQ.ini',
+# 'Elegoo Mars.ini',
+# 'Elegoo Mars 2 Pro.ini',
+# 'Elegoo Mars 3.ini',
+# 'Elegoo Mars C.ini',
+# 'Elegoo Saturn.ini',
+# 'Elegoo Jupiter.ini',
+# 'Peopoly Phenom.ini',
+# 'Peopoly Phenom L.ini',
+# 'Peopoly Phenom Noir.ini',
+# 'Peopoly Phenom XXL.ini',
+# 'QIDI Shadow5.5.ini',
+# 'QIDI Shadow6.0 Pro.ini',
+# 'QIDI S-Box.ini',
+# 'QIDI I-Box Mono.ini',
+# 'Phrozen Shuffle.ini',
+# 'Phrozen Shuffle Lite.ini',
+# 'Phrozen Shuffle XL.ini',
+# 'Phrozen Shuffle XL Lite.ini',
+# 'Phrozen Shuffle 16.ini',
+# 'Phrozen Shuffle 4K.ini',
+# 'Phrozen Sonic.ini',
+# 'Phrozen Sonic 4K.ini',
+# 'Phrozen Sonic Mighty 4K.ini',
+# 'Phrozen Sonic Mini.ini',
+# 'Phrozen Sonic Mini 4K.ini',
+# 'Phrozen Sonic Mini 8K.ini',
+# 'Phrozen Transform.ini',
+# 'Phrozen Sonic Mega 8K.ini',
+# 'Kelant S400.ini',
+# 'Wanhao D7.ini',
+# 'Wanhao D8.ini',
+# 'Wanhao CGR Mini Mono.ini',
+# 'Wanhao CGR Mono.ini',
+# 'Creality LD-002R.ini',
+# 'Creality LD-002H.ini',
+# 'Creality LD-006.ini',
+# 'Creality HALOT-ONE CL-60.ini',
+# 'Creality HALOT-SKY CL-89.ini',
+# 'Creality HALOT-MAX CL-133.ini',
+# 'Voxelab Polaris 5.5.ini',
+# 'Voxelab Proxima 6.ini',
+# 'Voxelab Ceres 8.9.ini',
+# 'Longer Orange 10.ini',
+# 'Longer Orange 30.ini',
+# 'Longer Orange 120.ini',
+# 'Longer Orange 4K.ini',
+# 'Uniz IBEE.ini',
+# 'FlashForge Explorer MAX.ini',
+# 'FlashForge Focus 8.9.ini',
+# 'FlashForge Focus 13.3.ini',
+# 'FlashForge Foto 6.0.ini',
+# 'FlashForge Foto 8.9.ini',
+# 'FlashForge Foto 13.3.ini',
+# 'FlashForge Hunter.ini'
+#;
Write-Output 'PrusaSlicer Printers Instalation'
Write-Output 'This will replace printers, all changes will be discarded'
Write-Output $input_dir
Write-Output $output_dir
-foreach ($printer in $printers) {
- xcopy /d /y "$input_dir\$printer_dir\$printer" "$output_dir\$printer_dir"
+# Need to ignore FDM printers since they are on the same folder
+Get-ChildItem "$input_dir\$printer_dir" -Filter "*.ini" |
+Foreach-Object {
+ $content = Get-Content $_.FullName
+ $regex = $content -match 'printer_technology.*=.*(SLA)'
+ if($regex){
+ xcopy /d /y $_.FullName "$output_dir\$printer_dir"
+ }
}
+#foreach ($printer in $printers) {
+# xcopy /d /y "$input_dir\$printer_dir\$printer" "$output_dir\$printer_dir"
+#}
+
Write-Output 'Importing Profiles'
xcopy /i /y /d "$input_dir\$print_dir" "$output_dir\$print_dir" \ No newline at end of file
diff --git a/UVtools.Cmd/Program.cs b/UVtools.Cmd/Program.cs
index 8f1a004..b75ff02 100644
--- a/UVtools.Cmd/Program.cs
+++ b/UVtools.Cmd/Program.cs
@@ -1,263 +1,215 @@
-using System;
-using System.Collections.Generic;
+/*
+ * 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.CommandLine.Invocation;
using System.Diagnostics;
-using System.Drawing;
using System.Globalization;
using System.IO;
-using System.Reflection;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using UVtools.Cmd.Symbols;
using UVtools.Core;
-using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Operations;
-namespace UVtools.Cmd
+namespace UVtools.Cmd;
+
+internal class Program
{
- class Program
+ internal const string EndOperationText = "Done in {0:F2}s";
+ internal static OperationProgress Progress { get; } = new();
+ internal static Stopwatch StopWatch { get; } = new();
+ internal static bool Quiet { get; private set; }
+ internal static bool NoProgress { get; private set; }
+
+ internal static string[] Args { get; private set; } = null!;
+
+ public static async Task<int> Main(params string[] args)
+ {
+ Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
+ Args = args;
+
+ var rootCommand = new RootCommand("MSLA/DLP, file analysis, repair, conversion and manipulation")
+ {
+ RunCommand.CreateCommand(),
+ ConvertCommand.CreateCommand(),
+ ExtractCommand.CreateCommand(),
+ CopyParametersCommand.CreateCommand(),
+
+ PrintPropertiesCommand.CreateCommand(),
+ PrintLayersCommand.CreateCommand(),
+ PrintGCodeCommand.CreateCommand(),
+ PrintMachinesCommand.CreateCommand(),
+
+ GlobalOptions.QuietOption,
+ GlobalOptions.NoProgressOption,
+ new Option("--core-version", "Show core version information"),
+ };
+
+ //rootCommand.SetHandler(() => { });
+
+ HandleGlobals();
+ await rootCommand.InvokeAsync(args);
+
+ return 1;
+
+ }
+
+ internal static void HandleGlobals()
{
- public static async Task<int> Main(params string[] args)
+ foreach (var arg in Args)
{
- Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
- OperationProgress progress = new OperationProgress();
- Stopwatch sw = new Stopwatch();
- uint count = 0;
- var rootCommand = new RootCommand("MSLA/DLP, file analysis, repair, conversion and manipulation")
+ bool found = false;
+ if (GlobalOptions.QuietOption.Aliases.Any(alias => arg == alias))
{
- new Option(new []{"-f", "--file"}, "Input file to read")
- {
- IsRequired = true,
- Argument = new Argument<FileSystemInfo>("filepath").ExistingOnly()
- },
- new Option(new []{"-o", "--output"}, "Output file to save the modifications, if aware, it saves to the same input file")
- {
- Argument = new Argument<FileSystemInfo>("filepath")
- },
- new Option(new []{"-e", "--extract"}, "Extract file content to a folder")
- {
- Argument = new Argument<DirectoryInfo>("folder")
- },
- new Option(new []{"-c", "--convert"}, "Converts input into a output file format by it extension")
- {
- Argument = new Argument<FileSystemInfo>("filepath"),
- },
-
- new Option(new []{"-p", "--properties"}, "Print a list of all properties/settings"),
- new Option(new []{"-gcode"}, "Print the GCode if available"),
- new Option(new []{"-i", "--issues"}, "Compute and print a list of all issues"),
- new Option(new []{"-r", "--repair"}, "Attempt to repair all issues"){
- Argument = new Argument<int[]>("[start layer index] [end layer index] [islands 0/1] [remove empty layers 0/1] [resin traps 0/1]"),
- },
-
- new Option(new []{"-mr", "--mut-resize"}, "Resizes layer images in a X and/or Y factor, starting from 100% value")
- {
- Argument = new Argument<decimal[]>("[x%] [y%] [start layer index] [end layer index] [fade 0/1]")
- },
- new Option(new []{"-ms", "--mut-solidify"}, "Closes all inner holes")
- {
- Argument = new Argument<uint[]>("[start layer index] [end layer index]")
- },
- new Option(new []{"-me", "--mut-erode"}, "Erodes away the boundaries of foreground object")
- {
- Argument = new Argument<uint[]>("[start iterations] [end iterations] [start layer index] [end layer index] [fade 0/1]")
- },
- new Option(new []{"-md", "--mut-dilate"}, "It is just opposite of erosion")
- {
- Argument = new Argument<uint[]>("[start iterations] [end iterations] [start layer index] [end layer index] [fade 0/1]")
- },
- new Option(new []{"-mc", "--mut-close"}, "Dilation followed by Erosion")
- {
- Argument = new Argument<uint[]>("[start iterations] [end iterations] [start layer index] [end layer index] [fade 0/1]")
- },
- new Option(new []{"-mo", "--mut-open"}, "Erosion followed by Dilation")
- {
- Argument = new Argument<uint[]>("[start iterations] [end iterations] [start layer index] [end layer index] [fade 0/1]")
- },
- new Option(new []{"-mg", "--mut-gradient"}, "The difference between dilation and erosion of an image")
- {
- Argument = new Argument<uint[]>("[kernel size] [start layer index] [end layer index] [fade 0/1]")
- },
-
- new Option(new []{"-mpy", "--mut-py"}, "Performs down-sampling step of Gaussian pyramid decomposition")
- {
- Argument = new Argument<uint[]>("[start layer index] [end layer index]")
- },
- new Option(new []{"-mgb", "--mut-gaussian-blur"}, "Each pixel is a sum of fractions of each pixel in its neighborhood")
- {
- Argument = new Argument<ushort[]>("[aperture] [sigmaX] [sigmaY]")
- },
- new Option(new []{"-mmb", "--mut-median-blur"}, "Each pixel becomes the median of its surrounding pixels")
- {
- Argument = new Argument<ushort>("[aperture]")
- },
- };
-
- rootCommand.Handler = CommandHandler.Create(
- (
- FileSystemInfo file,
- FileSystemInfo convert,
- DirectoryInfo extract,
- bool properties,
- bool gcode,
- bool issues,
- int[] repair
- //decimal[] mutResize
- ) =>
+ Quiet = true;
+ found = true;
+ }
+
+ if(found) continue;
+
+ if (GlobalOptions.NoProgressOption.Aliases.Any(alias => arg == alias))
{
- var fileFormat = FileFormat.FindByExtension(file.FullName, true, true);
- if (ReferenceEquals(fileFormat, null))
- {
- Console.WriteLine($"Error: {file.FullName} is not a known nor valid format.");
- }
- else
- {
- Console.Write($"Reading: {file}");
- sw.Restart();
- fileFormat.Decode(file.FullName, progress);
- sw.Stop();
- Console.WriteLine($", in {sw.ElapsedMilliseconds}ms");
- Console.WriteLine("----------------------");
- Console.WriteLine($"Layers: {fileFormat.LayerCount} x {fileFormat.LayerHeight}mm = {fileFormat.PrintHeight}mm");
- Console.WriteLine($"Resolution: {new Size((int) fileFormat.ResolutionX, (int) fileFormat.ResolutionY)}");
- Console.WriteLine($"AntiAlias: {fileFormat.ValidateAntiAliasingLevel()}");
-
- Console.WriteLine($"Bottom Layer Count: {fileFormat.BottomLayerCount}");
- Console.WriteLine($"Bottom Exposure Time: {fileFormat.BottomExposureTime}s");
- Console.WriteLine($"Layer Exposure Time: {fileFormat.ExposureTime}s");
- Console.WriteLine($"Print Time: {fileFormat.PrintTime}s");
- Console.WriteLine($"Cost: {fileFormat.MaterialCost}$");
- Console.WriteLine($"Resin Name: {fileFormat.MaterialName}");
- Console.WriteLine($"Machine Name: {fileFormat.MachineName}");
-
- Console.WriteLine($"Thumbnails: {fileFormat.CreatedThumbnailsCount}");
- Console.WriteLine("----------------------");
- }
-
- if (!ReferenceEquals(extract, null))
- {
- Console.Write($"Extracting to {extract.FullName}");
- sw.Restart();
- fileFormat.Extract(extract.FullName, true, true, progress);
- sw.Stop();
- Console.WriteLine($", finished in {sw.ElapsedMilliseconds}ms");
- }
-
- if (properties)
- {
- count = 0;
- Console.WriteLine("Listing all properties:");
- Console.WriteLine("----------------------");
- foreach (var config in fileFormat.Configs)
- {
- Console.WriteLine("******************************");
- Console.WriteLine($"\t{config.GetType().Name}");
- Console.WriteLine("******************************");
- foreach (PropertyInfo propertyInfo in config.GetType()
- .GetProperties(BindingFlags.Public | BindingFlags.Instance))
- {
- count++;
- if (propertyInfo.Name.Equals("Item")) continue;
- Console.WriteLine($"{propertyInfo.Name}: {propertyInfo.GetValue(config)}");
- }
- }
-
- Console.WriteLine("----------------------");
- Console.WriteLine($"Total properties: {count}");
- }
-
- if (gcode)
- {
- if (ReferenceEquals(fileFormat.GCode, null))
- {
- Console.WriteLine("No GCode available");
- }
- else
- {
- Console.WriteLine("----------------------");
- Console.WriteLine(fileFormat.GCode);
- Console.WriteLine("----------------------");
- Console.WriteLine($"Total lines: {fileFormat.GCode.Length}");
- }
-
- }
-
- if (issues)
- {
- Console.WriteLine("Computing Issues, please wait.");
- sw.Restart();
- var issueList = fileFormat.LayerManager.GetAllIssues(null, null, null, null, true, null, progress);
- sw.Stop();
-
- Console.WriteLine("Issues:");
- Console.WriteLine("----------------------");
- count = 0;
- foreach (var issue in issueList)
- {
- Console.WriteLine(issue);
- count++;
- }
- /*for (uint layerIndex = 0; layerIndex < fileFormat.LayerCount; layerIndex++)
- {
- if(!issuesDict.TryGetValue(layerIndex, out var list)) continue;
- foreach (var issue in list)
- {
- Console.WriteLine(issue);
- count++;
- }
- }*/
-
- Console.WriteLine("----------------------");
- Console.WriteLine($"Total Issues: {count} in {sw.ElapsedMilliseconds}ms");
- }
-
- if (!ReferenceEquals(convert, null))
- {
- var fileConvert = FileFormat.FindByExtension(convert.FullName, true, true);
- if (ReferenceEquals(fileFormat, null))
- {
- Console.WriteLine($"Error: {convert.FullName} is not a known nor valid format.");
- }
- else
- {
- Console.WriteLine($"Converting {fileFormat.GetType().Name} to {fileConvert.GetType().Name}: {convert.Name}");
-
- try
- {
- sw.Restart();
- fileFormat.Convert(fileConvert, convert.FullName, progress);
- sw.Stop();
- Console.WriteLine($"Convertion done in {sw.ElapsedMilliseconds}ms");
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- }
-
- }
-
- }
-
- if (!ReferenceEquals(repair, null))
- {
- uint layerStartIndex = (uint) (repair.Length >= 1 ? Math.Max(0, repair[0]) : 0);
- uint layerEndIndex = repair.Length >= 2 ? (uint) repair[1].Clamp(0, (int) (fileFormat.LayerCount - 1)) : fileFormat.LayerCount-1;
- bool repairIslands = repair.Length < 3 || repair[2] > 0 || repair[2] < 0;
- bool removeEmptyLayers = repair.Length < 4 || repair[3] > 0 || repair[3] < 0;
- bool repairResinTraps = repair.Length < 5 || repair[4] > 0 || repair[4] < 0;
-
- //fileFormat.LayerManager.RepairLayers(layerStartIndex, layerEndIndex, 2, 1, 4, repairIslands, removeEmptyLayers, repairResinTraps, null, progress);
- }
-
- });
-
-
- //await rootCommand.InvokeAsync(args);
- await rootCommand.InvokeAsync("-f body_Tough0.1mm_SL1_5h16m_HOLLOW_DRAIN.sl1 -r -1");
-
- return 1;
+ NoProgress = true;
+ found = true;
+ }
+
+ if (found) continue;
+ if (arg == "--core-version")
+ {
+ Console.WriteLine(About.VersionStr);
+ Environment.Exit(0);
+ }
+ }
+ }
+
+ internal static FileFormat OpenInputFile(FileInfo inputFile, FileFormat.FileDecodeType decodeType = FileFormat.FileDecodeType.Full)
+ {
+ return ProgressBarWork($"Opening file {inputFile.Name}", () =>
+ {
+ var slicerFile = FileFormat.Open(inputFile.FullName, decodeType, Progress);
+ if (slicerFile is null)
+ {
+ throw new IOException($"Invalid file: {inputFile.Name}");
+ }
+
+ return slicerFile;
+ });
+ }
+
+ internal static void SaveFile(FileFormat slicerFile, FileInfo? outputFile) => SaveFile(slicerFile, outputFile?.FullName);
+
+ internal static void SaveFile(FileFormat slicerFile, string? outputFile = null)
+ {
+ var fileName = outputFile is null ? slicerFile.Filename : Path.GetFileName(outputFile);
+ ProgressBarWork($"Saving file {fileName}", () =>
+ {
+ slicerFile.SaveAs(outputFile, Progress);
+ });
+ }
+
+ #region ProgressBar
+
+ internal static T ProgressBarWork<T>(string title, Func<T> action)
+ {
+ T result;
+ Progress.Title = title;
+
+ StopWatch.Restart();
+ Write($"{title}: ");
+ if (Quiet || NoProgress)
+ {
+ result = action.Invoke();
}
+ else
+ {
+ using var progressBar = new ProgressBar();
+ result = action.Invoke();
+ }
+ StopWatch.Stop();
+
+
+ WriteLine(string.Format(EndOperationText, StopWatch.ElapsedMilliseconds / 1000.0));
+ return result;
+ }
+
+ internal static void ProgressBarWork(string title, Action action)
+ {
+ ProgressBarWork(title, () =>
+ {
+ action.Invoke();
+ return true;
+ });
+ }
+
+ #endregion
+
+ #region Write to console methods
+ internal static void Write(object? obj)
+ {
+ if (Quiet) return;
+ Console.Write(obj);
+ }
+
+ internal static void WriteLine(object? obj)
+ {
+ if (Quiet) return;
+ Console.WriteLine(obj);
+ }
+
+ internal static void WriteWarning(object? obj)
+ {
+ if (Quiet) return;
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(obj);
+ Console.ResetColor();
+ }
+
+ internal static void WriteLineWarning(object? obj)
+ {
+ if (Quiet) return;
+
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(obj);
+ Console.ResetColor();
+ }
+
+ internal static void WriteError(object? obj, bool exit = false)
+ {
+ if (Quiet)
+ {
+ if (exit) Environment.Exit(-1);
+ return;
+ }
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(obj);
+ Console.ResetColor();
+ if (exit) Environment.Exit(-1);
+ }
+
+ internal static void WriteLineError(object? obj, bool exit = true)
+ {
+ if (Quiet)
+ {
+ if (exit) Environment.Exit(-1);
+ return;
+ }
+
+ var str = obj?.ToString();
+ if(str is not null && !str.StartsWith("Error:")) str = $"Error: {str}";
+
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(str);
+ Console.ResetColor();
+ if (exit) Environment.Exit(-1);
}
-}
+ #endregion
+} \ No newline at end of file
diff --git a/UVtools.Cmd/ProgressBar.cs b/UVtools.Cmd/ProgressBar.cs
new file mode 100644
index 0000000..278bcf8
--- /dev/null
+++ b/UVtools.Cmd/ProgressBar.cs
@@ -0,0 +1,126 @@
+/*
+ * 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.Cmd;
+
+using System;
+using System.Text;
+using System.Threading;
+
+/// <summary>
+/// An ASCII progress bar
+/// </summary>
+public class ProgressBar : IDisposable
+{
+ private const byte BlockCount = 10;
+ private readonly TimeSpan _animationInterval = TimeSpan.FromMilliseconds(125);
+ private const string Animation = @"|/-\";
+
+ private readonly Timer _timer;
+
+ private string _currentText = string.Empty;
+ private bool _disposed;
+ private int _animationIndex;
+
+ private double _lastProgressPercent = -1;
+
+ private readonly StringBuilder _outputBuilder = new();
+
+ public ProgressBar()
+ {
+ _timer = new Timer(TimerHandler);
+
+ // A progress bar is only for temporary display in a console window.
+ // If the console output is redirected to a file, draw nothing.
+ // Otherwise, we'll end up with a lot of garbage in the target file.
+ if (Program.Quiet || Program.NoProgress) return;
+ if(Console.IsOutputRedirected) Console.WriteLine();
+ ResetTimer();
+ }
+
+ private void TimerHandler(object? state)
+ {
+ lock (_timer)
+ {
+ if (_disposed) return;
+
+
+ if (Math.Abs(_lastProgressPercent - Program.Progress.ProgressPercent) > 0.009)
+ {
+ _lastProgressPercent = Program.Progress.ProgressPercent;
+ var progressBlockCount = (int)(_lastProgressPercent * BlockCount / 100);
+
+ if (Console.IsOutputRedirected)
+ {
+ var text = string.Format("[{0}{1}] {2:F2}% ({3:F2}s)",
+ new string('#', progressBlockCount), new string('-', BlockCount - progressBlockCount),
+ Program.Progress.ProgressPercent,
+ Program.StopWatch.ElapsedMilliseconds / 1000.0);
+ Console.WriteLine(text);
+ }
+ else
+ {
+ var text = string.Format("[{0}{1}] {2:F2}% {3} {4:F2}s",
+ new string('#', progressBlockCount), new string('-', BlockCount - progressBlockCount),
+ Program.Progress.ProgressPercent,
+ Animation[_animationIndex++ % Animation.Length],
+ Program.StopWatch.ElapsedMilliseconds / 1000.0);
+ UpdateText(text);
+ }
+ }
+
+ ResetTimer();
+ }
+ }
+
+ private void UpdateText(string text)
+ {
+ if (Console.IsOutputRedirected) return;
+ // Get length of common portion
+ var commonPrefixLength = 0;
+ var commonLength = Math.Min(_currentText.Length, text.Length);
+ while (commonPrefixLength < commonLength && text[commonPrefixLength] == _currentText[commonPrefixLength])
+ {
+ commonPrefixLength++;
+ }
+
+ // Backtrack to the first differing character
+ _outputBuilder.Clear();
+ _outputBuilder.Append('\b', _currentText.Length - commonPrefixLength);
+
+ // Output new suffix
+ _outputBuilder.Append(text[commonPrefixLength..]);
+
+ // If the new text is shorter than the old one: delete overlapping characters
+ var overlapCount = _currentText.Length - text.Length;
+ if (overlapCount > 0)
+ {
+ _outputBuilder.Append(' ', overlapCount);
+ _outputBuilder.Append('\b', overlapCount);
+ }
+
+ Console.Write(_outputBuilder);
+ _currentText = text;
+ }
+
+ private void ResetTimer()
+ {
+ _timer.Change(_animationInterval, TimeSpan.FromMilliseconds(-1));
+ }
+
+ public void Dispose()
+ {
+ TimerHandler(null);
+ lock (_timer)
+ {
+ _disposed = true;
+ UpdateText(string.Empty);
+ }
+ _timer.Dispose();
+ }
+
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/ConvertCommand.cs b/UVtools.Cmd/Symbols/ConvertCommand.cs
new file mode 100644
index 0000000..3d78239
--- /dev/null
+++ b/UVtools.Cmd/Symbols/ConvertCommand.cs
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class ConvertCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("convert", "Convert input file into a output file format by a known type or extension")
+ {
+ GlobalArguments.InputFileArgument,
+ new Argument<string>("target-type/ext", "Target format type or extension"),
+ GlobalArguments.OutputFileArgument,
+
+ new Option<ushort>(new[] {"-v", "--version"}, "Sets the file format version"),
+ new Option<bool>("--no-overwrite", "If the output file exists do not overwrite"),
+ };
+
+ command.SetHandler((FileInfo inputFile, string targetTypeExt, FileInfo? outputFile, ushort version, bool noOverwrite) =>
+ {
+
+ var targetType = FileFormat.FindByAnyMeans(targetTypeExt);
+ if (targetType is null)
+ {
+ Program.WriteLineError($"Unable to find a valid convert type candidate from {targetTypeExt}.");
+ return;
+ }
+
+ string? outputFilePath;
+ if (outputFile is not null)
+ {
+ outputFilePath = outputFile.FullName;
+ }
+ else
+ {
+ outputFilePath = FileFormat.GetFileNameStripExtensions(inputFile.Name)!;
+ if (targetType.FileExtensions.Length == 1)
+ {
+ outputFilePath = Path.Combine(inputFile.DirectoryName!, $"{outputFilePath}.{targetType.FileExtensions[0].Extension}");
+ }
+ else
+ {
+ var ext = FileExtension.Find(targetTypeExt);
+ if (ext is null)
+ {
+ Program.WriteLineError($"Unable to construct the output filename from {targetTypeExt}, there are {targetType.FileExtensions.Length} extensions on this format, please specify an output file.");
+ return;
+ }
+
+ outputFilePath = Path.Combine(inputFile.DirectoryName!, $"{outputFilePath}.{ext.Extension}");
+ }
+ }
+
+ var outputFileName = Path.GetFileName(outputFilePath);
+
+ if (noOverwrite && File.Exists(outputFilePath))
+ {
+ Program.WriteLineError($"{outputFileName} already exits! --no-overwrite is enabled.");
+ return;
+ }
+
+ var slicerFile = Program.OpenInputFile(inputFile);
+
+ Program.ProgressBarWork($"Converting to {outputFileName}",
+ () =>
+ {
+ try
+ {
+ return slicerFile.Convert(targetType, outputFilePath, version, Program.Progress);
+ }
+ catch (Exception)
+ {
+ File.Delete(outputFilePath);
+ throw;
+ }
+ });
+
+ }, command.Arguments[0], command.Arguments[1], command.Arguments[2],
+ command.Options[0], command.Options[1]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/CopyParametersCommand.cs b/UVtools.Cmd/Symbols/CopyParametersCommand.cs
new file mode 100644
index 0000000..942c5c8
--- /dev/null
+++ b/UVtools.Cmd/Symbols/CopyParametersCommand.cs
@@ -0,0 +1,53 @@
+/*
+ * 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.CommandLine;
+using System.IO;
+using System.Linq;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class CopyParametersCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("copy-parameters", "Copy print parameters from one file to another")
+ {
+ GlobalArguments.InputFileArgument,
+ new Argument<FileInfo[]>("target-files", "Target file(s) to set the parameters").ExistingOnly()
+ };
+
+ command.SetHandler((FileInfo inputFile, FileInfo[] targetFiles) =>
+ {
+ var slicerFile1 = Program.OpenInputFile(inputFile, FileFormat.FileDecodeType.Partial);
+
+ var distinctFiles = targetFiles.DistinctBy(fi => fi.FullName);
+
+ foreach (var file in distinctFiles)
+ {
+ if (inputFile.FullName == file.FullName)
+ {
+ Program.WriteWarning($"Skipping: {inputFile.Name}, same as input file");
+ continue;
+ }
+ var slicerFileTarget = Program.OpenInputFile(file, FileFormat.FileDecodeType.Partial);
+
+ var count = FileFormat.CopyParameters(slicerFile1, slicerFileTarget);
+ if (count > 0)
+ {
+ slicerFileTarget.Save(Program.Progress);
+ }
+
+ Program.WriteLine($"{count} properties changed");
+ }
+
+ }, command.Arguments[0], command.Arguments[1]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/ExtractCommand.cs b/UVtools.Cmd/Symbols/ExtractCommand.cs
new file mode 100644
index 0000000..02c19cf
--- /dev/null
+++ b/UVtools.Cmd/Symbols/ExtractCommand.cs
@@ -0,0 +1,50 @@
+/*
+ * 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.CommandLine;
+using System.IO;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class ExtractCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("extract", "Extract file contents to a folder")
+ {
+ GlobalArguments.InputFileArgument,
+ GlobalArguments.OutputDirectoryArgument,
+ new Option<bool>("--no-overwrite", "If the output folder exists do not overwrite"),
+ };
+
+ command.SetHandler((FileInfo inputFile, DirectoryInfo? outputDirectory, bool noOverwrite) =>
+ {
+ var path = outputDirectory is null
+ ? Path.Combine(inputFile.DirectoryName!, Path.GetFileNameWithoutExtension(inputFile.Name))
+ : outputDirectory.FullName;
+
+ if (noOverwrite && Directory.Exists(path))
+ {
+ Program.WriteLineError($"{path} already exits! --no-overwrite is enabled.");
+ return;
+ }
+
+ var slicerFile = Program.OpenInputFile(inputFile);
+
+ Program.ProgressBarWork($"Extracting to {Path.GetFileName(path)}",
+ () =>
+ {
+ slicerFile.Extract(path);
+ });
+
+ }, command.Arguments[0], command.Arguments[1],
+ command.Options[0]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/GlobalArguments.cs b/UVtools.Cmd/Symbols/GlobalArguments.cs
new file mode 100644
index 0000000..f21d4c8
--- /dev/null
+++ b/UVtools.Cmd/Symbols/GlobalArguments.cs
@@ -0,0 +1,19 @@
+/*
+ * 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.CommandLine;
+using System.IO;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class GlobalArguments
+{
+ internal static Argument<FileInfo> InputFileArgument { get; } = new Argument<FileInfo>("input-file", "Input file to open and read").ExistingOnly();
+ internal static Argument<FileInfo?> OutputFileArgument { get; } = new ("output-file", () => null, "Output file to save");
+ internal static Argument<DirectoryInfo?> OutputDirectoryArgument { get; } = new ("output-folder", () => null, "Output folder");
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/GlobalOptions.cs b/UVtools.Cmd/Symbols/GlobalOptions.cs
new file mode 100644
index 0000000..aca565a
--- /dev/null
+++ b/UVtools.Cmd/Symbols/GlobalOptions.cs
@@ -0,0 +1,21 @@
+/*
+ * 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.CommandLine;
+using System.IO;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class GlobalOptions
+{
+ internal static Option<bool> QuietOption { get; } = new(new[] { "-q", "--quiet" }, "Make output silent but exceptions error will still show");
+ internal static Option<bool> NoProgressOption { get; } = new(new[] { "--no-progress" }, "Show no progress");
+ internal static Option<FileInfo?> OutputFile { get; } = new(new[] { "-o", "--output" }, "Output file to save");
+
+ internal static Option<bool> OpenInPartialMode { get; } = new(new []{ "--partial-mode"}, "Fast load the file in partial mode");
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/PrintGCodeCommand.cs b/UVtools.Cmd/Symbols/PrintGCodeCommand.cs
new file mode 100644
index 0000000..08a4753
--- /dev/null
+++ b/UVtools.Cmd/Symbols/PrintGCodeCommand.cs
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class PrintGCodeCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("print-gcode", "Prints the gcode of the file if available")
+ {
+ GlobalArguments.InputFileArgument,
+ };
+
+ command.SetHandler((FileInfo inputFile) =>
+ {
+ var slicerFile = Program.OpenInputFile(inputFile, FileFormat.FileDecodeType.Partial);
+ if (slicerFile.SupportsGCode)
+ {
+ Console.WriteLine(slicerFile.GCodeStr);
+ }
+ else
+ {
+ Program.WriteLineWarning("File do not support gcode");
+ }
+
+
+ }, command.Arguments[0]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/PrintLayersCommand.cs b/UVtools.Cmd/Symbols/PrintLayersCommand.cs
new file mode 100644
index 0000000..143ced4
--- /dev/null
+++ b/UVtools.Cmd/Symbols/PrintLayersCommand.cs
@@ -0,0 +1,106 @@
+/*
+ * 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.Collections.Generic;
+using System.CommandLine;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
+using System.Xml.Serialization;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class PrintLayersCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("print-layers", "Prints layer(s) properties")
+ {
+ GlobalArguments.InputFileArgument,
+
+ new Option<string>(new []{ "-r", "--range"}, "Prints only the matching layer index(es) in a range"),
+ new Option<ushort[]>(new []{ "-i", "--indexes"}, "Prints only the matching layer index(es)"),
+ new Option<string[]>(new []{ "-n", "--names"}, "Prints only the name matching properties"),
+ GlobalOptions.OpenInPartialMode
+ };
+
+ command.SetHandler((FileInfo inputFile, string layerRange, ushort[] layerIndexes, string[] matchNames, bool partialMode) =>
+ {
+ var slicerFile = Program.OpenInputFile(inputFile, partialMode ? FileFormat.FileDecodeType.Partial : FileFormat.FileDecodeType.Full);
+
+ var layerIndexesList = new List<uint>();
+
+ if (!string.IsNullOrWhiteSpace(layerRange))
+ {
+ var match = Regex.Match(layerRange, @"(\d+)(:|\||-)(\d+)");
+ if (match.Success && match.Groups.Count >= 4)
+ {
+ var startNumberStr = match.Groups[1].Value;
+ var endNumberStr = match.Groups[3].Value;
+
+ if (uint.TryParse(startNumberStr, out var startLayerIndex) &&
+ uint.TryParse(endNumberStr, out var endLayerIndex))
+ {
+ if (startLayerIndex > endLayerIndex)
+ {
+ (startLayerIndex, endLayerIndex) = (endLayerIndex, startLayerIndex);
+ }
+
+ for (var layerIndex = startLayerIndex; layerIndex <= endLayerIndex; layerIndex++)
+ {
+ layerIndexesList.Add(layerIndex);
+ }
+ }
+ }
+ }
+
+ if (layerIndexes.Length == 0 && layerIndexesList.Count == 0)
+ {
+ for (uint i = 0; i < slicerFile.LayerCount; i++)
+ {
+ layerIndexesList.Add(i);
+ }
+ }
+ else
+ {
+ layerIndexesList.AddRange(layerIndexes.Select(layerIndex => (uint) layerIndex));
+ }
+
+ layerIndexesList = layerIndexesList.Distinct().OrderBy(layerIndex => layerIndex).ToList();
+
+ foreach (var layerIndex in layerIndexesList)
+ {
+ Console.WriteLine($"Layer: {layerIndex}");
+ foreach (var propertyInfo in slicerFile[layerIndex].GetType()
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.Name.Equals("Item")) continue;
+ if (matchNames is not null && matchNames.Length > 0)
+ {
+ if (matchNames.All(s => s != propertyInfo.Name)) continue;
+ }
+ if (propertyInfo.GetCustomAttributes().Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+ Console.WriteLine($"{propertyInfo.Name}: {propertyInfo.GetValue(slicerFile[layerIndex])}");
+ }
+ }
+
+ }, command.Arguments[0], command.Options[0], command.Options[1], command.Options[2], command.Options[3]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/PrintMachines.cs b/UVtools.Cmd/Symbols/PrintMachines.cs
new file mode 100644
index 0000000..e9d6e23
--- /dev/null
+++ b/UVtools.Cmd/Symbols/PrintMachines.cs
@@ -0,0 +1,53 @@
+/*
+ * 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 System.Text.Json;
+using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
+using UVtools.Core.Printer;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class PrintMachinesCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("print-machines", "Prints machine settings")
+ {
+ new Option<bool>("--json", "Print in json format"),
+ new Option<bool>("--xml", "Print in xml format")
+ };
+
+ command.SetHandler((bool jsonFormat, bool xmlFormat) =>
+ {
+ if (jsonFormat)
+ {
+ Console.WriteLine(JsonSerializer.Serialize(Machine.Machines, JsonExtensions.SettingsIndent));
+ return;
+ }
+
+ if (xmlFormat)
+ {
+ Console.WriteLine(XmlExtensions.SerializeObject(Machine.Machines, XmlExtensions.SettingsIndent));
+ return;
+ }
+
+ foreach (var machine in Machine.Machines)
+ {
+ Console.WriteLine(machine);
+ }
+
+
+ }, command.Options[0], command.Options[1]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/PrintPropertiesCommand.cs b/UVtools.Cmd/Symbols/PrintPropertiesCommand.cs
new file mode 100644
index 0000000..6ea937e
--- /dev/null
+++ b/UVtools.Cmd/Symbols/PrintPropertiesCommand.cs
@@ -0,0 +1,101 @@
+/*
+ * 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 System.Linq;
+using System.Reflection;
+using System.Text.Json.Serialization;
+using System.Xml.Serialization;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class PrintPropertiesCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("print-properties", "Prints available properties")
+ {
+ GlobalArguments.InputFileArgument,
+
+ new Option<string[]>(new []{ "-n", "--names"}, "Prints only the name matching properties"),
+ new Option<bool>(new []{ "-b", "--base"}, "Prints only the base properties of the file"),
+ GlobalOptions.OpenInPartialMode
+ };
+
+ command.SetHandler((FileInfo inputFile, string[] matchNames, bool baseOnly, bool partialMode) =>
+ {
+ var slicerFile = Program.OpenInputFile(inputFile, partialMode ? FileFormat.FileDecodeType.Partial : FileFormat.FileDecodeType.Full);
+ uint count = 0;
+
+ Console.WriteLine("Listing properties:");
+ Console.WriteLine("----------------------");
+ if (!baseOnly)
+ {
+ foreach (var config in slicerFile.Configs)
+ {
+ //Program.WriteLine("******************************");
+ //Program.WriteLine($"\t{config.GetType().Name}");
+ //Program.WriteLine("******************************");
+ foreach (var propertyInfo in config.GetType()
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.Name.Equals("Item")) continue;
+ if (matchNames.Length > 0)
+ {
+ if(matchNames.All(s => s != propertyInfo.Name)) continue;
+ }
+ if (propertyInfo.GetCustomAttributes().Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+ count++;
+ Console.WriteLine($"{propertyInfo.Name}: {propertyInfo.GetValue(config)}");
+ }
+ }
+ }
+
+ //Program.WriteLine("******************************");
+ //Program.WriteLine("\tBase");
+ //Program.WriteLine("******************************");
+
+ var fileFormat = slicerFile as FileFormat;
+
+ foreach (var propertyInfo in fileFormat.GetType()
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.Name.Equals("Item")) continue;
+ if (matchNames is not null && matchNames.Length > 0)
+ {
+ if (matchNames.All(s => s != propertyInfo.Name)) continue;
+ }
+ if (propertyInfo.GetCustomAttributes().Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+ count++;
+ Console.WriteLine($"{propertyInfo.Name}: {propertyInfo.GetValue(fileFormat)}");
+ }
+
+
+ Console.WriteLine("----------------------");
+ Console.WriteLine($"Total properties: {count}");
+
+ }, command.Arguments[0], command.Options[0], command.Options[1], command.Options[2]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/Symbols/RunCommand.cs b/UVtools.Cmd/Symbols/RunCommand.cs
new file mode 100644
index 0000000..bb86dfc
--- /dev/null
+++ b/UVtools.Cmd/Symbols/RunCommand.cs
@@ -0,0 +1,95 @@
+/*
+ * 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.CommandLine;
+using System.IO;
+using System.Linq;
+using UVtools.Core.FileFormats;
+using UVtools.Core.Operations;
+
+namespace UVtools.Cmd.Symbols;
+
+internal static class RunCommand
+{
+ internal static Command CreateCommand()
+ {
+ var command = new Command("run", "Run operations and/or scripts")
+ {
+ GlobalArguments.InputFileArgument,
+ new Argument<FileInfo[]>("files", "Operation and script files to run (.uvtop, .cs, .csx)").ExistingOnly(),
+
+ GlobalOptions.OutputFile,
+ GlobalOptions.OpenInPartialMode
+ };
+
+ command.SetHandler((FileInfo inputFile, FileInfo[] files, FileInfo? outputFile, bool partialMode) =>
+ {
+ if (files.Length == 0)
+ {
+ Program.WriteLineError("No files to run");
+ return;
+ }
+
+ var slicerFile = Program.OpenInputFile(inputFile, partialMode ? FileFormat.FileDecodeType.Partial : FileFormat.FileDecodeType.Full);
+ uint runs = 0;
+ uint sucessfullRuns = 0;
+
+
+ foreach (var file in files)
+ {
+ var operation = Operation.Deserialize(file.FullName);
+
+ if (operation is not null)
+ {
+ operation.SlicerFile = slicerFile;
+ var result = operation.ValidateInternally();
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ Program.ProgressBarWork($"Operation {++runs}: {operation.ProgressTitle}",
+ () =>
+ {
+ if(operation.Execute(Program.Progress)) sucessfullRuns++;
+ });
+ }
+ else
+ {
+ Program.WriteLineWarning($"Operation {file.Name} can not execute: {result}");
+ }
+
+ continue;
+ }
+
+ if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csx"))
+ {
+ var operationScripting = new OperationScripting(slicerFile);
+ operationScripting.ReloadScriptFromFile(file.FullName);
+ var result = operationScripting.ValidateInternally();
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ Program.ProgressBarWork($"Script {++runs}: {operationScripting.ScriptGlobals?.Script.Name ?? operationScripting.ProgressTitle}",
+ () =>
+ {
+ if (operationScripting.Execute(Program.Progress)) sucessfullRuns++;
+ });
+ }
+ else
+ {
+ Program.WriteLineWarning($"Script {file.Name} can not execute: {result}");
+ }
+ continue;
+ }
+
+ Program.WriteLineWarning($"Invalid file: {file.Name}");
+ }
+
+ if(sucessfullRuns > 0) Program.SaveFile(slicerFile, outputFile);
+ }, command.Arguments[0], command.Arguments[1], command.Options[0], command.Options[1]);
+
+ return command;
+ }
+} \ No newline at end of file
diff --git a/UVtools.Cmd/UVtools.Cmd.csproj b/UVtools.Cmd/UVtools.Cmd.csproj
index a6cc0cb..9240a90 100644
--- a/UVtools.Cmd/UVtools.Cmd.csproj
+++ b/UVtools.Cmd/UVtools.Cmd.csproj
@@ -2,10 +2,10 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
- <TargetFramework>net5.0</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
<AssemblyName>UVtoolsCmd</AssemblyName>
<ApplicationIcon>UVtools.ico</ApplicationIcon>
- <Version>0.1</Version>
+ <Version>1.0.0</Version>
<Authors>Tiago Conceição</Authors>
<Company>PTRTECH</Company>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -17,10 +17,11 @@
<RepositoryType>Git</RepositoryType>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Platforms>AnyCPU;x64</Platforms>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
+ <PackageReference Include="System.CommandLine" Version="2.0.0-beta3.22114.1" />
</ItemGroup>
<ItemGroup>
diff --git a/UVtools.Cmd/UVtools.ico b/UVtools.Cmd/UVtools.ico
index 2a642ec..aa3e3f1 100644
--- a/UVtools.Cmd/UVtools.ico
+++ b/UVtools.Cmd/UVtools.ico
Binary files differ
diff --git a/UVtools.Core/About.cs b/UVtools.Core/About.cs
index afde01e..db116bf 100644
--- a/UVtools.Core/About.cs
+++ b/UVtools.Core/About.cs
@@ -25,7 +25,9 @@ public static class About
public const string DemoFile = "UVtools_demo_file.sl1";
- public static Version Version => Assembly.GetExecutingAssembly().GetName().Version!;
+ public static Version Version => CoreAssembly.GetName().Version!;
public static string VersionStr => Version.ToString(3);
public static string Arch => Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits";
+
+ public static Assembly CoreAssembly => Assembly.GetExecutingAssembly();
} \ No newline at end of file
diff --git a/UVtools.Core/Converters/SpeedConverter.cs b/UVtools.Core/Converters/SpeedConverter.cs
new file mode 100644
index 0000000..1d93bb5
--- /dev/null
+++ b/UVtools.Core/Converters/SpeedConverter.cs
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+namespace UVtools.Core.Converters;
+
+public static class SpeedConverter
+{
+ /// <summary>
+ /// Converts a speed from one unit to another
+ /// </summary>
+ /// <param name="value"></param>
+ /// <param name="from"></param>
+ /// <param name="to"></param>
+ /// <param name="rounding"></param>
+ /// <returns></returns>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ public static float Convert(float value, SpeedUnit from, SpeedUnit to, byte rounding = 2)
+ {
+ if (from == to) return value;
+
+ return from switch
+ {
+ SpeedUnit.MillimetersPerSecond => to switch
+ {
+ SpeedUnit.MillimetersPerSecond => value,
+ SpeedUnit.MillimetersPerMinute => (float) Math.Round(value * 60, rounding),
+ SpeedUnit.CentimetersPerMinute => (float) Math.Round(value * 6, rounding),
+ _ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
+ },
+ SpeedUnit.MillimetersPerMinute => to switch
+ {
+ SpeedUnit.MillimetersPerSecond => (float) Math.Round(value / 60, rounding),
+ SpeedUnit.MillimetersPerMinute => value,
+ SpeedUnit.CentimetersPerMinute => (float) Math.Round(value / 10, rounding),
+ _ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
+ },
+ SpeedUnit.CentimetersPerMinute => to switch
+ {
+ SpeedUnit.MillimetersPerSecond => (float) Math.Round(value * (1.0/6.0), rounding),
+ SpeedUnit.MillimetersPerMinute => (float)Math.Round(value * 10, rounding),
+ SpeedUnit.CentimetersPerMinute => value,
+ _ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
+ },
+ _ => throw new ArgumentOutOfRangeException(nameof(from), from, null)
+ };
+ }
+
+} \ No newline at end of file
diff --git a/UVtools.Core/Extensions/TimeExtensions.cs b/UVtools.Core/Converters/TimeConverter.cs
index 2988613..06d47ab 100644
--- a/UVtools.Core/Extensions/TimeExtensions.cs
+++ b/UVtools.Core/Converters/TimeConverter.cs
@@ -9,9 +9,9 @@
using System;
-namespace UVtools.Core.Extensions;
+namespace UVtools.Core.Converters;
-public static class TimeExtensions
+public static class TimeConverter
{
/// <summary>
/// Converts seconds to milliseconds
diff --git a/UVtools.Core/Enumerations.cs b/UVtools.Core/Enumerations.cs
index d82c942..f389f02 100644
--- a/UVtools.Core/Enumerations.cs
+++ b/UVtools.Core/Enumerations.cs
@@ -12,74 +12,102 @@ using System.ComponentModel;
namespace UVtools.Core;
-public class Enumerations
+/// <summary>
+/// Gets index start number, if starts on 0 or 1
+/// </summary>
+public enum IndexStartNumber : byte
{
- /// <summary>
- /// Gets index start number
- /// </summary>
- public enum IndexStartNumber : byte
- {
- Zero,
- One
- }
+ Zero,
+ One
+}
- public enum LayerRangeSelection : byte
- {
- None,
- All,
- Current,
- Bottom,
- Normal,
- First,
- Last
- }
+public enum LayerRangeSelection : byte
+{
+ None,
+ All,
+ Current,
+ Bottom,
+ Normal,
+ First,
+ Last
+}
- public enum FlipDirection : byte
- {
- None,
- Horizontally,
- Vertically,
- Both,
- }
+public enum FlipDirection : byte
+{
+ None,
+ Horizontally,
+ Vertically,
+ Both,
+}
- public enum RotateDirection : sbyte
- {
- [Description("None")]
- None = -1,
- /// <summary>Rotate 90 degrees clockwise (0)</summary>
- [Description("Rotate 90º CW")]
- Rotate90Clockwise = 0,
- /// <summary>Rotate 180 degrees clockwise (1)</summary>
- [Description("Rotate 180º")]
- Rotate180 = 1,
- /// <summary>Rotate 270 degrees clockwise (2)</summary>
- [Description("Rotate 90º CCW")]
- Rotate90CounterClockwise = 2,
- }
+public enum RotateDirection : sbyte
+{
+ [Description("None")]
+ None = -1,
+ /// <summary>Rotate 90 degrees clockwise (0)</summary>
+ [Description("Rotate 90º CW")]
+ Rotate90Clockwise = 0,
+ /// <summary>Rotate 180 degrees clockwise (1)</summary>
+ [Description("Rotate 180º")]
+ Rotate180 = 1,
+ /// <summary>Rotate 270 degrees clockwise (2)</summary>
+ [Description("Rotate 90º CCW")]
+ Rotate90CounterClockwise = 2,
+}
- public enum Anchor : byte
- {
- TopLeft, TopCenter, TopRight,
- MiddleLeft, MiddleCenter, MiddleRight,
- BottomLeft, BottomCenter, BottomRight,
- None
- }
+public enum Anchor : byte
+{
+ TopLeft, TopCenter, TopRight,
+ MiddleLeft, MiddleCenter, MiddleRight,
+ BottomLeft, BottomCenter, BottomRight,
+ None
+}
- public enum LightOffDelaySetMode : byte
- {
- [Description("Set the light-off with an extra delay")]
- UpdateWithExtraDelay,
+public enum LightOffDelaySetMode : byte
+{
+ [Description("Set the light-off with an extra delay")]
+ UpdateWithExtraDelay,
- [Description("Set the light-off without an extra delay")]
- UpdateWithoutExtraDelay,
+ [Description("Set the light-off without an extra delay")]
+ UpdateWithoutExtraDelay,
- [Description("Set the light-off to zero")]
- SetToZero,
+ [Description("Set the light-off to zero")]
+ SetToZero,
- [Description("Disabled")]
- NoAction
- }
+ [Description("Disabled")]
+ NoAction
+}
+public enum SpeedUnit : byte
+{
+ /// <summary>
+ /// mm/s
+ /// </summary>
+ MillimetersPerSecond,
+ /// <summary>
+ /// mm/m
+ /// </summary>
+ MillimetersPerMinute,
+ /// <summary>
+ /// cm/m
+ /// </summary>
+ CentimetersPerMinute,
+}
+
+public enum TimeUnits : byte
+{
+ /// <summary>
+ /// ms
+ /// </summary>
+ Milliseconds,
+ /// <summary>
+ /// s
+ /// </summary>
+ Seconds
+}
+
+public static class Enumerations
+{
public static FlipType ToOpenCVFlipType(FlipDirection flip)
{
return flip switch
diff --git a/UVtools.Core/Extensions/JsonExtensions.cs b/UVtools.Core/Extensions/JsonExtensions.cs
index e1d44cb..90ce0d2 100644
--- a/UVtools.Core/Extensions/JsonExtensions.cs
+++ b/UVtools.Core/Extensions/JsonExtensions.cs
@@ -5,7 +5,10 @@
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
+
+using System.Text.Encodings.Web;
using System.Text.Json;
+using System.Text.Json.Serialization;
namespace UVtools.Core.Extensions;
@@ -13,6 +16,10 @@ public static class JsonExtensions
{
public static readonly JsonSerializerOptions SettingsIndent = new()
{
- WriteIndented = true
+ WriteIndented = true,
+ Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
+ Converters ={
+ new JsonStringEnumConverter()
+ },
};
} \ No newline at end of file
diff --git a/UVtools.Core/Extensions/TypeExtensions.cs b/UVtools.Core/Extensions/TypeExtensions.cs
index 99118f3..1c52839 100644
--- a/UVtools.Core/Extensions/TypeExtensions.cs
+++ b/UVtools.Core/Extensions/TypeExtensions.cs
@@ -7,6 +7,9 @@
*/
using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
namespace UVtools.Core.Extensions;
@@ -36,4 +39,10 @@ public static class TypeExtensions
}
public static byte ToByte(this bool value) => (byte)(value ? 1 : 0);
+
+ public static IEnumerable<Type> GetTypesInNamespace(Assembly assembly, string nameSpace)
+ {
+ return assembly.GetTypes()
+ .Where(t => string.Equals(t.Namespace, nameSpace, StringComparison.Ordinal));
+ }
} \ No newline at end of file
diff --git a/UVtools.Core/FileFormats/CTBEncryptedFile.cs b/UVtools.Core/FileFormats/CTBEncryptedFile.cs
index b86a406..14b0bd6 100644
--- a/UVtools.Core/FileFormats/CTBEncryptedFile.cs
+++ b/UVtools.Core/FileFormats/CTBEncryptedFile.cs
@@ -713,12 +713,12 @@ public class CTBEncryptedFile : FileFormat
set => base.MachineZ = Settings.MachineZ = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Settings.ProjectorType == 0 ? Enumerations.FlipDirection.None : Enumerations.FlipDirection.Horizontally;
+ get => Settings.ProjectorType == 0 ? FlipDirection.None : FlipDirection.Horizontally;
set
{
- Settings.ProjectorType = value == Enumerations.FlipDirection.None ? 0u : 1;
+ Settings.ProjectorType = value == FlipDirection.None ? 0u : 1;
RaisePropertyChanged();
}
}
@@ -1070,13 +1070,13 @@ public class CTBEncryptedFile : FileFormat
}
}
- public override bool CanProcess(string fileFullPath)
+ public override bool CanProcess(string? fileFullPath)
{
if (!base.CanProcess(fileFullPath)) return false;
try
{
- using var fs = new BinaryReader(new FileStream(fileFullPath, FileMode.Open, FileAccess.Read));
+ using var fs = new BinaryReader(new FileStream(fileFullPath!, FileMode.Open, FileAccess.Read));
var magic = fs.ReadUInt32();
return magic is MAGIC_CBT_ENCRYPTED;
}
@@ -1226,11 +1226,11 @@ public class CTBEncryptedFile : FileFormat
if (isBugged)
{
- this[layerIndex] = new Layer((uint)layerIndex, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, this);
}
else
{
- this[layerIndex] = new Layer((uint) layerIndex, layerDef.DecodeImage((uint) layerIndex), this);
+ _layers[layerIndex] = new Layer((uint) layerIndex, layerDef.DecodeImage((uint) layerIndex), this);
}
progress.LockAndIncrement();
@@ -1286,7 +1286,7 @@ public class CTBEncryptedFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
//uint currentOffset = 0;
/* Create the file header and fill out what we can. SignatureOffset will have to be populated later
* this will be the last thing written to file */
@@ -1413,7 +1413,7 @@ public class CTBEncryptedFile : FileFormat
{
SanitizeProperties();
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(Header.SettingsOffset, SeekOrigin.Begin);
var settingsBytes = Helpers.Serialize(Settings).ToArray();
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index bd7622c..8fb5f6a 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -20,6 +20,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;
+using UVtools.Core.Converters;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
using UVtools.Core.Layers;
@@ -414,19 +415,19 @@ public class CWSFile : FileFormat
set => base.MachineZ = OutputSettings.PlatformZSize = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
get
{
- if (OutputSettings.FlipX && OutputSettings.FlipY) return Enumerations.FlipDirection.Both;
- if (OutputSettings.FlipX) return Enumerations.FlipDirection.Horizontally;
- if (OutputSettings.FlipY) return Enumerations.FlipDirection.Vertically;
- return Enumerations.FlipDirection.None;
+ if (OutputSettings.FlipX && OutputSettings.FlipY) return FlipDirection.Both;
+ if (OutputSettings.FlipX) return FlipDirection.Horizontally;
+ if (OutputSettings.FlipY) return FlipDirection.Vertically;
+ return FlipDirection.None;
}
set
{
- OutputSettings.FlipX = value is Enumerations.FlipDirection.Horizontally or Enumerations.FlipDirection.Both;
- OutputSettings.FlipY = value is Enumerations.FlipDirection.Vertically or Enumerations.FlipDirection.Both;
+ OutputSettings.FlipX = value is FlipDirection.Horizontally or FlipDirection.Both;
+ OutputSettings.FlipY = value is FlipDirection.Vertically or FlipDirection.Both;
RaisePropertyChanged();
}
}
@@ -483,32 +484,32 @@ public class CWSFile : FileFormat
public override float WaitTimeBeforeCure
{
- get => TimeExtensions.MillisecondsToSeconds(SliceSettings.WaitBeforeExpoMs);
+ get => TimeConverter.MillisecondsToSeconds(SliceSettings.WaitBeforeExpoMs);
set
{
- SliceSettings.WaitBeforeExpoMs = TimeExtensions.SecondsToMillisecondsUint(value);
+ SliceSettings.WaitBeforeExpoMs = TimeConverter.SecondsToMillisecondsUint(value);
base.WaitTimeBeforeCure = base.LightOffDelay = value;
}
}
public override float BottomExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(OutputSettings.BottomLayersTime);
+ get => TimeConverter.MillisecondsToSeconds(OutputSettings.BottomLayersTime);
set
{
OutputSettings.BottomLayersTime =
- SliceSettings.HeadLayersExpoMs = TimeExtensions.SecondsToMillisecondsUint(value);
+ SliceSettings.HeadLayersExpoMs = TimeConverter.SecondsToMillisecondsUint(value);
base.BottomExposureTime = value;
}
}
public override float ExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(OutputSettings.LayerTime);
+ get => TimeConverter.MillisecondsToSeconds(OutputSettings.LayerTime);
set
{
OutputSettings.LayerTime =
- SliceSettings.LayersExpoMs = TimeExtensions.SecondsToMillisecondsUint(value);
+ SliceSettings.LayersExpoMs = TimeConverter.SecondsToMillisecondsUint(value);
base.ExposureTime = value;
}
}
@@ -564,7 +565,7 @@ public class CWSFile : FileFormat
{
SyncMovementsWithDelay = true,
UseComments = true,
- GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial,
+ GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Relative,
GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute,
GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds,
GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndex0Started,
@@ -613,7 +614,7 @@ public class CWSFile : FileFormat
throw new InvalidOperationException($"Filename for this format should not end with a digit: {filename}");
}
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
if (Printer == PrinterType.Wanhao)
{
var manifest = new CWSManifest
@@ -660,18 +661,18 @@ public class CWSFile : FileFormat
if (Printer == PrinterType.BeneMono)
{
- EncodeLayersInZip(outputFile, filename, LayerDigits, Enumerations.IndexStartNumber.Zero, progress, matGenFunc:
+ EncodeLayersInZip(outputFile, filename, LayerDigits, IndexStartNumber.Zero, progress, matGenFunc:
(_, mat) =>
{
- var matEncode = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
- var spanEncode = matEncode.GetDataByteSpan();
- for (int i = 0; i < span.Length; i++)
+ var bgrMat = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3);
+ var bgrMatSpan = bgrMat.GetDataByteSpan();
+ var greySpan = mat.GetDataByteSpan();
+ for (int i = 0; i < greySpan.Length; i++)
{
- spanEncode[i] = span[i];
+ bgrMatSpan[i] = greySpan[i];
}
- return matEncode;
+ return bgrMat;
});
/*Parallel.For(0, LayerCount, CoreSettings.GetParallelOptions(progress),
//new ParallelOptions { MaxDegreeOfParallelism = Printer == PrinterType.BeneMono ? 1 : 1 },
@@ -699,7 +700,7 @@ public class CWSFile : FileFormat
}
else
{
- EncodeLayersInZip(outputFile, filename, LayerDigits, Enumerations.IndexStartNumber.Zero, progress);
+ EncodeLayersInZip(outputFile, filename, LayerDigits, IndexStartNumber.Zero, progress);
}
RebuildGCode();
@@ -863,25 +864,25 @@ public class CWSFile : FileFormat
if (Printer == PrinterType.BeneMono)
{
- DecodeLayersFromZipRegex(inputFile, @"(\d+).png", Enumerations.IndexStartNumber.Zero, progress,
+ DecodeLayersFromZipRegex(inputFile, @"(\d+).png", IndexStartNumber.Zero, progress,
(layerIndex, pngBytes) =>
{
- using Mat mat = new();
- CvInvoke.Imdecode(pngBytes, ImreadModes.AnyColor, mat);
- var matDecode = new Mat(mat.Height, mat.GetRealStep(), DepthType.Cv8U, 1);
- var span = mat.GetDataByteSpan();
- var spanDecode = matDecode.GetDataByteSpan();
- for (int i = 0; i < span.Length; i++)
+ using Mat bgrMat = new();
+ CvInvoke.Imdecode(pngBytes, ImreadModes.AnyColor, bgrMat);
+ var greyMat = new Mat(bgrMat.Height, bgrMat.GetRealStep(), DepthType.Cv8U, 1);
+ var bgrSpan = bgrMat.GetDataByteSpan();
+ var greySpan = greyMat.GetDataByteSpan();
+ for (int i = 0; i < bgrSpan.Length; i++)
{
- spanDecode[i] = span[i];
+ greySpan[i] = bgrSpan[i];
}
- return matDecode;
+ return greyMat;
});
}
else
{
- DecodeLayersFromZipRegex(inputFile, @"(\d+).png", Enumerations.IndexStartNumber.Zero, progress);
+ DecodeLayersFromZipRegex(inputFile, @"(\d+).png", IndexStartNumber.Zero, progress);
}
GCode.ParseLayersFromGCode(this);
@@ -997,7 +998,7 @@ public class CWSFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
var arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits";
var entry = outputFile.GetPutFile("slice.conf");
var stream = entry.Open();
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
index e92316a..a90faf2 100644
--- a/UVtools.Core/FileFormats/CXDLPFile.cs
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -17,11 +17,14 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using UVtools.Core.Converters;
using UVtools.Core.Extensions;
using UVtools.Core.Layers;
using UVtools.Core.Objects;
using UVtools.Core.Operations;
+using UVtools.Core.Printer;
namespace UVtools.Core.FileFormats;
@@ -33,6 +36,7 @@ public class CXDLPFile : FileFormat
#endregion
#region Sub Classes
+
#region Header
public sealed class Header
{
@@ -247,18 +251,24 @@ public class CXDLPFile : FileFormat
[FieldOrder(1)] public NullTerminatedUintStringBigEndian MaterialName { get; set; } = new();
- [FieldOrder(2)] public uint Unknown1 { get; set; }
- [FieldOrder(3)] public uint Unknown2 { get; set; }
- [FieldOrder(4)] public uint Unknown3 { get; set; }
- [FieldOrder(5)] public uint Unknown4 { get; set; }
- [FieldOrder(6)] public byte Unknown5 { get; set; } = 1;
- [FieldOrder(7)] public byte LightPWM { get; set; } = byte.MaxValue;
- [FieldOrder(8)] public ushort Unknown6 { get; set; } = 2;
- [FieldOrder(9)] public PageBreak PageBreak { get; set; } = new();
+ [FieldOrder(2)] public byte DistortionCompensationEnabled { get; set; }
+ [FieldOrder(3)] public uint DistortionCompensationThickness { get; set; } = 600;
+ [FieldOrder(4)] public uint DistortionCompensationFocalLength { get; set; } = 300000;
+ [FieldOrder(5)] public byte XYAxisProfileCompensationEnabled { get; set; } = 1;
+ [FieldOrder(6)] public ushort XYAxisProfileCompensationValue { get; set; }
+ [FieldOrder(7)] public byte ZPenetrationCompensationEnabled { get; set; }
+ [FieldOrder(8)] public ushort ZPenetrationCompensationLevel { get; set; } = 1000;
+ [FieldOrder(9)] public byte AntiAliasEnabled { get; set; } = 1;
+ [FieldOrder(10)] public byte AntiAliasGreyMinValue { get; set; } = 1;
+ [FieldOrder(11)] public byte AntiAliasGreyMaxValue { get; set; } = byte.MaxValue;
+ [FieldOrder(12)] public byte ImageBlurEnabled { get; set; } = 0;
+ [FieldOrder(13)] public byte ImageBlurLevel { get; set; } = 2;
+ [FieldOrder(14)] public PageBreak PageBreak { get; set; } = new();
+
public override string ToString()
{
- return $"{nameof(SoftwareName)}: {SoftwareName}, {nameof(MaterialName)}: {MaterialName}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}, {nameof(Unknown5)}: {Unknown5}, {nameof(LightPWM)}: {LightPWM}, {nameof(Unknown6)}: {Unknown6}, {nameof(PageBreak)}: {PageBreak}";
+ return $"{nameof(SoftwareName)}: {SoftwareName}, {nameof(MaterialName)}: {MaterialName}, {nameof(DistortionCompensationEnabled)}: {DistortionCompensationEnabled}, {nameof(DistortionCompensationThickness)}: {DistortionCompensationThickness}, {nameof(DistortionCompensationFocalLength)}: {DistortionCompensationFocalLength}, {nameof(XYAxisProfileCompensationEnabled)}: {XYAxisProfileCompensationEnabled}, {nameof(XYAxisProfileCompensationValue)}: {XYAxisProfileCompensationValue}, {nameof(ZPenetrationCompensationEnabled)}: {ZPenetrationCompensationEnabled}, {nameof(ZPenetrationCompensationLevel)}: {ZPenetrationCompensationLevel}, {nameof(AntiAliasEnabled)}: {AntiAliasEnabled}, {nameof(AntiAliasGreyMinValue)}: {AntiAliasGreyMinValue}, {nameof(AntiAliasGreyMaxValue)}: {AntiAliasGreyMaxValue}, {nameof(ImageBlurEnabled)}: {ImageBlurEnabled}, {nameof(ImageBlurLevel)}: {ImageBlurLevel}, {nameof(PageBreak)}: {PageBreak}";
}
}
@@ -550,8 +560,13 @@ public class CXDLPFile : FileFormat
public override float ExposureTime
{
- get => SlicerInfoSettings.ExposureTime;
- set => base.ExposureTime = SlicerInfoSettings.ExposureTime = (ushort) value;
+ get => (float)Math.Round(SlicerInfoSettings.ExposureTime / 10.0f, 1);
+ set
+ {
+ value = (float)Math.Round(value, 1);
+ SlicerInfoSettings.ExposureTime = (ushort) (value * 10);
+ base.ExposureTime = value;
+ }
}
public override float BottomLiftHeight
@@ -560,30 +575,30 @@ public class CXDLPFile : FileFormat
set => base.BottomLiftHeight = SlicerInfoSettings.BottomLiftHeight = (ushort) value;
}
- public override float LiftHeight
+ public override float BottomLiftSpeed
{
- get => SlicerInfoSettings.LiftHeight;
- set => base.LiftHeight = SlicerInfoSettings.LiftHeight = (ushort)value;
+ get => SpeedConverter.Convert(SlicerInfoSettings.BottomLiftSpeed, SpeedUnit.MillimetersPerSecond, DefaultSpeedUnit);
+ set => base.BottomLiftSpeed = SlicerInfoSettings.BottomLiftSpeed = SlicerInfoSettings.BottomLiftSpeed = (ushort)SpeedConverter.Convert(value, DefaultSpeedUnit, SpeedUnit.MillimetersPerSecond);
}
- public override float BottomLiftSpeed
+ public override float LiftHeight
{
- get => SlicerInfoSettings.BottomLiftSpeed;
- set => base.BottomLiftSpeed = SlicerInfoSettings.BottomLiftSpeed = (ushort)value;
+ get => SlicerInfoSettings.LiftHeight;
+ set => base.LiftHeight = SlicerInfoSettings.LiftHeight = (ushort)value;
}
public override float LiftSpeed
{
- get => SlicerInfoSettings.LiftSpeed;
- set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)value;
+ get => SpeedConverter.Convert(SlicerInfoSettings.LiftSpeed, SpeedUnit.MillimetersPerSecond, DefaultSpeedUnit);
+ set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)SpeedConverter.Convert(value, DefaultSpeedUnit, SpeedUnit.MillimetersPerSecond);
}
public override float BottomRetractSpeed => RetractSpeed;
public override float RetractSpeed
{
- get => SlicerInfoSettings.RetractSpeed;
- set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)value;
+ get => SpeedConverter.Convert(SlicerInfoSettings.RetractSpeed, SpeedUnit.MillimetersPerSecond, DefaultSpeedUnit);
+ set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)SpeedConverter.Convert(value, DefaultSpeedUnit, SpeedUnit.MillimetersPerSecond);
}
public override byte BottomLightPWM
@@ -601,7 +616,19 @@ public class CXDLPFile : FileFormat
public override string MachineName
{
get => HeaderSettings.PrinterModel;
- set => base.MachineName = HeaderSettings.PrinterModel = value;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value) && !value.StartsWith("CL-") && !value.StartsWith("CT-"))
+ {
+ // Parse from machine name, if coming from PrusaSlicer this will help
+ var match = Regex.Match(value, @"(CL|CT)-\d+");
+ if (match.Success && match.Groups.Count > 1)
+ {
+ value = match.Value;
+ }
+ }
+ base.MachineName = HeaderSettings.PrinterModel = value;
+ }
}
public override string? MaterialName
@@ -626,26 +653,31 @@ public class CXDLPFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.ReadWrite);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.ReadWrite);
- if (!MachineName.StartsWith("CL-"))
+ if (string.IsNullOrWhiteSpace(MachineName))
{
- if (ResolutionX == 1620 && ResolutionY == 2560)
- {
- MachineName = "CL-60"; // One
- }
- else if (ResolutionX == 3840 && ResolutionY == 2400) // Sky or lite
- {
- MachineName = "CL-89"; // Sky
- }
- else if (ResolutionX == 3840 && ResolutionY == 2160)
- {
- MachineName = "CL-133"; // Max
- }
- else
+ throw new InvalidDataException("Unable to detect the printer model from resolution, check if resolution is well defined on slicer for your printer model.");
+ }
+
+
+ if (!MachineName.StartsWith("CL-") && !MachineName.StartsWith("CT"))
+ {
+ bool found = false;
+ foreach (var machine in Printer.Machine.Machines
+ .Where(machine => machine.Brand == PrinterBrand.Creality
+ && (machine.Model.StartsWith("CL-") || machine.Model.StartsWith("CT"))
+ ))
{
- throw new InvalidDataException("Unable to detect the printer model from resolution, check if resolution is well defined on slicer for your printer model.");
+ if (ResolutionX == machine.ResolutionX && ResolutionY == machine.ResolutionY)
+ {
+ found = true;
+ MachineName = machine.Model;
+ break;
+ }
}
+
+ if(!found) throw new InvalidDataException("Unable to detect the printer model from resolution, check if resolution is well defined on slicer for your printer model.");
}
SanitizeProperties();
@@ -952,7 +984,7 @@ public class CXDLPFile : FileFormat
linesBytes[layerIndex] = null!;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
@@ -978,7 +1010,7 @@ public class CXDLPFile : FileFormat
SanitizeProperties();
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.ReadWrite);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.ReadWrite);
outputFile.Seek(offset, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
diff --git a/UVtools.Core/FileFormats/CXDLPv1File.cs b/UVtools.Core/FileFormats/CXDLPv1File.cs
index 682c050..6e1bb1c 100644
--- a/UVtools.Core/FileFormats/CXDLPv1File.cs
+++ b/UVtools.Core/FileFormats/CXDLPv1File.cs
@@ -501,7 +501,7 @@ public class CXDLPv1File : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
if (ResolutionX == 2560 && ResolutionY == 1620)
{
@@ -697,7 +697,7 @@ public class CXDLPv1File : FileFormat
linesBytes[layerIndex] = null!;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
@@ -721,7 +721,7 @@ public class CXDLPv1File : FileFormat
offset += size.Area() * 2 + 2; // + page break
}
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(offset, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
}
diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index 49cf047..aa14430 100644
--- a/UVtools.Core/FileFormats/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -1290,12 +1290,12 @@ public class ChituboxFile : FileFormat
set => base.MachineZ = HeaderSettings.BedSizeZ = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => HeaderSettings.ProjectorType == 0 ? Enumerations.FlipDirection.None : Enumerations.FlipDirection.Horizontally;
+ get => HeaderSettings.ProjectorType == 0 ? FlipDirection.None : FlipDirection.Horizontally;
set
{
- HeaderSettings.ProjectorType = value == Enumerations.FlipDirection.None ? 0u : 1;
+ HeaderSettings.ProjectorType = value == FlipDirection.None ? 0u : 1;
RaisePropertyChanged();
}
}
@@ -1729,13 +1729,13 @@ public class ChituboxFile : FileFormat
LayerDefinitions = null;
}
- public override bool CanProcess(string fileFullPath)
+ public override bool CanProcess(string? fileFullPath)
{
if (!base.CanProcess(fileFullPath)) return false;
try
{
- using var fs = new BinaryReader(new FileStream(fileFullPath, FileMode.Open, FileAccess.Read));
+ using var fs = new BinaryReader(new FileStream(fileFullPath!, FileMode.Open, FileAccess.Read));
var magic = fs.ReadUInt32();
return magic is MAGIC_CBDDLP or MAGIC_CTB or MAGIC_CTBv4;
}
@@ -1838,7 +1838,7 @@ public class ChituboxFile : FileFormat
//uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
LayerDefinitions = new LayerDef[HeaderSettings.AntiAliasLevel, LayerCount];
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
Mat?[] thumbnails = {GetThumbnail(true), GetThumbnail(false)};
@@ -2145,7 +2145,7 @@ public class ChituboxFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex);
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
@@ -2169,7 +2169,7 @@ public class ChituboxFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
SanitizeProperties();
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index 43a6aff..ec53230 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -186,13 +186,13 @@ public class ChituboxZipFile : FileFormat
set => base.MachineZ = HeaderSettings.MachineZ = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => HeaderSettings.Mirror == 0 ? Enumerations.FlipDirection.None : Enumerations.FlipDirection.Horizontally;
+ get => HeaderSettings.Mirror == 0 ? FlipDirection.None : FlipDirection.Horizontally;
set
{
- HeaderSettings.ProjectType = value == Enumerations.FlipDirection.None ? "Normal" : "LCD_mirror";
- HeaderSettings.Mirror = (byte)(value == Enumerations.FlipDirection.None ? 0 : 1);
+ HeaderSettings.ProjectType = value == FlipDirection.None ? "Normal" : "LCD_mirror";
+ HeaderSettings.Mirror = (byte)(value == FlipDirection.None ? 0 : 1);
RaisePropertyChanged();
}
}
@@ -384,13 +384,13 @@ public class ChituboxZipFile : FileFormat
#region Methods
- public override bool CanProcess(string fileFullPath)
+ public override bool CanProcess(string? fileFullPath)
{
if (!base.CanProcess(fileFullPath)) return false;
try
{
- var zip = ZipFile.Open(fileFullPath, ZipArchiveMode.Read);
+ var zip = ZipFile.Open(fileFullPath!, ZipArchiveMode.Read);
if (zip.Entries.Any(entry => entry.Name.EndsWith(".gcode"))) return true;
}
catch (Exception e)
@@ -404,7 +404,7 @@ public class ChituboxZipFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
if (Thumbnails is not null && Thumbnails.Length > 0 && Thumbnails[0] is not null)
{
using var stream = outputFile.CreateEntry("preview.png").Open();
@@ -426,7 +426,7 @@ public class ChituboxZipFile : FileFormat
outputFile.PutFileContent(GCodeFilename, GCodeStr, ZipArchiveMode.Create);
}
- EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
+ EncodeLayersInZip(outputFile, IndexStartNumber.One, progress);
}
protected override void DecodeInternally(OperationProgress progress)
@@ -482,7 +482,7 @@ public class ChituboxZipFile : FileFormat
Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial);
- DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
+ DecodeLayersFromZip(inputFile, IndexStartNumber.One, progress);
if (IsPHZZip) // PHZ file
{
@@ -518,7 +518,7 @@ public class ChituboxZipFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, 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 29686ec..51b31ff 100644
--- a/UVtools.Core/FileFormats/FDGFile.cs
+++ b/UVtools.Core/FileFormats/FDGFile.cs
@@ -723,12 +723,12 @@ public class FDGFile : FileFormat
set => base.MachineZ = HeaderSettings.BedSizeZ = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => HeaderSettings.ProjectorType == 0 ? Enumerations.FlipDirection.None : Enumerations.FlipDirection.Horizontally;
+ get => HeaderSettings.ProjectorType == 0 ? FlipDirection.None : FlipDirection.Horizontally;
set
{
- HeaderSettings.ProjectorType = value == Enumerations.FlipDirection.None ? 0u : 1;
+ HeaderSettings.ProjectorType = value == FlipDirection.None ? 0u : 1;
RaisePropertyChanged();
}
}
@@ -925,7 +925,7 @@ public class FDGFile : FileFormat
HeaderSettings.EncryptionKey = (uint)rnd.Next(short.MaxValue, int.MaxValue);
}*/
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
for (byte i = 0; i < ThumbnailsCount; i++)
@@ -1111,7 +1111,7 @@ public class FDGFile : FileFormat
if (DecodeType == FileDecodeType.Full)
{
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
@@ -1128,7 +1128,7 @@ public class FDGFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
HeaderSettings.ModifiedTimestampMinutes = (uint)DateTimeExtensions.TimestampMinutes;
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
diff --git a/UVtools.Core/FileFormats/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs
index 173cc4c..20c6358 100644
--- a/UVtools.Core/FileFormats/FileExtension.cs
+++ b/UVtools.Core/FileFormats/FileExtension.cs
@@ -129,7 +129,13 @@ public sealed class FileExtension : IEquatable<FileExtension>, IEquatable<string
? FileFormat.FindByExtensionOrFilePath(Extension, createNewInstance)
: FileFormat.FindByType(FileFormatType, createNewInstance);
- public static FileExtension? Find(string extension) =>
- FileFormat.FindExtension(extension);
+ public static FileExtension? Find(string extension)
+ {
+ if (string.IsNullOrWhiteSpace(extension)) return null;
+ if (extension.StartsWith('.')) extension = extension.Remove(1);
+ return FileFormat.FindExtension(extension);
+ }
+
+
#endregion
} \ No newline at end of file
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 442b111..d651bdc 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -43,6 +43,8 @@ namespace UVtools.Core.FileFormats;
public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFormat>, IList<Layer>
{
#region Constants
+
+ public const SpeedUnit DefaultSpeedUnit = SpeedUnit.MillimetersPerMinute;
public const string TemporaryFileAppend = ".tmp";
public const ushort ExtraPrintTime = 300;
@@ -351,6 +353,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
new PhotonWorkshopFile(), // PSW
new CWSFile(), // CWS
new OSLAFile(), // OSLA
+ new JXSFile(), // jxs
new ZCodeFile(), // zcode
new ZCodexFile(), // zcodex
new MDLPFile(), // MKS v1
@@ -476,9 +479,37 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
: fileFormats[0];
}
- public static FileExtension? FindExtension(string extension)
+ /// <summary>
+ /// Find <see cref="FileFormat"/> by an type name
+ /// </summary>
+ /// <param name="type">Type name to find</param>
+ /// <param name="createNewInstance">True to create a new instance of found file format, otherwise will return a pre created one which should be used for read-only purpose</param>
+ /// <returns><see cref="FileFormat"/> object or null if not found</returns>
+ public static FileFormat? FindByType(string type, bool createNewInstance = false)
{
- return AvailableFormats.SelectMany(format => format.FileExtensions).FirstOrDefault(ext => ext.Equals(extension));
+ if (!type.EndsWith("File"))
+ {
+ type += "File";
+ }
+
+ var fileFormat = AvailableFormats.FirstOrDefault(format => string.Equals(format.GetType().Name, type, StringComparison.OrdinalIgnoreCase));
+ if (fileFormat is null) return null;
+ return createNewInstance
+ ? Activator.CreateInstance(fileFormat.GetType()) as FileFormat
+ : fileFormat;
+ //return (from t in AvailableFormats where type == t.GetType() select createNewInstance ? (FileFormat) Activator.CreateInstance(type) : t).FirstOrDefault();
+ }
+
+ /// <summary>
+ /// Find <see cref="FileFormat"/> by any means (type name, extension, filepath)
+ /// </summary>
+ /// <param name="name">Name to find</param>
+ /// <param name="createNewInstance">True to create a new instance of found file format, otherwise will return a pre created one which should be used for read-only purpose</param>
+ /// <returns><see cref="FileFormat"/> object or null if not found</returns>
+ public static FileFormat? FindByAnyMeans(string name, bool createNewInstance = false)
+ {
+ return FindByType(name, true)
+ ?? FindByExtensionOrFilePath(name, true);
}
/// <summary>
@@ -497,6 +528,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
//return (from t in AvailableFormats where type == t.GetType() select createNewInstance ? (FileFormat) Activator.CreateInstance(type) : t).FirstOrDefault();
}
+ public static FileExtension? FindExtension(string extension)
+ {
+ return AvailableFormats.SelectMany(format => format.FileExtensions).FirstOrDefault(ext => ext.Equals(extension));
+ }
+
public static string? GetFileNameStripExtensions(string? filepath)
{
if (filepath is null) return null;
@@ -521,6 +557,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
public static FileFormat? Open(string fileFullPath, OperationProgress? progress = null) =>
Open(fileFullPath, FileDecodeType.Full, progress);
+ public static Task<FileFormat?> OpenAsync(string fileFullPath, FileDecodeType decodeType, OperationProgress? progress = null)
+ => Task.Run(() => Open(fileFullPath, decodeType, progress), progress?.Token ?? default);
+
+ public static Task<FileFormat?> OpenAsync(string fileFullPath, OperationProgress? progress = null) => OpenAsync(fileFullPath, FileDecodeType.Full, progress);
+
/// <summary>
/// Copy parameters from one file to another
/// </summary>
@@ -889,7 +930,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
#region Members
public object Mutex = new();
- private Layer[] _layers = Array.Empty<Layer>();
+ protected Layer[] _layers = Array.Empty<Layer>();
private bool _haveModifiedLayers;
private uint _version;
@@ -1046,6 +1087,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
public bool SuppressRebuildProperties { get; set; }
/// <summary>
+ /// Gets the temporary output file path to use on save and encode
+ /// </summary>
+ public string TemporaryOutputFileFullPath => $"{FileFullPath}{TemporaryFileAppend}";
+
+ /// <summary>
/// Gets the input file path loaded into this <see cref="FileFormat"/>
/// </summary>
public string? FileFullPath { get; set; }
@@ -1476,7 +1522,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <summary>
/// Gets or sets if images need to be mirrored on lcd to print on the correct orientation
/// </summary>
- public virtual Enumerations.FlipDirection DisplayMirror { get; set; } = Enumerations.FlipDirection.None;
+ public virtual FlipDirection DisplayMirror { get; set; } = FlipDirection.None;
/// <summary>
/// Gets if the display is in portrait mode
@@ -2984,7 +3030,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </summary>
/// <param name="fileFullPath"></param>
/// <returns></returns>
- public virtual bool CanProcess(string fileFullPath)
+ public virtual bool CanProcess(string? fileFullPath)
{
if (fileFullPath is null) return false;
if (!File.Exists(fileFullPath)) return false;
@@ -2997,17 +3043,12 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// Validate if a file is a valid <see cref="FileFormat"/>
/// </summary>
/// <param name="fileFullPath">Full file path</param>
- public void FileValidation(string fileFullPath)
+ public void FileValidation(string? fileFullPath)
{
if (string.IsNullOrWhiteSpace(fileFullPath)) throw new ArgumentNullException(nameof(FileFullPath), "FileFullPath can't be null nor empty.");
if (!File.Exists(fileFullPath)) throw new FileNotFoundException("The specified file does not exists.", fileFullPath);
- if (IsExtensionValid(fileFullPath, true))
- {
- return;
- }
-
- throw new FileLoadException($"The specified file is not valid.", fileFullPath);
+ if (!IsExtensionValid(fileFullPath, true)) throw new FileLoadException("The specified file is not valid.", fileFullPath);
}
/// <summary>
@@ -3169,25 +3210,16 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <param name="progress"></param>
public void Encode(string? fileFullPath, OperationProgress? progress = null)
{
- if (fileFullPath is null)
- {
- throw new ArgumentNullException(nameof(fileFullPath));
- }
+ fileFullPath ??= FileFullPath ?? throw new ArgumentNullException(nameof(fileFullPath));
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);
Sanitize();
- if (File.Exists(fileFullPath)) File.Delete(fileFullPath);
-
- FileFullPath = fileFullPath;
-
for (var i = 0; i < Thumbnails.Length; i++)
{
if (Thumbnails[i] is null || Thumbnails[i]!.IsEmpty) continue;
@@ -3195,12 +3227,38 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height));
}
- EncodeInternally(progress);
+ // Backup old file name and prepare the temporary file to be written next
+ var oldFilePath = FileFullPath;
+ FileFullPath = fileFullPath;
+ var tempFile = TemporaryOutputFileFullPath;
+ if (File.Exists(tempFile)) File.Delete(tempFile);
- IsModified = false;
- RequireFullEncode = false;
+ try
+ {
+ EncodeInternally(progress);
+
+ IsModified = false;
+ RequireFullEncode = false;
+
+ // Move temporary output file in place
+ File.Move(tempFile, fileFullPath, true);
+ }
+ catch (Exception)
+ {
+ // Restore backup file path and delete the temporary
+ FileFullPath = oldFilePath;
+ if (File.Exists(tempFile)) File.Delete(tempFile);
+ throw;
+ }
}
+ public void Encode(OperationProgress progress) => Encode(null, progress);
+
+ public Task EncodeAsync(string? fileFullPath, OperationProgress? progress = null) =>
+ Task.Run(() => Encode(fileFullPath, progress), progress?.Token ?? default);
+
+ public Task EncodeAsync(OperationProgress progress) => EncodeAsync(null, progress);
+
/// <summary>
/// Decode a slicer file
/// </summary>
@@ -3210,26 +3268,28 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <summary>
/// Decode a slicer file
/// </summary>
- /// <param name="fileFullPath"></param>
+ /// <param name="fileFullPath">file path to load, use null to reload file</param>
/// <param name="progress"></param>
- public void Decode(string fileFullPath, OperationProgress? progress = null) => Decode(fileFullPath, FileDecodeType.Full, progress);
+ public void Decode(string? fileFullPath = null, OperationProgress? progress = null) => Decode(fileFullPath, FileDecodeType.Full, progress);
/// <summary>
/// Decode a slicer file
/// </summary>
- /// <param name="fileFullPath"></param>
+ /// <param name="fileFullPath">file path to load, use null to reload file</param>
/// <param name="fileDecodeType"></param>
/// <param name="progress"></param>
- public void Decode(string fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null)
+ public void Decode(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null)
{
Clear();
- FileValidation(fileFullPath);
- FileFullPath = fileFullPath;
+ if(!string.IsNullOrWhiteSpace(fileFullPath)) FileFullPath = fileFullPath;
+ FileValidation(FileFullPath);
+
DecodeType = fileDecodeType;
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
DecodeInternally(progress);
+ IsModified = false;
progress.ThrowIfCancellationRequested();
@@ -3249,7 +3309,40 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
GetBoundingRectangle(progress);
}
- public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default,
+ public Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
+ Task.Run(() => Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);
+
+ public Task DecodeAsync(string? fileFullPath = null, OperationProgress? progress = null)
+ => DecodeAsync(fileFullPath, FileDecodeType.Full, progress);
+
+
+ /// <summary>
+ /// Reloads the file
+ /// </summary>
+ /// <param name="fileDecodeType"></param>
+ /// <param name="progress"></param>
+ public void Reload(FileDecodeType fileDecodeType, OperationProgress? progress = null) => Decode(null, fileDecodeType, progress);
+
+ /// <summary>
+ /// Reloads the file
+ /// </summary>
+ /// <param name="progress"></param>
+ public void Reload(OperationProgress? progress = null) => Reload(FileDecodeType.Full, progress);
+
+ /// <summary>
+ /// Reloads the file
+ /// </summary>
+ /// <param name="fileDecodeType"></param>
+ /// <param name="progress"></param>
+ public Task ReloadAsync(FileDecodeType fileDecodeType, OperationProgress? progress = null) => DecodeAsync(null, fileDecodeType, progress);
+
+ /// <summary>
+ /// Reloads the file
+ /// </summary>
+ /// <param name="progress"></param>
+ public Task ReloadAsync(OperationProgress? progress = null) => ReloadAsync(FileDecodeType.Full, progress);
+
+ public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, byte padDigits, IndexStartNumber layerIndexStartNumber = default,
OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
{
if (DecodeType != FileDecodeType.Full || LayerCount == 0) return;
@@ -3283,17 +3376,17 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
}
}
- public void EncodeLayersInZip(ZipArchive zipArchive, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
+ public void EncodeLayersInZip(ZipArchive zipArchive, byte padDigits, IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, string.Empty, padDigits, layerIndexStartNumber, progress, path, matGenFunc);
- public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, Enumerations.IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
+ public void EncodeLayersInZip(ZipArchive zipArchive, string prepend, IndexStartNumber layerIndexStartNumber = default, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, prepend, 0, layerIndexStartNumber, progress, path, matGenFunc);
- public void EncodeLayersInZip(ZipArchive zipArchive, Enumerations.IndexStartNumber layerIndexStartNumber, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
+ public void EncodeLayersInZip(ZipArchive zipArchive, IndexStartNumber layerIndexStartNumber, OperationProgress? progress = null, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
=> EncodeLayersInZip(zipArchive, string.Empty, 0, layerIndexStartNumber, progress, path, matGenFunc);
public void EncodeLayersInZip(ZipArchive zipArchive, OperationProgress progress, string path = "", Func<uint, Mat, Mat>? matGenFunc = null)
- => EncodeLayersInZip(zipArchive, string.Empty, 0, Enumerations.IndexStartNumber.Zero, progress, path, matGenFunc);
+ => EncodeLayersInZip(zipArchive, string.Empty, 0, IndexStartNumber.Zero, progress, path, matGenFunc);
public void DecodeLayersFromZip(ZipArchiveEntry[] layerEntries, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
@@ -3313,19 +3406,19 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (matGenFunc is null)
{
- this[layerIndex] = new Layer((uint)layerIndex, pngBytes, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, pngBytes, this);
}
- if (matGenFunc is not null)
+ else
{
using var mat = matGenFunc.Invoke((uint) layerIndex, pngBytes);
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
});
}
- public void DecodeLayersFromZipRegex(ZipArchive zipArchive, string regex, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
+ public void DecodeLayersFromZipRegex(ZipArchive zipArchive, string regex, IndexStartNumber layerIndexStartNumber = IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
{
var layerEntries = new ZipArchiveEntry?[LayerCount];
@@ -3335,7 +3428,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (!match.Success || match.Groups.Count < 2) continue;
if (!uint.TryParse(match.Groups[1].Value, out var layerIndex)) continue;
- if (layerIndexStartNumber == Enumerations.IndexStartNumber.One && layerIndex > 0) layerIndex--;
+ if (layerIndexStartNumber == IndexStartNumber.One && layerIndex > 0) layerIndex--;
if (layerIndex >= LayerCount)
{
continue;
@@ -3355,17 +3448,17 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
DecodeLayersFromZip(layerEntries!, progress, matGenFunc);
}
- public void DecodeLayersFromZip(ZipArchive zipArchive, byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
+ public void DecodeLayersFromZip(ZipArchive zipArchive, byte padDigits, IndexStartNumber layerIndexStartNumber = IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, $@"(\d{{{padDigits}}}).png", layerIndexStartNumber, progress, matGenFunc);
- public void DecodeLayersFromZip(ZipArchive zipArchive, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
+ public void DecodeLayersFromZip(ZipArchive zipArchive, IndexStartNumber layerIndexStartNumber = IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, @"^(\d+).png", layerIndexStartNumber, progress, matGenFunc);
- public void DecodeLayersFromZip(ZipArchive zipArchive, string prepend, Enumerations.IndexStartNumber layerIndexStartNumber = Enumerations.IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
+ public void DecodeLayersFromZip(ZipArchive zipArchive, string prepend, IndexStartNumber layerIndexStartNumber = IndexStartNumber.Zero, OperationProgress? progress = null, Func<uint, byte[], Mat>? matGenFunc = null)
=> DecodeLayersFromZipRegex(zipArchive, $@"^{Regex.Escape(prepend)}(\d+).png", layerIndexStartNumber, progress, matGenFunc);
public void DecodeLayersFromZip(ZipArchive zipArchive, OperationProgress progress, Func<uint, byte[], Mat>? matGenFunc = null)
- => DecodeLayersFromZipRegex(zipArchive, @"^(\d+).png", Enumerations.IndexStartNumber.Zero, progress, matGenFunc);
+ => DecodeLayersFromZipRegex(zipArchive, @"^(\d+).png", IndexStartNumber.Zero, progress, matGenFunc);
/// <summary>
/// Extract contents to a folder
@@ -4281,11 +4374,12 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </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>
+ /// <exception cref="ArgumentNullException"><see cref="FileFullPath"/></exception>
public void SaveAs(string? filePath = null, OperationProgress? progress = null)
{
if (RequireFullEncode)
{
- if (!string.IsNullOrEmpty(filePath))
+ if (!string.IsNullOrWhiteSpace(filePath))
{
FileFullPath = filePath;
}
@@ -4293,20 +4387,39 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
return;
}
- if (FileFullPath is null)
+ if (string.IsNullOrWhiteSpace(FileFullPath))
{
- throw new ArgumentNullException(nameof(FileFullPath));
+ if (!string.IsNullOrWhiteSpace(filePath))
+ {
+ Encode(filePath, progress);
+ return;
+ }
+ throw new ArgumentNullException(nameof(FileFullPath), "Not encoded yet and both source and output files are null");
}
- if (!string.IsNullOrEmpty(filePath))
+
+ // Backup old file name and prepare the temporary file to be written next
+ var oldFilePath = FileFullPath!;
+ if(!string.IsNullOrWhiteSpace(filePath)) FileFullPath = filePath;
+ var tempFile = TemporaryOutputFileFullPath;
+ File.Copy(oldFilePath, tempFile, true);
+
+ try
{
- File.Copy(FileFullPath, filePath, true);
- FileFullPath = filePath;
+ progress ??= new OperationProgress();
+ PartialSaveInternally(progress);
+ // Move temporary output file in place
+ File.Move(tempFile, FileFullPath, true);
}
-
- progress ??= new OperationProgress();
- PartialSaveInternally(progress);
+ catch (Exception)
+ {
+ // Restore backup file path and delete the temporary
+ FileFullPath = oldFilePath;
+ if (File.Exists(tempFile)) File.Delete(tempFile);
+ throw;
+ }
+
}
/// <summary>
diff --git a/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs b/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs
index c9571b8..a1d21c0 100644
--- a/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs
+++ b/UVtools.Core/FileFormats/FlashForgeSVGXFile.cs
@@ -316,9 +316,9 @@ public class FlashForgeSVGXFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Enumerations.FlipDirection.Vertically;
+ get => FlipDirection.Vertically;
set {}
}
@@ -456,7 +456,7 @@ public class FlashForgeSVGXFile : FileFormat
"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(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
HeaderSettings.Preview1Address = 0;
@@ -723,14 +723,14 @@ public class FlashForgeSVGXFile : FileFormat
}
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
}
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(HeaderSettings.SVGDocumentAddress, SeekOrigin.Begin);
outputFile.SetLength(outputFile.Position);
outputFile.WriteString(SVGDocument.SerializeToString());
diff --git a/UVtools.Core/FileFormats/GR1File.cs b/UVtools.Core/FileFormats/GR1File.cs
index 46cf63f..b55f678 100644
--- a/UVtools.Core/FileFormats/GR1File.cs
+++ b/UVtools.Core/FileFormats/GR1File.cs
@@ -229,7 +229,7 @@ public class GR1File : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror { get; set; }
+ public override FlipDirection DisplayMirror { get; set; }
public override float LayerHeight
{
@@ -356,7 +356,7 @@ public class GR1File : FileFormat
#region Methods
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
var pageBreak = PageBreak.Bytes;
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
@@ -520,7 +520,7 @@ public class GR1File : FileFormat
linesBytes[layerIndex] = null!;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
@@ -540,7 +540,7 @@ public class GR1File : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(SlicerInfoAddress, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
}
diff --git a/UVtools.Core/FileFormats/GenericZIPFile.cs b/UVtools.Core/FileFormats/GenericZIPFile.cs
index 87a949c..0c9a956 100644
--- a/UVtools.Core/FileFormats/GenericZIPFile.cs
+++ b/UVtools.Core/FileFormats/GenericZIPFile.cs
@@ -156,13 +156,13 @@ public class GenericZIPFile : FileFormat
#region Methods
- public override bool CanProcess(string fileFullPath)
+ public override bool CanProcess(string? fileFullPath)
{
if(!base.CanProcess(fileFullPath)) return false;
try
{
- using var zip = ZipFile.Open(fileFullPath, ZipArchiveMode.Read);
+ using var zip = ZipFile.Open(fileFullPath!, ZipArchiveMode.Read);
foreach (var entry in zip.Entries)
{
if (entry.Name == ManifestFileName) return true;
@@ -182,7 +182,7 @@ public class GenericZIPFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
if (Thumbnails is not null)
{
@@ -202,7 +202,7 @@ public class GenericZIPFile : FileFormat
}
}
- EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
+ EncodeLayersInZip(outputFile, IndexStartNumber.One, progress);
ManifestFile.Update();
@@ -247,7 +247,7 @@ public class GenericZIPFile : FileFormat
}
Init(layerCount, DecodeType == FileDecodeType.Partial);
- DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
+ DecodeLayersFromZip(inputFile, IndexStartNumber.One, progress);
entry = inputFile.GetEntry("preview.png");
if (entry is not null)
@@ -267,7 +267,7 @@ public class GenericZIPFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
bool deleted;
do
diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs
index fc1be99..dc26d71 100644
--- a/UVtools.Core/FileFormats/ImageFile.cs
+++ b/UVtools.Core/FileFormats/ImageFile.cs
@@ -78,7 +78,7 @@ public class ImageFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- this[0].LayerMat.Save(FileFullPath);
+ this[0].LayerMat.Save(TemporaryOutputFileFullPath);
}
protected override void DecodeInternally(OperationProgress progress)
@@ -103,7 +103,7 @@ public class ImageFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- this[0].LayerMat.Save(FileFullPath);
+ this[0].LayerMat.Save(TemporaryOutputFileFullPath);
}
public override FileFormat Convert(Type to, string fileFullPath, uint version = 0, OperationProgress? progress = null)
diff --git a/UVtools.Core/FileFormats/JXSFile.cs b/UVtools.Core/FileFormats/JXSFile.cs
new file mode 100644
index 0000000..bc8758a
--- /dev/null
+++ b/UVtools.Core/FileFormats/JXSFile.cs
@@ -0,0 +1,698 @@
+/*
+ * 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 Emgu.CV;
+using Emgu.CV.CvEnum;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
+using System.Xml.Serialization;
+using UVtools.Core.Converters;
+using UVtools.Core.Extensions;
+using UVtools.Core.GCode;
+using UVtools.Core.Layers;
+using UVtools.Core.Operations;
+
+namespace UVtools.Core.FileFormats;
+
+public class JXSFile : FileFormat
+{
+ #region Constants
+
+ public const string ConfigFileName = "config.ini";
+ public const string ControlFilename = "control.json";
+
+ #endregion
+
+ #region Sub Classes
+
+ public sealed class JXSConfig
+ {
+ public string Action { get; set; } = "print";
+
+ [DisplayName("FirstLayerTime")] public uint BottomExposureTimeMs { get; set; } = TimeConverter.SecondsToMillisecondsUint(DefaultBottomExposureTime);
+ [DisplayName("LayerTime")] public uint ExposureTimeMs { get; set; } = TimeConverter.SecondsToMillisecondsUint(DefaultExposureTime);
+ public uint NumFade { get; set; }
+ [DisplayName("NumLayers")] public uint LayerCount { get; set; }
+ [DisplayName("UsedMaterial")] public float MaterialMl { get; set; }
+
+ [DisplayName("layerHeight")] public float LayerHeight { get; set; }
+
+ [DisplayName("nJobName")] public string JobName { get; set; } = string.Empty;
+ [DisplayName("NumBottomLayers")] public ushort BottomLayerCount { get; set; } = DefaultBottomLayerCount;
+ [DisplayName("LiftDistance1")] public float LiftHeight1 { get; set; } = DefaultBottomLiftHeight;
+ [DisplayName("LiftFeedrate1")] public float LiftSpeed1 { get; set; } = SpeedConverter.Convert(DefaultLiftSpeed, SpeedUnit.MillimetersPerMinute, SpeedUnit.MillimetersPerSecond);
+ [DisplayName("LiftDistance2")] public float LiftHeight2 { get; set; } = DefaultLiftHeight2;
+ [DisplayName("LiftFeedrate2")] public float LiftSpeed2 { get; set; } = SpeedConverter.Convert(DefaultLiftSpeed2, SpeedUnit.MillimetersPerMinute, SpeedUnit.MillimetersPerSecond);
+ [DisplayName("BottomLiftFeedrate")] public float BottomLiftSpeed { get; set; } = SpeedConverter.Convert(DefaultBottomLiftSpeed, SpeedUnit.MillimetersPerMinute, SpeedUnit.MillimetersPerSecond);
+ [DisplayName("RetractFeedrate")] public float RetractSpeed { get; set; } = SpeedConverter.Convert(DefaultRetractSpeed, SpeedUnit.MillimetersPerMinute, SpeedUnit.MillimetersPerSecond);
+ [DisplayName("ZMoveTimeCompensation")] public uint WaitTimeBeforeCure { get; set; } = 1500;
+ [DisplayName("ZMoveTimeCompensationBottom")] public uint BottomWaitTimeBeforeCure { get; set; } = 8000;
+ public string OnLightCode { get; set; } = "M106 S255";
+ public string OffLightCode { get; set; } = "M106 S0";
+ public string GcodeHeader { get; set; } = "G21|G91|M17|M106 S0";
+ public string GcodeFooter { get; set; } = "G0 Z100 F150";
+ public string ApplicationName { get; set; } = "GKone-Slicer";
+ }
+
+ public sealed class JXSControl
+ {
+ [JsonPropertyName("total_time")] public float PrintTime { get; set; }
+
+ [JsonPropertyName("total_slices")] public uint LayerCount { get; set; }
+
+ [JsonPropertyName("used_material")] public float MaterialMl { get; set; }
+
+ [JsonPropertyName("action_list")] public List<object[]> Actions { get; set; } = new();
+ }
+ #endregion
+
+ #region Properties
+ public JXSConfig ConfigFile { get; set; } = new ();
+ public JXSControl ControlFile { get; set; } = new ();
+
+ public override FileFormatType FileType => FileFormatType.Archive;
+
+ public override FileExtension[] FileExtensions { get; } = {
+ new(typeof(JXSFile), "jxs", "Uniformation GKone (JXS)")
+ };
+
+ public override PrintParameterModifier[]? PrintParameterModifiers { get; } = {
+ PrintParameterModifier.BottomLayerCount,
+
+ PrintParameterModifier.BottomWaitTimeBeforeCure,
+ PrintParameterModifier.WaitTimeBeforeCure,
+
+ PrintParameterModifier.BottomExposureTime,
+ PrintParameterModifier.ExposureTime,
+
+ PrintParameterModifier.BottomWaitTimeAfterCure,
+ PrintParameterModifier.WaitTimeAfterCure,
+
+ PrintParameterModifier.BottomLiftHeight,
+ PrintParameterModifier.BottomLiftSpeed,
+ PrintParameterModifier.LiftHeight,
+ PrintParameterModifier.LiftSpeed,
+
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
+ PrintParameterModifier.BottomWaitTimeAfterLift,
+ PrintParameterModifier.WaitTimeAfterLift,
+
+ PrintParameterModifier.BottomRetractSpeed,
+ PrintParameterModifier.RetractSpeed,
+
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
+
+ PrintParameterModifier.BottomLightPWM,
+ PrintParameterModifier.LightPWM,
+ };
+
+ public override PrintParameterModifier[]? PrintParameterPerLayerModifiers { get; } = {
+ PrintParameterModifier.PositionZ,
+ PrintParameterModifier.WaitTimeBeforeCure,
+ PrintParameterModifier.ExposureTime,
+ PrintParameterModifier.WaitTimeAfterCure,
+ PrintParameterModifier.LiftHeight,
+ PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+ PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
+ PrintParameterModifier.LightPWM,
+ };
+
+ //public override Size[]? ThumbnailsOriginalSize { get; } = {new(640, 480)};
+
+ public override uint ResolutionX
+ {
+ get => 4920;
+ set
+ {
+ if (value != ResolutionX) throw new ArgumentOutOfRangeException(nameof(ResolutionX), $"{nameof(ResolutionX)} can not be different from {ResolutionX}");
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint ResolutionY
+ {
+ get => 2880;
+ set
+ {
+ if(value != ResolutionY) throw new ArgumentOutOfRangeException(nameof(ResolutionY), $"{nameof(ResolutionY)} can not be different from {ResolutionY}");
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float DisplayWidth
+ {
+ get => 221.40f;
+ set => RaisePropertyChanged();
+ }
+
+ public override float DisplayHeight
+ {
+ get => 129.60f;
+ set => RaisePropertyChanged();
+ }
+
+ public override float MachineZ
+ {
+ get => 245;
+ set => RaisePropertyChanged();
+ }
+
+ public override FlipDirection DisplayMirror => FlipDirection.Vertically;
+
+ public override float LayerHeight
+ {
+ get => ConfigFile.LayerHeight;
+ set
+ {
+ ConfigFile.LayerHeight = Layer.RoundHeight(value);
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint LayerCount
+ {
+ get => base.LayerCount;
+ set => base.LayerCount = ConfigFile.LayerCount = ControlFile.LayerCount = base.LayerCount;
+ }
+
+ public override ushort BottomLayerCount
+ {
+ get => ConfigFile.BottomLayerCount;
+ set => base.BottomLayerCount = ConfigFile.BottomLayerCount = value;
+ }
+
+ public override float BottomLightOffDelay
+ {
+ get => BottomWaitTimeBeforeCure;
+ set => BottomWaitTimeBeforeCure = value;
+ }
+
+ public override float LightOffDelay
+ {
+ get => WaitTimeBeforeCure;
+ set => WaitTimeBeforeCure = value;
+ }
+
+ public override float BottomWaitTimeBeforeCure
+ {
+ get => TimeConverter.MillisecondsToSeconds(ConfigFile.BottomWaitTimeBeforeCure);
+ set
+ {
+ ConfigFile.BottomWaitTimeBeforeCure = TimeConverter.SecondsToMillisecondsUint(value);
+ base.BottomWaitTimeBeforeCure = base.BottomLightOffDelay = value;
+ }
+ }
+
+ public override float WaitTimeBeforeCure
+ {
+ get => TimeConverter.MillisecondsToSeconds(ConfigFile.WaitTimeBeforeCure);
+ set
+ {
+ ConfigFile.WaitTimeBeforeCure = TimeConverter.SecondsToMillisecondsUint(value);
+ base.WaitTimeBeforeCure = base.LightOffDelay = value;
+ }
+ }
+
+ public override float BottomExposureTime
+ {
+ get => TimeConverter.MillisecondsToSeconds(ConfigFile.BottomExposureTimeMs);
+ set
+ {
+ ConfigFile.BottomExposureTimeMs = TimeConverter.SecondsToMillisecondsUint(value);
+ base.BottomExposureTime = value;
+ }
+ }
+
+ public override float ExposureTime
+ {
+ get => TimeConverter.MillisecondsToSeconds(ConfigFile.ExposureTimeMs);
+ set
+ {
+ ConfigFile.ExposureTimeMs = TimeConverter.SecondsToMillisecondsUint(value);
+ base.ExposureTime = value;
+ }
+ }
+
+ public override float BottomLiftHeight
+ {
+ get => ConfigFile.LiftHeight1;
+ set => base.BottomLiftHeight = (float)Math.Round(value, 2);
+ }
+
+ public override float LiftHeight
+ {
+ get => ConfigFile.LiftHeight1;
+ set => base.LiftHeight = ConfigFile.LiftHeight1 = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomLiftSpeed
+ {
+ get => ConfigFile.BottomLiftSpeed;
+ set => base.BottomLiftSpeed = ConfigFile.BottomLiftSpeed = (float)Math.Round(value, 2);
+ }
+
+ public override float LiftSpeed
+ {
+ get => ConfigFile.LiftSpeed1;
+ set => base.LiftSpeed = ConfigFile.LiftSpeed1 = (float)Math.Round(value, 2);
+ }
+
+ public override float PrintTime
+ {
+ get => base.PrintTime;
+ set
+ {
+ base.PrintTime = value;
+ ControlFile.PrintTime = base.PrintTime;
+ }
+ }
+
+ public override float MaterialMilliliters
+ {
+ get => base.MaterialMilliliters;
+ set
+ {
+ base.MaterialMilliliters = value;
+ ConfigFile.MaterialMl = ControlFile.MaterialMl = base.MaterialMilliliters;
+ }
+ }
+
+ public override string MachineName
+ {
+ get => "Uniformation GKone";
+ set {}
+ }
+
+ public override object[] Configs => new object[] { ConfigFile };
+
+ #endregion
+
+ #region Constructor
+ public JXSFile()
+ {
+ GCode = new GCodeBuilder
+ {
+ UseTailComma = true,
+ UseComments = true,
+ GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Relative,
+ GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute,
+ GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds,
+ GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.FilenamePng0Started,
+ LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G0,
+ EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G0,
+ SyncMovementsWithDelay = true
+ };
+ }
+ #endregion
+
+ #region Methods
+
+ private void RebuildFileProperties()
+ {
+ ConfigFile.JobName = FilenameNoExt!;
+ ConfigFile.ApplicationName = About.SoftwareWithVersion;
+
+ RebuildGCode();
+ ControlFile.Actions.Clear();
+
+ using var tw = new StringReader(GCodeStr!);
+ string? line;
+ var lastG0 = "G1 Z100 F150";
+ while ((line = tw.ReadLine()) is not null)
+ {
+ line = line.Trim();
+ if (line == string.Empty) continue;
+
+ if (line.StartsWith(GCode!.CommandClearImage.Command))
+ {
+ ControlFile.Actions.Add(new object[]
+ {
+ "slice", "<BLANK>"
+ });
+ continue;
+ }
+
+ if(line[0] == ';') continue;
+
+ var index = line.IndexOf(';');
+ if (index >= 0)
+ {
+ line = line[..index].TrimEnd();
+ }
+
+ if (line == string.Empty) continue;
+
+ if (line.StartsWith(GCode.CommandShowImageM6054.Command))
+ {
+ var match = Regex.Match(line, GCode.GetShowImageString(@"(\d+)"));
+
+ if (!match.Success || match.Groups.Count <= 1)
+ {
+ throw new InvalidDataException($"Unable to parse layer index from: {line}");
+ }
+
+ var layerIndex = match.Groups[1].Value.PadLeft(5, '0');
+ if(!uint.TryParse(layerIndex, out var layerNumber))
+ {
+ throw new InvalidDataException($"Unable to parse layer number from: {line}");
+ }
+ layerNumber++;
+
+ ControlFile.Actions.Add(new object[]
+ {
+ "layerno", layerNumber,
+ });
+ ControlFile.Actions.Add(new object[]
+ {
+ "slice", $"{{PWD}}/{layerIndex}.png"
+ });
+ continue;
+ }
+
+ if (line.StartsWith(GCode.CommandWaitG4.Command))
+ {
+ var match = Regex.Match(line, GCode.CommandWaitG4.ToStringWithoutComments(@"(\d+)"));
+
+ if (!match.Success || match.Groups.Count <= 1)
+ {
+ throw new InvalidDataException($"Unable to delay from: {line}");
+ }
+
+ var delayStr = match.Groups[1].Value;
+ if (!uint.TryParse(delayStr, out var delay))
+ {
+ throw new InvalidDataException($"Unable to parse delay number from: {line}");
+ }
+
+ if(delay <= 0) continue;
+
+ ControlFile.Actions.Add(new object[]
+ {
+ "delay", delay
+ });
+ continue;
+ }
+
+ if (line.StartsWith("G0") || line.StartsWith("G1"))
+ {
+ lastG0 = line;
+ }
+
+ ControlFile.Actions.Add(new object[]
+ {
+ "gcode", line
+ });
+ }
+
+ ConfigFile.GcodeFooter = lastG0;
+ }
+
+ protected override void DecodeInternally(OperationProgress progress)
+ {
+ using var inputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Read);
+ var entry = inputFile.GetEntry(ConfigFileName);
+ if (entry is null)
+ {
+ Clear();
+ throw new FileLoadException($"{ConfigFileName} not found", FileFullPath);
+ }
+
+ try
+ {
+ using var stream = entry.Open();
+ using TextReader reader = new StreamReader(stream);
+ string? line;
+ while((line = reader.ReadLine()) is not null)
+ {
+ var keyValue = line.Split('=', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+ if(keyValue.Length < 2) continue;
+
+ foreach (var propertyInfo in ConfigFile.GetType().GetProperties())
+ {
+ if (!propertyInfo.CanWrite) continue;
+ var customAttributes = propertyInfo.GetCustomAttributes();
+ if (customAttributes.Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+
+ var property = propertyInfo.Name;
+ foreach (var attribute in customAttributes)
+ {
+ if (attribute.GetType() != typeof(DisplayNameAttribute)) continue;
+ property = ((DisplayNameAttribute)attribute).DisplayName;
+ break;
+ }
+
+ if(property != keyValue[0]) continue;
+
+ //Debug.WriteLine(attribute.Name);
+ Helpers.SetPropertyValue(propertyInfo, ConfigFile, keyValue[1]);
+ }
+ }
+
+ }
+ catch (Exception e)
+ {
+ Clear();
+ throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
+ }
+
+ entry = inputFile.GetEntry(ControlFilename);
+ if (entry is null)
+ {
+ Clear();
+ throw new FileLoadException($"{ControlFilename} not found", FileFullPath);
+ }
+
+ try
+ {
+ using var stream = entry.Open();
+ ControlFile = JsonSerializer.Deserialize<JXSControl>(stream)!;
+ if (ControlFile is null)
+ {
+ Clear();
+ throw new FileLoadException($"Unable to deserialize '{entry.Name}'", FileFullPath);
+ }
+ }
+ catch (Exception e)
+ {
+ Clear();
+ throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", FileFullPath);
+ }
+
+ Init(ConfigFile.LayerCount, DecodeType == FileDecodeType.Partial);
+ sbyte[] bgrToRgbTable = {
+ 2,
+ 0,
+ -2
+ };
+ DecodeLayersFromZip(inputFile, IndexStartNumber.Zero, progress,
+ (layerIndex, pngBytes) =>
+ {
+ using Mat rgbMat = new();
+ CvInvoke.Imdecode(pngBytes, ImreadModes.AnyColor, rgbMat);
+ var greyMat = new Mat(rgbMat.Height, rgbMat.GetRealStep(), DepthType.Cv8U, 1);
+ var rgbSpan = rgbMat.GetDataByteSpan();
+ var greySpan = greyMat.GetDataByteSpan();
+
+ for (var i = 0; i < rgbSpan.Length; i++)
+ {
+ greySpan[i] = rgbSpan[i + bgrToRgbTable[i%3]];
+ }
+
+ return greyMat;
+ });
+
+ GCode!.Clear();
+
+ string lastCommand = string.Empty;
+ // Rebuild gcode from json
+ foreach (var action in ControlFile.Actions)
+ {
+ var key = action[0].ToString()!;
+ var value = action[1].ToString()!;
+
+ switch (key)
+ {
+ case "gcode":
+ lastCommand = value;
+ if (value.StartsWith("M106 S") && value.StartsWith("M106 S0")) GCode.AppendWaitG4(0);
+ GCode.AppendLine(value);
+ break;
+ case "slice":
+ if (value.StartsWith("{PWD}/"))
+ {
+ GCode.AppendShowImageM6054(value.Remove(0, "{PWD}/".Length));
+ }
+ else if (value == "<BLANK>")
+ {
+ GCode.AppendClearImage();
+ }
+ break;
+ case "delay":
+ if (lastCommand.StartsWith("G0") || lastCommand.StartsWith("G1"))
+ {
+ lastCommand = $"G4 0{value}";
+ GCode.AppendWaitG4($"0{value}");
+ break;
+ }
+ GCode.AppendWaitG4(value);
+ break;
+ case "layerno":
+ GCode.AppendLine();
+ GCode.AppendLine($";LAYER_NUMBER:{value}");
+ break;
+ }
+ }
+
+ GCode!.ParseLayersFromGCode(this);
+
+ if (!ConfigFile.ApplicationName.StartsWith(About.Software))
+ {
+ BottomWaitTimeBeforeCure = TimeConverter.MillisecondsToSeconds(ConfigFile.BottomWaitTimeBeforeCure);
+ WaitTimeBeforeCure = TimeConverter.MillisecondsToSeconds(ConfigFile.WaitTimeBeforeCure);
+ }
+ }
+
+ protected override void EncodeInternally(OperationProgress progress)
+ {
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
+
+ sbyte[] bgrToRgbTable = {
+ 2,
+ 0,
+ -2
+ };
+ EncodeLayersInZip(outputFile, 5, IndexStartNumber.Zero, progress, matGenFunc:
+ (_, mat) =>
+ {
+ var rgbMat = new Mat(mat.Height, mat.GetRealStep() / 3, DepthType.Cv8U, 3);
+ var rgbMatSpan = rgbMat.GetDataByteSpan();
+ var greySpan = mat.GetDataByteSpan();
+ for (int i = 0; i < greySpan.Length; i++)
+ {
+ rgbMatSpan[i + bgrToRgbTable[i % 3]] = greySpan[i];
+ }
+
+ return rgbMat;
+ });
+
+
+ RebuildFileProperties();
+
+ var entry = outputFile.CreateEntry(ConfigFileName);
+ using (var stream = entry.Open())
+ using (var tw = new StreamWriter(stream))
+ {
+ foreach (var propertyInfo in ConfigFile.GetType()
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.Name.Equals("Item")) continue;
+
+ var customAttributes = propertyInfo.GetCustomAttributes();
+ if (customAttributes.Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+
+ var property = propertyInfo.Name;
+ foreach (var attribute in customAttributes)
+ {
+ if (attribute.GetType() != typeof(DisplayNameAttribute)) continue;
+ property = ((DisplayNameAttribute)attribute).DisplayName;
+ break;
+ }
+
+ tw.WriteLine($"{property}={propertyInfo.GetValue(ConfigFile)}");
+ }
+ }
+
+ entry = outputFile.CreateEntry(ControlFilename);
+ using (var stream = entry.Open())
+ {
+ JsonSerializer.Serialize(stream, ControlFile, JsonExtensions.SettingsIndent);
+ }
+ }
+
+ protected override void PartialSaveInternally(OperationProgress progress)
+ {
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
+ var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".ini") || zipEntry.Name.EndsWith(".json")).ToArray();
+ foreach (var zipEntry in entriesToRemove)
+ {
+ zipEntry.Delete();
+ }
+
+
+ RebuildFileProperties();
+
+ var entry = outputFile.CreateEntry(ConfigFileName);
+ using (var stream = entry.Open())
+ using (var tw = new StreamWriter(stream))
+ {
+ foreach (var propertyInfo in ConfigFile.GetType()
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.Name.Equals("Item")) continue;
+
+ var customAttributes = propertyInfo.GetCustomAttributes();
+ if (customAttributes.Any(attribute =>
+ {
+ var type = attribute.GetType();
+ if (type == typeof(XmlIgnoreAttribute)) return true;
+ if (type == typeof(JsonIgnoreAttribute)) return true;
+ return false;
+ })) continue;
+
+ var property = propertyInfo.Name;
+ foreach (var attribute in customAttributes)
+ {
+ if (attribute.GetType() != typeof(DisplayNameAttribute)) continue;
+ property = ((DisplayNameAttribute)attribute).DisplayName;
+ break;
+ }
+
+ tw.WriteLine($"{property}={propertyInfo.GetValue(ConfigFile)}");
+ }
+ }
+
+ entry = outputFile.CreateEntry(ControlFilename);
+ using (var stream = entry.Open())
+ {
+ JsonSerializer.Serialize(stream, ControlFile, JsonExtensions.SettingsIndent);
+ }
+ }
+ #endregion
+} \ No newline at end of file
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index 6210906..c4da12a 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -15,6 +15,7 @@ using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
+using UVtools.Core.Converters;
using UVtools.Core.Extensions;
using UVtools.Core.Layers;
using UVtools.Core.Operations;
@@ -345,9 +346,9 @@ public class LGSFile : FileFormat
set => base.MachineZ = HeaderSettings.MachineZ = (float)Math.Round(value, 2);
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Enumerations.FlipDirection.Horizontally;
+ get => FlipDirection.Horizontally;
set { }
}
@@ -379,20 +380,20 @@ public class LGSFile : FileFormat
public override float BottomLightOffDelay
{
- get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.BottomLightOffDelayMs);
+ get => TimeConverter.MillisecondsToSeconds(HeaderSettings.BottomLightOffDelayMs);
set
{
- HeaderSettings.BottomLightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value);
+ HeaderSettings.BottomLightOffDelayMs = TimeConverter.SecondsToMilliseconds(value);
base.BottomLightOffDelay = value;
}
}
public override float LightOffDelay
{
- get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.LightOffDelayMs);
+ get => TimeConverter.MillisecondsToSeconds(HeaderSettings.LightOffDelayMs);
set
{
- HeaderSettings.LightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value);
+ HeaderSettings.LightOffDelayMs = TimeConverter.SecondsToMilliseconds(value);
base.LightOffDelay = value;
}
}
@@ -419,20 +420,20 @@ public class LGSFile : FileFormat
public override float BottomExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.BottomExposureTimeMs);
+ get => TimeConverter.MillisecondsToSeconds(HeaderSettings.BottomExposureTimeMs);
set
{
- HeaderSettings.BottomExposureTimeMs = TimeExtensions.SecondsToMilliseconds(value);
+ HeaderSettings.BottomExposureTimeMs = TimeConverter.SecondsToMilliseconds(value);
base.BottomExposureTime = value;
}
}
public override float ExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.ExposureTimeMs);
+ get => TimeConverter.MillisecondsToSeconds(HeaderSettings.ExposureTimeMs);
set
{
- HeaderSettings.ExposureTimeMs = TimeExtensions.SecondsToMilliseconds(value);
+ HeaderSettings.ExposureTimeMs = TimeConverter.SecondsToMilliseconds(value);
base.ExposureTime = value;
}
}
@@ -511,7 +512,7 @@ public class LGSFile : FileFormat
}
//uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
- using (var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write))
+ using (var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write))
{
outputFile.WriteSerialize(HeaderSettings);
outputFile.WriteBytes(EncodeImage(DATATYPE_RGB565_BE, Thumbnails[0]!));
@@ -612,7 +613,7 @@ public class LGSFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = layerData[layerIndex].Decode();
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
@@ -624,7 +625,7 @@ public class LGSFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, 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 942ef0e..0680483 100644
--- a/UVtools.Core/FileFormats/MDLPFile.cs
+++ b/UVtools.Core/FileFormats/MDLPFile.cs
@@ -233,7 +233,7 @@ public class MDLPFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror { get; set; }
+ public override FlipDirection DisplayMirror { get; set; }
public override float LayerHeight
{
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
@@ -315,7 +315,7 @@ public class MDLPFile : FileFormat
#region Methods
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
var pageBreak = PageBreak.Bytes;
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
@@ -477,7 +477,7 @@ public class MDLPFile : FileFormat
linesBytes[layerIndex] = null!;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
}
progress.LockAndIncrement();
@@ -495,7 +495,7 @@ public class MDLPFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, 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 4baf114..a195bb8 100644
--- a/UVtools.Core/FileFormats/OSLAFile.cs
+++ b/UVtools.Core/FileFormats/OSLAFile.cs
@@ -363,9 +363,9 @@ public class OSLAFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => (Enumerations.FlipDirection)HeaderSettings.DisplayMirror;
+ get => (FlipDirection)HeaderSettings.DisplayMirror;
set
{
HeaderSettings.DisplayMirror = (byte)value;
@@ -458,7 +458,7 @@ public class OSLAFile : FileFormat
#region Methods
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
FileSettings.Update();
var fileDefSize = Helpers.SerializeWriteFileStream(outputFile, FileSettings);
HeaderSettings.TableSize = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
@@ -680,7 +680,7 @@ public class OSLAFile : FileFormat
using var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution);
layerBytes[layerIndex] = null!; // Clean
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
@@ -703,7 +703,7 @@ public class OSLAFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(0, SeekOrigin.Begin);
FileSettings.Update();
Helpers.SerializeWriteFileStream(outputFile, FileSettings);
diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index ed663bc..96f1054 100644
--- a/UVtools.Core/FileFormats/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -743,12 +743,12 @@ public class PHZFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => HeaderSettings.ProjectorType == 0 ? Enumerations.FlipDirection.None : Enumerations.FlipDirection.Horizontally;
+ get => HeaderSettings.ProjectorType == 0 ? FlipDirection.None : FlipDirection.Horizontally;
set
{
- HeaderSettings.ProjectorType = value == Enumerations.FlipDirection.None ? 0u : 1;
+ HeaderSettings.ProjectorType = value == FlipDirection.None ? 0u : 1;
RaisePropertyChanged();
}
}
@@ -950,7 +950,7 @@ public class PHZFile : FileFormat
}*/
LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
for (byte i = 0; i < ThumbnailsCount; i++)
@@ -1136,7 +1136,7 @@ public class PHZFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex);
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
}
@@ -1151,7 +1151,7 @@ public class PHZFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
HeaderSettings.ModifiedTimestampMinutes = (uint) DateTimeExtensions.TimestampMinutes;
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, 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 01087dc..fdf4683 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -311,9 +311,9 @@ public class PhotonSFile : FileFormat
set { }
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Enumerations.FlipDirection.Horizontally;
+ get => FlipDirection.Horizontally;
set { }
}
@@ -437,7 +437,7 @@ public class PhotonSFile : FileFormat
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(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
outputFile.WriteSerialize(HeaderSettings);
outputFile.WriteBytes(EncodeImage(DATATYPE_BGR565, Thumbnails[0]!));
outputFile.WriteSerialize(LayerSettings);
@@ -526,7 +526,7 @@ public class PhotonSFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = layersDefinitions[layerIndex].Decode();
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
progress.LockAndIncrement();
});
}
@@ -537,7 +537,7 @@ public class PhotonSFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, 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 d2db0fb..0e656ef 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -1223,9 +1223,9 @@ public class PhotonWorkshopFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Enumerations.FlipDirection.Horizontally;
+ get => FlipDirection.Horizontally;
set {}
}
@@ -1632,7 +1632,7 @@ public class PhotonWorkshopFile : FileFormat
FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings);
- using var outputFile = new FileStream(FileFullPath!, FileMode.Create, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write);
if (FileMarkSettings.Version >= VERSION_516)
{
HeaderSettings.Section.Length = 84;
@@ -1842,7 +1842,7 @@ public class PhotonWorkshopFile : FileFormat
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = LayersDefinition[layerIndex].Decode();
- this[layerIndex] = new Layer((uint)layerIndex, mat, this)
+ _layers[layerIndex] = new Layer((uint)layerIndex, mat, this)
{
PositionZ = LayersDefinition.Layers
.Where((_, i) => i <= layerIndex)
@@ -1874,7 +1874,7 @@ public class PhotonWorkshopFile : FileFormat
{
HeaderSettings.PerLayerOverride = AllLayersAreUsingGlobalParameters ? 0 : 1u;
- using var outputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Write);
+ using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(FileMarkSettings.HeaderAddress, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 1ad605e..f9ae380 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -405,19 +405,19 @@ public class SL1File : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
get
{
- if (PrinterSettings.DisplayMirrorX > 0 && PrinterSettings.DisplayMirrorY > 0) return Enumerations.FlipDirection.Both;
- if (PrinterSettings.DisplayMirrorX > 0) return Enumerations.FlipDirection.Horizontally;
- if (PrinterSettings.DisplayMirrorY > 0) return Enumerations.FlipDirection.Vertically;
- return Enumerations.FlipDirection.None;
+ if (PrinterSettings.DisplayMirrorX > 0 && PrinterSettings.DisplayMirrorY > 0) return FlipDirection.Both;
+ if (PrinterSettings.DisplayMirrorX > 0) return FlipDirection.Horizontally;
+ if (PrinterSettings.DisplayMirrorY > 0) return FlipDirection.Vertically;
+ return FlipDirection.None;
}
set
{
- PrinterSettings.DisplayMirrorX = (byte)(value is Enumerations.FlipDirection.Horizontally or Enumerations.FlipDirection.Both ? 1 : 0);
- PrinterSettings.DisplayMirrorY = (byte)(value is Enumerations.FlipDirection.Vertically or Enumerations.FlipDirection.Both ? 1 : 0);
+ PrinterSettings.DisplayMirrorX = (byte)(value is FlipDirection.Horizontally or FlipDirection.Both ? 1 : 0);
+ PrinterSettings.DisplayMirrorY = (byte)(value is FlipDirection.Vertically or FlipDirection.Both ? 1 : 0);
RaisePropertyChanged();
}
}
@@ -569,7 +569,7 @@ public class SL1File : FileFormat
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 var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
var entry = outputFile.CreateEntry("config.ini");
using (TextWriter tw = new StreamWriter(entry.Open()))
{
@@ -614,7 +614,7 @@ public class SL1File : FileFormat
stream.Close();
}
- EncodeLayersInZip(outputFile, filename, 5, Enumerations.IndexStartNumber.Zero, progress);
+ EncodeLayersInZip(outputFile, filename, 5, IndexStartNumber.Zero, progress);
}
@@ -637,10 +637,8 @@ public class SL1File : FileFormat
string? line;
while ((line = streamReader.ReadLine()) != null)
{
- string[] keyValue = line.Split(new[] {'='}, 2);
+ var keyValue = line.Split('=', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (keyValue.Length < 2) continue;
- keyValue[0] = keyValue[0].Trim();
- keyValue[1] = keyValue[1].Trim();
var fieldName = IniKeyToMemberName(keyValue[0]);
bool foundMember = false;
@@ -732,7 +730,7 @@ public class SL1File : FileFormat
//thumbnailIndex++;
}
- DecodeLayersFromZip(inputFile, 5, Enumerations.IndexStartNumber.Zero, progress);
+ DecodeLayersFromZip(inputFile, 5, IndexStartNumber.Zero, progress);
if (TransitionLayerCount > 0)
{
@@ -746,7 +744,7 @@ public class SL1File : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, 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 1b9e0ee..ebd7dc4 100644
--- a/UVtools.Core/FileFormats/UVJFile.cs
+++ b/UVtools.Core/FileFormats/UVJFile.cs
@@ -278,7 +278,7 @@ public class UVJFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror { get; set; }
+ public override FlipDirection DisplayMirror { get; set; }
public override byte AntiAliasing
{
@@ -485,7 +485,7 @@ public class UVJFile : FileFormat
JsonSettings.Layers.Add(new LayerDef(this[layerIndex]));
}
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
outputFile.PutFileContent(FileConfigName, JsonSerializer.SerializeToUtf8Bytes(JsonSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Create);
if (CreatedThumbnailsCount > 0)
@@ -502,7 +502,7 @@ public class UVJFile : FileFormat
stream.Close();
}
- EncodeLayersInZip(outputFile, 8, Enumerations.IndexStartNumber.Zero, progress, FolderImageName);
+ EncodeLayersInZip(outputFile, 8, IndexStartNumber.Zero, progress, FolderImageName);
}
protected override void DecodeInternally(OperationProgress progress)
@@ -566,7 +566,7 @@ public class UVJFile : FileFormat
JsonSettings.Layers.Add(new LayerDef(this[layerIndex]));
}
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
outputFile.PutFileContent(FileConfigName, JsonSerializer.SerializeToUtf8Bytes(JsonSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Update);
//Decode(FileFullPath, progress);
diff --git a/UVtools.Core/FileFormats/VDAFile.cs b/UVtools.Core/FileFormats/VDAFile.cs
index 4ced4d2..3f8e81a 100644
--- a/UVtools.Core/FileFormats/VDAFile.cs
+++ b/UVtools.Core/FileFormats/VDAFile.cs
@@ -284,13 +284,13 @@ public class VDAFile : FileFormat
#region Methods
- public override bool CanProcess(string fileFullPath)
+ public override bool CanProcess(string? fileFullPath)
{
if(!base.CanProcess(fileFullPath)) return false;
try
{
- using var zip = ZipFile.Open(fileFullPath, ZipArchiveMode.Read);
+ using var zip = ZipFile.Open(fileFullPath!, ZipArchiveMode.Read);
if (zip.Entries.Any(entry => entry.Name.EndsWith(".xml"))) return true;
}
catch (Exception e)
@@ -304,12 +304,12 @@ public class VDAFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
var manifestFilename = Filename!.
Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml").
Replace($".{FileExtensions[0].Extension}", ".xml");
- EncodeLayersInZip(outputFile, 4, Enumerations.IndexStartNumber.One, progress);
+ EncodeLayersInZip(outputFile, 4, IndexStartNumber.One, progress);
UpdateManifest();
@@ -341,12 +341,12 @@ public class VDAFile : FileFormat
Init(ManifestFile.Slices.LayerCount, DecodeType == FileDecodeType.Partial);
- DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
+ DecodeLayersFromZip(inputFile, IndexStartNumber.One, progress);
}
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
bool deleted;
do
@@ -381,7 +381,7 @@ public class VDAFile : FileFormat
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var layer = this[layerIndex];
- ManifestFile.Layers.Add(new VDARoot.VDALayer(layerIndex, layer.PositionZ, layer.FormatFileName(4, Enumerations.IndexStartNumber.One)));
+ ManifestFile.Layers.Add(new VDARoot.VDALayer(layerIndex, layer.PositionZ, layer.FormatFileName(4, IndexStartNumber.One)));
}
}
#endregion
diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs
index ac5abe2..bf82ad7 100644
--- a/UVtools.Core/FileFormats/VDTFile.cs
+++ b/UVtools.Core/FileFormats/VDTFile.cs
@@ -337,19 +337,19 @@ public class VDTFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
get
{
- if (ManifestFile.Machine.XMirror && ManifestFile.Machine.YMirror) return Enumerations.FlipDirection.Both;
- if (ManifestFile.Machine.XMirror) return Enumerations.FlipDirection.Horizontally;
- if (ManifestFile.Machine.YMirror) return Enumerations.FlipDirection.Vertically;
- return Enumerations.FlipDirection.None;
+ if (ManifestFile.Machine.XMirror && ManifestFile.Machine.YMirror) return FlipDirection.Both;
+ if (ManifestFile.Machine.XMirror) return FlipDirection.Horizontally;
+ if (ManifestFile.Machine.YMirror) return FlipDirection.Vertically;
+ return FlipDirection.None;
}
set
{
- ManifestFile.Machine.XMirror = value is Enumerations.FlipDirection.Horizontally or Enumerations.FlipDirection.Both;
- ManifestFile.Machine.YMirror = value is Enumerations.FlipDirection.Vertically or Enumerations.FlipDirection.Both;
+ ManifestFile.Machine.XMirror = value is FlipDirection.Horizontally or FlipDirection.Both;
+ ManifestFile.Machine.YMirror = value is FlipDirection.Vertically or FlipDirection.Both;
RaisePropertyChanged();
}
}
@@ -635,7 +635,7 @@ public class VDTFile : FileFormat
// Redo layer data
RebuildVDTLayers();
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
outputFile.PutFileContent(FileManifestName, JsonSerializer.SerializeToUtf8Bytes(ManifestFile, JsonExtensions.SettingsIndent), ZipArchiveMode.Create);
if (CreatedThumbnailsCount > 0)
@@ -695,7 +695,7 @@ public class VDTFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
RebuildVDTLayers();
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
outputFile.PutFileContent(FileManifestName, JsonSerializer.SerializeToUtf8Bytes(ManifestFile, JsonExtensions.SettingsIndent), ZipArchiveMode.Update);
//Decode(FileFullPath, progress);
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index 6e8613d..4c6ee4d 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -13,14 +13,13 @@ using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.OpenSsl;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
-using System.Threading.Tasks;
using System.Xml.Serialization;
+using UVtools.Core.Converters;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
using UVtools.Core.Layers;
@@ -86,10 +85,10 @@ public class ZCodePrint
public float LiftSpeed { get; set; } = FileFormat.DefaultLiftSpeed;
[XmlAttribute("cooldown_bottom")]
- public uint BottomLightOffDelay { get; set; }
+ public uint BottomWaitTimeBeforeCure { get; set; }
[XmlAttribute("cooldown")]
- public uint LightOffDelay { get; set; }
+ public uint WaitTimeBeforeCure { get; set; }
[XmlAttribute("thickness")]
public float LayerHeight { get; set; } = FileFormat.DefaultLayerHeight;
@@ -279,7 +278,7 @@ public class ZCodeFile : FileFormat
}
}
- public override Enumerations.FlipDirection DisplayMirror => Enumerations.FlipDirection.Vertically;
+ public override FlipDirection DisplayMirror => FlipDirection.Vertically;
public override byte AntiAliasing
{
@@ -323,40 +322,40 @@ public class ZCodeFile : FileFormat
public override float BottomWaitTimeBeforeCure
{
- get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomLightOffDelay);
+ get => TimeConverter.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomWaitTimeBeforeCure);
set
{
- ManifestFile.Profile.Slice.BottomLightOffDelay = TimeExtensions.SecondsToMillisecondsUint(value);
+ ManifestFile.Profile.Slice.BottomWaitTimeBeforeCure = TimeConverter.SecondsToMillisecondsUint(value);
base.BottomWaitTimeBeforeCure = base.BottomLightOffDelay = value;
}
}
public override float WaitTimeBeforeCure
{
- get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.LightOffDelay);
+ get => TimeConverter.MillisecondsToSeconds(ManifestFile.Profile.Slice.WaitTimeBeforeCure);
set
{
- ManifestFile.Profile.Slice.LightOffDelay = TimeExtensions.SecondsToMillisecondsUint(value);
+ ManifestFile.Profile.Slice.WaitTimeBeforeCure = TimeConverter.SecondsToMillisecondsUint(value);
base.WaitTimeBeforeCure = base.LightOffDelay = value;
}
}
public override float BottomExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomExposureTime);
+ get => TimeConverter.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomExposureTime);
set
{
- ManifestFile.Profile.Slice.BottomExposureTime = TimeExtensions.SecondsToMillisecondsUint(value);
+ ManifestFile.Profile.Slice.BottomExposureTime = TimeConverter.SecondsToMillisecondsUint(value);
base.BottomExposureTime = value;
}
}
public override float ExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.ExposureTime);
+ get => TimeConverter.MillisecondsToSeconds(ManifestFile.Profile.Slice.ExposureTime);
set
{
- ManifestFile.Profile.Slice.ExposureTime = TimeExtensions.SecondsToMillisecondsUint(value);
+ ManifestFile.Profile.Slice.ExposureTime = TimeConverter.SecondsToMillisecondsUint(value);
base.ExposureTime = value;
}
}
@@ -471,7 +470,7 @@ public class ZCodeFile : FileFormat
protected override void EncodeInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
if (Thumbnails.Length > 0 && Thumbnails[0] is not null)
{
using var thumbnailsStream = outputFile.CreateEntry(PreviewFilename).Open();
@@ -479,7 +478,7 @@ public class ZCodeFile : FileFormat
thumbnailsStream.Close();
}
- EncodeLayersInZip(outputFile, Enumerations.IndexStartNumber.One, progress);
+ EncodeLayersInZip(outputFile, IndexStartNumber.One, progress);
var entry = outputFile.CreateEntry(ManifestFilename);
using (var stream = entry.Open())
@@ -546,7 +545,7 @@ public class ZCodeFile : FileFormat
Init(ManifestFile.Job.LayerCount, DecodeType == FileDecodeType.Partial);
- DecodeLayersFromZip(inputFile, Enumerations.IndexStartNumber.One, progress);
+ DecodeLayersFromZip(inputFile, IndexStartNumber.One, progress);
GCode!.ParseLayersFromGCode(this);
@@ -560,7 +559,7 @@ public class ZCodeFile : FileFormat
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
var entriesToRemove = outputFile.Entries.Where(zipEntry => zipEntry.Name.EndsWith(".gcode") || zipEntry.Name.EndsWith(".xml")).ToArray();
foreach (var zipEntry in entriesToRemove)
diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index fc02a16..6ecbe4b 100644
--- a/UVtools.Core/FileFormats/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -16,6 +16,7 @@ using System.IO;
using System.IO.Compression;
using System.Text.Json;
using System.Text.RegularExpressions;
+using UVtools.Core.Converters;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
using UVtools.Core.Layers;
@@ -210,9 +211,9 @@ public class ZCodexFile : FileFormat
set { }
}
- public override Enumerations.FlipDirection DisplayMirror
+ public override FlipDirection DisplayMirror
{
- get => Enumerations.FlipDirection.Horizontally;
+ get => FlipDirection.Horizontally;
set { }
}
@@ -256,30 +257,30 @@ public class ZCodexFile : FileFormat
public override float BottomWaitTimeBeforeCure => WaitTimeBeforeCure;
public override float WaitTimeBeforeCure
{
- get => TimeExtensions.MillisecondsToSeconds(ResinMetadataSettings.BlankingLayerTime);
+ get => TimeConverter.MillisecondsToSeconds(ResinMetadataSettings.BlankingLayerTime);
set
{
- UserSettings.ExposureOffTime = ResinMetadataSettings.BlankingLayerTime = TimeExtensions.SecondsToMillisecondsUint(value);
+ UserSettings.ExposureOffTime = ResinMetadataSettings.BlankingLayerTime = TimeConverter.SecondsToMillisecondsUint(value);
base.WaitTimeBeforeCure = base.LightOffDelay = value;
}
}
public override float BottomExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(UserSettings.BottomLayerExposureTime);
+ get => TimeConverter.MillisecondsToSeconds(UserSettings.BottomLayerExposureTime);
set
{
- ResinMetadataSettings.BottomLayersTime = UserSettings.BottomLayerExposureTime = TimeExtensions.SecondsToMillisecondsUint(value);
+ ResinMetadataSettings.BottomLayersTime = UserSettings.BottomLayerExposureTime = TimeConverter.SecondsToMillisecondsUint(value);
base.BottomExposureTime = value;
}
}
public override float ExposureTime
{
- get => TimeExtensions.MillisecondsToSeconds(UserSettings.LayerExposureTime);
+ get => TimeConverter.MillisecondsToSeconds(UserSettings.LayerExposureTime);
set
{
- ResinMetadataSettings.LayerTime = UserSettings.LayerExposureTime = TimeExtensions.SecondsToMillisecondsUint(value);
+ ResinMetadataSettings.LayerTime = UserSettings.LayerExposureTime = TimeConverter.SecondsToMillisecondsUint(value);
base.ExposureTime = value;
}
}
@@ -357,7 +358,7 @@ public class ZCodexFile : FileFormat
GCode = new()
{
UseComments = true,
- GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial,
+ GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Relative,
GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute,
GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds,
GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndex0Started,
@@ -389,7 +390,7 @@ public class ZCodexFile : FileFormat
});
}
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Create);
outputFile.PutFileContent("ResinMetadata", JsonSerializer.SerializeToUtf8Bytes(ResinMetadataSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Create);
outputFile.PutFileContent("UserSettingsData", JsonSerializer.SerializeToUtf8Bytes(UserSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Create);
outputFile.PutFileContent("ZCodeMetadata", JsonSerializer.SerializeToUtf8Bytes(ZCodeMetadataSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Create);
@@ -401,7 +402,7 @@ public class ZCodexFile : FileFormat
stream.Close();
}
- EncodeLayersInZip(outputFile, FolderImageName, 5, Enumerations.IndexStartNumber.Zero, progress, FolderImages);
+ EncodeLayersInZip(outputFile, FolderImageName, 5, IndexStartNumber.Zero, progress, FolderImages);
GCode!.Clear();
@@ -486,7 +487,7 @@ public class ZCodexFile : FileFormat
}
Init(ResinMetadataSettings.TotalLayersCount, DecodeType == FileDecodeType.Partial);
- DecodeLayersFromZip(inputFile, FolderImageName, Enumerations.IndexStartNumber.Zero, progress);
+ DecodeLayersFromZip(inputFile, FolderImageName, IndexStartNumber.Zero, progress);
GCode!.Clear();
using (TextReader tr = new StreamReader(entry.Open()))
@@ -571,7 +572,7 @@ M106 S0
/*if (DecodeType == FileDecodeType.Full)
{
using var stream = LayersSettings[layerIndex].LayerEntry!.Open();
- this[layerIndex] = new Layer((uint)layerIndex, stream, this);
+ _layers[layerIndex] = new Layer((uint)layerIndex, stream, this);
}*/
this[layerIndex].PositionZ = currentHeight;
@@ -615,7 +616,7 @@ M106 S0
protected override void PartialSaveInternally(OperationProgress progress)
{
- using var outputFile = ZipFile.Open(FileFullPath!, ZipArchiveMode.Update);
+ using var outputFile = ZipFile.Open(TemporaryOutputFileFullPath, ZipArchiveMode.Update);
outputFile.PutFileContent("ResinMetadata", JsonSerializer.SerializeToUtf8Bytes(ResinMetadataSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Update);
outputFile.PutFileContent("UserSettingsData", JsonSerializer.SerializeToUtf8Bytes(UserSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Update);
outputFile.PutFileContent("ZCodeMetadata", JsonSerializer.SerializeToUtf8Bytes(ZCodeMetadataSettings, JsonExtensions.SettingsIndent), ZipArchiveMode.Update);
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index d56d9cd..98b224f 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -16,7 +16,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
-using UVtools.Core.Extensions;
+using UVtools.Core.Converters;
using UVtools.Core.FileFormats;
using UVtools.Core.Layers;
using UVtools.Core.Objects;
@@ -51,7 +51,7 @@ public class GCodeBuilder : BindableBase
public enum GCodePositioningTypes : byte
{
Absolute,
- Partial
+ Relative
}
public enum GCodeTimeUnits : byte
@@ -317,15 +317,74 @@ public class GCodeBuilder : BindableBase
AppendLineIfCanComment(BeginStartGCodeComments);
AppendUnitsMmG21();
AppendPositioningType();
- AppendLightOffM106();
AppendMotorsOn();
+ AppendLightOffM106();
AppendClearImage();
AppendHomeZG28();
AppendLineIfCanComment(EndStartGCodeComments);
AppendLine();
}
- public void AppendEndGCode(float raiseZ = 0, float feedRate = 0)
+ public void AppendEndGCode(FileFormat slicerFile)
+ {
+ AppendLineIfCanComment(BeginEndGCodeComments);
+ AppendLightOffM106();
+
+ var lastLayer = slicerFile.LastLayer;
+
+ if (lastLayer is not null && lastLayer.PositionZ < slicerFile.MachineZ)
+ {
+ float lastLiftHeight = Math.Max(4, lastLayer.LiftHeight);
+ float lastPosition = Math.Min(Layer.RoundHeight(lastLayer.PositionZ + lastLiftHeight), slicerFile.MachineZ);
+
+ var lift = new List<(float z, float feedrate)>();
+ switch (_gCodePositioningType)
+ {
+ case GCodePositioningTypes.Absolute:
+ lift.Add((lastPosition, ConvertFromMillimetersPerMinute(slicerFile.LiftSpeed)));
+ break;
+ case GCodePositioningTypes.Relative:
+ lift.Add((lastLiftHeight, ConvertFromMillimetersPerMinute(slicerFile.LiftSpeed)));
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ AppendLiftMoveGx(lift, new List<(float z, float feedrate)>(), 0, 0, lastLayer);
+
+ if (lastPosition < slicerFile.MachineZ)
+ {
+ float finalRaiseZPositionRelative = Layer.RoundHeight(slicerFile.MachineZ - lastPosition);
+ var finalRaiseZPosition = _gCodePositioningType switch
+ {
+ GCodePositioningTypes.Relative => finalRaiseZPositionRelative,
+ _ => slicerFile.MachineZ
+ };
+
+
+ if (finalRaiseZPositionRelative > 0)
+ {
+ if (_endGCodeMoveCommand == GCodeMoveCommands.G0)
+ AppendMoveG0(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.MaximumSpeed));
+ else
+ AppendMoveG1(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.MaximumSpeed));
+
+ if (_syncMovementsWithDelay)
+ {
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(
+ finalRaiseZPositionRelative + lastLiftHeight, slicerFile.MaximumSpeed, 0.75f);
+ var time = ConvertFromSeconds(seconds);
+ if (seconds > 0) AppendWaitG4($"0{time}", "Sync movement");
+ }
+ }
+ }
+ }
+
+ AppendMotorsOff();
+ AppendLineIfCanComment(EndEndGCodeComments);
+ }
+
+ public void AppendEndGCode(float raiseZ = 0, float feedRate = 0, float absRaiseZ = 0, float rawSpeed = 0)
{
AppendLineIfCanComment(BeginEndGCodeComments);
AppendLightOffM106();
@@ -335,6 +394,13 @@ public class GCodeBuilder : BindableBase
AppendMoveG0(raiseZ, feedRate);
else
AppendMoveG1(raiseZ, feedRate);
+
+ if (_syncMovementsWithDelay)
+ {
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(absRaiseZ, rawSpeed, 0.75f);
+ var time = ConvertFromSeconds(seconds);
+ AppendWaitG4($"0{time}", "Sync movement");
+ }
}
AppendMotorsOff();
@@ -353,7 +419,7 @@ public class GCodeBuilder : BindableBase
case GCodePositioningTypes.Absolute:
AppendLine(CommandPositioningAbsoluteG90);
break;
- case GCodePositioningTypes.Partial:
+ case GCodePositioningTypes.Relative:
AppendLine(CommandPositioningPartialG91);
break;
default:
@@ -429,7 +495,7 @@ public class GCodeBuilder : BindableBase
AppendWaitG4(waitAfterLift, "Wait after lift");
}
- if (retracts.Count > 0 || retracts.All(tuple => tuple.z != 0))
+ if (retracts.Count > 0 && retracts.All(tuple => tuple.z != 0))
{
for (var i = 0; i < retracts.Count; i++)
{
@@ -443,11 +509,11 @@ public class GCodeBuilder : BindableBase
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
- }
- if (waitAfterRetract > 0)
- {
- AppendWaitG4(waitAfterRetract, "Wait after retract");
+ if (waitAfterRetract > 0)
+ {
+ AppendWaitG4(waitAfterRetract, "Wait after retract");
+ }
}
}
@@ -486,7 +552,7 @@ public class GCodeBuilder : BindableBase
AppendWaitG4(waitAfterLift, "Wait after lift");
}
- if (retracts.Count > 0 || retracts.All(tuple => tuple.z != 0))
+ if (retracts.Count > 0 && retracts.All(tuple => tuple.z != 0))
{
for (var i = 0; i < retracts.Count; i++)
{
@@ -500,11 +566,11 @@ public class GCodeBuilder : BindableBase
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
- }
- if (waitAfterRetract > 0)
- {
- AppendWaitG4(waitAfterRetract, "Wait after retract");
+ if (waitAfterRetract > 0)
+ {
+ AppendWaitG4(waitAfterRetract, "Wait after retract");
+ }
}
}
@@ -637,7 +703,7 @@ public class GCodeBuilder : BindableBase
if (retractHeight > 0 && absRetractPos >= layer.PositionZ) retracts.Add((absRetractPos, retractSpeed));
if (retractHeight2 > 0 && absRetractPos > layer.PositionZ) retracts.Add((layer.PositionZ, retractSpeed2));
break;
- case GCodePositioningTypes.Partial:
+ case GCodePositioningTypes.Relative:
var partialLiftPos = Layer.RoundHeight(layer.PositionZ - lastZPosition + liftHeight);
if (liftHeight > 0)
{
@@ -680,7 +746,7 @@ public class GCodeBuilder : BindableBase
case GCodePositioningTypes.Absolute:
AppendMoveGx(layer.PositionZ, lastZPosition < layer.PositionZ ? liftSpeed : retractSpeed);
break;
- case GCodePositioningTypes.Partial:
+ case GCodePositioningTypes.Relative:
AppendMoveGx(Layer.RoundHeight(layer.PositionZ - lastZPosition), lastZPosition < layer.PositionZ ? liftSpeed : retractSpeed);
break;
}
@@ -697,17 +763,7 @@ public class GCodeBuilder : BindableBase
lastZPosition = layer.PositionZ;
}
- float finalRaiseZPosition = Math.Max(lastZPosition, slicerFile.MachineZ);
- switch (GCodePositioningType)
- {
-
- case GCodePositioningTypes.Partial:
- finalRaiseZPosition = Layer.RoundHeight(finalRaiseZPosition - lastZPosition);
- break;
- }
-
-
- AppendEndGCode(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.RetractSpeed));
+ AppendEndGCode(slicerFile);
}
public void RebuildGCode(FileFormat slicerFile, object[]? configs, string separator = ":")
@@ -746,7 +802,7 @@ public class GCodeBuilder : BindableBase
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith(CommandPositioningAbsoluteG90.Command)) return GCodePositioningTypes.Absolute;
- if (line.StartsWith(CommandPositioningPartialG91.Command)) return GCodePositioningTypes.Partial;
+ if (line.StartsWith(CommandPositioningPartialG91.Command)) return GCodePositioningTypes.Relative;
}
return _gCodePositioningType;
@@ -797,7 +853,7 @@ public class GCodeBuilder : BindableBase
if (line.StartsWith(CommandPositioningPartialG91.Command))
{
- positionType = GCodePositioningTypes.Partial;
+ positionType = GCodePositioningTypes.Relative;
continue;
}
@@ -1098,7 +1154,7 @@ public class GCodeBuilder : BindableBase
return _gCodeTimeUnit switch
{
GCodeTimeUnits.Seconds => seconds,
- GCodeTimeUnits.Milliseconds => TimeExtensions.SecondsToMilliseconds(seconds),
+ GCodeTimeUnits.Milliseconds => TimeConverter.SecondsToMilliseconds(seconds),
_ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}")
};
}
@@ -1129,7 +1185,7 @@ public class GCodeBuilder : BindableBase
return _gCodeTimeUnit switch
{
GCodeTimeUnits.Seconds => time,
- GCodeTimeUnits.Milliseconds => TimeExtensions.MillisecondsToSeconds(time),
+ GCodeTimeUnits.Milliseconds => TimeConverter.MillisecondsToSeconds(time),
_ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}")
};
}
diff --git a/UVtools.Core/GCode/GCodeLayer.cs b/UVtools.Core/GCode/GCodeLayer.cs
index baf2c27..3f9501e 100644
--- a/UVtools.Core/GCode/GCodeLayer.cs
+++ b/UVtools.Core/GCode/GCodeLayer.cs
@@ -177,7 +177,7 @@ public class GCodeLayer
partialPositionZ = Layer.RoundHeight(pos - currentZ);
currentZ = pos;
break;
- case GCodeBuilder.GCodePositioningTypes.Partial:
+ case GCodeBuilder.GCodePositioningTypes.Relative:
partialPositionZ = pos;
currentZ = Layer.RoundHeight(currentZ + pos);
break;
diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs
index f5b49aa..2015ac7 100644
--- a/UVtools.Core/Layers/Layer.cs
+++ b/UVtools.Core/Layers/Layer.cs
@@ -15,6 +15,8 @@ using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
+using System.Text.Json.Serialization;
+using System.Xml.Serialization;
using K4os.Compression.LZ4;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
@@ -649,6 +651,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// <summary>
/// Gets or sets a new image instance
/// </summary>
+ [XmlIgnore]
+ [JsonInclude]
public Mat LayerMat
{
get
@@ -728,6 +732,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// <summary>
/// Gets a new Brg image instance
/// </summary>
+ [XmlIgnore]
+ [JsonInclude]
public Mat BrgMat
{
get
@@ -1087,20 +1093,20 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
WaitTimeAfterLift = 0;
}
- public string FormatFileName(string prepend = "", byte padDigits = 0, Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
+ public string FormatFileName(string prepend = "", byte padDigits = 0, IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
{
var index = Index;
- if (layerIndexStartNumber == Enumerations.IndexStartNumber.One)
+ if (layerIndexStartNumber == IndexStartNumber.One)
{
index++;
}
return $"{prepend}{index.ToString().PadLeft(padDigits, '0')}{appendExt}";
}
- public string FormatFileName(byte padDigits, Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
+ public string FormatFileName(byte padDigits, IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
=> FormatFileName(string.Empty, padDigits, layerIndexStartNumber, appendExt);
- public string FormatFileNameWithLayerDigits(string prepend = "", Enumerations.IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
+ public string FormatFileNameWithLayerDigits(string prepend = "", IndexStartNumber layerIndexStartNumber = default, string appendExt = ".png")
=> FormatFileName(prepend, SlicerFile.LayerDigits, layerIndexStartNumber, appendExt);
diff --git a/UVtools.Core/Managers/MatCacheManager.cs b/UVtools.Core/Managers/MatCacheManager.cs
index 82c19d2..2934c3f 100644
--- a/UVtools.Core/Managers/MatCacheManager.cs
+++ b/UVtools.Core/Managers/MatCacheManager.cs
@@ -51,12 +51,12 @@ public class MatCacheManager : IDisposable
/// <summary>
/// Gets the image rotation to cache
/// </summary>
- public Enumerations.RotateDirection Rotate { get; init; } = Enumerations.RotateDirection.None;
+ public RotateDirection Rotate { get; init; } = RotateDirection.None;
/// <summary>
/// Gets the image flip to cache
/// </summary>
- public Enumerations.FlipDirection Flip { get; init; } = Enumerations.FlipDirection.None;
+ public FlipDirection Flip { get; init; } = FlipDirection.None;
/// <summary>
/// Gets if striping anti-aliasing is enabled, cache will be threshold'ed
@@ -168,12 +168,12 @@ public class MatCacheManager : IDisposable
MatCache[currentCacheIndex] = new Mat[ElementsPerCache];
MatCache[currentCacheIndex][0] = SlicerFile[currentLayerIndex].LayerMat;
- if (Flip != Enumerations.FlipDirection.None)
+ if (Flip != FlipDirection.None)
{
CvInvoke.Flip(MatCache[currentCacheIndex][0], MatCache[currentCacheIndex][0], Enumerations.ToOpenCVFlipType(Flip));
}
- if (Rotate != Enumerations.RotateDirection.None)
+ if (Rotate != RotateDirection.None)
{
CvInvoke.Rotate(MatCache[currentCacheIndex][0], MatCache[currentCacheIndex][0], Enumerations.ToOpenCVRotateFlags(Rotate));
}
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index 4b9f788..c22cee7 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -50,7 +50,7 @@ public abstract class Operation : BindableBase, IDisposable
private uint _layerIndexStart;
private string? _profileName;
private bool _profileIsDefault;
- private Enumerations.LayerRangeSelection _layerRangeSelection = Enumerations.LayerRangeSelection.All;
+ private LayerRangeSelection _layerRangeSelection = LayerRangeSelection.All;
public const byte ClassNameLength = 9;
#endregion
@@ -93,12 +93,12 @@ public abstract class Operation : BindableBase, IDisposable
/// </summary>
public string Id => GetType().Name.Remove(0, ClassNameLength);
- public virtual Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.All;
+ public virtual LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.All;
/// <summary>
/// Gets the last used layer range selection, returns none if custom
/// </summary>
- public Enumerations.LayerRangeSelection LayerRangeSelection
+ public LayerRangeSelection LayerRangeSelection
{
get => _layerRangeSelection;
set => RaiseAndSetIfChanged(ref _layerRangeSelection, value);
@@ -108,7 +108,7 @@ public abstract class Operation : BindableBase, IDisposable
{
get
{
- if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
+ if (LayerRangeSelection == LayerRangeSelection.None)
{
return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
}
@@ -354,39 +354,39 @@ public abstract class Operation : BindableBase, IDisposable
{
LayerIndexStart = 0;
LayerIndexEnd = SlicerFile.LastLayerIndex;
- LayerRangeSelection = Enumerations.LayerRangeSelection.All;
+ LayerRangeSelection = LayerRangeSelection.All;
}
public void SelectCurrentLayer(uint layerIndex)
{
LayerIndexStart = LayerIndexEnd = layerIndex;
- LayerRangeSelection = Enumerations.LayerRangeSelection.Current;
+ LayerRangeSelection = LayerRangeSelection.Current;
}
public void SelectBottomLayers()
{
LayerIndexStart = 0;
LayerIndexEnd = Math.Max(1, SlicerFile.FirstNormalLayer?.Index ?? 1) - 1u;
- LayerRangeSelection = Enumerations.LayerRangeSelection.Bottom;
+ LayerRangeSelection = LayerRangeSelection.Bottom;
}
public void SelectNormalLayers()
{
LayerIndexStart = SlicerFile.FirstNormalLayer?.Index ?? 0;
LayerIndexEnd = SlicerFile.LastLayerIndex;
- LayerRangeSelection = Enumerations.LayerRangeSelection.Normal;
+ LayerRangeSelection = LayerRangeSelection.Normal;
}
public void SelectFirstLayer()
{
LayerIndexStart = LayerIndexEnd = 0;
- LayerRangeSelection = Enumerations.LayerRangeSelection.First;
+ LayerRangeSelection = LayerRangeSelection.First;
}
public void SelectLastLayer()
{
LayerIndexStart = LayerIndexEnd = SlicerFile.LastLayerIndex;
- LayerRangeSelection = Enumerations.LayerRangeSelection.Last;
+ LayerRangeSelection = LayerRangeSelection.Last;
}
public void SelectFirstToCurrentLayer(uint currentLayerIndex)
@@ -401,28 +401,28 @@ public abstract class Operation : BindableBase, IDisposable
LayerIndexEnd = SlicerFile.LastLayerIndex;
}
- public void SelectLayers(Enumerations.LayerRangeSelection range)
+ public void SelectLayers(LayerRangeSelection range)
{
switch (range)
{
- case Enumerations.LayerRangeSelection.None:
+ case LayerRangeSelection.None:
break;
- case Enumerations.LayerRangeSelection.All:
+ case LayerRangeSelection.All:
SelectAllLayers();
break;
- case Enumerations.LayerRangeSelection.Current:
+ case LayerRangeSelection.Current:
//SelectCurrentLayer();
break;
- case Enumerations.LayerRangeSelection.Bottom:
+ case LayerRangeSelection.Bottom:
SelectBottomLayers();
break;
- case Enumerations.LayerRangeSelection.Normal:
+ case LayerRangeSelection.Normal:
SelectNormalLayers();
break;
- case Enumerations.LayerRangeSelection.First:
+ case LayerRangeSelection.First:
SelectFirstLayer();
break;
- case Enumerations.LayerRangeSelection.Last:
+ case LayerRangeSelection.Last:
SelectLastLayer();
break;
default:
@@ -557,14 +557,14 @@ public abstract class Operation : BindableBase, IDisposable
return result;
}
- public async Task<bool> ExecuteAsync(OperationProgress? progress = null) => await new Task<bool>(() => Execute(progress));
+ public Task<bool> ExecuteAsync(OperationProgress? progress = null) => Task.Run(() => Execute(progress), progress?.Token ?? default);
public virtual bool Execute(Mat mat, params object[]? arguments)
{
throw new NotImplementedException();
}
- public async Task<bool> ExecuteAsync(Mat mat, params object[]? arguments) => await new Task<bool>(() => Execute(mat, arguments));
+ public Task<bool> ExecuteAsync(Mat mat, params object[]? arguments) => Task.Run(() => Execute(mat, arguments));
/// <summary>
/// Get the selected layer range in a new array, array index will not match layer index when a range is selected
diff --git a/UVtools.Core/Operations/OperationCalculator.cs b/UVtools.Core/Operations/OperationCalculator.cs
index b6395e3..fe407af 100644
--- a/UVtools.Core/Operations/OperationCalculator.cs
+++ b/UVtools.Core/Operations/OperationCalculator.cs
@@ -32,7 +32,7 @@ public class OperationCalculator : Operation
public override string ProgressAction => null!;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override bool CanHaveProfiles => false;
diff --git a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
index b8e17aa..bce1855 100644
--- a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
+++ b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
@@ -57,7 +57,7 @@ public sealed class OperationCalibrateElephantFoot : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "mdi-elephant";
public override string Title => "Elephant foot";
public override string Description =>
@@ -380,7 +380,7 @@ public sealed class OperationCalibrateElephantFoot : Operation
if (_bottomLayers <= 0) _bottomLayers = (ushort) Slicer.Slicer.MillimetersToLayers(1M, _layerHeight);
if (_normalLayers <= 0) _normalLayers = (ushort) Slicer.Slicer.MillimetersToLayers(3.5M, _layerHeight);
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
}
#endregion
@@ -670,7 +670,7 @@ public sealed class OperationCalibrateElephantFoot : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
Parallel.ForEach(layers, CoreSettings.ParallelOptions, mat => CvInvoke.Flip(mat, mat, Enumerations.ToOpenCVFlipType(flip)));
}
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index 3a281d6..5adc175 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -202,7 +202,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
public override bool CanROI => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "mdi-timer-cog";
public override string Title => "Exposure time finder";
public override string Description =>
@@ -1162,7 +1162,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
{
base.InitWithSlicerFile();
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
@@ -2237,7 +2237,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
new OperationFlip(SlicerFile) { FlipDirection = Enumerations.ToOpenCVFlipType(flip) }.Execute(progress);
}
}
diff --git a/UVtools.Core/Operations/OperationCalibrateExternalTests.cs b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs
index bebef99..8cc5f3c 100644
--- a/UVtools.Core/Operations/OperationCalibrateExternalTests.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs
@@ -18,7 +18,7 @@ public class OperationCalibrateExternalTests : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override bool CanHaveProfiles => false;
public override string ButtonOkText => null!;
diff --git a/UVtools.Core/Operations/OperationCalibrateGrayscale.cs b/UVtools.Core/Operations/OperationCalibrateGrayscale.cs
index 49bc53e..4b64dd4 100644
--- a/UVtools.Core/Operations/OperationCalibrateGrayscale.cs
+++ b/UVtools.Core/Operations/OperationCalibrateGrayscale.cs
@@ -54,7 +54,7 @@ public sealed class OperationCalibrateGrayscale : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-chart-pie";
public override string Title => "Grayscale";
public override string Description =>
@@ -114,7 +114,7 @@ public sealed class OperationCalibrateGrayscale : Operation
if(_bottomLayers <= 0) _bottomLayers = SlicerFile.BottomLayerCount;
if(_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime;
if(_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime;
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
}
#endregion
@@ -466,7 +466,7 @@ public sealed class OperationCalibrateGrayscale : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
Parallel.ForEach(layers, CoreSettings.ParallelOptions, mat => CvInvoke.Flip(mat, mat, Enumerations.ToOpenCVFlipType(flip)));
}
diff --git a/UVtools.Core/Operations/OperationCalibrateLiftHeight.cs b/UVtools.Core/Operations/OperationCalibrateLiftHeight.cs
index db74a36..45d81ac 100644
--- a/UVtools.Core/Operations/OperationCalibrateLiftHeight.cs
+++ b/UVtools.Core/Operations/OperationCalibrateLiftHeight.cs
@@ -46,7 +46,7 @@ public sealed class OperationCalibrateLiftHeight : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "mdi-arrow-expand-up";
public override string Title => "Lift height";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationCalibrateStressTower.cs b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
index ff22030..c651fe4 100644
--- a/UVtools.Core/Operations/OperationCalibrateStressTower.cs
+++ b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
@@ -49,7 +49,7 @@ public sealed class OperationCalibrateStressTower : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-chess-rook";
public override string Title => "Stress tower";
public override string Description =>
@@ -111,7 +111,7 @@ public sealed class OperationCalibrateStressTower : Operation
if(_bottomLayers <= 0) _bottomLayers = SlicerFile.BottomLayerCount;
if(_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime;
if(_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime;
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
@@ -386,7 +386,7 @@ public sealed class OperationCalibrateStressTower : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
Parallel.ForEach(layers, CoreSettings.ParallelOptions, mat => CvInvoke.Flip(mat, mat, Enumerations.ToOpenCVFlipType(flip)));
}
diff --git a/UVtools.Core/Operations/OperationCalibrateTolerance.cs b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
index 57615bc..d675c82 100644
--- a/UVtools.Core/Operations/OperationCalibrateTolerance.cs
+++ b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
@@ -59,7 +59,7 @@ public sealed class OperationCalibrateTolerance : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-dot-circle";
public override string Title => "Tolerance";
public override string Description =>
@@ -430,7 +430,7 @@ public sealed class OperationCalibrateTolerance : Operation
if (_bottomLayers <= 0) _bottomLayers = SlicerFile.BottomLayerCount;
if (_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime;
if (_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime;
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
@@ -686,7 +686,7 @@ public sealed class OperationCalibrateTolerance : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
Parallel.ForEach(layers, CoreSettings.ParallelOptions, mat => CvInvoke.Flip(mat, mat, Enumerations.ToOpenCVFlipType(flip)));
}
diff --git a/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs b/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs
index 77b6a1d..8e64255 100644
--- a/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs
+++ b/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs
@@ -60,7 +60,7 @@ public sealed class OperationCalibrateXYZAccuracy : Operation
public override bool CanCancel => false;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-cubes";
public override string Title => "XYZ Accuracy";
public override string Description =>
@@ -464,7 +464,7 @@ public sealed class OperationCalibrateXYZAccuracy : Operation
if (_bottomLayers <= 0) _bottomLayers = SlicerFile.BottomLayerCount;
if (_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime;
if (_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime;
- _mirrorOutput = SlicerFile.DisplayMirror != Enumerations.FlipDirection.None;
+ _mirrorOutput = SlicerFile.DisplayMirror != FlipDirection.None;
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
@@ -721,7 +721,7 @@ public sealed class OperationCalibrateXYZAccuracy : Operation
if (_mirrorOutput)
{
var flip = SlicerFile.DisplayMirror;
- if (flip == Enumerations.FlipDirection.None) flip = Enumerations.FlipDirection.Horizontally;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
Parallel.ForEach(layers, CoreSettings.ParallelOptions, mat => CvInvoke.Flip(mat, mat, Enumerations.ToOpenCVFlipType(flip)));
}
diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs
index 5762366..b9bd0aa 100644
--- a/UVtools.Core/Operations/OperationChangeResolution.cs
+++ b/UVtools.Core/Operations/OperationChangeResolution.cs
@@ -23,6 +23,8 @@ public sealed class OperationChangeResolution : Operation
private uint _newResolutionX;
private uint _newResolutionY;
private bool _fixRatio;
+ private decimal _newDisplayWidth;
+ private decimal _newDisplayHeight;
#endregion
@@ -56,7 +58,7 @@ public sealed class OperationChangeResolution : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override string IconClass => "mdi-resize";
public override string Title => "Change print resolution";
@@ -64,13 +66,11 @@ public sealed class OperationChangeResolution : Operation
"Crops or resizes all layer images to fit an alternate print resolution.\n" +
"Useful to make files printable on a different printer than they were originally sliced for without the need to re-slice.\n\n" +
"NOTE: Please ensure that the actual model will fit within the new print resolution. The operation will be aborted if it will result in any of the actual model being clipped.\n" +
- "Only use this tool if both source and target printer have the same pixel pitch spec, otherwise the model size will be invalidated and result in a different size than the originally sliced for. " +
- "As alternative is possible to resize the model to match the new pixel pitch.";
+ "Only use this tool if both source and target printer have the same pixel pitch spec, otherwise the model size will be invalidated and result in a different size than the originally sliced for.\n" +
+ "As alternative, set the correct display size of the target printer or select an machine preset to match the new pixel pitch and let it auto fix the pixel ratio. It's always good practice to set the correct display size, even if you don't want to fix the pixel ratio, that is a critical information for both software and printers.";
public override string ConfirmationText =>
- "change print resolution " +
- $"from {SlicerFile.ResolutionX}x{SlicerFile.ResolutionY} " +
- $"to {NewResolutionX}x{NewResolutionY}?";
+ $"change print resolution from {SlicerFile.ResolutionX}x{SlicerFile.ResolutionY} to {NewResolutionX}x{NewResolutionY}?";
public override string ProgressTitle =>
$"Changing print resolution from ({SlicerFile.ResolutionX}x{SlicerFile.ResolutionY}) to ({NewResolutionX}x{NewResolutionY})";
@@ -98,7 +98,7 @@ public sealed class OperationChangeResolution : Operation
public override string ToString()
{
- var result = $"{_newResolutionX} x {_newResolutionY} [Fix ratio: {_fixRatio}]";
+ var result = $"{_newResolutionX}x{_newResolutionY} [Display: {_newDisplayWidth}x{_newDisplayHeight}] [Fix ratio: {_fixRatio}]";
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -111,8 +111,8 @@ public sealed class OperationChangeResolution : Operation
get => _newResolutionX;
set
{
- if(!RaiseAndSetIfChanged(ref _newResolutionX, value)) return;
- RaisePropertyChanged(nameof(NewRatioX));
+ if(!RaiseAndSetIfChanged(ref _newResolutionX, Math.Max(1, value))) return;
+ RaisePropertyChanged(nameof(NewPixelSizeMicrons));
RaisePropertyChanged(nameof(NewFixedRatioX));
RaisePropertyChanged(nameof(FinalBoundsWidth));
}
@@ -123,18 +123,63 @@ public sealed class OperationChangeResolution : Operation
get => _newResolutionY;
set
{
- RaiseAndSetIfChanged(ref _newResolutionY, value);
- RaisePropertyChanged(nameof(NewRatioY));
+ if(!RaiseAndSetIfChanged(ref _newResolutionY, Math.Max(1, value))) return;
+ RaisePropertyChanged(nameof(NewPixelSizeMicrons));
RaisePropertyChanged(nameof(NewFixedRatioY));
RaisePropertyChanged(nameof(FinalBoundsHeight));
}
}
- public double NewRatioX => Math.Round((double)SlicerFile.ResolutionX / _newResolutionX, 2);
- public double NewRatioY => Math.Round((double)SlicerFile.ResolutionY / _newResolutionY, 2);
+ public decimal NewDisplayWidth
+ {
+ get => _newDisplayWidth;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _newDisplayWidth, Math.Max(0, value))) return;
+ RaisePropertyChanged(nameof(NewPixelSizeMicrons));
+ RaisePropertyChanged(nameof(NewFixedRatioX));
+ }
+ }
+
+ public decimal NewDisplayHeight
+ {
+ get => _newDisplayHeight;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _newDisplayHeight, Math.Max(0, value))) return;
+ RaisePropertyChanged(nameof(NewPixelSizeMicrons));
+ RaisePropertyChanged(nameof(NewFixedRatioY));
+ }
+ }
+
+ public SizeF NewPixelSizeMicrons =>
+ new (_newResolutionX <= 0 || SlicerFile.Display.Width <= 0 || _newDisplayWidth <= 0
+ ? SlicerFile.PixelWidthMicrons
+ : (float) Math.Round((float) _newDisplayWidth / _newResolutionX * 1000, 3),
+ _newResolutionY <= 0 || SlicerFile.Display.Height <= 0 || _newDisplayHeight <= 0
+ ? SlicerFile.PixelHeightMicrons
+ : (float) Math.Round((float) _newDisplayHeight / _newResolutionY * 1000, 3));
+
+ public double NewFixedRatioX
+ {
- public double NewFixedRatioX => Math.Round((double)_newResolutionX / SlicerFile.ResolutionX, 2);
- public double NewFixedRatioY => Math.Round((double)_newResolutionY / SlicerFile.ResolutionY, 2);
+ get
+ {
+ if (_newResolutionX <= 0 || SlicerFile.Display.Width <= 0 || _newDisplayWidth <= 0) return 1;
+ var ratio = SlicerFile.PixelWidth / ((double)_newDisplayWidth / _newResolutionX);
+ return Math.Round(ratio, 3);
+ }
+ }
+
+ public double NewFixedRatioY
+ {
+ get
+ {
+ if (_newResolutionY <= 0 || SlicerFile.Display.Height <= 0 || _newDisplayHeight <= 0) return 1;
+ var ratio = SlicerFile.PixelHeight / ((double)_newDisplayHeight / _newResolutionY);
+ return Math.Round(ratio, 3);
+ }
+ }
public bool FixRatio
{
@@ -164,6 +209,8 @@ public sealed class OperationChangeResolution : Operation
base.InitWithSlicerFile();
if(_newResolutionX <= 0) _newResolutionX = SlicerFile.ResolutionX;
if(_newResolutionY <= 0) _newResolutionY = SlicerFile.ResolutionY;
+ if(_newDisplayWidth <= 0) _newDisplayWidth = (decimal) SlicerFile.DisplayWidth;
+ if(_newDisplayHeight <= 0) _newDisplayHeight = (decimal) SlicerFile.DisplayHeight;
}
#endregion
@@ -217,6 +264,7 @@ public sealed class OperationChangeResolution : Operation
var newFixedRatioY = NewFixedRatioY;
if (_fixRatio && (newFixedRatioX != 1.0 || newFixedRatioY != 1.0))
{
+ //mat.TransformFromCenter();
CvInvoke.Resize(mat, mat, SlicerFile.Resolution.Multiply(newFixedRatioX, newFixedRatioY));
}
@@ -228,8 +276,19 @@ public sealed class OperationChangeResolution : Operation
progress.LockAndIncrement();
});
- SlicerFile.ResolutionX = NewResolutionX;
- SlicerFile.ResolutionY = NewResolutionY;
+ SlicerFile.ResolutionX = _newResolutionX;
+ SlicerFile.ResolutionY = _newResolutionY;
+ if (_newDisplayWidth > 0)
+ {
+ SlicerFile.DisplayWidth = (float) _newDisplayWidth;
+ }
+
+ if (_newDisplayHeight > 0)
+ {
+ SlicerFile.DisplayHeight = (float)_newDisplayHeight;
+ }
+
+ SlicerFile.BoundingRectangle = Rectangle.Empty;
return !progress.Token.IsCancellationRequested;
}
@@ -254,7 +313,7 @@ public sealed class OperationChangeResolution : Operation
private bool Equals(OperationChangeResolution other)
{
- return _newResolutionX == other._newResolutionX && _newResolutionY == other._newResolutionY && _fixRatio == other._fixRatio;
+ return _newResolutionX == other._newResolutionX && _newResolutionY == other._newResolutionY && _fixRatio == other._fixRatio && _newDisplayWidth == other._newDisplayWidth && _newDisplayHeight == other._newDisplayHeight;
}
public override bool Equals(object? obj)
@@ -264,7 +323,7 @@ public sealed class OperationChangeResolution : Operation
public override int GetHashCode()
{
- return HashCode.Combine(_newResolutionX, _newResolutionY, _fixRatio);
+ return HashCode.Combine(_newResolutionX, _newResolutionY, _fixRatio, _newDisplayWidth, _newDisplayHeight);
}
#endregion
diff --git a/UVtools.Core/Operations/OperationDoubleExposure.cs b/UVtools.Core/Operations/OperationDoubleExposure.cs
index 5b6d42d..9cfd608 100644
--- a/UVtools.Core/Operations/OperationDoubleExposure.cs
+++ b/UVtools.Core/Operations/OperationDoubleExposure.cs
@@ -41,7 +41,7 @@ public class OperationDoubleExposure : Operation
#endregion
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Bottom;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Bottom;
public override string IconClass => "fas fa-grip-lines";
public override string Title => "Double exposure";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs
index 90d2c6e..10e9e1f 100644
--- a/UVtools.Core/Operations/OperationDynamicLifts.cs
+++ b/UVtools.Core/Operations/OperationDynamicLifts.cs
@@ -66,7 +66,7 @@ public sealed class OperationDynamicLifts : Operation
public override bool CanRunInPartialMode => true;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Normal;
public override string IconClass => "fas fa-chart-line";
public override string Title => "Dynamic lifts";
diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs
index b3a9cdd..515989b 100644
--- a/UVtools.Core/Operations/OperationEditParameters.cs
+++ b/UVtools.Core/Operations/OperationEditParameters.cs
@@ -29,7 +29,7 @@ public class OperationEditParameters : Operation
#region Overrides
public override bool CanRunInPartialMode => true;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override string IconClass => "fas fa-edit";
diff --git a/UVtools.Core/Operations/OperationFadeExposureTime.cs b/UVtools.Core/Operations/OperationFadeExposureTime.cs
index 16cb2f4..a2fa304 100644
--- a/UVtools.Core/Operations/OperationFadeExposureTime.cs
+++ b/UVtools.Core/Operations/OperationFadeExposureTime.cs
@@ -27,7 +27,7 @@ public class OperationFadeExposureTime : Operation
#region Overrides
public override bool CanRunInPartialMode => true;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Normal;
public override bool LayerIndexEndEnabled => false;
public override string IconClass => "fas fa-history";
public override string Title => "Fade exposure time";
diff --git a/UVtools.Core/Operations/OperationIPrintedThisFile.cs b/UVtools.Core/Operations/OperationIPrintedThisFile.cs
index 742db65..466a378 100644
--- a/UVtools.Core/Operations/OperationIPrintedThisFile.cs
+++ b/UVtools.Core/Operations/OperationIPrintedThisFile.cs
@@ -29,7 +29,7 @@ public class OperationIPrintedThisFile : Operation
public override bool CanRunInPartialMode => true;
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override bool CanHaveProfiles => false;
diff --git a/UVtools.Core/Operations/OperationInfill.cs b/UVtools.Core/Operations/OperationInfill.cs
index 5384e5d..5e2e5d6 100644
--- a/UVtools.Core/Operations/OperationInfill.cs
+++ b/UVtools.Core/Operations/OperationInfill.cs
@@ -10,6 +10,7 @@ using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System;
+using System.ComponentModel;
using System.Drawing;
using System.Threading.Tasks;
using UVtools.Core.Extensions;
@@ -21,11 +22,13 @@ namespace UVtools.Core.Operations;
public sealed class OperationInfill : Operation
{
#region Members
- private InfillAlgorithm _infillType = InfillAlgorithm.CubicDynamicLink;
+ private InfillAlgorithm _infillType = InfillAlgorithm.CubicCrossAlternating;
private ushort _wallThickness = 64;
private ushort _infillThickness = 45;
- private ushort _infillSpacing = 160;
+ private ushort _infillSpacing = 200;
private ushort _infillBrightness = 255;
+ private bool _reinforceInfill;
+
#endregion
#region Overrides
@@ -49,16 +52,24 @@ public sealed class OperationInfill : Operation
public enum InfillAlgorithm
{
//Rhombus,
- Cubic,
- CubicCenterLink,
- CubicDynamicLink,
- CubicInterlinked,
+ [Description("Straight pillars (Weak)")]
+ Pillars,
+
+ [Description("Cubic cross: Fixed pilars with crossing sections (Optimal)")]
+ CubicCross,
+
+ [Description("Cubic alternating cross: Fixed pilars with crossing sections alternating in directions (Optimal)")]
+ CubicCrossAlternating,
+
+ [Description("Cubic star: Fixed pilars with crossing sections in star pattern (Strong)")]
+ CubicStar,
+
+ [Description("Honeycomb (Strong)")]
Honeycomb
}
#endregion
#region Properties
- public static Array InfillAlgorithmTypes => Enum.GetValues(typeof(InfillAlgorithm));
public InfillAlgorithm InfillType
{
get => _infillType;
@@ -89,9 +100,15 @@ public sealed class OperationInfill : Operation
set => RaiseAndSetIfChanged(ref _infillSpacing, value);
}
+ public bool ReinforceInfill
+ {
+ get => _reinforceInfill;
+ set => RaiseAndSetIfChanged(ref _reinforceInfill, value);
+ }
+
public override string ToString()
{
- var result = $"[{_infillType}] [Wall: {_wallThickness}px] [B: {_infillBrightness}px] [T: {_infillThickness}px] [S: {_infillSpacing}px]" + LayerRangeString;
+ var result = $"[{_infillType}] [Wall: {_wallThickness}px] [B: {_infillBrightness}px] [T: {_infillThickness}px] [S: {_infillSpacing}px] [R: {_reinforceInfill}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -110,7 +127,7 @@ public sealed class OperationInfill : Operation
private bool Equals(OperationInfill other)
{
- return _infillType == other._infillType && _wallThickness == other._wallThickness && _infillThickness == other._infillThickness && _infillSpacing == other._infillSpacing && _infillBrightness == other._infillBrightness;
+ return _infillType == other._infillType && _wallThickness == other._wallThickness && _infillThickness == other._infillThickness && _infillSpacing == other._infillSpacing && _infillBrightness == other._infillBrightness && _reinforceInfill == other._reinforceInfill;
}
public override bool Equals(object? obj)
@@ -120,7 +137,7 @@ public sealed class OperationInfill : Operation
public override int GetHashCode()
{
- return HashCode.Combine((int) _infillType, _wallThickness, _infillThickness, _infillSpacing, _infillBrightness);
+ return HashCode.Combine((int) _infillType, _wallThickness, _infillThickness, _infillSpacing, _infillBrightness, _reinforceInfill);
}
#endregion
@@ -163,10 +180,10 @@ public sealed class OperationInfill : Operation
using var mask = GetMask(mat);
bool disposeTargetMask = true;
- if (_infillType is InfillAlgorithm.Cubic
- or InfillAlgorithm.CubicCenterLink
- or InfillAlgorithm.CubicDynamicLink
- or InfillAlgorithm.CubicInterlinked)
+ if (_infillType is InfillAlgorithm.Pillars
+ or InfillAlgorithm.CubicCross
+ or InfillAlgorithm.CubicCrossAlternating
+ or InfillAlgorithm.CubicStar)
{
using var infillPattern = EmguExtensions.InitMat(new Size(_infillSpacing, _infillSpacing));
using var matPattern = mat.NewBlank();
@@ -180,8 +197,16 @@ public sealed class OperationInfill : Operation
accumulator += _infillSpacing;
if (accumulator >= layerIndex) break;
- firstPattern = false;
- accumulator += _infillThickness;
+
+ if (_reinforceInfill)
+ {
+ firstPattern = false;
+ accumulator += _infillThickness;
+ }
+ else
+ {
+ //accumulator += _infillSpacing;
+ }
}
if (firstPattern)
@@ -212,10 +237,10 @@ public sealed class OperationInfill : Operation
int margin = (int) (InfillSpacing - accumulator + layerIndex) - thickness;
int marginInv = (int) (accumulator - layerIndex) - thickness;
- if (_infillType == InfillAlgorithm.CubicCenterLink ||
- (_infillType == InfillAlgorithm.CubicDynamicLink &&
+ if (_infillType == InfillAlgorithm.CubicCross ||
+ (_infillType == InfillAlgorithm.CubicCrossAlternating &&
dynamicCenter) ||
- _infillType == InfillAlgorithm.CubicInterlinked)
+ _infillType == InfillAlgorithm.CubicStar)
{
CvInvoke.Rectangle(infillPattern,
@@ -239,8 +264,8 @@ public sealed class OperationInfill : Operation
}
- if (_infillType == InfillAlgorithm.CubicInterlinked ||
- (_infillType == InfillAlgorithm.CubicDynamicLink &&
+ if (_infillType == InfillAlgorithm.CubicStar ||
+ (_infillType == InfillAlgorithm.CubicCrossAlternating &&
!dynamicCenter))
{
CvInvoke.Rectangle(infillPattern,
diff --git a/UVtools.Core/Operations/OperationLayerArithmetic.cs b/UVtools.Core/Operations/OperationLayerArithmetic.cs
index 0a11d10..026bcde 100644
--- a/UVtools.Core/Operations/OperationLayerArithmetic.cs
+++ b/UVtools.Core/Operations/OperationLayerArithmetic.cs
@@ -55,7 +55,7 @@ public class OperationLayerArithmetic : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-square-root-alt";
public override string Title => "Layer arithmetic";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationLayerClone.cs b/UVtools.Core/Operations/OperationLayerClone.cs
index 3dd6229..cce810f 100644
--- a/UVtools.Core/Operations/OperationLayerClone.cs
+++ b/UVtools.Core/Operations/OperationLayerClone.cs
@@ -25,7 +25,7 @@ public sealed class OperationLayerClone : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Current;
public override bool CanROI => false;
public override bool PassActualLayerIndex => true;
public override string IconClass => "fas fa-clone";
diff --git a/UVtools.Core/Operations/OperationLayerExportGif.cs b/UVtools.Core/Operations/OperationLayerExportGif.cs
index dcea6f0..cce026a 100644
--- a/UVtools.Core/Operations/OperationLayerExportGif.cs
+++ b/UVtools.Core/Operations/OperationLayerExportGif.cs
@@ -32,8 +32,8 @@ public sealed class OperationLayerExportGif : Operation
private ushort _repeats;
private ushort _skip;
private decimal _scale = 50;
- private Enumerations.RotateDirection _rotateDirection = Enumerations.RotateDirection.None;
- private Enumerations.FlipDirection _flipDirection = Enumerations.FlipDirection.None;
+ private RotateDirection _rotateDirection = RotateDirection.None;
+ private FlipDirection _flipDirection = FlipDirection.None;
#endregion
@@ -165,13 +165,13 @@ public sealed class OperationLayerExportGif : Operation
public float ScaleFactor => (float)_scale / 100f;
- public Enumerations.RotateDirection RotateDirection
+ public RotateDirection RotateDirection
{
get => _rotateDirection;
set => RaiseAndSetIfChanged(ref _rotateDirection, value);
}
- public Enumerations.FlipDirection FlipDirection
+ public FlipDirection FlipDirection
{
get => _flipDirection;
set => RaiseAndSetIfChanged(ref _flipDirection, value);
@@ -237,12 +237,12 @@ public sealed class OperationLayerExportGif : Operation
CvInvoke.Resize(matRoi, matRoi, new Size((int) (matRoi.Width * ScaleFactor), (int)(matRoi.Height * ScaleFactor)));
}
- if (_flipDirection != Enumerations.FlipDirection.None)
+ if (_flipDirection != FlipDirection.None)
{
CvInvoke.Flip(matRoi, matRoi, Enumerations.ToOpenCVFlipType(_flipDirection));
}
- if (_rotateDirection != Enumerations.RotateDirection.None)
+ if (_rotateDirection != RotateDirection.None)
{
CvInvoke.Rotate(matRoi, matRoi, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
}
diff --git a/UVtools.Core/Operations/OperationLayerExportHeatMap.cs b/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
index c65ed6b..47ca83c 100644
--- a/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
+++ b/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
@@ -22,8 +22,8 @@ public sealed class OperationLayerExportHeatMap : Operation
{
#region Members
private string _filePath = null!;
- private Enumerations.RotateDirection _rotateDirection = Enumerations.RotateDirection.None;
- private Enumerations.FlipDirection _flipDirection = Enumerations.FlipDirection.None;
+ private RotateDirection _rotateDirection = RotateDirection.None;
+ private FlipDirection _flipDirection = FlipDirection.None;
private bool _mergeSamePositionedLayers = true;
private bool _cropByRoi = true;
@@ -78,13 +78,13 @@ public sealed class OperationLayerExportHeatMap : Operation
set => RaiseAndSetIfChanged(ref _filePath, value);
}
- public Enumerations.RotateDirection RotateDirection
+ public RotateDirection RotateDirection
{
get => _rotateDirection;
set => RaiseAndSetIfChanged(ref _rotateDirection, value);
}
- public Enumerations.FlipDirection FlipDirection
+ public FlipDirection FlipDirection
{
get => _flipDirection;
set => RaiseAndSetIfChanged(ref _flipDirection, value);
@@ -173,12 +173,12 @@ public sealed class OperationLayerExportHeatMap : Operation
using var sumMat = EmguExtensions.InitMat(sumMat32.Size);
sumMat32.ConvertTo(sumMat, DepthType.Cv8U, 1.0 / layerRange.Length);
- if (_flipDirection != Enumerations.FlipDirection.None)
+ if (_flipDirection != FlipDirection.None)
{
CvInvoke.Flip(sumMat, sumMat, Enumerations.ToOpenCVFlipType(_flipDirection));
}
- if (_rotateDirection != Enumerations.RotateDirection.None)
+ if (_rotateDirection != RotateDirection.None)
{
CvInvoke.Rotate(sumMat, sumMat, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
}
diff --git a/UVtools.Core/Operations/OperationLayerExportImage.cs b/UVtools.Core/Operations/OperationLayerExportImage.cs
index 8839e52..918c66b 100644
--- a/UVtools.Core/Operations/OperationLayerExportImage.cs
+++ b/UVtools.Core/Operations/OperationLayerExportImage.cs
@@ -59,8 +59,8 @@ public sealed class OperationLayerExportImage : Operation
private string _outputFolder = null!;
private string _filename = "layer";
private LayerExportImageTypes _imageType = LayerExportImageTypes.PNG;
- private Enumerations.RotateDirection _rotateDirection = Enumerations.RotateDirection.None;
- private Enumerations.FlipDirection _flipDirection = Enumerations.FlipDirection.None;
+ private RotateDirection _rotateDirection = RotateDirection.None;
+ private FlipDirection _flipDirection = FlipDirection.None;
private bool _padLayerIndex = true;
private bool _cropByRoi = true;
@@ -126,13 +126,13 @@ public sealed class OperationLayerExportImage : Operation
set => RaiseAndSetIfChanged(ref _imageType, value);
}
- public Enumerations.RotateDirection RotateDirection
+ public RotateDirection RotateDirection
{
get => _rotateDirection;
set => RaiseAndSetIfChanged(ref _rotateDirection, value);
}
- public Enumerations.FlipDirection FlipDirection
+ public FlipDirection FlipDirection
{
get => _flipDirection;
set => RaiseAndSetIfChanged(ref _flipDirection, value);
@@ -189,17 +189,17 @@ public sealed class OperationLayerExportImage : Operation
matRoi = GetRoiOrDefault(mat);
}
- if (_flipDirection != Enumerations.FlipDirection.None)
+ if (_flipDirection != FlipDirection.None)
{
CvInvoke.Flip(matRoi, matRoi, Enumerations.ToOpenCVFlipType(_flipDirection));
}
- if (_rotateDirection != Enumerations.RotateDirection.None)
+ if (_rotateDirection != RotateDirection.None)
{
CvInvoke.Rotate(matRoi, matRoi, Enumerations.ToOpenCVRotateFlags(_rotateDirection));
}
- var filename = SlicerFile[layerIndex].FormatFileName(_filename, _padLayerIndex ? SlicerFile.LayerDigits : byte.MinValue, Enumerations.IndexStartNumber.Zero, string.Empty);
+ var filename = SlicerFile[layerIndex].FormatFileName(_filename, _padLayerIndex ? SlicerFile.LayerDigits : byte.MinValue, IndexStartNumber.Zero, string.Empty);
var fileFullPath = Path.Combine(_outputFolder, $"{filename}.{_imageType.ToString().ToLower()}");
if (_imageType != LayerExportImageTypes.SVG)
diff --git a/UVtools.Core/Operations/OperationLayerExportMesh.cs b/UVtools.Core/Operations/OperationLayerExportMesh.cs
index 8240ad2..fda3d5e 100644
--- a/UVtools.Core/Operations/OperationLayerExportMesh.cs
+++ b/UVtools.Core/Operations/OperationLayerExportMesh.cs
@@ -46,8 +46,8 @@ public sealed class OperationLayerExportMesh : Operation
private string _filePath = null!;
private MeshFile.MeshFileFormat _meshFileFormat = MeshFile.MeshFileFormat.BINARY;
private ExportMeshQuality _quality = ExportMeshQuality.Accurate;
- private Enumerations.RotateDirection _rotateDirection = Enumerations.RotateDirection.None;
- private Enumerations.FlipDirection _flipDirection = Enumerations.FlipDirection.None;
+ private RotateDirection _rotateDirection = RotateDirection.None;
+ private FlipDirection _flipDirection = FlipDirection.None;
private bool _stripAntiAliasing = true;
#endregion
@@ -113,13 +113,13 @@ public sealed class OperationLayerExportMesh : Operation
set => RaiseAndSetIfChanged(ref _quality, value);
}
- public Enumerations.RotateDirection RotateDirection
+ public RotateDirection RotateDirection
{
get => _rotateDirection;
set => RaiseAndSetIfChanged(ref _rotateDirection, value);
}
- public Enumerations.FlipDirection FlipDirection
+ public FlipDirection FlipDirection
{
get => _flipDirection;
set => RaiseAndSetIfChanged(ref _flipDirection, value);
@@ -181,10 +181,10 @@ public sealed class OperationLayerExportMesh : Operation
* ideally we would fix the algorithm itself but that's more invovled. for the time being we'll just flip it verticaly. */
var workAroundFlip = _flipDirection switch
{
- Enumerations.FlipDirection.None => Enumerations.FlipDirection.Vertically,
- Enumerations.FlipDirection.Horizontally => Enumerations.FlipDirection.Both,
- Enumerations.FlipDirection.Vertically => Enumerations.FlipDirection.None,
- Enumerations.FlipDirection.Both => Enumerations.FlipDirection.Horizontally,
+ FlipDirection.None => FlipDirection.Vertically,
+ FlipDirection.Horizontally => FlipDirection.Both,
+ FlipDirection.Vertically => FlipDirection.None,
+ FlipDirection.Both => FlipDirection.Horizontally,
_ => throw new NotImplementedException($"Flip type: {_flipDirection} not handled!")
};
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index e1b0d39..d22c732 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -63,7 +63,7 @@ public sealed class OperationLayerImport : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override string IconClass => "mdi-database-import";
@@ -288,7 +288,7 @@ public sealed class OperationLayerImport : Operation
if (_importType == ImportTypes.Stack)
{
- new OperationMove(SlicerFile, Enumerations.Anchor.TopLeft).Execute(progress);
+ new OperationMove(SlicerFile, Anchor.TopLeft).Execute(progress);
}
foreach (var fileFormat in fileFormats)
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index e4aec8f..682ddaa 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -56,7 +56,7 @@ public sealed class OperationLayerReHeight : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override bool CanROI => false;
public override string IconClass => "mdi-arrow-split-horizontal";
public override string Title => "Adjust layer height";
diff --git a/UVtools.Core/Operations/OperationLayerRemove.cs b/UVtools.Core/Operations/OperationLayerRemove.cs
index c2563e2..20e53ba 100644
--- a/UVtools.Core/Operations/OperationLayerRemove.cs
+++ b/UVtools.Core/Operations/OperationLayerRemove.cs
@@ -25,7 +25,7 @@ public sealed class OperationLayerRemove : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Current;
public override bool CanROI => false;
public override bool PassActualLayerIndex => true;
public override string IconClass => "mdi-layers-remove";
diff --git a/UVtools.Core/Operations/OperationLightBleedCompensation.cs b/UVtools.Core/Operations/OperationLightBleedCompensation.cs
index 4cd5030..d307a71 100644
--- a/UVtools.Core/Operations/OperationLightBleedCompensation.cs
+++ b/UVtools.Core/Operations/OperationLightBleedCompensation.cs
@@ -47,7 +47,7 @@ public class OperationLightBleedCompensation : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Normal;
public override string IconClass => "mdi-lightbulb-on";
public override string Title => "Light bleed compensation";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index d3df8b9..b83a116 100644
--- a/UVtools.Core/Operations/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -63,7 +63,7 @@ public class OperationMove : Operation
private Rectangle _dstRoi = Rectangle.Empty;
private uint _imageWidth;
private uint _imageHeight;
- private Enumerations.Anchor _anchor = Enumerations.Anchor.MiddleCenter;
+ private Anchor _anchor = Anchor.MiddleCenter;
private int _marginLeft;
private int _marginTop;
private int _marginRight;
@@ -96,7 +96,7 @@ public class OperationMove : Operation
set => RaiseAndSetIfChanged(ref _imageHeight, value);
}
- public Enumerations.Anchor Anchor
+ public Anchor Anchor
{
get => _anchor;
set
@@ -176,15 +176,15 @@ public class OperationMove : Operation
public OperationMove() { }
- public OperationMove(FileFormat slicerFile) : this(slicerFile, Enumerations.Anchor.MiddleCenter)
+ public OperationMove(FileFormat slicerFile) : this(slicerFile, Anchor.MiddleCenter)
{ }
- public OperationMove(FileFormat slicerFile, Enumerations.Anchor anchor) : base(slicerFile)
+ public OperationMove(FileFormat slicerFile, Anchor anchor) : base(slicerFile)
{
_anchor = anchor;
}
- public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) : this(slicerFile, anchor)
+ public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Anchor anchor = Anchor.MiddleCenter) : this(slicerFile, anchor)
{
if(!srcRoi.IsEmpty) ROI = srcRoi;
}
@@ -197,7 +197,7 @@ public class OperationMove : Operation
_imageHeight = SlicerFile.ResolutionY;
}
- /*public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Mat mat, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) : this(slicerFile, srcRoi, anchor)
+ /*public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Mat mat, Anchor anchor = Anchor.MiddleCenter) : this(slicerFile, srcRoi, anchor)
{
ImageWidth = (uint) mat.Width;
ImageHeight = (uint) mat.Height;
@@ -212,15 +212,15 @@ public class OperationMove : Operation
_dstRoi.Location = Anchor switch
{
- Enumerations.Anchor.TopLeft => new Point(0, 0),
- Enumerations.Anchor.TopCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), 0),
- Enumerations.Anchor.TopRight => new Point((int) (ImageWidth - ROI.Width), 0),
- Enumerations.Anchor.MiddleLeft => new Point(0, (int) (ImageHeight / 2 - ROI.Height / 2)),
- Enumerations.Anchor.MiddleCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), (int) (ImageHeight / 2 - ROI.Height / 2)),
- Enumerations.Anchor.MiddleRight => new Point((int) (ImageWidth - ROI.Width), (int) (ImageHeight / 2 - ROI.Height / 2)),
- Enumerations.Anchor.BottomLeft => new Point(0, (int) (ImageHeight - ROI.Height)),
- Enumerations.Anchor.BottomCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), (int) (ImageHeight - ROI.Height)),
- Enumerations.Anchor.BottomRight => new Point((int) (ImageWidth - ROI.Width), (int) (ImageHeight - ROI.Height)),
+ Anchor.TopLeft => new Point(0, 0),
+ Anchor.TopCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), 0),
+ Anchor.TopRight => new Point((int) (ImageWidth - ROI.Width), 0),
+ Anchor.MiddleLeft => new Point(0, (int) (ImageHeight / 2 - ROI.Height / 2)),
+ Anchor.MiddleCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), (int) (ImageHeight / 2 - ROI.Height / 2)),
+ Anchor.MiddleRight => new Point((int) (ImageWidth - ROI.Width), (int) (ImageHeight / 2 - ROI.Height / 2)),
+ Anchor.BottomLeft => new Point(0, (int) (ImageHeight - ROI.Height)),
+ Anchor.BottomCenter => new Point((int) (ImageWidth / 2 - ROI.Width / 2), (int) (ImageHeight - ROI.Height)),
+ Anchor.BottomRight => new Point((int) (ImageWidth - ROI.Width), (int) (ImageHeight - ROI.Height)),
_ => throw new ArgumentOutOfRangeException()
};
@@ -242,14 +242,14 @@ public class OperationMove : Operation
public void Reset()
{
MarginLeft = MarginTop = MarginRight = MarginBottom = 0;
- Anchor = Enumerations.Anchor.MiddleCenter;
+ Anchor = Anchor.MiddleCenter;
IsCutMove = true;
}
public void SetAnchor(byte value)
{
- Anchor = (Enumerations.Anchor)value;
+ Anchor = (Anchor)value;
}
diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs
index 24023a3..b4a2127 100644
--- a/UVtools.Core/Operations/OperationPattern.cs
+++ b/UVtools.Core/Operations/OperationPattern.cs
@@ -20,7 +20,7 @@ namespace UVtools.Core.Operations;
public class OperationPattern : Operation
{
#region Members
- private Enumerations.Anchor _anchor = Enumerations.Anchor.None;
+ private Anchor _anchor = Anchor.None;
private ushort _colSpacing;
private ushort _rowSpacing;
private ushort _maxColSpacing;
@@ -80,7 +80,7 @@ public class OperationPattern : Operation
#endregion
#region Properties
- public Enumerations.Anchor Anchor
+ public Anchor Anchor
{
get => _anchor;
set => RaiseAndSetIfChanged(ref _anchor, value);
@@ -227,7 +227,7 @@ public class OperationPattern : Operation
#region Methods
public void SetAnchor(byte value)
{
- Anchor = (Enumerations.Anchor)value;
+ Anchor = (Anchor)value;
}
public void SetRoi(Rectangle srcRoi)
@@ -319,7 +319,7 @@ public class OperationPattern : Operation
SlicerFile.BoundingRectangle = Rectangle.Empty;
- if (Anchor == Enumerations.Anchor.None) return true;
+ if (Anchor == Anchor.None) return true;
var operationMove = new OperationMove(SlicerFile, Anchor)
{
LayerIndexStart = LayerIndexStart,
diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs
index 8314d75..9725317 100644
--- a/UVtools.Core/Operations/OperationRaftRelief.cs
+++ b/UVtools.Core/Operations/OperationRaftRelief.cs
@@ -70,8 +70,8 @@ public class OperationRaftRelief : Operation
public override string ProgressAction => "Relieved layers";
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection =>
- Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection =>
+ LayerRangeSelection.None;
public override string? ValidateInternally()
{
diff --git a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
index d8473d6..c958e34 100644
--- a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
+++ b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
@@ -28,7 +28,7 @@ public class OperationRaiseOnPrintFinish : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None;
public override string IconClass => "fas fa-level-up-alt";
public override string Title => "Raise platform on print finish";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationRedrawModel.cs b/UVtools.Core/Operations/OperationRedrawModel.cs
index 9407d49..479d51d 100644
--- a/UVtools.Core/Operations/OperationRedrawModel.cs
+++ b/UVtools.Core/Operations/OperationRedrawModel.cs
@@ -33,7 +33,7 @@ public class OperationRedrawModel : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection { get; } = Enumerations.LayerRangeSelection.None;
+ public override LayerRangeSelection StartLayerRangeSelection { get; } = LayerRangeSelection.None;
public override string IconClass => "mdi-puzzle-edit";
public override string Title => "Redraw model/supports";
diff --git a/UVtools.Core/Operations/OperationTimelapse.cs b/UVtools.Core/Operations/OperationTimelapse.cs
index 256d797..41b5a1e 100644
--- a/UVtools.Core/Operations/OperationTimelapse.cs
+++ b/UVtools.Core/Operations/OperationTimelapse.cs
@@ -50,7 +50,7 @@ public class OperationTimelapse : Operation
#region Overrides
- public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Normal;
+ public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.Normal;
public override string IconClass => "fas fa-camera";
public override string Title => "Timelapse";
public override string Description =>
diff --git a/UVtools.Core/Printer/Machine.cs b/UVtools.Core/Printer/Machine.cs
new file mode 100644
index 0000000..2c93cfc
--- /dev/null
+++ b/UVtools.Core/Printer/Machine.cs
@@ -0,0 +1,409 @@
+/*
+ * 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.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using UVtools.Core.Extensions;
+
+namespace UVtools.Core.Printer
+{
+ public class Machine
+ {
+ #region Properties
+ public PrinterBrand Brand { get; set; }
+ public string Name { get; set; } = FileFormats.FileFormat.DefaultMachineName;
+ public string Model { get; set; } = FileFormats.FileFormat.DefaultMachineName;
+
+ public ushort ResolutionX { get; set; }
+
+ public ushort ResolutionY { get; set; }
+
+ public float DisplayWidth { get; set; }
+
+ public float DisplayHeight { get; set; }
+
+ public float MachineZ { get; set; }
+
+ public FlipDirection DisplayMirror { get; set; }
+
+ public object? Tag { get; set; }
+ #endregion
+
+ #region Constructor
+
+ public Machine() { }
+
+ public Machine(PrinterBrand brand, string name, string? model, ushort resolutionX, ushort resolutionY, float displayWidth, float displayHeight, float machineZ, FlipDirection displayMirror = default)
+ {
+ Brand = brand;
+ Name = name;
+ Model = model ?? name;
+ ResolutionX = resolutionX;
+ ResolutionY = resolutionY;
+ DisplayWidth = displayWidth;
+ DisplayHeight = displayHeight;
+ MachineZ = machineZ;
+ DisplayMirror = displayMirror;
+ }
+
+ public Machine(PrinterBrand brand, string name, string? model, Size resolution, SizeF display, float machineZ, FlipDirection displayMirror = default)
+ : this(brand, name, model, (ushort)resolution.Width, (ushort)resolution.Height, display.Width, display.Height, machineZ, displayMirror) { }
+
+ public Machine(ushort resolutionX, ushort resolutionY, float displayWidth, float displayHeight, float machineZ, FlipDirection displayMirror = default, PrinterBrand brand = default, string name = FileFormats.FileFormat.DefaultMachineName, string? model = null)
+ : this(brand, name, model, resolutionX, resolutionY, displayWidth, displayHeight, machineZ, displayMirror) {}
+
+ #endregion
+
+ #region Overrides
+
+ protected bool Equals(Machine other)
+ {
+ return ResolutionX == other.ResolutionX && ResolutionY == other.ResolutionY && DisplayWidth.Equals(other.DisplayWidth) && DisplayHeight.Equals(other.DisplayHeight) && MachineZ.Equals(other.MachineZ) && Brand == other.Brand && Name == other.Name && Model == other.Model;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Machine)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(ResolutionX, ResolutionY, DisplayWidth, DisplayHeight, MachineZ, (int)Brand, Name, Model);
+ }
+
+ public override string ToString()
+ {
+ return $"{Name} | Resolution={ResolutionX}x{ResolutionY}(px) Display={DisplayWidth}x{DisplayHeight}(mm) Z={MachineZ}mm";
+ }
+ #endregion
+
+ #region Methods
+ /// <summary>
+ /// Gets or sets the pixels per mm on X direction
+ /// </summary>
+ public virtual float Xppmm => DisplayWidth > 0 ? ResolutionX / DisplayWidth : 0;
+
+ /// <summary>
+ /// Gets or sets the pixels per mm on Y direction
+ /// </summary>
+ public virtual float Yppmm => DisplayHeight > 0 ? ResolutionY / DisplayHeight : 0;
+
+ /// <summary>
+ /// Gets or sets the pixels per mm
+ /// </summary>
+ public SizeF Ppmm => new(Xppmm, Yppmm);
+
+ /// <summary>
+ /// Gets the maximum (Width or Height) pixels per mm
+ /// </summary>
+ public float PpmmMax => Ppmm.Max();
+
+ /// <summary>
+ /// Gets the pixel width in millimeters
+ /// </summary>
+ public float PixelWidth => DisplayWidth > 0 && ResolutionX > 0 ? (float)Math.Round(DisplayWidth / ResolutionX, 3) : 0;
+
+ /// <summary>
+ /// Gets the pixel height in millimeters
+ /// </summary>
+ public float PixelHeight => DisplayHeight > 0 && ResolutionY > 0 ? (float)Math.Round(DisplayHeight / ResolutionY, 3) : 0;
+
+ /// <summary>
+ /// Gets the pixel size in millimeters
+ /// </summary>
+ public SizeF PixelSize => new(PixelWidth, PixelHeight);
+
+ /// <summary>
+ /// Gets the maximum pixel between width and height in millimeters
+ /// </summary>
+ public float PixelSizeMax => PixelSize.Max();
+
+ /// <summary>
+ /// Gets the pixel area in millimeters
+ /// </summary>
+ public float PixelArea => PixelSize.Area();
+
+ /// <summary>
+ /// Gets the pixel width in microns
+ /// </summary>
+ public float PixelWidthMicrons => DisplayWidth > 0 ? (float)Math.Round(DisplayWidth / ResolutionX * 1000, 3) : 0;
+
+ /// <summary>
+ /// Gets the pixel height in microns
+ /// </summary>
+ public float PixelHeightMicrons => DisplayHeight > 0 ? (float)Math.Round(DisplayHeight / ResolutionY * 1000, 3) : 0;
+
+ /// <summary>
+ /// Gets the pixel size in microns
+ /// </summary>
+ public SizeF PixelSizeMicrons => new(PixelWidthMicrons, PixelHeightMicrons);
+
+ /// <summary>
+ /// Gets the maximum pixel between width and height in microns
+ /// </summary>
+ public float PixelSizeMicronsMax => PixelSizeMicrons.Max();
+
+ /// <summary>
+ /// Gets the pixel area in millimeters
+ /// </summary>
+ public float PixelAreaMicrons => PixelSizeMicrons.Area();
+
+ public Machine Clone()
+ {
+ return (Machine)MemberwiseClone();
+ }
+ #endregion
+
+ #region Static methods
+
+ /// <summary>
+ /// Preset list of machines
+ /// </summary>
+ public static Machine[] Machines =>
+ new Machine[]{
+ // Creality
+ /*new(PrinterBrand.Creality, "Halot One", "CL-60", 1620, 2560, 81, 128, 160),
+ new(PrinterBrand.Creality, "Halot One Pro", "CL-70", 2560, 2400, 130.56f, 122.4f, 160),
+ new(PrinterBrand.Creality, "Halot One Plus", "CL-79", 4320, 2560, 172.8f, 102.4f, 160),
+ new(PrinterBrand.Creality, "Halot Sky", "CL-89", 3840, 2400, 192, 120, 200),
+ new(PrinterBrand.Creality, "Halot Sky Plus", "CL-92", 5760, 3600, 198.14f, 123.84f, 210),
+ new(PrinterBrand.Creality, "Halot Lite", "CL-89L", 3840, 2400, 192, 120, 200),
+ new(PrinterBrand.Creality, "Halot Max", "CL-133", 3840, 2160, 293.76f, 165.28f, 300),
+ new(PrinterBrand.Creality, "CT133 Pro", "CT133PRO", 3840, 2160, 293.76f, 165.24f, 300),
+ new(PrinterBrand.Creality, "CT-005 Pro", "CT-005", 3840, 2400, 192, 120, 250),*/
+
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono 4K", "Photon Mono 4K", 3840, 2400, 134.4f, 84f, 165f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono SE", "Photon Mono SE", 1620, 2560, 82.62f, 130.56f, 160f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono SQ", "Photon Mono SQ", 2400, 2560, 120f, 128f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono X 6K", "Photon Mono X 6K", 5760, 3600, 198.14f, 123.84f, 245f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono X", "Photon Mono X", 3840, 2400, 192f, 120f, 245f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Mono", "Photon Mono", 1620, 2560, 82.62f, 130.56f, 165f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon S", "Photon S", 1440, 2560, 68.04f, 120.96f, 165f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Ultra", "Photon Ultra", 1280, 720, 102.4f, 57.6f, 165f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon X", "Photon X", 2560, 1600, 192f, 120f, 245f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon Zero", "Photon Zero", 480, 854, 55.4f, 98.63f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.AnyCubic, "AnyCubic Photon", "Photon", 1440, 2560, 68.04f, 120.96f, 155f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Creality, "Creality CT-005 Pro", "CT-005", 3840, 2400, 192f, 120f, 250f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality CT-133 Pro", "CT133PRO", 3840, 2160, 293.76f, 165.24f, 300f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot Lite CL-89L", "CL-89L", 3840, 2400, 192f, 120f, 200f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot Max CL-133", "CL-133", 3840, 2160, 293.76f, 165.24f, 300f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot One CL-60", "CL-60", 1620, 2560, 81f, 128f, 160f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot One Plus CL-79", "CL-79", 4320, 2560, 172.8f, 102.4f, 160f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot One Pro CL-70", "CL-70", 2560, 2400, 130.56f, 122.4f, 160f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot Sky CL-89", "", 3840, 2400, 192f, 120f, 200f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality Halot Sky Plus CL-92", "CL-92", 5760, 3600, 198.14f, 123.84f, 210f, FlipDirection.None),
+ new(PrinterBrand.Creality, "Creality LD-002H", "LD-002H", 1620, 2560, 82.62f, 130.56f, 160f, FlipDirection.Horizontally),
+ new(PrinterBrand.Creality, "Creality LD-002R", "LD-002R", 1440, 2560, 68.04f, 120.96f, 160f, FlipDirection.Horizontally),
+ new(PrinterBrand.Creality, "Creality LD-006", "LD-006", 3840, 2400, 192f, 120f, 245f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Elegoo, "Elegoo Jupiter", "Jupiter", 5448, 3064, 277.848f, 156.264f, 300f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Mars 2 Pro", "Mars 2 Pro", 1620, 2560, 82.62f, 130.56f, 160f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Mars 2", "Mars 2", 1620, 2560, 82.62f, 130.56f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Mars 3", "Mars 3", 4098, 2560, 143.43f, 89.6f, 175f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Mars C", "Mars C", 1440, 2560, 68.04f, 120.96f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Mars", "Mars", 1440, 2560, 68.04f, 120.96f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.Elegoo, "Elegoo Saturn", "Saturn", 3840, 2400, 192f, 120f, 200f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.EPAX, "EPAX DX1 PRO", "DX1 PRO", 4098, 2560, 143.43f, 89.6f, 155f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX DX10 Pro 5K", "DX10 Pro 5K", 4920, 2880, 221.4f, 129.6f, 120f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX DX10 Pro 8K", "DX10 Pro 8K", 7680, 4320, 218.88f, 123.12f, 120f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX E10 5K", "E10 5K", 4920, 2880, 221.4f, 129.6f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX E10 8K", "E10 8K", 7680, 4320, 218.88f, 123.12f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX E10 Mono", "E10 Mono", 3840, 2400, 192f, 120f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX E6 Mono", "E6 Mono", 1620, 2560, 81f, 128f, 155f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X1 4KS", "X1 4KS", 4098, 2560, 143.43f, 89.6f, 155f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X1", "X1", 1440, 2560, 68.04f, 120.96f, 155f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X10 4K Mono", "X10 4K Mono", 3840, 2400, 192f, 120f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X10 5K", "X10 5K", 4920, 2880, 221.4f, 129.6f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X10", "X10", 1600, 2560, 135.36f, 216.57f, 250f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X133 4K Mono", "X133 4K Mono", 3840, 2160, 293.76f, 165.24f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X133 6K", "X133 6K", 5760, 3240, 288f, 162f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X156 4K Color", "X156 4K Color", 3840, 2160, 345.6f, 194.4f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.EPAX, "EPAX X1K 2K Mono", "X1K 2K Mono", 1620, 2560, 82.62f, 130.56f, 155f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.FlashForge, "FlashForge Explorer MAX", "Explorer MAX", 2560, 1600, 192f, 120f, 200f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Focus 13.3", "Focus 13.3", 3842, 2171, 292f, 165f, 400f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Focus 8.9", "Focus 8.9", 3840, 2400, 192f, 120f, 200f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Foto 13.3", "Foto 13.3", 3842, 2171, 292f, 165f, 400f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Foto 6.0", "Foto 6.0", 2600, 1560, 130f, 78f, 155f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Foto 8.9", "Foto 8.9", 3840, 2400, 192f, 120f, 200f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Foto 8.9S", "Foto 8.9S", 3840, 2400, 192f, 120f, 200f, FlipDirection.Vertically),
+ new(PrinterBrand.FlashForge, "FlashForge Hunter", "Hunter", 1920, 1080, 120f, 67.5f, 150f, FlipDirection.Vertically),
+
+ new(PrinterBrand.Kelant, "Kelant S400", "S400", 2560, 1600, 192f, 120f, 200f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Longer, "Longer Orange 10", "Orange 10", 480, 854, 55.44f, 98.64f, 140f, FlipDirection.Horizontally),
+ new(PrinterBrand.Longer, "Longer Orange 120", "Orange 120", 1440, 2560, 68.04f, 120.96f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.Longer, "Longer Orange 30", "Orange 30", 1440, 2560, 68.04f, 120.96f, 170f, FlipDirection.Horizontally),
+ new(PrinterBrand.Longer, "Longer Orange 4K", "Orange 4K", 3840, 6480, 120.96f, 68.04f, 190f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Nova3D, "Nova3D Bene4 Mono", "Bene4 Mono", 1566, 2549, 79.865f, 129.998f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Bene4", "Bene4", 1352, 2512, 70f, 130f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Bene5", "Bene5", 1566, 2549, 79.865f, 129.998f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Elfin", "Elfin", 1410, 2531, 73f, 131f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Elfin2 Mono SE", "Elfin2 Mono SE", 1470, 2549, 75f, 130f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Elfin2", "Elfin2", 1352, 2512, 70f, 130f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Elfin3 Mini", "Elfin3 Mini", 1079, 1904, 68f, 120f, 150f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Whale", "Whale", 3840, 2400, 192f, 120f, 250f, FlipDirection.Vertically),
+ new(PrinterBrand.Nova3D, "Nova3D Whale2", "Whale2", 3840, 2400, 192f, 120f, 250f, FlipDirection.Vertically),
+
+ new(PrinterBrand.Peopoly, "Peopoly Phenom L", "Phenom L", 3840, 2160, 345.6f, 194.4f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.Peopoly, "Peopoly Phenom Noir", "Phenom Noir", 3840, 2160, 293.76f, 165.24f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.Peopoly, "Peopoly Phenom XXL", "Phenom XXL", 3840, 2160, 527.04f, 296.46f, 550f, FlipDirection.Horizontally),
+ new(PrinterBrand.Peopoly, "Peopoly Phenom", "Phenom", 3840, 2160, 276.48f, 155.52f, 400f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle 16", "Shuffle 16", 3840, 2160, 337.92f, 190.08f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle 4K", "Shuffle 4K", 2160, 3840, 68.04f, 120.96f, 170f, FlipDirection.None),
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle Lite", "Shuffle Lite", 1440, 2560, 68.04f, 120.96f, 170f, FlipDirection.None),
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle XL Lite", "Shuffle XL Lite", 2560, 1600, 192f, 120f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle XL", "Shuffle XL", 2560, 1600, 192f, 120f, 200f, FlipDirection.None),
+ new(PrinterBrand.Phrozen, "Phrozen Shuffle", "Shuffle", 1440, 2560, 67.68f, 120.32f, 200f, FlipDirection.None),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic 4K", "Sonic 4K", 3840, 2160, 134.4f, 75.6f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic Mega 8K", "Sonic Mega 8K", 7680, 4320, 330.24f, 185.76f, 400f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic Mighty 4K", "Sonic Mighty 4K", 3840, 2400, 199.68f, 124.8f, 220f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic Mini 4K", "Sonic Mini 4K", 3840, 2160, 134.4f, 75.6f, 130f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic Mini 8K", "Sonic Mini 8K", 7500, 3240, 165f, 71.28f, 180f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic Mini", "Sonic Mini", 1080, 1920, 68.04f, 120.96f, 130f, FlipDirection.None),
+ new(PrinterBrand.Phrozen, "Phrozen Sonic", "Sonic", 1080, 1920, 68.04f, 120.96f, 170f, FlipDirection.Horizontally),
+ new(PrinterBrand.Phrozen, "Phrozen Transform", "Transform", 3840, 2160, 291.84f, 164.16f, 400f, FlipDirection.None),
+
+ new(PrinterBrand.QIDI, "QIDI I-Box Mono", "I-Box Mono", 3840, 2400, 192f, 120f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.QIDI, "QIDI S-Box", "S-Box", 1600, 2560, 135.36f, 216.576f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.QIDI, "QIDI Shadow5.5", "Shadow5.5", 1440, 2560, 68.04f, 120.96f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.QIDI, "QIDI Shadow6.0 Pro", "Shadow6.0 Pro", 1440, 2560, 74.52f, 132.48f, 150f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Uniformation, "Uniformation GKone", "GKone", 4920, 2880, 221.4f, 129.6f, 245f, FlipDirection.Vertically),
+
+ new(PrinterBrand.Uniz, "Uniz IBEE", "IBEE", 3840, 2400, 192f, 120f, 220f, FlipDirection.Vertically),
+
+ new(PrinterBrand.Prusa, "Prusa SL1", "SL1", 1440, 2560, 68.04f, 120.96f, 150f, FlipDirection.Horizontally),
+ new(PrinterBrand.Prusa, "Prusa SL1S SPEED", "SL1S SPEED", 1620, 2560, 128f, 81f, 150f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Voxelab, "Voxelab Ceres 8.9", "Ceres 8.9", 3840, 2400, 192f, 120f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.Voxelab, "Voxelab Polaris 5.5", "Polaris 5.5", 1440, 2560, 68.04f, 120.96f, 155f, FlipDirection.Horizontally),
+ new(PrinterBrand.Voxelab, "Voxelab Proxima 6", "Proxima 6", 1620, 2560, 82.62f, 130.56f, 155f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Wanhao, "Wanhao CGR Mini Mono", "CGR Mini Mono", 1620, 2560, 82.62f, 130.56f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.Wanhao, "Wanhao CGR Mono", "CGR Mono", 1620, 2560, 192f, 120f, 200f, FlipDirection.Horizontally),
+ new(PrinterBrand.Wanhao, "Wanhao D7", "D7", 2560, 1440, 120.96f, 68.5f, 180f, FlipDirection.Horizontally),
+ new(PrinterBrand.Wanhao, "Wanhao D8", "D8", 2560, 1600, 192f, 120f, 180f, FlipDirection.Horizontally),
+
+ new(PrinterBrand.Zortrax, "Zortrax Inkspire", "Inkspire", 1440, 2560, 74.67f, 132.88f, 175f, FlipDirection.Horizontally),
+ };
+
+ /// <summary>
+ /// Gets all machines from PrusaSlicer profiles
+ /// </summary>
+ /// <returns></returns>
+ public static IEnumerable<Machine> GetMachinesFromPrusaSlicer()
+ {
+ var psPrinterFiles = Directory.GetFiles(Path.Combine(AppContext.BaseDirectory, "Assets", "PrusaSlicer", "printer"));
+ foreach (var file in psPrinterFiles)
+ {
+ var displayMirror = FlipDirection.None;
+ var filenameNoExt = Path.GetFileNameWithoutExtension(file);
+ var split = filenameNoExt.Split(' ', 2);
+ if (!Enum.TryParse(split[0], true, out PrinterBrand brand))
+ {
+ brand = filenameNoExt.StartsWith("UVtools Prusa") ? PrinterBrand.Prusa : PrinterBrand.Generic;
+ }
+
+ using var reader = new StreamReader(file);
+ string? line;
+
+ var machine = new Machine
+ {
+ Name = filenameNoExt,
+ Model = split[1]
+ };
+
+ while ((line = reader.ReadLine()) is not null)
+ {
+ var keyValue = line.Split('=', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+ if(keyValue.Length < 2) continue;
+
+ var key = keyValue[0];
+ var value = keyValue[1];
+ if (key.StartsWith("display_pixels_x"))
+ {
+ if (!ushort.TryParse(value, out var resolutionX)) continue;
+ machine.ResolutionX = resolutionX;
+ }
+
+ if (key.StartsWith("display_pixels_y"))
+ {
+ if (!ushort.TryParse(value, out var resolutionY)) continue;
+ machine.ResolutionY = resolutionY;
+ }
+
+ if (key.StartsWith("display_width"))
+ {
+ if (!float.TryParse(value, out var displayWidth)) continue;
+ machine.DisplayWidth = displayWidth;
+ }
+
+ if (key.StartsWith("display_height"))
+ {
+ if (!float.TryParse(value, out var displayHeight)) continue;
+ machine.DisplayHeight = displayHeight;
+ }
+
+ if (key.StartsWith("max_print_height"))
+ {
+ if (!float.TryParse(value, out var machineZ)) continue;
+ machine.MachineZ = machineZ;
+ }
+
+ if (key.StartsWith("display_mirror_x"))
+ {
+ if(value.StartsWith("1")) displayMirror = displayMirror == FlipDirection.None ? FlipDirection.Horizontally : FlipDirection.Both;
+ }
+
+ if (key.StartsWith("display_mirror_y"))
+ {
+ if (value.StartsWith("1")) displayMirror = displayMirror == FlipDirection.None ? FlipDirection.Vertically : FlipDirection.Both;
+ }
+ }
+
+ if(machine.ResolutionX == 0 || machine.ResolutionY == 0) continue;
+ machine.Brand = brand;
+ machine.DisplayMirror = displayMirror;
+ yield return machine;
+ }
+ }
+
+
+ public static string GenerateMachinePresetsFromPrusaSlicer()
+ {
+ var machines = GetMachinesFromPrusaSlicer();
+ var sb = new StringBuilder();
+
+ PrinterBrand lastBrand = default;
+ foreach (var machine in machines)
+ {
+ if (lastBrand != machine.Brand)
+ {
+ if(sb.Length > 0) sb.AppendLine();
+ lastBrand = machine.Brand;
+ }
+ sb.AppendLine($"new(PrinterBrand.{machine.Brand}, \"{machine.Name}\", \"{machine.Model}\", {machine.ResolutionX}, {machine.ResolutionY}, {machine.DisplayWidth}f, {machine.DisplayHeight}f, {machine.MachineZ}f, FlipDirection.{machine.DisplayMirror}),");
+ }
+
+ return sb.ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Printer/PrinterBrand.cs b/UVtools.Core/Printer/PrinterBrand.cs
new file mode 100644
index 0000000..3bfd459
--- /dev/null
+++ b/UVtools.Core/Printer/PrinterBrand.cs
@@ -0,0 +1,31 @@
+/*
+ * 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.Printer
+{
+ public enum PrinterBrand : byte
+ {
+ Generic,
+ AnyCubic,
+ Creality,
+ Elegoo,
+ EPAX,
+ FlashForge,
+ Kelant,
+ Longer,
+ Nova3D,
+ Peopoly,
+ Phrozen,
+ Prusa,
+ QIDI,
+ Uniformation,
+ Uniz,
+ Voxelab,
+ Wanhao,
+ Zortrax,
+ }
+}
diff --git a/UVtools.Core/SystemOS/SystemAware.cs b/UVtools.Core/SystemOS/SystemAware.cs
index ea19e80..33a8d43 100644
--- a/UVtools.Core/SystemOS/SystemAware.cs
+++ b/UVtools.Core/SystemOS/SystemAware.cs
@@ -255,6 +255,11 @@ public static class SystemAware
}
}
+ public static string GetExecutableName(string executable)
+ {
+ return OperatingSystem.IsWindows() ? $"{executable}.exe" : executable;
+ }
+
public static string? GetProcessOutput(string filename, string? arguments = null)
{
using var proc = Process.Start(new ProcessStartInfo
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 6a9120b..f54b303 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>3.1.1</Version>
+ <Version>3.2.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -62,6 +62,8 @@
<PackageReference Include="AnimatedGif" Version="1.0.5" />
<PackageReference Include="BinarySerializer" Version="8.6.2.2" />
<PackageReference Include="Emgu.CV" Version="4.5.5.4823" />
+ <PackageReference Include="Emgu.CV.runtime.ubuntu.20.04-x64" Version="4.5.4.4788" />
+ <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
<PackageReference Include="KdTree" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
index 5ba08d3..bd403a9 100644
--- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs
+++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
@@ -2,7 +2,7 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ComponentRules="OneToOne"?>
<!-- SourceDir instructs IsWiX the location of the directory that contains files for this merge module -->
- <?define SourceDir="..\publish\UVtools_win-x64_v3.1.1"?>
+ <?define SourceDir="..\publish\UVtools_win-x64_v3.2.0"?>
<Module Id="UVtools" Language="1033" Version="1.0.0.0">
<Package Id="12aaa1cf-ff06-4a02-abd5-2ac01ac4f83b" Manufacturer="PTRTECH" InstallerVersion="200" Keywords="MSLA, DLP" Description="MSLA/DLP, file analysis, repair, conversion and manipulation" InstallScope="perMachine" Platform="x64" />
<Directory Id="TARGETDIR" Name="SourceDir">
@@ -903,15 +903,6 @@
<Component Id="owc1C3DE0BEF10A5791E37D4C3D97AED5E1" Guid="b1851a14-1200-d448-1acd-b229bf6ac918" Win64="yes">
<File Id="owf1C3DE0BEF10A5791E37D4C3D97AED5E1" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\AnyCubic Photon.ini" KeyPath="yes" />
</Component>
- <Component Id="owcD9B52941C3B939A8B3215DD20CF242D0" Guid="19f42433-a592-01d2-ece1-41f37945261d" Win64="yes">
- <File Id="owfD9B52941C3B939A8B3215DD20CF242D0" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality HALOT-MAX CL-133.ini" KeyPath="yes" />
- </Component>
- <Component Id="owc64BDFB521E8E34CAE3547B3D1B8F3996" Guid="71d86e2a-c6b7-884a-65ff-2260e4edd56f" Win64="yes">
- <File Id="owf64BDFB521E8E34CAE3547B3D1B8F3996" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality HALOT-ONE CL-60.ini" KeyPath="yes" />
- </Component>
- <Component Id="owc88F58B3D3A8E53CEFC3FE84F6C20FAB8" Guid="8f66ab9b-8ff1-f324-9ec5-5cbb688dd5f6" Win64="yes">
- <File Id="owf88F58B3D3A8E53CEFC3FE84F6C20FAB8" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality HALOT-SKY CL-89.ini" KeyPath="yes" />
- </Component>
<Component Id="owc0402794BACCC21B2ADA93D76665B1076" Guid="f9949f30-9613-fe85-e9f8-432d4764ed1f" Win64="yes">
<File Id="owf0402794BACCC21B2ADA93D76665B1076" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality LD-002H.ini" KeyPath="yes" />
</Component>
@@ -1143,12 +1134,48 @@
<Component Id="owc318341AC165041A4B1B4EB091AE038D4" Guid="318341AC-1650-41A4-B1B4-EB091AE038D4">
<File Id="owf318341AC165041A4B1B4EB091AE038D4" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\EPAX E10 8K.ini" KeyPath="yes" />
</Component>
- <Component Id="owcA62B68A4B6C441CFAE564C091A135E47" Guid="A62B68A4-B6C4-41CF-AE56-4C091A135E47">
- <File Id="owfA62B68A4B6C441CFAE564C091A135E47" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Epax X1 4KS.ini" KeyPath="yes" />
- </Component>
<Component Id="owc935F38E5C9A44BB897F2C3B7EF7EED98" Guid="935F38E5-C9A4-4BB8-97F2-C3B7EF7EED98">
<File Id="owf935F38E5C9A44BB897F2C3B7EF7EED98" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\EPAX X133 6K.ini" KeyPath="yes" />
</Component>
+ <Component Id="owcDF42EE7BB1F24B69B4B51D272C2AB957" Guid="DF42EE7B-B1F2-4B69-B4B5-1D272C2AB957">
+ <File Id="owfDF42EE7BB1F24B69B4B51D272C2AB957" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality CT-005 Pro.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owcA7BE67166EEA474DAA5CFAE114644D2C" Guid="A7BE6716-6EEA-474D-AA5C-FAE114644D2C">
+ <File Id="owfA7BE67166EEA474DAA5CFAE114644D2C" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality CT-133 Pro.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc61B730E3A3B74D04A8AA3CF0A20309FF" Guid="61B730E3-A3B7-4D04-A8AA-3CF0A20309FF">
+ <File Id="owf61B730E3A3B74D04A8AA3CF0A20309FF" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot Lite CL-89L.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc633003EB97D14199B1BAB2F41E13BAD9" Guid="633003EB-97D1-4199-B1BA-B2F41E13BAD9">
+ <File Id="owf633003EB97D14199B1BAB2F41E13BAD9" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot Max CL-133.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc410AA7D3FC5B4B179554EC72D8F5BAE6" Guid="410AA7D3-FC5B-4B17-9554-EC72D8F5BAE6">
+ <File Id="owf410AA7D3FC5B4B179554EC72D8F5BAE6" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot One CL-60.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owcF4F1D794E3D3499483148C0EACBEF51C" Guid="F4F1D794-E3D3-4994-8314-8C0EACBEF51C">
+ <File Id="owfF4F1D794E3D3499483148C0EACBEF51C" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot One Plus CL-79.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc3193576CB9E7494FA52919ED76022428" Guid="3193576C-B9E7-494F-A529-19ED76022428">
+ <File Id="owf3193576CB9E7494FA52919ED76022428" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot One Pro CL-70.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc8633DB6E10114CE79261C920360E27A2" Guid="8633DB6E-1011-4CE7-9261-C920360E27A2">
+ <File Id="owf8633DB6E10114CE79261C920360E27A2" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot Sky CL-89.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc94A1CD7580274320B169802BB809DB82" Guid="94A1CD75-8027-4320-B169-802BB809DB82">
+ <File Id="owf94A1CD7580274320B169802BB809DB82" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Creality Halot Sky Plus CL-92.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc99F8B737BC4E44DEB2231C8A39513A42" Guid="99F8B737-BC4E-44DE-B223-1C8A39513A42">
+ <File Id="owf99F8B737BC4E44DEB2231C8A39513A42" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Elegoo Mars 2.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owc1E7E41228CDF4169B70D6A22E69953E8" Guid="1E7E4122-8CDF-4169-B70D-6A22E69953E8">
+ <File Id="owf1E7E41228CDF4169B70D6A22E69953E8" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\EPAX X1 4KS.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owcAD7701A6FBC441058690CCC4060F62FB" Guid="AD7701A6-FBC4-4105-8690-CCC4060F62FB">
+ <File Id="owfAD7701A6FBC441058690CCC4060F62FB" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\FlashForge Foto 8.9S.ini" KeyPath="yes" />
+ </Component>
+ <Component Id="owcE58B020744224713A7CD07B20B6ECB5A" Guid="E58B0207-4422-4713-A7CD-07B20B6ECB5A">
+ <File Id="owfE58B020744224713A7CD07B20B6ECB5A" Source="$(var.SourceDir)\Assets\PrusaSlicer\printer\Uniformation GKone.ini" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd324203F33CD6B2D491618D3D363F997F" Name="sla_print">
<Component Id="owc988205CB4C2FC6EA3D41704B657C5681" Guid="5dd3f394-0e58-76db-f891-78c219b5339e">
@@ -1250,6 +1277,9 @@
<Component Id="owc8370BED3D17A58E88E193350B14A5450" Guid="cc521992-26e9-bf12-e777-68f8e2102405">
<File Id="owf8370BED3D17A58E88E193350B14A5450" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcCB98727B387246ECB61E92C565A1472C" Guid="CB98727B-3872-46EC-B61E-92C565A1472C">
+ <File Id="owfCB98727B387246ECB61E92C565A1472C" Source="$(var.SourceDir)\cs\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd17C6A2D314297F8FF3C608803909F7BE" Name="de">
<Component Id="owc6A8D7823467C066EA1EC2F740C66084D" Guid="82c152c6-97bf-f75d-44fc-294474d9a7cb">
@@ -1264,6 +1294,9 @@
<Component Id="owcF790A17350C2437C0E1E354B9D980161" Guid="627f2dc4-5b88-d3f7-3acf-7630111e30e8">
<File Id="owfF790A17350C2437C0E1E354B9D980161" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc433CD233B1E34988900522E9DFA584DE" Guid="433CD233-B1E3-4988-9005-22E9DFA584DE">
+ <File Id="owf433CD233B1E34988900522E9DFA584DE" Source="$(var.SourceDir)\de\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdF542F1E9B1CF46F5EC5BF0998941ED93" Name="es">
<Component Id="owcDD2F3A9E1BC6C55110A95C76B075BB2A" Guid="1082627f-113d-241a-abee-cb25d4b696fe">
@@ -1278,6 +1311,9 @@
<Component Id="owcB59CB618361B113CFA57D75E883608EA" Guid="ddc56db3-e6a2-c7aa-dc21-3b247964758c">
<File Id="owfB59CB618361B113CFA57D75E883608EA" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc6BF60AD9179E41168945B6C42CFF2D8B" Guid="6BF60AD9-179E-4116-8945-B6C42CFF2D8B">
+ <File Id="owf6BF60AD9179E41168945B6C42CFF2D8B" Source="$(var.SourceDir)\es\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdA426C3729D5D59516430C8F667ED8DE8" Name="fr">
<Component Id="owcFECC4FDE99CBE3816D982D1FF8E5E196" Guid="703ebe68-adaa-3f9c-606b-b42fec5159e8">
@@ -1292,6 +1328,9 @@
<Component Id="owcE8E57F27B5A0C2D7A27A164639AA95F9" Guid="caac4561-da90-4c7b-02cd-bdfca5be1694">
<File Id="owfE8E57F27B5A0C2D7A27A164639AA95F9" Source="$(var.SourceDir)\fr\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcBC3C3AAC6D3840F88E5C8D6C7B754E1E" Guid="BC3C3AAC-6D38-40F8-8E5C-8D6C7B754E1E">
+ <File Id="owfBC3C3AAC6D3840F88E5C8D6C7B754E1E" Source="$(var.SourceDir)\fr\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd74DAE01CDA8C981B3918AC92ED360AA1" Name="it">
<Component Id="owc4DD3418A4620DABCBBB6CCAA8ECA2707" Guid="421c92b6-85d7-3733-b9a5-ed10229c89a5">
@@ -1306,6 +1345,9 @@
<Component Id="owc8B74032559230C1C0C2B5082475A5CD4" Guid="39eabb54-8dd8-65e8-fe00-359ad09cae2a">
<File Id="owf8B74032559230C1C0C2B5082475A5CD4" Source="$(var.SourceDir)\it\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcC5BDCB6F102D450F8A077E8772BA5337" Guid="C5BDCB6F-102D-450F-8A07-7E8772BA5337">
+ <File Id="owfC5BDCB6F102D450F8A077E8772BA5337" Source="$(var.SourceDir)\it\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd939A7C952EF97FFE1E5F44BC8281E343" Name="ja">
<Component Id="owc51FE3ECF820BD499CDE7DBB22A69167D" Guid="3201321c-b8c7-5cbb-2ad8-f8bf5b451b3d">
@@ -1320,6 +1362,9 @@
<Component Id="owc0A9733AEBD37AD14413D6F786BB5FA8A" Guid="f57405c2-169e-0504-01db-e115d156226b">
<File Id="owf0A9733AEBD37AD14413D6F786BB5FA8A" Source="$(var.SourceDir)\ja\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc336210A1AB1A4F1D9E15297121711688" Guid="336210A1-AB1A-4F1D-9E15-297121711688">
+ <File Id="owf336210A1AB1A4F1D9E15297121711688" Source="$(var.SourceDir)\ja\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd26824DD7BA688994CEC324C96033C66B" Name="ko">
<Component Id="owc82B969E8D4D535732FCF01718B7E606D" Guid="993f9efe-f89f-7b95-8443-2341e293e7a6">
@@ -1334,6 +1379,9 @@
<Component Id="owc49136EC48B42F29310D5FAB96EB39C77" Guid="7d59fb12-e36d-3b98-1b54-8182dc102913">
<File Id="owf49136EC48B42F29310D5FAB96EB39C77" Source="$(var.SourceDir)\ko\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcF366C6A34BC246A4BCAAC960B9CE4D51" Guid="F366C6A3-4BC2-46A4-BCAA-C960B9CE4D51">
+ <File Id="owfF366C6A34BC246A4BCAAC960B9CE4D51" Source="$(var.SourceDir)\ko\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdC3B37D0EB36BEDA1B06A324A062DC94D" Name="pl">
<Component Id="owc4D2D720AD4B25046F5C3A8337C58558F" Guid="f9f595eb-39b5-e326-d983-3aca9a6bb500">
@@ -1348,6 +1396,9 @@
<Component Id="owc01C7CE26E845E06F3A50D520FB278BCF" Guid="d1ddafed-c698-3973-d2a4-4c4d00620030">
<File Id="owf01C7CE26E845E06F3A50D520FB278BCF" Source="$(var.SourceDir)\pl\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc201ED0FBC5634A63B276744A6A4568C4" Guid="201ED0FB-C563-4A63-B276-744A6A4568C4">
+ <File Id="owf201ED0FBC5634A63B276744A6A4568C4" Source="$(var.SourceDir)\pl\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdE3101CE52C8B10FCC8A2CC81C4C96F39" Name="pt-BR">
<Component Id="owc66101D80AE2357408A5C5CDB0D87BEB0" Guid="9fa0b68e-9b5f-699d-79d5-b93a4344d2eb">
@@ -1362,6 +1413,9 @@
<Component Id="owc233F59943A3FA33488E78259D09163C6" Guid="e99cb644-a268-a6af-face-e2e7834333cb">
<File Id="owf233F59943A3FA33488E78259D09163C6" Source="$(var.SourceDir)\pt-BR\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc0AE0796E0CC041FBA07B4073EC80B7B9" Guid="0AE0796E-0CC0-41FB-A07B-4073EC80B7B9">
+ <File Id="owf0AE0796E0CC041FBA07B4073EC80B7B9" Source="$(var.SourceDir)\pt-BR\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdEAE4E7B6D44EEB507A9E5B7539B1C34A" Name="ru">
<Component Id="owcB065F45686216D7224FE9E57071535B1" Guid="e96c2dc1-7b2a-91cf-dfb2-add81e62ac2b">
@@ -1376,6 +1430,9 @@
<Component Id="owc53575A00E0697BB0E07983D26C103FEA" Guid="64e7fa95-8227-2c96-6a82-e914b6ce047c">
<File Id="owf53575A00E0697BB0E07983D26C103FEA" Source="$(var.SourceDir)\ru\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owc843CF10750AE4D3482AFE6C0EF22BAB1" Guid="843CF107-50AE-4D34-82AF-E6C0EF22BAB1">
+ <File Id="owf843CF10750AE4D3482AFE6C0EF22BAB1" Source="$(var.SourceDir)\ru\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdFCC3FD9F99A4D5BEDEAC61F3322D2D93" Name="tr">
<Component Id="owcEC06D7EB1988F1B550C8B3569B0261D3" Guid="07379a43-cb0f-ea5f-0cfe-d71fddfe14e6">
@@ -1390,6 +1447,9 @@
<Component Id="owc91567B2B4E8154089395D1A78358BE89" Guid="1c327c0f-a510-b334-7130-5c9e6609dc7b">
<File Id="owf91567B2B4E8154089395D1A78358BE89" Source="$(var.SourceDir)\tr\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcA539F189A0C84A9F8E802FEE9FDEBEDD" Guid="A539F189-A0C8-4A9F-8E80-2FEE9FDEBEDD">
+ <File Id="owfA539F189A0C84A9F8E802FEE9FDEBEDD" Source="$(var.SourceDir)\tr\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owd7142663FADDFFB05CCE01DC370DE4995" Name="zh-Hans">
<Component Id="owc28B8853BEB28067D4AB79B73216A3AC8" Guid="f6b6af15-bb3a-3eda-972d-47cb28af6c03">
@@ -1404,6 +1464,9 @@
<Component Id="owc5371E4C6A9B06D411E8EAC3E5A48E7EA" Guid="a7649dfb-52b9-08d3-6f03-f7aed4d2cce3">
<File Id="owf5371E4C6A9B06D411E8EAC3E5A48E7EA" Source="$(var.SourceDir)\zh-Hans\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcC563AB6969004ECC97A8859CCEE8A25A" Guid="C563AB69-6900-4ECC-97A8-859CCEE8A25A">
+ <File Id="owfC563AB6969004ECC97A8859CCEE8A25A" Source="$(var.SourceDir)\zh-Hans\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="owdA86DB5E08AB73906A10F69BC4AA81DE2" Name="zh-Hant">
<Component Id="owc18EA70FFACC7303C11A678723F8E1919" Guid="71c1ee6c-af04-89be-a2f7-20205b5f371e">
@@ -1418,6 +1481,9 @@
<Component Id="owc505D5854210A555AEF782935C164E813" Guid="778f403b-5deb-df93-7dc7-44b5fa099c25">
<File Id="owf505D5854210A555AEF782935C164E813" Source="$(var.SourceDir)\zh-Hant\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
+ <Component Id="owcC2225AC993F14DADA08B59442159798E" Guid="C2225AC9-93F1-4DAD-A08B-59442159798E">
+ <File Id="owfC2225AC993F14DADA08B59442159798E" Source="$(var.SourceDir)\zh-Hant\System.CommandLine.resources.dll" KeyPath="yes" />
+ </Component>
</Directory>
<Component Id="owc2B1C136C44C740F48CDFE91A80F48B4B" Guid="2B1C136C-44C7-40F4-8CDF-E91A80F48B4B">
<File Id="owf2B1C136C44C740F48CDFE91A80F48B4B" Source="$(var.SourceDir)\opencv_videoio_ffmpeg455_64.dll" KeyPath="yes" />
@@ -1464,6 +1530,24 @@
<Component Id="owc2DE24885E97D4FD3AB633AA53F125FED" Guid="2DE24885-E97D-4FD3-AB63-3AA53F125FED">
<File Id="owf2DE24885E97D4FD3AB633AA53F125FED" Source="$(var.SourceDir)\UVtools.sh" KeyPath="yes" />
</Component>
+ <Component Id="owcEF2C9ED70B264423B1145D94F760DF42" Guid="EF2C9ED7-0B26-4423-B114-5D94F760DF42">
+ <File Id="owfEF2C9ED70B264423B1145D94F760DF42" Source="$(var.SourceDir)\System.CommandLine.dll" KeyPath="yes" />
+ </Component>
+ <Component Id="owcED313361637349C1B3515192A64FDE80" Guid="ED313361-6373-49C1-B351-5192A64FDE80">
+ <File Id="owfED313361637349C1B3515192A64FDE80" Source="$(var.SourceDir)\UVtoolsCmd.deps.json" KeyPath="yes" />
+ </Component>
+ <Component Id="owcE8F653F9E34A4D0FA5A5A0D3B7C353F3" Guid="E8F653F9-E34A-4D0F-A5A5-A0D3B7C353F3">
+ <File Id="owfE8F653F9E34A4D0FA5A5A0D3B7C353F3" Source="$(var.SourceDir)\UVtoolsCmd.dll" KeyPath="yes" />
+ </Component>
+ <Component Id="owc524AFA435EB94D5B84D9A52E96983FF5" Guid="524AFA43-5EB9-4D5B-84D9-A52E96983FF5">
+ <File Id="owf524AFA435EB94D5B84D9A52E96983FF5" Source="$(var.SourceDir)\UVtoolsCmd.exe" KeyPath="yes" />
+ </Component>
+ <Component Id="owc7739FB911743477F89DF57A0A2503357" Guid="7739FB91-1743-477F-89DF-57A0A2503357">
+ <File Id="owf7739FB911743477F89DF57A0A2503357" Source="$(var.SourceDir)\UVtoolsCmd.pdb" KeyPath="yes" />
+ </Component>
+ <Component Id="owcD2245B900E5C448485AD96FE57629D9D" Guid="D2245B90-0E5C-4484-85AD-96FE57629D9D">
+ <File Id="owfD2245B900E5C448485AD96FE57629D9D" Source="$(var.SourceDir)\UVtoolsCmd.runtimeconfig.json" KeyPath="yes" />
+ </Component>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="scd220707349D4C8FA275285514283F3E2A" Name="UVtools" />
diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs
index 45e55c6..7003486 100644
--- a/UVtools.WPF/App.axaml.cs
+++ b/UVtools.WPF/App.axaml.cs
@@ -9,7 +9,6 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
-using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -182,7 +181,7 @@ public class App : Application
LayerHeight = 0.05f,
Resolution = new (1440, 2560),
Display = new (68.04f, 120.96f),
- DisplayMirror = Enumerations.FlipDirection.Horizontally,
+ DisplayMirror = FlipDirection.Horizontally,
MachineZ = 155,
BottomLayerCount = 3,
MachineName = "Epax X1"
diff --git a/UVtools.WPF/ConsoleArguments.cs b/UVtools.WPF/ConsoleArguments.cs
index d8e99cc..788b104 100644
--- a/UVtools.WPF/ConsoleArguments.cs
+++ b/UVtools.WPF/ConsoleArguments.cs
@@ -12,6 +12,7 @@ using System.Linq;
using UVtools.Core.FileFormats;
using UVtools.Core.MeshFormats;
using UVtools.Core.Operations;
+using UVtools.Core.SystemOS;
namespace UVtools.WPF;
@@ -26,6 +27,13 @@ public static class ConsoleArguments
{
if(args is null || args.Length == 0) return false;
+ if (args[0] is "--cmd" && args.Length > 1)
+ {
+ var newArgs = string.Join(' ', args[1..]);
+ SystemAware.StartProcess(Path.Combine(App.ApplicationPath, SystemAware.GetExecutableName("UVtoolsCmd")), newArgs);
+ return true;
+ }
+
// Convert to other file
if (args[0] is "-c" or "--convert")
{
diff --git a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml
index 5cc041e..be89a95 100644
--- a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml
@@ -2,77 +2,103 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="300"
x:Class="UVtools.WPF.Controls.Tools.ToolChangeResolutionControl">
<StackPanel Orientation="Vertical" Spacing="10">
- <TextBlock Text="{Binding Operation.SlicerFile.Resolution, StringFormat=Current resolution (X/Y): {0}}"/>
- <TextBlock Text="{Binding Operation.SlicerFile.PixelSizeMicrons, StringFormat=Current pixel pitch (X/Y): {0}µm}"/>
+ <TextBlock Text="{Binding SlicerFile.Resolution, StringFormat=Current resolution (X/Y): {0}}"/>
+ <TextBlock Text="{Binding SlicerFile.PixelSizeMicrons, StringFormat=Current pixel pitch (X/Y): {0}µm}"/>
<TextBlock Text="{Binding SlicerFile.BoundingRectangle.Size, StringFormat=Object volume (X/Y): {0}}"/>
- <TextBlock FontWeight="Bold">
- <TextBlock.Text>
- <MultiBinding StringFormat="Resulting pixel ratio: {{X={0}x, Y={1}x}}">
- <Binding Path="Operation.NewRatioX"/>
- <Binding Path="Operation.NewRatioY"/>
- </MultiBinding>
- </TextBlock.Text>
- </TextBlock>
-
- <Grid RowDefinitions="Auto,10,Auto"
- ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,10,Auto">
-
- <TextBlock Grid.Row="0" Grid.Column="0"
- VerticalAlignment="Center" Text="New X/Y:"/>
-
- <NumericUpDown Grid.Row="0" Grid.Column="2"
- MinWidth="120"
+ <TextBlock FontWeight="Bold" Text="{Binding Operation.NewPixelSizeMicrons, StringFormat=New pixel pitch (X/Y): {0}µm}"/>
+
+ <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,200,5,Auto,5,200,10,Auto">
+
+ <TextBlock Grid.Row="0" Grid.Column="2"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center"
+ FontWeight="Bold"
+ Text="X / Width"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center"
+ FontWeight="Bold"
+ Text="Y / Height"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ VerticalAlignment="Center" Text="New resolution:"/>
+
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ Classes="ValueLabel ValueLabel_px"
Minimum="1"
Maximum="50000"
- Width="150"
Value="{Binding Operation.NewResolutionX}"/>
- <TextBlock Grid.Row="0" Grid.Column="4" VerticalAlignment="Center" Text="x"/>
+ <TextBlock Grid.Row="2" Grid.Column="4" VerticalAlignment="Center" Text="x"/>
- <NumericUpDown Grid.Row="0" Grid.Column="6"
- MinWidth="120"
+ <NumericUpDown Grid.Row="2" Grid.Column="6"
+ Classes="ValueLabel ValueLabel_px"
Minimum="1"
Maximum="50000"
- Width="150"
Value="{Binding Operation.NewResolutionY}"/>
- <ComboBox Grid.Row="0" Grid.Column="8"
+ <ComboBox Grid.Row="2" Grid.Column="8"
MinWidth="250"
SelectedItem="{Binding SelectedPresetItem}"
Items="{Binding Operation.Presets}"
PlaceholderText="Resolution presets"/>
- <TextBlock Grid.Row="2" Grid.Column="0"
+ <TextBlock Grid.Row="4" Grid.Column="0"
+ VerticalAlignment="Center" Text="New display:"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="2"
+ Classes="ValueLabel ValueLabel_mm"
+ Minimum="0"
+ Maximum="50000"
+ FormatString="F3"
+ Value="{Binding Operation.NewDisplayWidth}"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="4" VerticalAlignment="Center" Text="x"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="6"
+ Classes="ValueLabel ValueLabel_mm"
+ Minimum="0"
+ Maximum="50000"
+ FormatString="F3"
+ Value="{Binding Operation.NewDisplayHeight}"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="0"
VerticalAlignment="Center" Text="Fix pixel ratio:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
+ <NumericUpDown Grid.Row="6" Grid.Column="2"
Classes="ValueLabel ValueLabel_times ReadOnly"
- FormatString="F2"
- MinWidth="120"
- Width="150"
+ FormatString="F3"
IsEnabled="{Binding Operation.FixRatio}"
Value="{Binding Operation.NewFixedRatioX}"/>
- <TextBlock Grid.Row="2" Grid.Column="4" VerticalAlignment="Center" Text="x"/>
+ <TextBlock Grid.Row="6" Grid.Column="4" VerticalAlignment="Center" Text="x"/>
- <NumericUpDown Grid.Row="2" Grid.Column="6"
+ <NumericUpDown Grid.Row="6" Grid.Column="6"
Classes="ValueLabel ValueLabel_times ReadOnly"
- FormatString="F2"
- MinWidth="120"
- Width="150"
+ FormatString="F3"
IsEnabled="{Binding Operation.FixRatio}"
Value="{Binding Operation.NewFixedRatioY}"/>
- <CheckBox Grid.Row="2" Grid.Column="8"
+ <CheckBox Grid.Row="6" Grid.Column="8"
Content="Resize layers with proposed ratio"
IsChecked="{Binding Operation.FixRatio}"
ToolTip.Tip="Fix the pixel ratio by resize the layers images with the proposed ratio to match the new resolution.
&#x0a;Only use this option when both source and target display have the same dimensions / build volume.
Otherwise, the new display size must be taken into account and you need to manually resize after this."/>
+ <ComboBox Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="7"
+ HorizontalAlignment="Stretch"
+ SelectedItem="{Binding SelectedMachinePresetItem}"
+ Items="{Binding MachinePresets}"
+ PlaceholderText="Machine presets"/>
+
</Grid>
+
+
</StackPanel>
diff --git a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
index 43e5044..92a7814 100644
--- a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
@@ -1,15 +1,17 @@
-using System.Diagnostics;
-using System.Timers;
+using System.Collections.Generic;
using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
using UVtools.Core.Operations;
+using UVtools.Core.Printer;
namespace UVtools.WPF.Controls.Tools;
public class ToolChangeResolutionControl : ToolControl
{
- private OperationChangeResolution.Resolution _selectedPresetItem;
- public OperationChangeResolution Operation => BaseOperation as OperationChangeResolution;
+ public static IEnumerable<Machine> MachinePresets => Machine.Machines;
+ public OperationChangeResolution Operation => BaseOperation as OperationChangeResolution;
+ private OperationChangeResolution.Resolution _selectedPresetItem;
public OperationChangeResolution.Resolution SelectedPresetItem
{
get => _selectedPresetItem;
@@ -19,15 +21,24 @@ public class ToolChangeResolutionControl : ToolControl
if (_selectedPresetItem is null || _selectedPresetItem.IsEmpty) return;
Operation.NewResolutionX = _selectedPresetItem.ResolutionX;
Operation.NewResolutionY = _selectedPresetItem.ResolutionY;
-
- //SelectedPresetItem = null;
- Timer timer = new(1);
- timer.Elapsed += (sender, args) =>
- {
- SelectedPresetItem = null;
- timer.Dispose();
- };
- timer.Start();
+ Dispatcher.UIThread.Post(() => SelectedPresetItem = null, DispatcherPriority.Loaded);
+ }
+ }
+
+ private Machine _selectedMachinePresetItem;
+ public Machine SelectedMachinePresetItem
+ {
+ get => _selectedMachinePresetItem;
+ set
+ {
+ RaiseAndSetIfChanged(ref _selectedMachinePresetItem, value);
+ if (_selectedMachinePresetItem is null) return;
+ Operation.NewResolutionX = _selectedMachinePresetItem.ResolutionX;
+ Operation.NewResolutionY = _selectedMachinePresetItem.ResolutionY;
+ Operation.NewDisplayWidth = (decimal)_selectedMachinePresetItem.DisplayWidth;
+ Operation.NewDisplayHeight = (decimal)_selectedMachinePresetItem.DisplayHeight;
+ Operation.FixRatio = true;
+ Dispatcher.UIThread.Post(() => SelectedMachinePresetItem = null, DispatcherPriority.Loaded);
}
}
diff --git a/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml
index 21f319c..71c97ed 100644
--- a/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml
@@ -2,32 +2,29 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300"
+ mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="300"
x:Class="UVtools.WPF.Controls.Tools.ToolInfillControl">
<Grid
- RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
- ColumnDefinitions="Auto,10,200,5,Auto"
+ RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,300,5,Auto"
>
<!--Pattern-->
<TextBlock
VerticalAlignment="Center"
- Text="Pattern:"
- />
+ Text="Pattern:"/>
<ComboBox Grid.Row="0" Grid.Column="2"
- Items="{Binding Operation.InfillAlgorithmTypes}"
- SelectedItem="{Binding Operation.InfillType}"
- HorizontalAlignment="Stretch"
- />
+ Items="{Binding Operation.InfillType, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
+ SelectedItem="{Binding Operation.InfillType, Converter={StaticResource FromValueDescriptionToEnumConverter}}"
+ HorizontalAlignment="Stretch"/>
- <!--Wall thickness-->
+ <!--Wall thickness-->
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
- Text="Wall thickness:"
- />
+ Text="Wall thickness:"/>
<NumericUpDown Grid.Row="2" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
@@ -74,5 +71,9 @@
Maximum="65535"
Increment="1"
Value="{Binding Operation.InfillSpacing}"/>
+
+ <CheckBox Grid.Row="10" Grid.Column="2"
+ IsChecked="{Binding Operation.ReinforceInfill}"
+ Content="Reinforce infill if possible"/>
</Grid>
</UserControl>
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 46524a6..c5a16bb 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -1401,6 +1401,18 @@ public partial class MainWindow : WindowEx
IsGUIEnabled = false;
ShowProgressWindow($"Opening: {fileNameOnly}");
+ /*var success = false;
+ try
+ {
+ await SlicerFile.DecodeAsync(fileName, fileDecodeType, Progress);
+ success = true;
+ }
+ catch (OperationCanceledException) { }
+ catch (Exception exception)
+ {
+ await this.MessageBoxError(exception.ToString(), "Error opening the file");
+ }*/
+
var task = await Task.Factory.StartNew( () =>
{
try
@@ -1408,10 +1420,8 @@ public partial class MainWindow : WindowEx
SlicerFile.Decode(fileName, fileDecodeType, Progress);
return true;
}
- catch (OperationCanceledException)
- {
- }
- catch (Exception exception)
+ catch (OperationCanceledException) {}
+ catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(exception.ToString(), "Error opening the file"));
@@ -1626,15 +1636,15 @@ public partial class MainWindow : WindowEx
if (Settings.LayerPreview.AutoFlipLayerIfMirrored)
{
- if (SlicerFile.DisplayMirror == Enumerations.FlipDirection.None)
+ if (SlicerFile.DisplayMirror == FlipDirection.None)
{
_showLayerImageFlipped = false;
}
else
{
_showLayerImageFlipped = true;
- _showLayerImageFlippedHorizontally = SlicerFile.DisplayMirror is Enumerations.FlipDirection.Horizontally or Enumerations.FlipDirection.Both;
- _showLayerImageFlippedVertically = SlicerFile.DisplayMirror is Enumerations.FlipDirection.Vertically or Enumerations.FlipDirection.Both;
+ _showLayerImageFlippedHorizontally = SlicerFile.DisplayMirror is FlipDirection.Horizontally or FlipDirection.Both;
+ _showLayerImageFlippedVertically = SlicerFile.DisplayMirror is FlipDirection.Vertically or FlipDirection.Both;
}
}
}
@@ -1910,44 +1920,25 @@ public partial class MainWindow : WindowEx
if(result != ButtonResult.Yes) return false;
}
-
- filepath = SlicerFile.FileFullPath;
}
- var oldFile = SlicerFile.FileFullPath;
- var tempFile = filepath + FileFormat.TemporaryFileAppend;
-
IsGUIEnabled = false;
ShowProgressWindow($"Saving {Path.GetFileName(filepath)}");
-
+
+ var oldFile = SlicerFile.FileFullPath;
+
var task = await Task.Factory.StartNew( () =>
{
try
{
- SlicerFile.SaveAs(tempFile, Progress);
- if (File.Exists(filepath))
- {
- File.Delete(filepath);
- }
- File.Move(tempFile, filepath);
- SlicerFile.FileFullPath = filepath;
+ SlicerFile.SaveAs(filepath, Progress);
return true;
}
catch (OperationCanceledException)
{
- SlicerFile.FileFullPath = oldFile;
- if (File.Exists(tempFile))
- {
- File.Delete(tempFile);
- }
}
catch (Exception ex)
{
- SlicerFile.FileFullPath = oldFile;
- if (File.Exists(tempFile))
- {
- File.Delete(tempFile);
- }
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(ex.ToString(), "Error while saving the file"));
}
diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs
index 92ae882..27672a8 100644
--- a/UVtools.WPF/Program.cs
+++ b/UVtools.WPF/Program.cs
@@ -1,7 +1,6 @@
using System;
using System.Diagnostics;
using System.Globalization;
-using System.IO;
using System.Runtime.ExceptionServices;
using Avalonia;
using Projektanker.Icons.Avalonia;
@@ -39,6 +38,39 @@ public static class Program
return;
}
+ //var mat = EmguExtensions.InitMat(new System.Drawing.Size(2000, 1080));
+ /*const byte z = 1;
+ int pixel = 1000;
+
+ for (int y = 0; y < mat.Height; y+=200)
+ for (int x = 0; x < mat.Width; x+=1)
+ {
+ float x1 = x / (float)mat.Width;
+ float y1 = y / (float)mat.Height;
+
+ //var result = Math.Sin(x1) * Math.Cos(y1) + Math.Sin(y1) * Math.Cos(1) + Math.Sin(1) * Math.Cos(x1);
+ //mat.SetByte((int) result* mat.Width, 255);
+
+ //CvInvoke.Circle(mat, new Point(x, (int)pixelY + y), 1, EmguExtensions.WhiteColor, -1, LineType.AntiAlias);
+ }*/
+
+
+ /*var sineHeight = 100;
+ var sineWidth = 100;
+ byte radius = 10;
+
+ for (int y1 = 0; y1 < mat.Height; y1 += sineHeight)
+ for (int x = 0; x < mat.Width; x++)
+ {
+ int y2 = (int)(Math.Sin((double)x / sineWidth) * sineHeight / 2.0 + sineHeight / 2.0 + radius);
+
+ CvInvoke.Circle(mat, new Point(x, y1+y2), radius, EmguExtensions.WhiteColor, -1, LineType.AntiAlias);
+ }
+
+ CvInvoke.Imshow("gyroid", mat);
+ CvInvoke.WaitKey();
+ return;*/
+
/*Slicer slicer = new(Size.Empty, SizeF.Empty, "D:\\Cube100x100x100.stl");
var slices = slicer.SliceModel(0.05f);
@@ -51,6 +83,10 @@ public static class Program
mat.Save(@$"D:\SLICE\{slice.Key}.png");
}*/
+ // PrusaSlicer to Machine.cs
+ //var machines = Machine.GetMachinesFromPrusaSlicer();
+ //var machinesText = Machine.GenerateMachinePresetsFromPrusaSlicer();
+
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
//AppDomain.CurrentDomain.FirstChanceException += CurrentDomainOnFirstChanceException;
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index d240df3..40f70d1 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>3.1.1</Version>
+ <Version>3.2.0</Version>
<Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
@@ -43,8 +43,6 @@
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.13" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.13" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.13" />
- <PackageReference Include="Emgu.CV.runtime.ubuntu.20.04-x64" Version="4.5.4.4788" />
- <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
<PackageReference Include="MessageBox.Avalonia" Version="2.0.0" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="4.2.1" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="4.2.1" />
diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs
index d764ed9..73f3d37 100644
--- a/UVtools.WPF/UserSettings.cs
+++ b/UVtools.WPF/UserSettings.cs
@@ -1789,7 +1789,7 @@ public sealed class UserSettings : BindableBase
{
var application = new MappedProcess(executable, "Open archive: WinRAR")
{
- CompatibleExtensions = "zip;sl1;sl1s;cws;zcode;zcodex;vdt;uvj"
+ CompatibleExtensions = "zip;sl1;sl1s;cws;zcode;zcodex;jxs;vdt;uvj"
};
_instance.General.SendToProcess.Add(application);
}
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml b/UVtools.WPF/Windows/ToolWindow.axaml
index 504f6c4..3ad837b 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml
+++ b/UVtools.WPF/Windows/ToolWindow.axaml
@@ -370,7 +370,7 @@
i:MenuItem.Icon="fas fa-file-import"/>
- <MenuItem IsVisible="{Binding CanHaveProfiles}"
+ <MenuItem
Command="{Binding ExportSettings}"
Header="Export settings"
i:MenuItem.Icon="fas fa-file-export"/>
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
index 4dd0356..a7772fa 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml.cs
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -123,7 +123,7 @@ public class ToolWindow : WindowEx
if (ToolControl?.BaseOperation is not null)
{
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.None;
ToolControl.BaseOperation.LayerIndexStart = value;
}
@@ -151,7 +151,7 @@ public class ToolWindow : WindowEx
if (ToolControl?.BaseOperation is not null)
{
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.None;
ToolControl.BaseOperation.LayerIndexEnd = value;
}
@@ -189,14 +189,14 @@ public class ToolWindow : WindowEx
LayerIndexStart = 0;
LayerIndexEnd = MaximumLayerIndex;
if(ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.All;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.All;
}
public void SelectCurrentLayer()
{
LayerIndexStart = LayerIndexEnd = App.MainWindow.ActualLayer;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Current;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.Current;
}
public void SelectFirstToCurrentLayer()
@@ -204,7 +204,7 @@ public class ToolWindow : WindowEx
LayerIndexEnd = App.MainWindow.ActualLayer;
LayerIndexStart = 0;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.None;
}
public void SelectCurrentToLastLayer()
@@ -212,7 +212,7 @@ public class ToolWindow : WindowEx
LayerIndexStart = App.MainWindow.ActualLayer;
LayerIndexEnd = SlicerFile.LastLayerIndex;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.None;
}
public void SelectBottomLayers()
@@ -220,7 +220,7 @@ public class ToolWindow : WindowEx
LayerIndexStart = 0;
LayerIndexEnd = Math.Max(1, SlicerFile.FirstNormalLayer?.Index ?? 1) - 1u;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Bottom;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.Bottom;
}
public void SelectNormalLayers()
@@ -228,45 +228,45 @@ public class ToolWindow : WindowEx
LayerIndexStart = SlicerFile.FirstNormalLayer?.Index ?? 0;
LayerIndexEnd = MaximumLayerIndex;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Normal;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.Normal;
}
public void SelectFirstLayer()
{
LayerIndexStart = LayerIndexEnd = 0;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.First;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.First;
}
public void SelectLastLayer()
{
LayerIndexStart = LayerIndexEnd = MaximumLayerIndex;
if (ToolControl is not null)
- ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Last;
+ ToolControl.BaseOperation.LayerRangeSelection = LayerRangeSelection.Last;
}
- public void SelectLayers(Enumerations.LayerRangeSelection range)
+ public void SelectLayers(LayerRangeSelection range)
{
switch (range)
{
- case Enumerations.LayerRangeSelection.None:
+ case LayerRangeSelection.None:
break;
- case Enumerations.LayerRangeSelection.All:
+ case LayerRangeSelection.All:
SelectAllLayers();
break;
- case Enumerations.LayerRangeSelection.Current:
+ case LayerRangeSelection.Current:
SelectCurrentLayer();
break;
- case Enumerations.LayerRangeSelection.Bottom:
+ case LayerRangeSelection.Bottom:
SelectBottomLayers();
break;
- case Enumerations.LayerRangeSelection.Normal:
+ case LayerRangeSelection.Normal:
SelectNormalLayers();
break;
- case Enumerations.LayerRangeSelection.First:
+ case LayerRangeSelection.First:
SelectFirstLayer();
break;
- case Enumerations.LayerRangeSelection.Last:
+ case LayerRangeSelection.Last:
SelectLastLayer();
break;
default:
@@ -387,7 +387,7 @@ public class ToolWindow : WindowEx
ToolControl.BaseOperation = operation;
switch (operation.LayerRangeSelection)
{
- case Enumerations.LayerRangeSelection.None:
+ case LayerRangeSelection.None:
LayerIndexStart = operation.LayerIndexStart;
LayerIndexEnd = operation.LayerIndexEnd;
break;
@@ -598,7 +598,7 @@ public class ToolWindow : WindowEx
_layerIndexEndEnabled = layerEndIndexEnabled;
}
- public ToolWindow(ToolControl toolControl) : this(toolControl.BaseOperation.Description, toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None, toolControl.BaseOperation.LayerIndexEndEnabled)
+ public ToolWindow(ToolControl toolControl) : this(toolControl.BaseOperation.Description, toolControl.BaseOperation.StartLayerRangeSelection != LayerRangeSelection.None, toolControl.BaseOperation.LayerIndexEndEnabled)
{
ToolControl = toolControl;
toolControl.ParentWindow = this;
@@ -607,7 +607,7 @@ public class ToolWindow : WindowEx
ToolControl.BaseOperation.MaskPoints = Masks;
Title = toolControl.BaseOperation.Title;
- //LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None;
+ //LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != LayerRangeSelection.None;
//IsROIVisible = toolControl.BaseOperation.CanROI;
_contentControl = toolControl;
_buttonOkText = toolControl.BaseOperation.ButtonOkText;
@@ -639,7 +639,7 @@ public class ToolWindow : WindowEx
App.MainWindow.AddMaskPoints(toolControl.BaseOperation.MaskPoints);
}
- if (toolControl.BaseOperation.LayerRangeSelection == Enumerations.LayerRangeSelection.None)
+ if (toolControl.BaseOperation.LayerRangeSelection == LayerRangeSelection.None)
{
LayerIndexStart = toolControl.BaseOperation.LayerIndexStart;
LayerIndexEnd = toolControl.BaseOperation.LayerIndexEnd;
@@ -884,7 +884,7 @@ public class ToolWindow : WindowEx
ToolControl.BaseOperation = operation;
switch (operation.LayerRangeSelection)
{
- case Enumerations.LayerRangeSelection.None:
+ case LayerRangeSelection.None:
LayerIndexStart = operation.LayerIndexStart;
LayerIndexEnd = operation.LayerIndexEnd;
break;
diff --git a/UVtools.sln b/UVtools.sln
index 329a646..9253b9e 100644
--- a/UVtools.sln
+++ b/UVtools.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29926.136
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "UVtools.InstallerMM", "UVtools.InstallerMM\UVtools.InstallerMM.wixproj", "{E53BAA5D-29A8-4287-B3AA-1AFF5A4BDC6C}"
ProjectSection(ProjectDependencies) = postProject
@@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UVtools.ScriptSample", "UVt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UVtools.AvaloniaControls", "UVtools.AvaloniaControls\UVtools.AvaloniaControls.csproj", "{0858E09F-023D-4F9B-A0E9-802C26EF9C0A}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UVtools.Cmd", "UVtools.Cmd\UVtools.Cmd.csproj", "{D0733F51-0CB1-483B-8F93-36B815FBFFF3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -99,6 +101,18 @@ Global
{0858E09F-023D-4F9B-A0E9-802C26EF9C0A}.Release|x64.Build.0 = Release|Any CPU
{0858E09F-023D-4F9B-A0E9-802C26EF9C0A}.Release|x86.ActiveCfg = Release|Any CPU
{0858E09F-023D-4F9B-A0E9-802C26EF9C0A}.Release|x86.Build.0 = Release|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|x64.ActiveCfg = Debug|x64
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|x64.Build.0 = Debug|x64
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Debug|x86.Build.0 = Debug|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|x64.ActiveCfg = Release|x64
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|x64.Build.0 = Release|x64
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|x86.ActiveCfg = Release|Any CPU
+ {D0733F51-0CB1-483B-8F93-36B815FBFFF3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE