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>2021-08-17 22:17:08 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-08-17 22:17:08 +0300
commit95020ce2f103b781d65318059adc6768e16e4a6f (patch)
tree695a4f1cfeae946317ab8074d87b3de050362630
parent44de1f3bd8ce0910765f1f51807f3ff0bd2dfbd9 (diff)
v2.19.0v2.19.0
- **File formats:** - Add and remove some image types that can be open - (Add) `CanProcess` method to know if a file can be read under a format and to allow diferent formats with same extension - (Fix) `LiftHeightTotal` and `RetractHeight` was rounding to no decimals and returning wrong values - (Improvement) Round all float setters on `Layer` class - (Improvement) Decode/encode RAM usage and performance by processing in batch groups - **Pixel Dimming:** (#262) - (Add) Option "Lightening pixels" to add brightness/lightening instead of dimming/subtract pixels - (Fix) "Dim walls only" would reset body brightness by increase pixel brightness two times it value - **Pixel Arithmetic:** - (Change) Transpose "Pixel Dimming" to "Pixel Arithmetic" - (Improvement) New options and manipulations - **(Fix) Exposure time finder:** - Generate top staircase based on selected measure (px or mm) - Zebra bars when used in mm measures, it was using X density instead Y to calculate the thickness - Move 'Unit of measure' to 'Object configuration' - Custom text with wrong Y position when using out of portion resolutions/LCDs - **CTBv4:** - (Fix) More Unknown fields discovered and implemented - (Fix) Reserved table is 384 bytes instead of 420 - (Fix) When full encoding it was forcing to change to version 3. This also affected convertions. (#263) - (Fix) `BottomRetractHeight2` was being set to `BottomRetractSpeed2` - (Fix) `RetractHeight2` was being set to `RetracSpeed2` - (Fix) The PrintParametersV4 table address - (Fix) Generates invalid files to open with Chitubox and printers (#263) - (Fix) Better progress report - **(Add) PrusaSlicer printer notes variables:** - BottomLiftHeight2 - BottomLiftSpeed2 - LiftHeight2 - LiftSpeed2 - BottomRetractSpeed - BottomRetractSpeed2 - BottomRetractHeight2 - BottomRetractSpeed2 - RetractHeight2 - RetractSpeed2 - **UI:** - (Add) File - Open current file folder (Ctrl+Shift+L): Locate and open the folder that contain the current loaded file - (Improvement) Hide some virtual extensions from file open dialog filters - (Improvement) UI: Refresh active thumbnail when changed - (Change) Icon for File - Open and Open in a new file - (Change) Rename File - Extract to: Extract file contents - (Upgrade) AvaloniaUI from 0.10.6 to 0.10.7 - (Fix) PW0, PWM, PWMX, PWMO, PWMS: Unable to decode some files with AntiAliasing (#143)
-rw-r--r--CHANGELOG.md48
-rw-r--r--Scripts/010 Editor/PhotonWorkshop.bt116
-rw-r--r--Scripts/010 Editor/ctb.bt18
-rw-r--r--UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj2
-rw-r--r--UVtools.Core/Extensions/FileStreamExtensions.cs19
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs3
-rw-r--r--UVtools.Core/FileFormats/CXDLPFile.cs164
-rw-r--r--UVtools.Core/FileFormats/CXDLPv1File.cs155
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs367
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs27
-rw-r--r--UVtools.Core/FileFormats/FDGFile.cs341
-rw-r--r--UVtools.Core/FileFormats/FileExtension.cs18
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs383
-rw-r--r--UVtools.Core/FileFormats/GR1File.cs119
-rw-r--r--UVtools.Core/FileFormats/ImageFile.cs6
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs135
-rw-r--r--UVtools.Core/FileFormats/MDLPFile.cs141
-rw-r--r--UVtools.Core/FileFormats/OSLAFile.cs178
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs329
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs220
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs334
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs23
-rw-r--r--UVtools.Core/FileFormats/UVJFile.cs35
-rw-r--r--UVtools.Core/FileFormats/VDAFile.cs27
-rw-r--r--UVtools.Core/FileFormats/VDTFile.cs61
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs6
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs7
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs1
-rw-r--r--UVtools.Core/Helpers.cs6
-rw-r--r--UVtools.Core/Layer/Layer.cs31
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs45
-rw-r--r--UVtools.Core/Operations/OperationPixelArithmetic.cs895
-rw-r--r--UVtools.Core/Operations/OperationPixelDimming.cs41
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.WPF/App.axaml.cs19
-rw-r--r--UVtools.WPF/Assets/Icons/folder-open-16x16.pngbin0 -> 156 bytes
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml317
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml1516
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml4
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateGrayscaleControl.axaml25
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateStressTowerControl.axaml486
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateToleranceControl.axaml279
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateXYZAccuracyControl.axaml44
-rw-r--r--UVtools.WPF/Controls/Helpers.cs3
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMorphControl.axaml26
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml353
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml.cs15
-rw-r--r--UVtools.WPF/MainWindow.Information.cs67
-rw-r--r--UVtools.WPF/MainWindow.axaml16
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs34
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj10
-rw-r--r--UVtools.WPF/Windows/MaterialManagerWindow.axaml4
-rw-r--r--UVtools.WPF/Windows/SettingsWindow.axaml.cs2
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml.cs2
-rw-r--r--build/CreateRelease.WPF.ps16
55 files changed, 4514 insertions, 3017 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 316c0ba..3c57c1d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,53 @@
# Changelog
+## 17/08/2021 - v2.19.0
+
+- **File formats:**
+ - Add and remove some image types that can be open
+ - (Add) `CanProcess` method to know if a file can be read under a format and to allow diferent formats with same extension
+ - (Fix) `LiftHeightTotal` and `RetractHeight` was rounding to no decimals and returning wrong values
+ - (Improvement) Round all float setters on `Layer` class
+ - (Improvement) Decode/encode RAM usage and performance by processing in batch groups
+- **Pixel Dimming:** (#262)
+ - (Add) Option "Lightening pixels" to add brightness/lightening instead of dimming/subtract pixels
+ - (Fix) "Dim walls only" would reset body brightness by increase pixel brightness two times it value
+- **Pixel Arithmetic:**
+ - (Change) Transpose "Pixel Dimming" to "Pixel Arithmetic"
+ - (Improvement) New options and manipulations
+- **(Fix) Exposure time finder:**
+ - Generate top staircase based on selected measure (px or mm)
+ - Zebra bars when used in mm measures, it was using X density instead Y to calculate the thickness
+ - Move 'Unit of measure' to 'Object configuration'
+ - Custom text with wrong Y position when using out of portion resolutions/LCDs
+- **CTBv4:**
+ - (Fix) More Unknown fields discovered and implemented
+ - (Fix) Reserved table is 384 bytes instead of 420
+ - (Fix) When full encoding it was forcing to change to version 3. This also affected convertions. (#263)
+ - (Fix) `BottomRetractHeight2` was being set to `BottomRetractSpeed2`
+ - (Fix) `RetractHeight2` was being set to `RetracSpeed2`
+ - (Fix) The PrintParametersV4 table address
+ - (Fix) Generates invalid files to open with Chitubox and printers (#263)
+ - (Fix) Better progress report
+- **(Add) PrusaSlicer printer notes variables:**
+ - BottomLiftHeight2
+ - BottomLiftSpeed2
+ - LiftHeight2
+ - LiftSpeed2
+ - BottomRetractSpeed
+ - BottomRetractSpeed2
+ - BottomRetractHeight2
+ - BottomRetractSpeed2
+ - RetractHeight2
+ - RetractSpeed2
+- **UI:**
+ - (Add) File - Open current file folder (Ctrl+Shift+L): Locate and open the folder that contain the current loaded file
+ - (Improvement) Hide some virtual extensions from file open dialog filters
+ - (Improvement) UI: Refresh active thumbnail when changed
+ - (Change) Icon for File - Open and Open in a new file
+ - (Change) Rename File - Extract to: Extract file contents
+- (Upgrade) AvaloniaUI from 0.10.6 to 0.10.7
+- (Fix) PW0, PWM, PWMX, PWMO, PWMS: Unable to decode some files with AntiAliasing (#143)
+
## 12/08/2021 - v2.18.0
- **Command line arguments:**
diff --git a/Scripts/010 Editor/PhotonWorkshop.bt b/Scripts/010 Editor/PhotonWorkshop.bt
new file mode 100644
index 0000000..6c08bed
--- /dev/null
+++ b/Scripts/010 Editor/PhotonWorkshop.bt
@@ -0,0 +1,116 @@
+//------------------------------------------------
+//--- 010 Editor v8.0.1 Binary Template
+//
+// File: pws, pw0, pwm, pwmo, pwms, pwmx
+// Authors: Tiago Conceição
+//------------------------------------------------
+
+LittleEndian();
+
+struct FILEMARK {
+ char Mark[12] <fgcolor=cBlack, bgcolor=cRed>;
+ uint Version <fgcolor=cBlack, bgcolor=cRed>;
+ uint AreaNum <fgcolor=cBlack, bgcolor=cRed>;
+ uint HeaderAddress <fgcolor=cBlack, bgcolor=cRed>;
+ uint Padding1 <fgcolor=cBlack, bgcolor=cRed>;
+ uint PreviewAddress <fgcolor=cBlack, bgcolor=cRed>;
+ uint Padding2 <fgcolor=cBlack, bgcolor=cRed>;
+ uint LayerDefinitionAddress <fgcolor=cBlack, bgcolor=cRed>;
+ uint Padding3 <fgcolor=cBlack, bgcolor=cRed>;
+ uint LayerImageAddress <fgcolor=cBlack, bgcolor=cRed>;
+} fileMark;
+
+struct SECTION {
+ char Mark[12] <fgcolor=cBlack, bgcolor=cYellow>;
+ uint Length <fgcolor=cBlack, bgcolor=cYellow>;
+};
+
+struct HEADER {
+ SECTION section;
+
+ float PixelSizeUm <fgcolor=cBlack, bgcolor=cRed>;
+ float LayerHeight <fgcolor=cBlack, bgcolor=cRed>;
+ float LayerExposureTime <fgcolor=cBlack, bgcolor=cRed>;
+
+ float LightOffDelay <fgcolor=cBlack, bgcolor=cRed>;
+ float BottomExposureSeconds <fgcolor=cBlack, bgcolor=cRed>;
+ float BottomLayersCount <fgcolor=cBlack, bgcolor=cRed>;
+ float LiftHeight <fgcolor=cBlack, bgcolor=cRed>;
+ float LiftSpeed <fgcolor=cBlack, bgcolor=cRed>;
+ float RetractSpeed <fgcolor=cBlack, bgcolor=cRed>;
+ float VolumeMl <fgcolor=cBlack, bgcolor=cRed>;
+ uint AntiAliasing <fgcolor=cBlack, bgcolor=cRed>;
+ uint ResolutionX <fgcolor=cBlack, bgcolor=cRed>;
+ uint ResolutionY <fgcolor=cBlack, bgcolor=cRed>;
+ float WeightG <fgcolor=cBlack, bgcolor=cRed>;
+ float Price <fgcolor=cBlack, bgcolor=cRed>;
+ uint PriceCurrencyDec <fgcolor=cBlack, bgcolor=cRed>;
+ uint PerLayerOverride <fgcolor=cBlack, bgcolor=cRed>;
+ uint PrintTime <fgcolor=cBlack, bgcolor=cRed>;
+ uint Padding1 <fgcolor=cBlack, bgcolor=cRed>;
+ uint Padding2 <fgcolor=cBlack, bgcolor=cRed>;
+};
+
+if(fileMark.HeaderAddress > 0){
+ FSeek(fileMark.HeaderAddress);
+ HEADER header;
+}
+
+
+struct PREVIEW {
+ SECTION section;
+ uint ResolutionX <fgcolor=cBlack, bgcolor=cRed>;
+ uint DpiResolution <fgcolor=cBlack, bgcolor=cRed>;
+ uint ResolutionY <fgcolor=cBlack, bgcolor=cRed>;
+ uint Unknown1 <fgcolor=cBlack, bgcolor=cRed>;
+ uint Unknown2 <fgcolor=cBlack, bgcolor=cRed>;
+ uint Unknown3 <fgcolor=cBlack, bgcolor=cRed>;
+ uint Unknown4 <fgcolor=cBlack, bgcolor=cRed>;
+
+ ubyte Data[ResolutionX*ResolutionY*2] <fgcolor=cBlack, bgcolor=cGreen>;
+};
+
+if(fileMark.PreviewAddress > 0){
+ FSeek(fileMark.PreviewAddress);
+ PREVIEW preview;
+}
+
+
+typedef struct(int size) {
+ ubyte layerDataBlock[size] <fgcolor=cBlack, bgcolor=cGreen>;
+} LAYER_RLE;
+
+struct LayerDefinition {
+ SECTION section;
+ uint LayerCount <fgcolor=cBlack, bgcolor=cRed>;
+};
+
+struct LAYER_DEF {
+ uint DataAddress <fgcolor=cWhite, bgcolor=cBlue>;
+ uint DataLength <fgcolor=cWhite, bgcolor=cBlue>;
+ float LiftHeight <fgcolor=cWhite, bgcolor=cBlue>;
+ float LiftSpeed <fgcolor=cWhite, bgcolor=cBlue>;
+ float ExposureTime <fgcolor=cWhite, bgcolor=cBlue>;
+ float LayerHeight <fgcolor=cWhite, bgcolor=cBlue>;
+ uint NonZeroPixelCount <fgcolor=cWhite, bgcolor=cBlue>;
+ uint Padding1 <fgcolor=cWhite, bgcolor=cBlue>;
+
+ local uint currentPos = FTell();
+ FSeek(DataAddress);
+ ubyte RLE[DataLength];
+ FSeek(currentPos);
+};
+
+
+
+if(fileMark.LayerDefinitionAddress > 0){
+ FSeek(fileMark.LayerDefinitionAddress);
+ LayerDefinition layerDefinition;
+ struct LAYERS{
+ local uint i;
+
+ for(i = 0; i < layerDefinition.LayerCount; i++ ){
+ LAYER_DEF layerDef;
+ }
+ } layers;
+}
diff --git a/Scripts/010 Editor/ctb.bt b/Scripts/010 Editor/ctb.bt
index e4be65a..c54041a 100644
--- a/Scripts/010 Editor/ctb.bt
+++ b/Scripts/010 Editor/ctb.bt
@@ -52,7 +52,7 @@ struct PREVIEW {
uint Unknown3 <fgcolor=cBlack, bgcolor=cRed>;
uint Unknown4 <fgcolor=cBlack, bgcolor=cRed>;
- ubyte Data[ImageLength] <fgcolor=cBlack, bgcolor=cRed>;
+ ubyte Data[ImageLength] <fgcolor=cBlack, bgcolor=cYellow>;
};
struct PRINT_PARAMETERS {
@@ -92,7 +92,7 @@ struct SLICER_INFO {
float RestTimeAfterRetract <fgcolor=cBlack, bgcolor=cRed>;
float RestTimeAfterLift2 <fgcolor=cBlack, bgcolor=cRed>;
uint TransitionLayerCount <fgcolor=cBlack, bgcolor=cRed>;
- uint Padding1 <fgcolor=cBlack, bgcolor=cRed>;
+ uint PrintParametersV4Address <fgcolor=cBlack, bgcolor=cRed>;
uint Padding2 <fgcolor=cBlack, bgcolor=cRed>;
uint Padding3 <fgcolor=cBlack, bgcolor=cRed>;
@@ -126,9 +126,9 @@ if(header.SlicerOffset > 0){
if(header.Version >= 4)
{
+ FSeek(SlicerInfo.PrintParametersV4Address);
struct PRINT_PARAMETERS_V4
{
- char Disclaimer[320] <fgcolor=cBlack, bgcolor=cYellow>;
float BottomRetractSpeed <fgcolor=cWhite, bgcolor=cBlue>;
float BottomRetractSpeed2 <fgcolor=cWhite, bgcolor=cBlue>;
uint Padding1 <fgcolor=cWhite, bgcolor=cBlue>;
@@ -151,9 +151,13 @@ if(header.Version >= 4)
uint DisclaimerLength <fgcolor=cWhite, bgcolor=cBlue>; // 320
ubyte Reserved[384] <fgcolor=cYellow, bgcolor=cBlue>;
} printParametersV4;
+
+ FSeek(printParametersV4.DisclaimerAddress);
+ char DisclaimerText[printParametersV4.DisclaimerLength] <fgcolor=cBlack, bgcolor=cYellow>;;
+
}
-typedef struct() {
+struct LAYER_DATA {
float LayerPositionZ <fgcolor=cBlack, bgcolor=cRed>;
float LayerExposure <fgcolor=cBlack, bgcolor=cRed>;
float LightOffSeconds <fgcolor=cBlack, bgcolor=cRed>;
@@ -163,9 +167,9 @@ typedef struct() {
uint Unknown2 <fgcolor=cBlack, bgcolor=cRed>;
uint Unknown3 <fgcolor=cBlack, bgcolor=cRed>;
uint Unknown4 <fgcolor=cBlack, bgcolor=cRed>;
-} LAYER_DATA;
+};
-typedef struct() {
+struct LAYER_DATAEX {
LAYER_DATA LayerData <fgcolor=cBlack, bgcolor=cRed>;
uint TotalSize <fgcolor=cBlack, bgcolor=cRed>;
float LiftHeight <fgcolor=cBlack, bgcolor=cRed>;
@@ -179,7 +183,7 @@ typedef struct() {
float RestTimeAfterLift <fgcolor=cBlack, bgcolor=cRed>;
float RestTimeAfterRetract <fgcolor=cBlack, bgcolor=cRed>;
float LightPWM <fgcolor=cBlack, bgcolor=cRed>;
-} LAYER_DATAEX;
+};
typedef struct(int size) {
diff --git a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
index 71dad58..2832bc4 100644
--- a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
+++ b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
@@ -34,7 +34,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Avalonia" Version="0.10.6" />
+ <PackageReference Include="Avalonia" Version="0.10.7" />
</ItemGroup>
<ItemGroup>
diff --git a/UVtools.Core/Extensions/FileStreamExtensions.cs b/UVtools.Core/Extensions/FileStreamExtensions.cs
index c9b530c..86f84cb 100644
--- a/UVtools.Core/Extensions/FileStreamExtensions.cs
+++ b/UVtools.Core/Extensions/FileStreamExtensions.cs
@@ -6,6 +6,7 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.IO;
namespace UVtools.Core.Extensions
@@ -88,5 +89,23 @@ namespace UVtools.Core.Extensions
{
return Helpers.SerializeWriteFileStream(fs, data, offset);
}
+
+ /// <summary>
+ /// Seek to a position, do work and rewind to initial position
+ /// </summary>
+ /// <param name="fs"></param>
+ /// <param name="action"></param>
+ /// <param name="offset"></param>
+ /// <param name="seekOrigin"></param>
+ public static void SeekDoWorkAndRewind(this FileStream fs, long offset, Action action)
+ => fs.SeekDoWorkAndRewind(offset, SeekOrigin.Begin, action);
+
+ public static void SeekDoWorkAndRewind(this FileStream fs, long offset, SeekOrigin seekOrigin, Action action)
+ {
+ var currentPos = fs.Position;
+ fs.Seek(offset, seekOrigin); // Go to
+ action.Invoke(); // Do work
+ fs.Seek(currentPos, SeekOrigin.Begin); // Rewind
+ }
}
}
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index 1dae648..44f3c8a 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -426,9 +426,8 @@ namespace UVtools.Core.FileFormats
get => (byte) OutputSettings.AntiAliasingValue;
set
{
- OutputSettings.AntiAliasingValue = value.Clamp(1, 16);
+ base.AntiAliasing = (byte)(OutputSettings.AntiAliasingValue = value.Clamp(1, 16));
OutputSettings.AntiAliasing = OutputSettings.AntiAliasingValue > 1;
- RaisePropertyChanged();
}
}
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
index a81ad75..fb0f1bb 100644
--- a/UVtools.Core/FileFormats/CXDLPFile.cs
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -36,7 +36,7 @@ namespace UVtools.Core.FileFormats
#region Header
public sealed class Header
{
- private string _printerModel = "CL-89";
+ //private string _printerModel = "CL-89";
/// <summary>
/// Gets the size of the header
@@ -447,12 +447,6 @@ namespace UVtools.Core.FileFormats
}
}
- public override byte AntiAliasing
- {
- get => 8;
- set {}
- }
-
public override float LayerHeight
{
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
@@ -608,33 +602,24 @@ namespace UVtools.Core.FileFormats
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- byte[][] previews = new byte[ThumbnailsOriginalSize.Length][];
- for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
- {
- previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
- }
+ var previews = new byte[ThumbnailsOriginalSize.Length][];
+
// Previews
Parallel.For(0, previews.Length, previewIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- if (Thumbnails[previewIndex] is null) return;
- var span = Thumbnails[previewIndex].GetDataByteSpan();
- int index = 0;
- for (int i = 0; i < span.Length; i += 3)
+ var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
+ if (Thumbnails[previewIndex] is null)
{
- byte b = span[i];
- byte g = span[i + 1];
- byte r = span[i + 2];
-
- ushort rgb15 = (ushort)(((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));
-
- previews[previewIndex][index++] = (byte)(rgb15 >> 8);
- previews[previewIndex][index++] = (byte)(rgb15 & 0xff);
+ previews[previewIndex] = new byte[encodeLength];
+ return;
}
- if (index != previews[previewIndex].Length)
+ previews[previewIndex] = EncodeImage(DATATYPE_RGB565_BE, Thumbnails[previewIndex]);
+
+ if (encodeLength != previews[previewIndex].Length)
{
- throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {index}");
+ throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {encodeLength}");
}
});
@@ -642,7 +627,7 @@ namespace UVtools.Core.FileFormats
{
Helpers.SerializeWriteFileStream(outputFile, previews[i]);
outputFile.WriteBytes(pageBreak);
- //Helpers.SerializeWriteFileStream(outputFile, pageBreak);
+ previews[i] = null;
}
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
@@ -662,10 +647,8 @@ namespace UVtools.Core.FileFormats
//Helpers.SerializeWriteFileStream(outputFile, pageBreak);
outputFile.WriteBytes(pageBreak);
- var range = Enumerable.Range(0, (int) LayerCount);
-
var layerBytes = new List<byte>[LayerCount];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -673,48 +656,52 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex];
- using var mat = layer.LayerMat;
- var span = mat.GetDataByteSpan();
+ using (var mat = layer.LayerMat)
+ {
+ var span = mat.GetDataByteSpan();
- layerBytes[layerIndex] = new();
+ layerBytes[layerIndex] = new();
- uint lineCount = 0;
+ uint lineCount = 0;
- for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
- {
- int y = layer.BoundingRectangle.Y;
- int startY = -1;
- byte lastColor = 0;
- for (; y < layer.BoundingRectangle.Bottom; y++)
+ for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
{
- int pos = mat.GetPixelPos(x, y);
- byte color = span[pos];
+ int y = layer.BoundingRectangle.Y;
+ int startY = -1;
+ byte lastColor = 0;
+ for (; y < layer.BoundingRectangle.Bottom; y++)
+ {
+ int pos = mat.GetPixelPos(x, y);
+ byte color = span[pos];
+
+ if (lastColor == color && color != 0) continue;
- if (lastColor == color && color != 0) continue;
+ if (startY >= 0)
+ {
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1),
+ (ushort)x, lastColor));
+ lineCount++;
+ }
+
+ startY = color == 0 ? -1 : y;
+
+ lastColor = color;
+ }
if (startY >= 0)
{
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1),
+ (ushort)x, lastColor));
lineCount++;
}
-
- startY = color == 0 ? -1 : y;
-
- lastColor = color;
}
- if (startY >= 0)
- {
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
- lineCount++;
- }
+ layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes(
+ (uint)Math.Round(layer.BoundingRectangleMillimeters.Area() * 1000),
+ lineCount));
+ layerBytes[layerIndex].AddRange(pageBreak);
}
- layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes(
- (uint)Math.Round(layer.BoundingRectangleMillimeters.Area()*1000),
- lineCount));
- layerBytes[layerIndex].AddRange(pageBreak);
-
progress.LockAndIncrement();
});
@@ -842,23 +829,8 @@ namespace UVtools.Core.FileFormats
Parallel.For(0, previews.Length, previewIndex =>
{
- var mat = new Mat(ThumbnailsOriginalSize[previewIndex], DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
-
- int spanIndex = 0;
- for (int i = 0; i < previews[previewIndex].Length; i += 2)
- {
- ushort rgb15 = (ushort)((ushort)(previews[previewIndex][i + 0] << 8) | previews[previewIndex][i + 1]);
- byte r = (byte)((rgb15 >> 11) << 3);
- byte g = (byte)((rgb15 >> 5) << 2);
- byte b = (byte)((rgb15 >> 0) << 3);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- Thumbnails[previewIndex] = mat;
+ Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
+ previews[previewIndex] = null;
});
@@ -877,10 +849,9 @@ namespace UVtools.Core.FileFormats
}*/
//inputFile.Seek(2, SeekOrigin.Current);
- var range = Enumerable.Range(0, (int)LayerCount);
var linesBytes = new byte[LayerCount][];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -899,29 +870,32 @@ namespace UVtools.Core.FileFormats
Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var mat = EmguExtensions.InitMat(Resolution);
-
- for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+ using (var mat = EmguExtensions.InitMat(Resolution))
{
- LayerLine line = new()
+
+ for (int i = 0; i < linesBytes[layerIndex].Length; i++)
{
- Coordinates =
+ LayerLine line = new()
{
- [0] = linesBytes[layerIndex][i++],
- [1] = linesBytes[layerIndex][i++],
- [2] = linesBytes[layerIndex][i++],
- [3] = linesBytes[layerIndex][i++],
- [4] = linesBytes[layerIndex][i++]
- },
- Gray = linesBytes[layerIndex][i]
- };
-
- CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY), new MCvScalar(line.Gray));
- }
+ Coordinates =
+ {
+ [0] = linesBytes[layerIndex][i++],
+ [1] = linesBytes[layerIndex][i++],
+ [2] = linesBytes[layerIndex][i++],
+ [3] = linesBytes[layerIndex][i++],
+ [4] = linesBytes[layerIndex][i++]
+ },
+ Gray = linesBytes[layerIndex][i]
+ };
+
+ CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY),
+ new MCvScalar(line.Gray));
+ }
- linesBytes[layerIndex] = null;
+ linesBytes[layerIndex] = null;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ }
progress.LockAndIncrement();
});
diff --git a/UVtools.Core/FileFormats/CXDLPv1File.cs b/UVtools.Core/FileFormats/CXDLPv1File.cs
index 137f839..445396c 100644
--- a/UVtools.Core/FileFormats/CXDLPv1File.cs
+++ b/UVtools.Core/FileFormats/CXDLPv1File.cs
@@ -397,12 +397,6 @@ namespace UVtools.Core.FileFormats
}
}
- public override byte AntiAliasing
- {
- get => 8;
- set { }
- }
-
public override float LayerHeight
{
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
@@ -543,33 +537,24 @@ namespace UVtools.Core.FileFormats
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- byte[][] previews = new byte[ThumbnailsOriginalSize.Length][];
- for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
- {
- previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
- }
+ var previews = new byte[ThumbnailsOriginalSize.Length][];
+
// Previews
Parallel.For(0, previews.Length, previewIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- if (Thumbnails[previewIndex] is null) return;
- var span = Thumbnails[previewIndex].GetDataByteSpan();
- int index = 0;
- for (int i = 0; i < span.Length; i += 3)
+ var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
+ if (Thumbnails[previewIndex] is null)
{
- byte b = span[i];
- byte g = span[i + 1];
- byte r = span[i + 2];
-
- ushort rgb15 = (ushort)(((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));
-
- previews[previewIndex][index++] = (byte)(rgb15 >> 8);
- previews[previewIndex][index++] = (byte)(rgb15 & 0xff);
+ previews[previewIndex] = new byte[encodeLength];
+ return;
}
- if (index != previews[previewIndex].Length)
+ previews[previewIndex] = EncodeImage(DATATYPE_RGB565_BE, Thumbnails[previewIndex]);
+
+ if (encodeLength != previews[previewIndex].Length)
{
- throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {index}");
+ throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {encodeLength}");
}
});
@@ -577,6 +562,7 @@ namespace UVtools.Core.FileFormats
{
Helpers.SerializeWriteFileStream(outputFile, previews[i]);
outputFile.WriteBytes(pageBreak);
+ previews[i] = null;
}
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
@@ -589,10 +575,8 @@ namespace UVtools.Core.FileFormats
}
outputFile.WriteBytes(pageBreak);
- var range = Enumerable.Range(0, (int)LayerCount);
-
var layerBytes = new List<byte>[LayerCount];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -600,46 +584,50 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex];
- using var mat = layer.LayerMat;
- var span = mat.GetDataByteSpan();
+ using (var mat = layer.LayerMat)
+ {
+ var span = mat.GetDataByteSpan();
- layerBytes[layerIndex] = new();
+ layerBytes[layerIndex] = new();
- uint lineCount = 0;
+ uint lineCount = 0;
- for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
- {
- int y = layer.BoundingRectangle.Y;
- int startY = -1;
- byte lastColor = 0;
- for (; y < layer.BoundingRectangle.Bottom; y++)
+ for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
{
- int pos = mat.GetPixelPos(x, y);
- byte color = span[pos];
+ int y = layer.BoundingRectangle.Y;
+ int startY = -1;
+ byte lastColor = 0;
+ for (; y < layer.BoundingRectangle.Bottom; y++)
+ {
+ int pos = mat.GetPixelPos(x, y);
+ byte color = span[pos];
- if (lastColor == color && color != 0) continue;
+ if (lastColor == color && color != 0) continue;
+
+ if (startY >= 0)
+ {
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1),
+ (ushort)x, lastColor));
+ lineCount++;
+ }
+
+ startY = color == 0 ? -1 : y;
+
+ lastColor = color;
+ }
if (startY >= 0)
{
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1),
+ (ushort)x, lastColor));
lineCount++;
}
-
- startY = color == 0 ? -1 : y;
-
- lastColor = color;
}
- if (startY >= 0)
- {
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
- lineCount++;
- }
+ layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes(layer.NonZeroPixelCount, lineCount));
+ layerBytes[layerIndex].AddRange(pageBreak);
}
- layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes(layer.NonZeroPixelCount, lineCount));
- layerBytes[layerIndex].AddRange(pageBreak);
-
progress.LockAndIncrement();
});
@@ -679,23 +667,8 @@ namespace UVtools.Core.FileFormats
Parallel.For(0, previews.Length, previewIndex =>
{
- var mat = new Mat(ThumbnailsOriginalSize[previewIndex], DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
-
- int spanIndex = 0;
- for (int i = 0; i < previews[previewIndex].Length; i += 2)
- {
- ushort rgb15 = (ushort)((ushort)(previews[previewIndex][i + 0] << 8) | previews[previewIndex][i + 1]);
- byte r = (byte)((rgb15 >> 11) << 3);
- byte g = (byte)((rgb15 >> 5) << 2);
- byte b = (byte)((rgb15 >> 0) << 3);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- Thumbnails[previewIndex] = mat;
+ Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
+ previews[previewIndex] = null;
});
@@ -711,7 +684,7 @@ namespace UVtools.Core.FileFormats
var range = Enumerable.Range(0, (int)LayerCount);
var linesBytes = new byte[LayerCount][];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -730,29 +703,31 @@ namespace UVtools.Core.FileFormats
Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var mat = EmguExtensions.InitMat(Resolution);
-
- for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+ using (var mat = EmguExtensions.InitMat(Resolution))
{
- LayerLine line = new()
+ for (int i = 0; i < linesBytes[layerIndex].Length; i++)
{
- Coordinates =
+ LayerLine line = new()
{
- [0] = linesBytes[layerIndex][i++],
- [1] = linesBytes[layerIndex][i++],
- [2] = linesBytes[layerIndex][i++],
- [3] = linesBytes[layerIndex][i++],
- [4] = linesBytes[layerIndex][i++]
- },
- Gray = linesBytes[layerIndex][i]
- };
-
- CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY), new MCvScalar(line.Gray));
- }
+ Coordinates =
+ {
+ [0] = linesBytes[layerIndex][i++],
+ [1] = linesBytes[layerIndex][i++],
+ [2] = linesBytes[layerIndex][i++],
+ [3] = linesBytes[layerIndex][i++],
+ [4] = linesBytes[layerIndex][i++]
+ },
+ Gray = linesBytes[layerIndex][i]
+ };
+
+ CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY),
+ new MCvScalar(line.Gray));
+ }
- linesBytes[layerIndex] = null;
+ linesBytes[layerIndex] = null;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ }
progress.LockAndIncrement();
});
diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index 046aea8..92ba36b 100644
--- a/UVtools.Core/FileFormats/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -14,10 +14,12 @@ using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
+using System.Text;
using System.Threading.Tasks;
using BinarySerialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
+using MoreLinq;
using UVtools.Core.Extensions;
using UVtools.Core.Operations;
@@ -45,15 +47,8 @@ namespace UVtools.Core.FileFormats
private const string CTBv4_DISCLAIMER = "Layout and record format for the ctb and cbddlp file types are the copyrighted programs or codes of CBD Technology (China) Inc..The Customer or User shall not in any manner reproduce, distribute, modify, decompile, disassemble, decrypt, extract, reverse engineer, lease, assign, or sublicense the said programs or codes.";
private const ushort CTBv4_DISCLAIMER_SIZE = 320;
+ private const ushort CTBv4_RESERVED_SIZE = 384;
- public static readonly byte[] SomethingNew1 = {
- 0xD0, 0x5B, 0x8E, 0x33, 0x71, 0xDE, 0x3D, 0x1A, 0xE5, 0x4F, 0x22, 0xDD, 0xDF, 0x5B, 0xFD, 0x94,
- 0xAB, 0x5D, 0x64, 0x3A, 0x9D, 0x7E, 0xBF, 0xAF, 0x42, 0x03, 0xF3, 0x10, 0xD8, 0x52, 0x2A, 0xEA
- };
-
- public static readonly byte[] SomethingNew2 = {
- 0x0F, 0x01, 0x0A, 0x05, 0x05, 0x0B, 0x06, 0x07, 0x08, 0x06, 0x0A, 0x0C, 0x0C, 0x0D, 0x09, 0x0F
- };
#endregion
#region Sub Classes
@@ -176,6 +171,7 @@ namespace UVtools.Core.FileFormats
/// This is used to implement antialiasing in cbddlp files. When greater than 1,
/// the layer table will actually contain layer_table_count * level_set_count entries.
/// See the section on antialiasing for details.
+ /// 1 for ctb
/// </summary>
[FieldOrder(23)] public uint AntiAliasLevel { get; set; } = 1;
@@ -330,7 +326,7 @@ namespace UVtools.Core.FileFormats
[FieldOrder(13)] public float RestTimeAfterRetract { get; set; }
[FieldOrder(14)] public float RestTimeAfterLift2 { get; set; }
[FieldOrder(15)] public uint TransitionLayerCount { get; set; } // CTB not all printers
- [FieldOrder(16)] public uint Padding1 { get; set; }
+ [FieldOrder(16)] public uint PrintParametersV4Address { get; set; } // V4 Only
[FieldOrder(17)] public uint Padding2 { get; set; }
[FieldOrder(18)] public uint Padding3 { get; set; }
@@ -354,7 +350,7 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(BottomLiftHeight2)}: {BottomLiftHeight2}, {nameof(BottomLiftSpeed2)}: {BottomLiftSpeed2}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift2)}: {RestTimeAfterLift2}, {nameof(TransitionLayerCount)}: {TransitionLayerCount}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(MachineName)}: {MachineName}";
+ return $"{nameof(BottomLiftHeight2)}: {BottomLiftHeight2}, {nameof(BottomLiftSpeed2)}: {BottomLiftSpeed2}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift2)}: {RestTimeAfterLift2}, {nameof(TransitionLayerCount)}: {TransitionLayerCount}, {nameof(PrintParametersV4Address)}: {PrintParametersV4Address}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(MachineName)}: {MachineName}";
}
}
@@ -363,9 +359,10 @@ namespace UVtools.Core.FileFormats
#region PrintParametersV4
public sealed class PrintParametersV4
{
- [FieldOrder(0)]
- [FieldLength(CTBv4_DISCLAIMER_SIZE)]
+ /*[FieldOrder(0)]
+ [FieldLength(nameof(DisclaimerLength))]
public string Disclaimer { get; set; } = CTBv4_DISCLAIMER; // 320 bytes
+ */
[FieldOrder(1)]
public float BottomRetractSpeed { get; set; }
@@ -407,7 +404,7 @@ namespace UVtools.Core.FileFormats
public uint Unknown3 { get; set; } = 5; // 5?
[FieldOrder(14)]
- public uint Unknown4 { get; set; } // 139 but changes
+ public uint LastLayerIndex { get; set; }
[FieldOrder(15)]
public uint Padding3 { get; set; }
@@ -422,18 +419,17 @@ namespace UVtools.Core.FileFormats
public uint Padding6 { get; set; }
[FieldOrder(19)]
- public uint Unknown5 { get; set; } // 23047 but changes
+ public uint DisclaimerAddress { get; set; }
- [FieldOrder(20)]
- public uint Unknown6 { get; set; } // 320 but changes
+ [FieldOrder(20)] public uint DisclaimerLength { get; set; } = CTBv4_DISCLAIMER_SIZE;
[FieldOrder(21)]
- [FieldLength(384)]
- public byte[] Reserved { get; set; } = new byte[384]; // 384 bytes
+ [FieldLength(CTBv4_RESERVED_SIZE)]
+ public byte[] Reserved { get; set; } = new byte[CTBv4_RESERVED_SIZE]; // 384 bytes
public override string ToString()
{
- return $"{nameof(Disclaimer)}: {Disclaimer}, {nameof(BottomRetractSpeed)}: {BottomRetractSpeed}, {nameof(BottomRetractSpeed2)}: {BottomRetractSpeed2}, {nameof(Padding1)}: {Padding1}, {nameof(Four1)}: {Four1}, {nameof(Padding2)}: {Padding2}, {nameof(Four2)}: {Four2}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(RestTimeBeforeLift)}: {RestTimeBeforeLift}, {nameof(BottomRetractHeight2)}: {BottomRetractHeight2}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}, {nameof(Padding3)}: {Padding3}, {nameof(Padding4)}: {Padding4}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(Unknown5)}: {Unknown5}, {nameof(Unknown6)}: {Unknown6}, {nameof(Reserved)}: {Reserved}";
+ return $"{nameof(BottomRetractSpeed)}: {BottomRetractSpeed}, {nameof(BottomRetractSpeed2)}: {BottomRetractSpeed2}, {nameof(Padding1)}: {Padding1}, {nameof(Four1)}: {Four1}, {nameof(Padding2)}: {Padding2}, {nameof(Four2)}: {Four2}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(RestTimeBeforeLift)}: {RestTimeBeforeLift}, {nameof(BottomRetractHeight2)}: {BottomRetractHeight2}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(LastLayerIndex)}: {LastLayerIndex}, {nameof(Padding3)}: {Padding3}, {nameof(Padding4)}: {Padding4}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(DisclaimerAddress)}: {DisclaimerAddress}, {nameof(DisclaimerLength)}: {DisclaimerLength}, {nameof(Reserved)}: {Reserved}";
}
}
#endregion
@@ -589,12 +585,12 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the build platform Z position for this layer, measured in millimeters.
/// </summary>
- [FieldOrder(0)] public float LayerPositionZ { get; set; }
+ [FieldOrder(0)] public float PositionZ { get; set; }
/// <summary>
/// Gets the exposure time for this layer, in seconds.
/// </summary>
- [FieldOrder(1)] public float LayerExposure { get; set; }
+ [FieldOrder(1)] public float ExposureTime { get; set; }
/// <summary>
/// Gets how long to keep the light off after exposing this layer, in seconds.
@@ -626,7 +622,7 @@ namespace UVtools.Core.FileFormats
public LayerDef(ChituboxFile parent, Layer layer)
{
Parent = parent;
- RefreshLayerData(layer);
+ SetFrom(layer);
if (parent.HeaderSettings.Version >= 3 && Unknown2 == 0)
{
@@ -634,20 +630,32 @@ namespace UVtools.Core.FileFormats
}
}
- public void RefreshLayerData(Layer layer)
+ public void SetFrom(Layer layer)
{
- LayerPositionZ = layer.PositionZ;
- LayerExposure = layer.ExposureTime;
+ PositionZ = layer.PositionZ;
+ ExposureTime = layer.ExposureTime;
LightOffSeconds = layer.LightOffDelay;
}
+ public void CopyTo(Layer layer)
+ {
+ layer.PositionZ = PositionZ;
+ layer.ExposureTime = ExposureTime;
+ layer.LightOffDelay = LightOffSeconds;
+ }
+
public Mat Decode(uint layerIndex, bool consumeData = true)
{
var image = Parent.IsCtbFile ? DecodeCtbImage(layerIndex) : DecodeCbddlpImage(Parent, layerIndex);
if (consumeData)
- EncodedRle = null;
+ {
+ for (byte aaIndex = 0; aaIndex < Parent.HeaderSettings.AntiAliasLevel; aaIndex++)
+ {
+ Parent.LayerDefinitions[aaIndex, layerIndex].EncodedRle = null;
+ }
+ }
return image;
}
@@ -945,10 +953,8 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(LayerPositionZ)}: {LayerPositionZ}, {nameof(LayerExposure)}: {LayerExposure}, {nameof(LightOffSeconds)}: {LightOffSeconds}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
+ return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffSeconds)}: {LightOffSeconds}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
}
-
-
}
public class LayerDefEx
@@ -974,21 +980,19 @@ namespace UVtools.Core.FileFormats
[FieldOrder(11)] public float RestTimeAfterRetract { get; set; } // 28672 v3?
[FieldOrder(12)] public float LightPWM { get; set; }
- public LayerDefEx()
- {
- }
+ public LayerDefEx() { }
public LayerDefEx(LayerDef layerDef, Layer layer)
{
LayerDef = layerDef;
- if (layerDef.Parent is not null && layer is not null)
+ if (layer is not null)
{
LiftHeight = layer.LiftHeight;
LiftSpeed = layer.LiftSpeed;
RetractSpeed = layer.RetractSpeed;
LightPWM = layer.LightPWM;
- if (layerDef.Parent.HeaderSettings.Version >= 4)
+ if (layerDef.Parent is not null && layerDef.Parent.HeaderSettings.Version >= 4)
{
LiftHeight2 = layer.LiftHeight2;
LiftSpeed2 = layer.LiftSpeed2;
@@ -1008,10 +1012,35 @@ namespace UVtools.Core.FileFormats
}
}
+ public void CopyTo(Layer layer)
+ {
+ LayerDef.CopyTo(layer);
+
+ layer.LiftHeight = LiftHeight;
+ layer.LiftSpeed = LiftSpeed;
+ layer.RetractSpeed = RetractSpeed;
+ layer.LightPWM = (byte)LightPWM;
+
+ if (LayerDef.Parent is not null && LayerDef.Parent.HeaderSettings.Version >= 4)
+ {
+ layer.LiftHeight2 = LiftHeight2;
+ layer.LiftSpeed2 = LiftSpeed2;
+
+ layer.RetractHeight2 = RetractHeight2;
+ layer.RetractSpeed2 = RetractSpeed2;
+
+ layer.WaitTimeBeforeCure = RestTimeAfterRetract;
+ layer.WaitTimeAfterCure = RestTimeBeforeLift;
+ layer.WaitTimeAfterLift = RestTimeAfterLift;
+ }
+ }
+
public override string ToString()
{
return $"{nameof(LayerDef)}: {LayerDef}, {nameof(TotalSize)}: {TotalSize}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeBeforeLift)}: {RestTimeBeforeLift}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(LightPWM)}: {LightPWM}";
}
+
+
}
#endregion
@@ -1080,8 +1109,6 @@ namespace UVtools.Core.FileFormats
public LayerDef[,] LayerDefinitions { get; private set; }
- public Dictionary<string, LayerDef> LayersHash { get; } = new();
-
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
@@ -1289,14 +1316,13 @@ namespace UVtools.Core.FileFormats
{
if (IsCtbFile)
{
- SlicerInfoSettings.AntiAliasLevel = value;
+ base.AntiAliasing = (byte)(SlicerInfoSettings.AntiAliasLevel = value.Clamp(1, 16));
}
- else
+ else if(IsCbddlpFile)
{
- HeaderSettings.AntiAliasLevel = value.Clamp(1, 16);
+ base.AntiAliasing = (byte)(SlicerInfoSettings.AntiAliasLevel = HeaderSettings.AntiAliasLevel = value.Clamp(1, 16));
ValidateAntiAliasingLevel();
}
- RaisePropertyChanged();
}
}
@@ -1319,7 +1345,11 @@ namespace UVtools.Core.FileFormats
public override uint LayerCount
{
get => base.LayerCount;
- set => base.LayerCount = HeaderSettings.LayerCount = base.LayerCount;
+ set
+ {
+ base.LayerCount = HeaderSettings.LayerCount = base.LayerCount;
+ PrintParametersV4Settings.LastLayerIndex = LastLayerIndex;
+ }
}
public override ushort BottomLayerCount
@@ -1526,7 +1556,8 @@ namespace UVtools.Core.FileFormats
set
{
if (HeaderSettings.Version < 4) return;
- base.BottomRetractHeight2 = PrintParametersV4Settings.BottomRetractHeight2 = (float)Math.Round(value, 2);
+ value = Math.Clamp((float)Math.Round(value, 2), 0, BottomRetractHeightTotal);
+ base.BottomRetractHeight2 = PrintParametersV4Settings.BottomRetractHeight2 = value;
}
}
@@ -1543,7 +1574,12 @@ namespace UVtools.Core.FileFormats
public override float RetractHeight2
{
get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.RetractHeight2 : 0;
- set => base.RetractHeight2 = SlicerInfoSettings.RetractHeight2 = (float)Math.Round(value, 2);
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ value = Math.Clamp((float)Math.Round(value, 2), 0, RetractHeightTotal);
+ base.RetractHeight2 = SlicerInfoSettings.RetractHeight2 = value;
+ }
}
public override float RetractSpeed2
@@ -1623,7 +1659,7 @@ namespace UVtools.Core.FileFormats
public bool IsCbddlpFile => HeaderSettings.Magic == MAGIC_CBDDLP;
public bool IsCtbFile => HeaderSettings.Magic is MAGIC_CTB or MAGIC_CTBv4;
- public bool CanHash => !IsCtbFile && HeaderSettings.Version <= 2;
+ public bool CanHash => IsCbddlpFile && HeaderSettings.Version <= 2;
#endregion
#region Constructors
@@ -1702,8 +1738,6 @@ namespace UVtools.Core.FileFormats
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
- LayersHash.Clear();
-
if (FileEndsWith(".ctb"))
{
if (HeaderSettings.Magic is not MAGIC_CTB and not MAGIC_CTBv4)
@@ -1734,7 +1768,6 @@ namespace UVtools.Core.FileFormats
HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
-
SanitizeProperties();
if (IsCtbFile)
{
@@ -1751,10 +1784,10 @@ namespace UVtools.Core.FileFormats
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CBDDLP;
}
- uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
+ //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
LayerDefinitions = new LayerDef[HeaderSettings.AntiAliasLevel, HeaderSettings.LayerCount];
using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
- outputFile.Seek((int) currentOffset, SeekOrigin.Begin);
+ outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
Mat[] thumbnails = {GetThumbnail(true), GetThumbnail(false)};
for (byte i = 0; i < thumbnails.Length; i++)
@@ -1774,105 +1807,127 @@ namespace UVtools.Core.FileFormats
if (i == 0)
{
- HeaderSettings.PreviewLargeOffsetAddress = currentOffset;
+ HeaderSettings.PreviewLargeOffsetAddress = (uint)outputFile.Position;
}
else
{
- HeaderSettings.PreviewSmallOffsetAddress = currentOffset;
+ HeaderSettings.PreviewSmallOffsetAddress = (uint)outputFile.Position;
}
- currentOffset += (uint) Helpers.Serializer.SizeOf(preview);
- preview.ImageOffset = currentOffset;
+ preview.ImageOffset = (uint)(outputFile.Position + Helpers.Serializer.SizeOf(preview));
Helpers.SerializeWriteFileStream(outputFile, preview);
- currentOffset += outputFile.WriteBytes(previewBytes);
+ outputFile.WriteBytes(previewBytes);
}
if (HeaderSettings.Version >= 2)
{
- HeaderSettings.PrintParametersOffsetAddress = currentOffset;
+ HeaderSettings.PrintParametersOffsetAddress = (uint)outputFile.Position;
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, PrintParametersSettings);
+ Helpers.SerializeWriteFileStream(outputFile, PrintParametersSettings);
- HeaderSettings.SlicerOffset = currentOffset;
+ HeaderSettings.SlicerOffset = (uint)outputFile.Position;
HeaderSettings.SlicerSize = (uint) Helpers.Serializer.SizeOf(SlicerInfoSettings) - SlicerInfoSettings.MachineNameSize;
- SlicerInfoSettings.MachineNameAddress = currentOffset + HeaderSettings.SlicerSize;
+ SlicerInfoSettings.MachineNameAddress = HeaderSettings.SlicerOffset + HeaderSettings.SlicerSize;
+ if (HeaderSettings.Version >= 4)
+ {
+ SlicerInfoSettings.PrintParametersV4Address = (uint)(HeaderSettings.SlicerOffset +
+ Helpers.Serializer.SizeOf(SlicerInfoSettings) +
+ CTBv4_DISCLAIMER_SIZE);
+ }
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
+
+ Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
if (HeaderSettings.Version >= 4)
{
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, PrintParametersV4Settings);
+ PrintParametersV4Settings.DisclaimerAddress = (uint)outputFile.Position;
+ PrintParametersV4Settings.DisclaimerLength = (uint)CTBv4_DISCLAIMER.Length;
+ outputFile.WriteBytes(Encoding.UTF8.GetBytes(CTBv4_DISCLAIMER));
+ Helpers.SerializeWriteFileStream(outputFile, PrintParametersV4Settings);
}
}
- HeaderSettings.LayersDefinitionOffsetAddress = currentOffset;
- uint layerDataCurrentOffset = currentOffset + (uint)Helpers.Serializer.SizeOf(new LayerDef()) * HeaderSettings.LayerCount * HeaderSettings.AntiAliasLevel;
-
- progress.ItemCount *= 2 * HeaderSettings.AntiAliasLevel;
+ HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
+ uint layerDefSize = (uint)Helpers.Serializer.SizeOf(new LayerDef());
+ //uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + layerDefSize * HeaderSettings.LayerCount * HeaderSettings.AntiAliasLevel;
- for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
+ var layersHash = new Dictionary<string, LayerDef>();
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+
+ foreach (var batch in BatchLayersIndexes())
{
- progress.Token.ThrowIfCancellationRequested();
- Parallel.For(0, LayerCount, /*new ParallelOptions{MaxDegreeOfParallelism = 1},*/ layerIndex =>
+ Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- var layerDef = new LayerDef(this, this[layerIndex]);
- using (var image = this[layerIndex].LayerMat)
+ using (var mat = this[layerIndex].LayerMat)
{
- layerDef.Encode(image, aaIndex, (uint) layerIndex);
- LayerDefinitions[aaIndex, layerIndex] = layerDef;
+ for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
+ {
+ var layerDef = new LayerDef(this, this[layerIndex]);
+ layerDef.Encode(mat, aaIndex, (uint)layerIndex);
+ LayerDefinitions[aaIndex, layerIndex] = layerDef;
+ }
}
-
progress.LockAndIncrement();
});
- for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ foreach (var layerIndex in batch)
{
- progress.Token.ThrowIfCancellationRequested();
- var layerDef = LayerDefinitions[aaIndex, layerIndex];
- LayerDef layerDefHash = null;
-
- if (CanHash)
+ if (layerIndex == 0) layerDefSize = (uint)Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]);
+ for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{
- string hash = Helpers.ComputeSHA1Hash(layerDef.EncodedRle);
- if (LayersHash.TryGetValue(hash, out layerDefHash))
- {
- layerDef.DataAddress = layerDefHash.DataAddress;
- layerDef.DataSize = layerDefHash.DataSize;
- }
- else
+ progress.Token.ThrowIfCancellationRequested();
+
+ var layerDef = LayerDefinitions[aaIndex, layerIndex];
+ LayerDef layerDefHash = null;
+
+ if (CanHash)
{
- LayersHash.Add(hash, layerDef);
+ var hash = Helpers.ComputeSHA1Hash(layerDef.EncodedRle);
+ if (layersHash.TryGetValue(hash, out layerDefHash))
+ {
+ layerDef.DataAddress = layerDefHash.DataAddress;
+ layerDef.DataSize = layerDefHash.DataSize;
+ }
+ else
+ {
+ layersHash.Add(hash, layerDef);
+ }
}
- }
-
- if (layerDefHash is null)
- {
- layerDef.DataAddress = layerDataCurrentOffset;
- outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
- if (HeaderSettings.Version >= 3)
+ if (layerDefHash is null)
{
- var layerDataEx = new LayerDefEx(layerDef, this[layerIndex]);
- layerDataCurrentOffset += (uint)Helpers.Serializer.SizeOf(layerDataEx);
layerDef.DataAddress = layerDataCurrentOffset;
- Helpers.SerializeWriteFileStream(outputFile, layerDataEx);
+ outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
+
+ if (HeaderSettings.Version >= 3)
+ {
+ var layerDataEx = new LayerDefEx(layerDef, this[layerIndex]);
+ layerDataCurrentOffset += (uint)Helpers.Serializer.SizeOf(layerDataEx);
+ layerDef.DataAddress = layerDataCurrentOffset;
+ Helpers.SerializeWriteFileStream(outputFile, layerDataEx);
+ }
+
+ layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle);
}
- layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle);
- }
-
- outputFile.Seek(currentOffset, SeekOrigin.Begin);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerDef);
+ outputFile.Seek(HeaderSettings.LayersDefinitionOffsetAddress +
+ aaIndex * HeaderSettings.LayerCount * layerDefSize +
+ layerDefSize * layerIndex
+ , SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, layerDef);
- progress++;
+ layerDef.EncodedRle = null; // Free this
+ }
}
}
+
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
@@ -1928,7 +1983,7 @@ namespace UVtools.Core.FileFormats
inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
byte[] rawImageData = new byte[Previews[i].ImageLength];
inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength);
-
+
Thumbnails[i] = Previews[i].Decode(rawImageData);
progress++;
}
@@ -1959,13 +2014,29 @@ namespace UVtools.Core.FileFormats
if (HeaderSettings.Version >= 4)
{
+ if (SlicerInfoSettings.PrintParametersV4Address == 0)
+ {
+ throw new FileLoadException(
+ $"Malformed file, PrintParametersV4Address is missing",
+ fileFullPath);
+ }
+
+ inputFile.Seek(SlicerInfoSettings.PrintParametersV4Address, SeekOrigin.Begin);
PrintParametersV4Settings = Helpers.Deserialize<PrintParametersV4>(inputFile);
Debug.Write("Print Parameters V4 -> ");
Debug.WriteLine(PrintParametersV4Settings);
+
+ if (PrintParametersV4Settings.Four1 != 4 && PrintParametersV4Settings.Four2 != 4)
+ {
+ throw new FileLoadException(
+ $"Malformed file, PrintParametersV4 found invalid validation values, expected (4, 4) " +
+ $"but got ({PrintParametersV4Settings.Four1}, {PrintParametersV4Settings.Four2})",
+ fileFullPath);
+ }
}
LayerDefinitions = new LayerDef[HeaderSettings.AntiAliasLevel, HeaderSettings.LayerCount];
- var LayerDefinitionsEx = HeaderSettings.Version >= 3 ? new LayerDefEx[HeaderSettings.LayerCount] : null;
+ var layerDefinitionsEx = HeaderSettings.Version >= 3 ? new LayerDefEx[HeaderSettings.LayerCount] : null;
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
@@ -1977,35 +2048,31 @@ namespace UVtools.Core.FileFormats
Debug.WriteLine($"-Image GROUP {aaIndex}-");
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
+ progress.Token.ThrowIfCancellationRequested();
inputFile.Seek(layerOffset, SeekOrigin.Begin);
- LayerDef layerDef = Helpers.Deserialize<LayerDef>(inputFile);
+ var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
layerDef.Parent = this;
LayerDefinitions[aaIndex, layerIndex] = layerDef;
+ LayerDefinitions[aaIndex, layerIndex].Parent = this;
layerOffset += (uint) Helpers.Serializer.SizeOf(layerDef);
Debug.Write($"LAYER {layerIndex} -> ");
Debug.WriteLine(layerDef);
- layerDef.EncodedRle = new byte[layerDef.DataSize];
+ //layerDef.EncodedRle = new byte[layerDef.DataSize];
-
- if (HeaderSettings.Version < 3)
+ if (HeaderSettings.Version >= 3)
{
- inputFile.Seek(layerDef.DataAddress, SeekOrigin.Begin);
- }
- else
- {
- inputFile.Seek(layerDef.DataAddress - 84, SeekOrigin.Begin);
- LayerDefinitionsEx[layerIndex] = Helpers.Deserialize<LayerDefEx>(inputFile);
- Debug.Write($"LAYER {layerIndex} -> ");
- Debug.WriteLine(LayerDefinitionsEx[layerIndex]);
+ inputFile.SeekDoWorkAndRewind(layerDef.DataAddress - 84, () =>
+ {
+ layerDefinitionsEx[layerIndex] = Helpers.Deserialize<LayerDefEx>(inputFile);
+ layerDefinitionsEx[layerIndex].LayerDef.Parent = this;
+ Debug.Write($"LAYER {layerIndex} -> ");
+ Debug.WriteLine(layerDefinitionsEx[layerIndex]);
+ });
}
-
- inputFile.Read(layerDef.EncodedRle, 0, (int) layerDef.DataSize);
-
progress++;
- progress.Token.ThrowIfCancellationRequested();
}
}
@@ -2013,46 +2080,40 @@ namespace UVtools.Core.FileFormats
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
- Parallel.For(0, LayerCount, layerIndex =>
- //for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ foreach (var batch in BatchLayersIndexes())
{
- if (progress.Token.IsCancellationRequested)
- {
- return;
- }
-
- using var image = LayerDefinitions[0, layerIndex].Decode((uint) layerIndex);
- var layer = new Layer((uint) layerIndex, image, LayerManager)
- {
- PositionZ = LayerDefinitions[0, layerIndex].LayerPositionZ,
- ExposureTime = LayerDefinitions[0, layerIndex].LayerExposure,
- LightOffDelay = LayerDefinitions[0, layerIndex].LightOffSeconds,
- };
-
- if (LayerDefinitionsEx is not null)
+ foreach (var layerIndex in batch)
{
- layer.LiftHeight = LayerDefinitionsEx[layerIndex].LiftHeight;
- layer.LiftSpeed = LayerDefinitionsEx[layerIndex].LiftSpeed;
- layer.RetractSpeed = LayerDefinitionsEx[layerIndex].RetractSpeed;
- layer.LightPWM = (byte) LayerDefinitionsEx[layerIndex].LightPWM;
-
- if (HeaderSettings.Version >= 4)
+ for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
{
- layer.LiftHeight2 = LayerDefinitionsEx[layerIndex].LiftHeight2;
- layer.LiftSpeed2 = LayerDefinitionsEx[layerIndex].LiftSpeed2;
- layer.RetractHeight2 = LayerDefinitionsEx[layerIndex].RetractHeight2;
- layer.RetractSpeed2 = LayerDefinitionsEx[layerIndex].RetractSpeed2;
- layer.WaitTimeBeforeCure = LayerDefinitionsEx[layerIndex].RestTimeAfterRetract;
- layer.WaitTimeAfterCure = LayerDefinitionsEx[layerIndex].RestTimeBeforeLift;
- layer.WaitTimeAfterLift = LayerDefinitionsEx[layerIndex].RestTimeAfterLift;
+ progress.Token.ThrowIfCancellationRequested();
+
+ inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
+ LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize);
}
}
- this[layerIndex] = layer;
+ Parallel.ForEach(batch, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = LayerDefinitions[0, layerIndex].Decode((uint)layerIndex))
+ {
+ var layer = new Layer((uint)layerIndex, mat, this);
+ if (layerDefinitionsEx is not null) // CTBv4
+ {
+ layerDefinitionsEx[layerIndex].CopyTo(layer);
+ }
+ else // others
+ {
+ LayerDefinitions[0, layerIndex].CopyTo(layer);
+ }
+ this[layerIndex] = layer;
+ }
- progress.LockAndIncrement();
- });
+ progress.LockAndIncrement();
+ });
+ }
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
@@ -2092,7 +2153,7 @@ namespace UVtools.Core.FileFormats
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
var layer = this[layerIndex];
- LayerDefinitions[aaIndex, layerIndex].RefreshLayerData(layer);
+ LayerDefinitions[aaIndex, layerIndex].SetFrom(layer);
outputFile.Seek(layerOffset, SeekOrigin.Begin);
layerOffset += Helpers.SerializeWriteFileStream(outputFile, LayerDefinitions[aaIndex, layerIndex]);
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index cc1da56..3982e02 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -8,6 +8,7 @@
using System;
using System.ComponentModel;
+using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
@@ -197,11 +198,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => HeaderSettings.AntiAliasing;
- set
- {
- HeaderSettings.AntiAliasing = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
+ set => base.AntiAliasing = HeaderSettings.AntiAliasing = value.Clamp(1, 16);
}
public override float LayerHeight
@@ -367,6 +364,7 @@ namespace UVtools.Core.FileFormats
public bool IsPHZZip;
#endregion
+ #region Constructor
public ChituboxZipFile()
{
GCode = new GCodeBuilder
@@ -380,9 +378,28 @@ namespace UVtools.Core.FileFormats
EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1
};
}
+ #endregion
#region Methods
+ public override bool CanProcess(string fileFullPath)
+ {
+ if (!base.CanProcess(fileFullPath)) return false;
+
+ try
+ {
+ var zip = ZipFile.Open(fileFullPath, ZipArchiveMode.Read);
+ if (zip.Entries.Any(entry => entry.Name.EndsWith(".gcode"))) return true;
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ }
+
+
+ return false;
+ }
+
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs
index b67cc0e..2f02dc4 100644
--- a/UVtools.Core/FileFormats/FDGFile.cs
+++ b/UVtools.Core/FileFormats/FDGFile.cs
@@ -405,7 +405,7 @@ namespace UVtools.Core.FileFormats
#endregion
#region Layer
- public class LayerData
+ public class LayerDef
{
/// <summary>
/// Gets the build platform Z position for this layer, measured in millimeters.
@@ -440,21 +440,28 @@ namespace UVtools.Core.FileFormats
[Ignore] public FDGFile Parent { get; set; }
- public LayerData()
+ public LayerDef()
{
}
- public LayerData(FDGFile parent, uint layerIndex)
+ public LayerDef(FDGFile parent, Layer layer)
{
Parent = parent;
- RefreshLayerData(layerIndex);
+ SetFrom(layer);
}
- public void RefreshLayerData(uint layerIndex)
+ public void SetFrom(Layer layer)
{
- LayerPositionZ = Parent[layerIndex].PositionZ;
- LayerExposure = Parent[layerIndex].ExposureTime;
- LightOffDelay = Parent[layerIndex].LightOffDelay;
+ LayerPositionZ = layer.PositionZ;
+ LayerExposure = layer.ExposureTime;
+ LightOffDelay = layer.LightOffDelay;
+ }
+
+ public void CopyTo(Layer layer)
+ {
+ layer.PositionZ = LayerPositionZ;
+ layer.ExposureTime = LayerExposure;
+ layer.LightOffDelay = LightOffDelay;
}
public unsafe Mat Decode(uint layerIndex, bool consumeData = true)
@@ -522,7 +529,7 @@ namespace UVtools.Core.FileFormats
return image;
}
- public void Encode(Mat image, uint layerIndex)
+ public void Encode(Mat mat, uint layerIndex)
{
List<byte> rawData = new();
@@ -550,12 +557,12 @@ namespace UVtools.Core.FileFormats
}
}
- int halfWidth = image.Width / 2;
+ int halfWidth = mat.Width / 2;
//int pixel = 0;
- for (int y = 0; y < image.Height; y++)
+ for (int y = 0; y < mat.Height; y++)
{
- var span = image.GetRowSpan<byte>(y);
+ var span = mat.GetRowSpan<byte>(y);
for (int x = 0; x < span.Length; x++)
{
@@ -589,7 +596,7 @@ namespace UVtools.Core.FileFormats
if (Parent.HeaderSettings.EncryptionKey > 0)
{
- KeyRing kr = new(Parent.HeaderSettings.EncryptionKey, layerIndex);
+ var kr = new KeyRing(Parent.HeaderSettings.EncryptionKey, layerIndex);
EncodedRle = kr.Read(rawData).ToArray();
}
else
@@ -664,9 +671,7 @@ namespace UVtools.Core.FileFormats
public Preview[] Previews { get; protected internal set; }
- public LayerData[] LayersDefinitions { get; private set; }
-
- public Dictionary<string, LayerData> LayersHash { get; } = new();
+ public LayerDef[] LayersDefinitions { get; private set; }
public override FileFormatType FileType => FileFormatType.Binary;
@@ -764,11 +769,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => (byte) HeaderSettings.AntiAliasLevelInfo;
- set
- {
- HeaderSettings.AntiAliasLevelInfo = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
+ set => base.AntiAliasing = (byte)(HeaderSettings.AntiAliasLevelInfo = value.Clamp(1, 16));
}
public override float LayerHeight
@@ -955,221 +956,201 @@ namespace UVtools.Core.FileFormats
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
- LayersHash.Clear();
-
/*if (HeaderSettings.EncryptionKey == 0)
{
Random rnd = new Random();
HeaderSettings.EncryptionKey = (uint)rnd.Next(short.MaxValue, int.MaxValue);
}*/
- uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
- LayersDefinitions = new LayerData[HeaderSettings.LayerCount];
- using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
- {
- outputFile.Seek((int) currentOffset, SeekOrigin.Begin);
+ using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
+ outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
- for (byte i = 0; i < ThumbnailsCount; i++)
- {
- var image = Thumbnails[i];
+ for (byte i = 0; i < ThumbnailsCount; i++)
+ {
+ var image = Thumbnails[i];
- var bytes = Preview.Encode(image);
+ var bytes = Preview.Encode(image);
- if (bytes.Length == 0) continue;
+ if (bytes.Length == 0) continue;
- if (i == (byte) FileThumbnailSize.Small)
- {
- HeaderSettings.PreviewSmallOffsetAddress = currentOffset;
- }
- else
- {
- HeaderSettings.PreviewLargeOffsetAddress = currentOffset;
- }
+ if (i == (byte) FileThumbnailSize.Small)
+ {
+ HeaderSettings.PreviewSmallOffsetAddress = (uint)outputFile.Position;
+ }
+ else
+ {
+ HeaderSettings.PreviewLargeOffsetAddress = (uint)outputFile.Position;
+ }
- Preview preview = new()
- {
- ResolutionX = (uint) image.Width,
- ResolutionY = (uint) image.Height,
- ImageLength = (uint)bytes.Length,
- };
+ Preview preview = new()
+ {
+ ResolutionX = (uint) image.Width,
+ ResolutionY = (uint) image.Height,
+ ImageLength = (uint)bytes.Length,
+ };
- currentOffset += (uint) Helpers.Serializer.SizeOf(preview);
- preview.ImageOffset = currentOffset;
+ preview.ImageOffset = (uint)(outputFile.Position + Helpers.Serializer.SizeOf(preview));
- Helpers.SerializeWriteFileStream(outputFile, preview);
+ Helpers.SerializeWriteFileStream(outputFile, preview);
- currentOffset += (uint)bytes.Length;
- outputFile.WriteBytes(bytes);
- }
+ outputFile.WriteBytes(bytes);
+ }
- if (HeaderSettings.MachineNameSize > 0)
- {
- HeaderSettings.MachineNameAddress = currentOffset;
- var machineBytes = Encoding.ASCII.GetBytes(HeaderSettings.MachineName);
- outputFile.Write(machineBytes, 0, machineBytes.Length);
- currentOffset += (uint)machineBytes.Length;
- }
+ if (HeaderSettings.MachineNameSize > 0)
+ {
+ HeaderSettings.MachineNameAddress = (uint)outputFile.Position;
+ var machineBytes = Encoding.ASCII.GetBytes(HeaderSettings.MachineName);
+ outputFile.Write(machineBytes, 0, machineBytes.Length);
+ }
+
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ var layersHash = new Dictionary<string, LayerDef>();
+ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
+ HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
+ uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + (uint)Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
- Parallel.For(0, LayerCount, /*new ParallelOptions{MaxDegreeOfParallelism = 1},*/ layerIndex =>
+ foreach (var batch in BatchLayersIndexes())
+ {
+ Parallel.ForEach(batch, layerIndex =>
{
- if(progress.Token.IsCancellationRequested) return;
- LayerData layer = new(this, (uint) layerIndex);
- using (var image = this[layerIndex].LayerMat)
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
{
- layer.Encode(image, (uint) layerIndex);
- LayersDefinitions[layerIndex] = layer;
+ LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
+ LayersDefinitions[layerIndex].Encode(mat, (uint)layerIndex);
}
-
progress.LockAndIncrement();
});
- progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
-
- HeaderSettings.LayersDefinitionOffsetAddress = currentOffset;
- uint layerDataCurrentOffset = currentOffset + (uint) Helpers.Serializer.SizeOf(LayersDefinitions[0]) * LayerCount;
- for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ foreach (var layerIndex in batch)
{
progress.Token.ThrowIfCancellationRequested();
- LayerData layerData = LayersDefinitions[layerIndex];
- LayerData layerDataHash = null;
+
+ var layerDef = LayersDefinitions[layerIndex];
+ LayerDef layerDefHash = null;
if (HeaderSettings.EncryptionKey == 0)
{
- string hash = Helpers.ComputeSHA1Hash(layerData.EncodedRle);
- if (LayersHash.TryGetValue(hash, out layerDataHash))
+ string hash = Helpers.ComputeSHA1Hash(layerDef.EncodedRle);
+ if (layersHash.TryGetValue(hash, out layerDefHash))
{
- layerData.DataAddress = layerDataHash.DataAddress;
- layerData.DataSize = layerDataHash.DataSize;
+ layerDef.DataAddress = layerDefHash.DataAddress;
+ layerDef.DataSize = layerDefHash.DataSize;
}
else
{
- LayersHash.Add(hash, layerData);
+ layersHash.Add(hash, layerDef);
}
}
- if (ReferenceEquals(layerDataHash, null))
+ if (layerDefHash is null)
{
- layerData.DataAddress = layerDataCurrentOffset;
+ layerDef.DataAddress = layerDataCurrentOffset;
outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
- layerDataCurrentOffset += outputFile.WriteBytes(layerData.EncodedRle);
+ layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle);
}
- LayersDefinitions[layerIndex] = layerData;
+ outputFile.Seek(layerDefCurrentOffset, SeekOrigin.Begin);
+ layerDefCurrentOffset += Helpers.SerializeWriteFileStream(outputFile, layerDef);
- outputFile.Seek(currentOffset, SeekOrigin.Begin);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData);
- progress++;
+ layerDef.EncodedRle = null; // Free
}
+ }
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- Debug.WriteLine("Encode Results:");
- Debug.WriteLine(HeaderSettings);
- Debug.WriteLine(Previews[0]);
- Debug.WriteLine(Previews[1]);
- Debug.WriteLine("-End-");
- }
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+
+ Debug.WriteLine("Encode Results:");
+ Debug.WriteLine(HeaderSettings);
+ Debug.WriteLine(Previews[0]);
+ Debug.WriteLine(Previews[1]);
+ Debug.WriteLine("-End-");
}
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
- using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
+ using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read);
+ //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
+ //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header))));
+ HeaderSettings = Helpers.Deserialize<Header>(inputFile);
+ if (HeaderSettings.Magic != MAGIC)
{
+ throw new FileLoadException("Not a valid FDG file!", fileFullPath);
+ }
- //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
- //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header))));
- HeaderSettings = Helpers.Deserialize<Header>(inputFile);
- if (HeaderSettings.Magic != MAGIC)
- {
- throw new FileLoadException("Not a valid FDG file!", fileFullPath);
- }
-
- HeaderSettings.AntiAliasLevel = 1;
-
- FileFullPath = fileFullPath;
-
-
- progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount);
- Debug.Write("Header -> ");
- Debug.WriteLine(HeaderSettings);
-
- for (byte i = 0; i < ThumbnailsCount; i++)
- {
- uint offsetAddress = i == 0
- ? HeaderSettings.PreviewSmallOffsetAddress
- : HeaderSettings.PreviewLargeOffsetAddress;
- if (offsetAddress == 0) continue;
+ HeaderSettings.AntiAliasLevel = 1;
- inputFile.Seek(offsetAddress, SeekOrigin.Begin);
- Previews[i] = Helpers.Deserialize<Preview>(inputFile);
+ FileFullPath = fileFullPath;
- Debug.Write($"Preview {i} -> ");
- Debug.WriteLine(Previews[i]);
- inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
- byte[] rawImageData = new byte[Previews[i].ImageLength];
- inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength);
+ progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount);
+ Debug.Write("Header -> ");
+ Debug.WriteLine(HeaderSettings);
- Thumbnails[i] = Previews[i].Decode(rawImageData);
- progress++;
- }
+ for (byte i = 0; i < ThumbnailsCount; i++)
+ {
+ uint offsetAddress = i == 0
+ ? HeaderSettings.PreviewSmallOffsetAddress
+ : HeaderSettings.PreviewLargeOffsetAddress;
+ if (offsetAddress == 0) continue;
- if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
- {
- inputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
- byte[] buffer = new byte[HeaderSettings.MachineNameSize];
- inputFile.Read(buffer, 0, (int) HeaderSettings.MachineNameSize);
- HeaderSettings.MachineName = Encoding.ASCII.GetString(buffer);
- }
+ inputFile.Seek(offsetAddress, SeekOrigin.Begin);
+ Previews[i] = Helpers.Deserialize<Preview>(inputFile);
+ Debug.Write($"Preview {i} -> ");
+ Debug.WriteLine(Previews[i]);
- LayersDefinitions = new LayerData[HeaderSettings.LayerCount];
+ inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
+ byte[] rawImageData = new byte[Previews[i].ImageLength];
+ inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength);
- uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ Thumbnails[i] = Previews[i].Decode(rawImageData);
+ progress++;
+ }
- progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.LayerCount);
+ if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
+ {
+ inputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
+ var buffer = new byte[HeaderSettings.MachineNameSize];
+ inputFile.Read(buffer, 0, (int) HeaderSettings.MachineNameSize);
+ HeaderSettings.MachineName = Encoding.ASCII.GetString(buffer);
+ }
- for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
+ LayerManager.Init(HeaderSettings.LayerCount);
+ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
+
+ progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
+ foreach (var batch in BatchLayersIndexes())
+ {
+ foreach (var layerIndex in batch)
{
- inputFile.Seek(layerOffset, SeekOrigin.Begin);
- LayerData layerData = Helpers.Deserialize<LayerData>(inputFile);
- layerData.Parent = this;
- LayersDefinitions[layerIndex] = layerData;
+ progress.Token.ThrowIfCancellationRequested();
- layerOffset += (uint) Helpers.Serializer.SizeOf(layerData);
+ var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
+ layerDef.Parent = this;
+ LayersDefinitions[layerIndex] = layerDef;
+
Debug.Write($"LAYER {layerIndex} -> ");
- Debug.WriteLine(layerData);
+ Debug.WriteLine(layerDef);
- layerData.EncodedRle = new byte[layerData.DataSize];
- inputFile.Seek(layerData.DataAddress, SeekOrigin.Begin);
- inputFile.Read(layerData.EncodedRle, 0, (int) layerData.DataSize);
-
- progress++;
- progress.Token.ThrowIfCancellationRequested();
+ inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, () =>
+ {
+ layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize);
+ });
}
- LayerManager.Init(HeaderSettings.LayerCount);
-
- progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
-
- Parallel.For(0, LayerCount, layerIndex =>
+ Parallel.ForEach(batch, layerIndex =>
{
- if (progress.Token.IsCancellationRequested)
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex))
{
- return;
- }
-
- using (var image = LayersDefinitions[layerIndex].Decode((uint) layerIndex, true))
- {
- this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager)
- {
- PositionZ = LayersDefinitions[layerIndex].LayerPositionZ,
- ExposureTime = LayersDefinitions[layerIndex].LayerExposure,
- LightOffDelay = LayersDefinitions[layerIndex].LightOffDelay,
- };
+ var layer = new Layer((uint)layerIndex, mat, this);
+ LayersDefinitions[layerIndex].CopyTo(layer);
+ this[layerIndex] = layer;
}
progress.LockAndIncrement();
@@ -1195,26 +1176,24 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
- using (var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write))
- {
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+ using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- /*if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
+ /*if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
{
outputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
byte[] buffer = new byte[HeaderSettings.MachineNameSize];
outputFile.Write(Encoding.ASCII.GetBytes(HeaderSettings.MachineName), 0, (int)HeaderSettings.MachineNameSize);
}*/
- uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
- for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
- {
- LayersDefinitions[layerIndex].RefreshLayerData(layerIndex);
- outputFile.Seek(layerOffset, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex]);
- layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
- }
+ uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
+ {
+ LayersDefinitions[layerIndex].SetFrom(this[layerIndex]);
+ outputFile.Seek(layerOffset, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex]);
+ layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
}
}
diff --git a/UVtools.Core/FileFormats/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs
index 693a450..b83ad9f 100644
--- a/UVtools.Core/FileFormats/FileExtension.cs
+++ b/UVtools.Core/FileFormats/FileExtension.cs
@@ -32,7 +32,15 @@ namespace UVtools.Core.FileFormats
/// </summary>
public string Description { get; }
- public bool IsVisible { get; }
+ /// <summary>
+ /// Gets if the extension shows up on open file dialog filters
+ /// </summary>
+ public bool IsVisibleOnFileFilters { get; }
+
+ /// <summary>
+ /// Gets if the extension shows up on convert to menu
+ /// </summary>
+ public bool IsVisibleOnConvertMenu { get; }
/// <summary>
/// Gets a tag object
@@ -53,14 +61,16 @@ namespace UVtools.Core.FileFormats
/// <param name="fileFormatType">The exact <see cref="FileFormat"/> type</param>
/// <param name="extension">The extension name without the dot (.)</param>
/// <param name="description">The extension description</param>
- /// <param name="isVisible">True if this extension is visible on open dialog filters</param>
+ /// <param name="isVisibleOnFileFilters">True if this extension is visible on open file dialog filters</param>
+ /// <param name="isVisibleOnConvertMenu">True if this extension is visible on convert to menu</param>
/// <param name="tag">Tag object</param>
- public FileExtension(Type fileFormatType, string extension, string description, bool isVisible = true, object tag = null)
+ public FileExtension(Type fileFormatType, string extension, string description, bool isVisibleOnFileFilters = true, bool isVisibleOnConvertMenu = true, object tag = null)
{
FileFormatType = fileFormatType;
Extension = extension;
Description = description;
- IsVisible = isVisible;
+ IsVisibleOnFileFilters = isVisibleOnFileFilters;
+ IsVisibleOnConvertMenu = isVisibleOnConvertMenu;
Tag = tag;
}
#endregion
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index b528ccc..b0eaa67 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -73,6 +73,31 @@ namespace UVtools.Core.FileFormats
public const float MaximumLayerHeight = 0.20f;
private const ushort QueueTimerPrintTime = 250; // ms
+
+ public const string DATATYPE_PNG = "PNG";
+ public const string DATATYPE_JPG = "JPG";
+ public const string DATATYPE_JPEG = "JPEG";
+ public const string DATATYPE_JP2 = "JP2";
+ public const string DATATYPE_BMP = "BMP";
+ public const string DATATYPE_TIF = "TIF";
+ public const string DATATYPE_TIFF = "TIFF";
+ public const string DATATYPE_PPM = "PPM";
+ public const string DATATYPE_PMG = "PMG";
+ public const string DATATYPE_SR = "SR";
+ public const string DATATYPE_RAS = "RAS";
+
+ public const string DATATYPE_RGB555 = "RGB555";
+ public const string DATATYPE_RGB565 = "RGB565";
+ public const string DATATYPE_RGB555_BE = "RGB555-BE";
+ public const string DATATYPE_RGB565_BE = "RGB565-BE";
+ public const string DATATYPE_RGB888 = "RGB888";
+
+
+ public const string DATATYPE_BGR555 = "BGR555";
+ public const string DATATYPE_BGR565 = "BGR565";
+ public const string DATATYPE_BGR555_BE = "BGR555-BE";
+ public const string DATATYPE_BGR565_BE = "BGR565-BE";
+ public const string DATATYPE_BGR888 = "BGR888";
#endregion
#region Enums
@@ -299,6 +324,7 @@ namespace UVtools.Core.FileFormats
{
foreach (var fileExtension in AvailableFormats[i].FileExtensions)
{
+ if(!fileExtension.IsVisibleOnFileFilters) continue;
result[0].Value.Add(fileExtension.Extension);
result.Add(new KeyValuePair<string, List<string>>(fileExtension.Description, new List<string>
{
@@ -410,12 +436,260 @@ namespace UVtools.Core.FileFormats
//if (file.EndsWith(TemporaryFileAppend)) file = Path.GetFileNameWithoutExtension(file);
return PathExtensions.GetFileNameStripExtensions(filepath, AllFileExtensionsString.OrderByDescending(s => s.Length).ToList(), out strippedExtension);
}
+
+
+ public static byte[] EncodeImage(string dataType, Mat mat)
+ {
+ dataType = dataType.ToUpperInvariant();
+ if (dataType
+ is DATATYPE_PNG
+ or DATATYPE_JPG
+ or DATATYPE_JPEG
+ or DATATYPE_JP2
+ or DATATYPE_BMP
+ or DATATYPE_TIF
+ or DATATYPE_TIFF
+ or DATATYPE_PPM
+ or DATATYPE_PMG
+ or DATATYPE_SR
+ or DATATYPE_RAS
+ )
+ {
+ return CvInvoke.Imencode($".{dataType.ToLowerInvariant()}", mat);
+ }
+
+ if (dataType
+ is DATATYPE_RGB555
+ or DATATYPE_RGB565
+ or DATATYPE_RGB555_BE
+ or DATATYPE_RGB565_BE
+ or DATATYPE_RGB888
+
+ or DATATYPE_BGR555
+ or DATATYPE_BGR565
+ or DATATYPE_BGR555_BE
+ or DATATYPE_BGR565_BE
+ or DATATYPE_BGR888
+ )
+ {
+ var bytesPerPixel = dataType is "RGB888" or "BGR888" ? 3 : 2;
+ var bytes = new byte[mat.Width * mat.Height * bytesPerPixel];
+ uint index = 0;
+ var span = mat.GetDataByteSpan();
+ for (int i = 0; i < span.Length;)
+ {
+ byte b = span[i++];
+ byte g;
+ byte r;
+
+ if (mat.NumberOfChannels == 1) // 8 bit safe-guard
+ {
+ r = g = b;
+ }
+ else
+ {
+ g = span[i++];
+ r = span[i++];
+ }
+
+ if (mat.NumberOfChannels == 4) i++; // skip alpha
+
+ switch (dataType)
+ {
+ case DATATYPE_RGB555:
+ var rgb555 = (ushort)(((r & 0b11111000) << 7) | ((g & 0b11111000) << 2) | (b >> 3));
+ BitExtensions.ToBytesLittleEndian(rgb555, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_RGB565:
+ var rgb565 = (ushort)(((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3));
+ BitExtensions.ToBytesLittleEndian(rgb565, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_RGB555_BE:
+ var rgb555Be = (ushort)(((r & 0b11111000) << 7) | ((g & 0b11111000) << 2) | (b >> 3));
+ BitExtensions.ToBytesBigEndian(rgb555Be, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_RGB565_BE:
+ var rgb565Be = (ushort)(((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3));
+ BitExtensions.ToBytesBigEndian(rgb565Be, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_RGB888:
+ bytes[index++] = r;
+ bytes[index++] = g;
+ bytes[index++] = b;
+ break;
+ case DATATYPE_BGR555:
+ var bgr555 = (ushort)(((b & 0b11111000) << 7) | ((g & 0b11111000) << 2) | (r >> 3));
+ BitExtensions.ToBytesLittleEndian(bgr555, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_BGR565:
+ var bgr565 = (ushort)(((b & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (r >> 3));
+ BitExtensions.ToBytesLittleEndian(bgr565, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_BGR555_BE:
+ var bgr555Be = (ushort)(((b & 0b11111000) << 7) | ((g & 0b11111000) << 2) | (r >> 3));
+ BitExtensions.ToBytesBigEndian(bgr555Be, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_BGR565_BE:
+ var bgr565Be = (ushort)(((b & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (r >> 3));
+ BitExtensions.ToBytesBigEndian(bgr565Be, bytes, index);
+ index += 2;
+ break;
+ case DATATYPE_BGR888:
+ bytes[index++] = b;
+ bytes[index++] = g;
+ bytes[index++] = r;
+ break;
+ }
+ }
+
+ return bytes;
+ }
+
+ throw new NotSupportedException($"The encode type: {dataType} is not supported.");
+ }
+
+ public static Mat DecodeImage(string dataType, byte[] bytes, Size resolution)
+ {
+ if (dataType
+ is DATATYPE_PNG
+ or DATATYPE_JPG
+ or DATATYPE_JPEG
+ or DATATYPE_JP2
+ or DATATYPE_BMP
+ or DATATYPE_TIF
+ or DATATYPE_TIFF
+ or DATATYPE_PPM
+ or DATATYPE_PMG
+ or DATATYPE_SR
+ or DATATYPE_RAS
+ )
+ {
+ var mat = new Mat();
+ CvInvoke.Imdecode(bytes, ImreadModes.AnyColor, mat);
+ return mat;
+ }
+
+ if (dataType
+ is DATATYPE_RGB555
+ or DATATYPE_RGB565
+ or DATATYPE_RGB555_BE
+ or DATATYPE_RGB565_BE
+ or DATATYPE_RGB888
+
+ or DATATYPE_BGR555
+ or DATATYPE_BGR565
+ or DATATYPE_BGR555_BE
+ or DATATYPE_BGR565_BE
+ or DATATYPE_BGR888
+ )
+ {
+ var mat = new Mat(resolution, DepthType.Cv8U, 3);
+ var span = mat.GetDataByteSpan();
+ var pixel = 0;
+ for (int i = 0; i < bytes.Length;)
+ {
+ switch (dataType)
+ {
+ case DATATYPE_RGB555:
+ ushort rgb555 = BitExtensions.ToUShortLittleEndian(bytes, i);
+ // 0b0rrrrrgggggbbbbb
+ span[pixel++] = (byte)((rgb555 & 0b00000000_00011111) << 3); // b
+ span[pixel++] = (byte)((rgb555 & 0b00000011_11100000) >> 2); // g
+ span[pixel++] = (byte)((rgb555 & 0b01111100_00000000) >> 7); // r
+ /*span[pixel++] = (byte)((rgb555 << 3) & 0b11111000); // b
+ span[pixel++] = (byte)((rgb555 >> 2) & 0b11111000); // g
+ span[pixel++] = (byte)((rgb555 >> 7) & 0b11111000); // r*/
+ i += 2;
+ break;
+ case DATATYPE_RGB565:
+ // 0brrrrrggggggbbbbb
+ ushort rgb565 = BitExtensions.ToUShortLittleEndian(bytes, i);
+ span[pixel++] = (byte)((rgb565 & 0b00000000_00011111) << 3); // b
+ span[pixel++] = (byte)((rgb565 & 0b00000111_11100000) >> 3); // g
+ span[pixel++] = (byte)((rgb565 & 0b11111000_00000000) >> 8); // r
+ i += 2;
+ break;
+ case DATATYPE_RGB555_BE:
+ ushort rgb555Be = BitExtensions.ToUShortBigEndian(bytes, i);
+ span[pixel++] = (byte)((rgb555Be & 0b00000000_00011111) << 3); // b
+ span[pixel++] = (byte)((rgb555Be & 0b00000011_11100000) >> 2); // g
+ span[pixel++] = (byte)((rgb555Be & 0b01111100_00000000) >> 7); // r
+ i += 2;
+ break;
+ case DATATYPE_RGB565_BE:
+ ushort rgb565Be = BitExtensions.ToUShortBigEndian(bytes, i);
+ span[pixel++] = (byte)((rgb565Be & 0b00000000_00011111) << 3); // b
+ span[pixel++] = (byte)((rgb565Be & 0b00000111_11100000) >> 3); // g
+ span[pixel++] = (byte)((rgb565Be & 0b11111000_00000000) >> 8); // r
+ i += 2;
+ break;
+ case DATATYPE_RGB888:
+ span[pixel++] = bytes[i + 2]; // b
+ span[pixel++] = bytes[i + 1]; // g
+ span[pixel++] = bytes[i]; // r
+ i += 3;
+ break;
+ case DATATYPE_BGR555:
+ ushort bgr555 = BitExtensions.ToUShortLittleEndian(bytes, i);
+ span[pixel++] = (byte)((bgr555 & 0b01111100_00000000) >> 7); // b
+ span[pixel++] = (byte)((bgr555 & 0b00000011_11100000) >> 2); // g
+ span[pixel++] = (byte)((bgr555 & 0b00000000_00011111) << 3); // r
+ i += 2;
+ break;
+ case DATATYPE_BGR565:
+ ushort bgr565 = BitExtensions.ToUShortLittleEndian(bytes, i);
+ span[pixel++] = (byte)((bgr565 & 0b11111000_00000000) >> 8); // b
+ span[pixel++] = (byte)((bgr565 & 0b00000111_11100000) >> 3); // g
+ span[pixel++] = (byte)((bgr565 & 0b00000000_00011111) << 3); // r
+ i += 2;
+ break;
+ case DATATYPE_BGR555_BE:
+ ushort bgr555Be = BitExtensions.ToUShortBigEndian(bytes, i);
+ span[pixel++] = (byte)((bgr555Be & 0b01111100_00000000) >> 7); // b
+ span[pixel++] = (byte)((bgr555Be & 0b00000011_11100000) >> 2); // g
+ span[pixel++] = (byte)((bgr555Be & 0b00000000_00011111) << 3); // r
+ i += 2;
+ break;
+ case DATATYPE_BGR565_BE:
+ ushort bgr565Be = BitExtensions.ToUShortBigEndian(bytes, i);
+ span[pixel++] = (byte)((bgr565Be & 0b11111000_00000000) >> 8); // b
+ span[pixel++] = (byte)((bgr565Be & 0b00000111_11100000) >> 3); // g
+ span[pixel++] = (byte)((bgr565Be & 0b00000000_00011111) << 3); // r
+ i += 2;
+ break;
+ case DATATYPE_BGR888:
+ span[pixel++] = bytes[i]; // b
+ span[pixel++] = bytes[i + 1]; // g
+ span[pixel++] = bytes[i + 2]; // r
+ i += 3;
+ break;
+ }
+ }
+ return mat;
+ }
+
+ throw new NotSupportedException($"The decode type: {dataType} is not supported.");
+ }
+
+ public static Mat DecodeImage(string dataType, byte[] bytes, uint resolutionX = 0, uint resolutionY = 0)
+ => DecodeImage(dataType, bytes, new Size((int)resolutionX, (int)resolutionY));
#endregion
#region Members
+ public object Mutex = new();
+
private bool _haveModifiedLayers;
private LayerManager _layerManager;
+ private byte _antiAliasing = 1;
+
private ushort _bottomLayerCount = DefaultBottomLayerCount;
private float _bottomLightOffDelay;
@@ -468,8 +742,6 @@ namespace UVtools.Core.FileFormats
#region Properties
- public object Mutex = new();
-
/// <summary>
/// Gets the file format type
/// </summary>
@@ -752,6 +1024,7 @@ namespace UVtools.Core.FileFormats
{
RaisePropertyChanged(nameof(Xppmm));
RaisePropertyChanged(nameof(Ppmm));
+ RaisePropertyChanged(nameof(PpmmMax));
}
}
@@ -765,6 +1038,7 @@ namespace UVtools.Core.FileFormats
{
RaisePropertyChanged(nameof(Yppmm));
RaisePropertyChanged(nameof(Ppmm));
+ RaisePropertyChanged(nameof(PpmmMax));
}
}
@@ -782,14 +1056,19 @@ namespace UVtools.Core.FileFormats
}
/// <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 ? (float) Math.Round(DisplayWidth / ResolutionX, 3) : 0;
+ 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 ? (float) Math.Round(DisplayHeight / ResolutionY, 3) : 0;
+ public float PixelHeight => DisplayHeight > 0 && ResolutionY > 0 ? (float) Math.Round(DisplayHeight / ResolutionY, 3) : 0;
/// <summary>
/// Gets the pixel size in millimeters
@@ -844,7 +1123,11 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets or sets the AntiAliasing level
/// </summary>
- public abstract byte AntiAliasing { get; set; }
+ public virtual byte AntiAliasing
+ {
+ get => _antiAliasing;
+ set => RaiseAndSet(ref _antiAliasing, value);
+ }
/// <summary>
/// Gets Layer Height in mm
@@ -862,7 +1145,7 @@ namespace UVtools.Core.FileFormats
/// </summary>
public virtual float PrintHeight
{
- get => LayerCount == 0 ? 0 : this[LayerCount - 1]?.PositionZ ?? 0;
+ get => LayerCount == 0 ? 0 : LastLayer?.PositionZ ?? 0;
set => RaisePropertyChanged();
}
@@ -881,7 +1164,7 @@ namespace UVtools.Core.FileFormats
/// </summary>
public virtual uint LayerCount
{
- get => LayerManager?.LayerCount ?? 0;
+ get => _layerManager?.LayerCount ?? 0;
set {
RaisePropertyChanged();
RaisePropertyChanged(nameof(NormalLayerCount));
@@ -1019,10 +1302,10 @@ namespace UVtools.Core.FileFormats
/// </summary>
public float BottomLiftHeightTotal
{
- get => (float)Math.Round(_bottomLiftHeight + _bottomLiftHeight2);
+ get => (float)Math.Round(BottomLiftHeight + BottomLiftHeight2, 2);
set
{
- BottomLiftHeight = value;
+ BottomLiftHeight = (float)Math.Round(value, 2);
BottomLiftHeight2 = 0;
}
}
@@ -1033,10 +1316,10 @@ namespace UVtools.Core.FileFormats
/// </summary>
public float LiftHeightTotal
{
- get => (float)Math.Round(_liftHeight + _liftHeight2);
+ get => (float)Math.Round(LiftHeight + LiftHeight2, 2);
set
{
- LiftHeight = value;
+ LiftHeight = (float)Math.Round(value, 2);
LiftHeight2 = 0;
}
}
@@ -1195,7 +1478,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the bottom retract height in mm
/// </summary>
- public float BottomRetractHeight => (float)Math.Round(BottomLiftHeightTotal - _bottomRetractHeight2);
+ public float BottomRetractHeight => (float)Math.Round(BottomLiftHeightTotal - BottomRetractHeight2, 2);
/// <summary>
/// Gets the speed in mm/min for the bottom retracts
@@ -1213,7 +1496,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the retract height in mm
/// </summary>
- public float RetractHeight => (float)Math.Round(LiftHeightTotal - _retractHeight2);
+ public float RetractHeight => (float)Math.Round(LiftHeightTotal - RetractHeight2, 2);
/// <summary>
/// Gets the speed in mm/min for the retracts
@@ -1407,19 +1690,32 @@ namespace UVtools.Core.FileFormats
var haveBottomLiftHeight2 = CanUseBottomLiftHeight2;
var haveLiftHeight2 = CanUseLiftHeight2;
+ var haveBottomLiftSpeed2 = CanUseBottomLiftSpeed2;
+ var haveLiftSpeed2 = CanUseLiftSpeed2;
+
if (!haveBottomLiftHeight && !haveLiftHeight && !haveBottomLiftHeight2 && !haveLiftHeight2) return str;
// Sequence 1
if (haveBottomLiftHeight)
{
str += BottomLiftHeight.ToString(CultureInfo.InvariantCulture);
+ if (haveBottomLiftHeight2 && BottomLiftHeight2 > 0)
+ {
+ str += $"+{BottomLiftHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
+
if (haveLiftHeight)
{
if (!string.IsNullOrEmpty(str)) str += '/';
str += LiftHeight.ToString(CultureInfo.InvariantCulture);
- }
+ if (haveLiftHeight2 && LiftHeight2 > 0)
+ {
+ str += $"+{LiftHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
+ }
+
if (string.IsNullOrEmpty(str)) return str;
str += "mm @ ";
@@ -1429,16 +1725,24 @@ namespace UVtools.Core.FileFormats
if (haveBottomLiftSpeed)
{
str += BottomLiftSpeed.ToString(CultureInfo.InvariantCulture);
+ if (haveBottomLiftSpeed2 && haveBottomLiftHeight2 && BottomLiftHeight2 > 0)
+ {
+ str += $"+{BottomLiftSpeed2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
if (haveLiftSpeed)
{
if (haveBottomLiftSpeed) str += '/';
str += LiftSpeed.ToString(CultureInfo.InvariantCulture);
+ if (haveLiftSpeed2 && haveLiftHeight2 && LiftHeight2 > 0)
+ {
+ str += $"+{LiftSpeed2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
str += "mm/min";
- // Sequence 2
+ /*// Sequence 2
if (haveBottomLiftHeight2)
{
str += $"\n2th: {BottomLiftHeight2.ToString(CultureInfo.InvariantCulture)}";
@@ -1465,7 +1769,7 @@ namespace UVtools.Core.FileFormats
str += LiftSpeed2.ToString(CultureInfo.InvariantCulture);
}
- str += "mm/min";
+ str += "mm/min";*/
return str;
}
@@ -1492,11 +1796,19 @@ namespace UVtools.Core.FileFormats
if (haveBottomRetractHeight)
{
str += BottomRetractHeight.ToString(CultureInfo.InvariantCulture);
+ if (haveBottomRetractHeight2 && BottomRetractHeight2 > 0)
+ {
+ str += $"+{BottomRetractHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
if (haveRetractHeight)
{
if (!string.IsNullOrEmpty(str)) str += '/';
str += RetractHeight.ToString(CultureInfo.InvariantCulture);
+ if (haveRetractHeight2 && RetractHeight2 > 0)
+ {
+ str += $"+{RetractHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
if (string.IsNullOrEmpty(str)) return str;
@@ -1507,17 +1819,25 @@ namespace UVtools.Core.FileFormats
if (haveBottomRetractSpeed)
{
str += BottomRetractSpeed.ToString(CultureInfo.InvariantCulture);
+ if (haveBottomRetractSpeed2 && haveBottomRetractHeight2 && BottomRetractHeight2 > 0)
+ {
+ str += $"+{BottomRetractSpeed2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
if (haveRetractSpeed)
{
if (haveBottomRetractSpeed) str += '/';
str += RetractSpeed.ToString(CultureInfo.InvariantCulture);
+ if (haveRetractSpeed2 && haveRetractHeight2 && RetractHeight2 > 0)
+ {
+ str += $"+{RetractSpeed2.ToString(CultureInfo.InvariantCulture)}";
+ }
}
str += "mm/min";
// Sequence 2
- if (haveBottomRetractHeight2)
+ /*if (haveBottomRetractHeight2)
{
str += $"\n2th: {BottomRetractHeight2.ToString(CultureInfo.InvariantCulture)}";
}
@@ -1541,7 +1861,7 @@ namespace UVtools.Core.FileFormats
str += RetractSpeed2.ToString(CultureInfo.InvariantCulture);
}
- str += "mm/min";
+ str += "mm/min";*/
return str;
}
@@ -1589,6 +1909,18 @@ namespace UVtools.Core.FileFormats
}
}
+ public IEnumerable<IEnumerable<int>> BatchLayersIndexes(int batchSize = 0)
+ {
+ if (batchSize <= 0) batchSize = Environment.ProcessorCount * 10;
+ return MoreLinq.MoreEnumerable.Batch(Enumerable.Range(0, (int)LayerCount), batchSize);
+ }
+
+ public IEnumerable<IEnumerable<Layer>> BatchLayers(int batchSize = 0)
+ {
+ if (batchSize <= 0) batchSize = Environment.ProcessorCount * 10;
+ return MoreLinq.MoreEnumerable.Batch(this, batchSize);
+ }
+
#endregion
/// <summary>
@@ -1723,8 +2055,13 @@ namespace UVtools.Core.FileFormats
{
if (value <= 0)
{
- value = (float)Math.Round(this.Where(layer => layer is not null).Sum(layer => layer.MaterialMilliliters), 3); ;
+ value = (float)Math.Round(this.Where(layer => layer is not null).Sum(layer => layer.MaterialMilliliters), 3);
+ }
+ else
+ {
+ value = (float)Math.Round(value, 3);
}
+
RaiseAndSetIfChanged(ref _materialMilliliters, value);
}
}
@@ -2094,6 +2431,8 @@ namespace UVtools.Core.FileFormats
CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]);
}
}
+
+ RaisePropertyChanged(nameof(Thumbnails));
}
/// <summary>
@@ -2112,6 +2451,7 @@ namespace UVtools.Core.FileFormats
CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]);
}
}
+ RaisePropertyChanged(nameof(Thumbnails));
}
/// <summary>
@@ -2126,6 +2466,7 @@ namespace UVtools.Core.FileFormats
{
CvInvoke.Resize(Thumbnails[index], Thumbnails[index], ThumbnailsOriginalSize[index]);
}
+ RaisePropertyChanged(nameof(Thumbnails));
}
/// <summary>
@@ -3041,8 +3382,8 @@ namespace UVtools.Core.FileFormats
/// </summary>
public byte ValidateAntiAliasingLevel()
{
- if (AntiAliasing < 2) return 1;
- if(AntiAliasing % 2 != 0) throw new ArgumentException("AntiAliasing must be multiples of 2, otherwise use 0 or 1 to disable it", nameof(AntiAliasing));
+ if (AntiAliasing <= 1) return 1;
+ //if(AntiAliasing % 2 != 0) throw new ArgumentException("AntiAliasing must be multiples of 2, otherwise use 0 or 1 to disable it", nameof(AntiAliasing));
return AntiAliasing;
}
diff --git a/UVtools.Core/FileFormats/GR1File.cs b/UVtools.Core/FileFormats/GR1File.cs
index c0a6441..ad0a7ff 100644
--- a/UVtools.Core/FileFormats/GR1File.cs
+++ b/UVtools.Core/FileFormats/GR1File.cs
@@ -232,12 +232,6 @@ namespace UVtools.Core.FileFormats
public override bool DisplayMirror { get; set; }
- public override byte AntiAliasing
- {
- get => 1;
- set { }
- }
-
public override float LayerHeight
{
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
@@ -368,33 +362,24 @@ namespace UVtools.Core.FileFormats
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- byte[][] previews = new byte[ThumbnailsOriginalSize.Length][];
- for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
- {
- previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
- }
+ var previews = new byte[ThumbnailsOriginalSize.Length][];
+
// Previews
Parallel.For(0, previews.Length, previewIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- if (Thumbnails[previewIndex] is null) return;
- var span = Thumbnails[previewIndex].GetDataByteSpan();
- int index = 0;
- for (int i = 0; i < span.Length; i += 3)
+ var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
+ if (Thumbnails[previewIndex] is null)
{
- byte b = span[i];
- byte g = span[i + 1];
- byte r = span[i + 2];
-
- ushort rgb15 = (ushort)(((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));
-
- previews[previewIndex][index++] = (byte)(rgb15 >> 8);
- previews[previewIndex][index++] = (byte)(rgb15 & 0xff);
+ previews[previewIndex] = new byte[encodeLength];
+ return;
}
- if (index != previews[previewIndex].Length)
+ previews[previewIndex] = EncodeImage(DATATYPE_RGB565_BE, Thumbnails[previewIndex]);
+
+ if (encodeLength != previews[previewIndex].Length)
{
- throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {index}");
+ throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {encodeLength}");
}
});
@@ -402,15 +387,15 @@ namespace UVtools.Core.FileFormats
{
Helpers.SerializeWriteFileStream(outputFile, previews[i]);
outputFile.WriteBytes(pageBreak);
+ //Helpers.SerializeWriteFileStream(outputFile, pageBreak);
+ previews[i] = null;
}
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
- var range = Enumerable.Range(0, (int)LayerCount);
-
var layerBytes = new List<byte>[LayerCount];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -418,44 +403,47 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex];
- using var mat = layer.LayerMat;
- var span = mat.GetDataByteSpan();
+ using (var mat = layer.LayerMat)
+ {
+ var span = mat.GetDataByteSpan();
- layerBytes[layerIndex] = new();
+ layerBytes[layerIndex] = new();
- uint lineCount = 0;
+ uint lineCount = 0;
- for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
- {
- int y = layer.BoundingRectangle.Y;
- int startY = -1;
- for (; y < layer.BoundingRectangle.Bottom; y++)
+ for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
{
- int pos = mat.GetPixelPos(x, y);
- if (span[pos] < 128) // Black pixel
+ int y = layer.BoundingRectangle.Y;
+ int startY = -1;
+ for (; y < layer.BoundingRectangle.Bottom; y++)
{
- if (startY == -1) continue; // Keep ignoring
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
- startY = -1;
- lineCount++;
+ int pos = mat.GetPixelPos(x, y);
+ if (span[pos] < 128) // Black pixel
+ {
+ if (startY == -1) continue; // Keep ignoring
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
+ startY = -1;
+ lineCount++;
+ }
+ else
+ {
+ if (startY >= 0) continue; // Keep sum
+ startY = y;
+ }
}
- else
+
+ if (startY >= 0)
{
- if (startY >= 0) continue; // Keep sum
- startY = y;
+ layerBytes[layerIndex]
+ .AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
+ lineCount++;
}
}
- if (startY >= 0)
- {
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
- lineCount++;
- }
+ layerBytes[layerIndex].InsertRange(0, BitExtensions.ToBytesBigEndian(lineCount));
+ layerBytes[layerIndex].AddRange(pageBreak);
}
- layerBytes[layerIndex].InsertRange(0, BitExtensions.ToBytesBigEndian(lineCount));
- layerBytes[layerIndex].AddRange(pageBreak);
-
progress.LockAndIncrement();
});
@@ -497,25 +485,10 @@ namespace UVtools.Core.FileFormats
Parallel.For(0, previews.Length, previewIndex =>
{
- var mat = new Mat(ThumbnailsOriginalSize[previewIndex], DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
-
- int spanIndex = 0;
- for (int i = 0; i < previews[previewIndex].Length; i += 2)
- {
- ushort rgb15 = (ushort)((ushort)(previews[previewIndex][i + 0] << 8) | previews[previewIndex][i + 1]);
- byte r = (byte)((rgb15 >> 11) << 3);
- byte g = (byte)((rgb15 >> 5) << 2);
- byte b = (byte)((rgb15 >> 0) << 3);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- Thumbnails[previewIndex] = mat;
+ Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
+ previews[previewIndex] = null;
});
-
+
SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(inputFile);
@@ -527,7 +500,7 @@ namespace UVtools.Core.FileFormats
var range = Enumerable.Range(0, (int)LayerCount);
var linesBytes = new byte[LayerCount][];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs
index 45f69fb..59ce84a 100644
--- a/UVtools.Core/FileFormats/ImageFile.cs
+++ b/UVtools.Core/FileFormats/ImageFile.cs
@@ -72,12 +72,6 @@ namespace UVtools.Core.FileFormats
set { }
}
- public override byte AntiAliasing
- {
- get => 1;
- set { }
- }
-
public override float LayerHeight { get; set; } = 0.01f;
/*public override float PrintTime { get; } = 0;
public override float UsedMaterial { get; } = 0;
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index 71fb3a4..5c79a18 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -126,7 +126,7 @@ namespace UVtools.Core.FileFormats
#region LayerData
- public class LayerData
+ public class LayerDef
{
[Ignore] public LGSFile Parent { get; set; }
@@ -137,9 +137,9 @@ namespace UVtools.Core.FileFormats
[FieldLength(nameof(DataSize))]
public byte[] EncodedRle { get; set; }
- public LayerData() { }
+ public LayerDef() { }
- public LayerData(LGSFile parent)
+ public LayerDef(LGSFile parent)
{
Parent = parent;
}
@@ -211,7 +211,7 @@ namespace UVtools.Core.FileFormats
{
var b = EncodedRle[i];
byte colorNibble = (byte)(b >> 4);
- byte color = (byte)(colorNibble << 0x4 | colorNibble);
+ byte color = (byte)(colorNibble << 4 | colorNibble);
int repeat = b & 0xf;
while (i + 1 < EncodedRle.Length && (EncodedRle[i + 1] >> 4) == colorNibble)
@@ -350,12 +350,6 @@ namespace UVtools.Core.FileFormats
set { }
}
- public override byte AntiAliasing
- {
- get => 4;
- set { }
- }
-
public override float LayerHeight
{
get => HeaderSettings.LayerHeight;
@@ -492,54 +486,7 @@ namespace UVtools.Core.FileFormats
#region Methods
- public unsafe byte[] PreviewEncode(Mat mat)
- {
- byte[] bytes = new byte[mat.Width * mat.Height * 2];
- var span = mat.GetBytePointer();
- var imageLength = mat.GetLength();
-
- int index = 0;
- for (int i = 0; i < imageLength; i+=3)
- {
- byte b = span[i];
- byte g = span[i+1];
- byte r = span[i+2];
-
- ushort rgb15 = (ushort) (((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 0));
-
- bytes[index++] = (byte) (rgb15 >> 8);
- bytes[index++] = (byte) (rgb15 & 0xff);
- }
-
- if (index != bytes.Length)
- {
- throw new FileLoadException($"Preview encode incomplete encode, expected: {bytes.Length}, encoded: {index}");
- }
-
- return bytes;
- }
-
- public unsafe Mat PreviewDecode(byte[] data)
- {
- Mat mat = new((int)HeaderSettings.PreviewSizeY, (int)HeaderSettings.PreviewSizeX, DepthType.Cv8U, 3);
- var span = mat.GetBytePointer();
- int spanIndex = 0;
- for (int i = 0; i < data.Length; i += 2)
- {
- ushort rgb15 = BitExtensions.ToUShortBigEndian(data[i], data[i + 1]);
- byte r = (byte)((((rgb15 >> 11) & 0x1f) << 3) | 0x7);
- byte g = (byte)((((rgb15 >> 6) & 0x1f) << 3) | 0x7);
- byte b = (byte)((((rgb15 >> 0) & 0x1f) << 3) | 0x7);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- return mat;
- }
-
- protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
+ protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
if (FileEndsWith(".lgs")) // Longer Orange 10
{
@@ -566,7 +513,7 @@ namespace UVtools.Core.FileFormats
using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
{
outputFile.WriteSerialize(HeaderSettings);
- outputFile.WriteBytes(PreviewEncode(Thumbnails[0]));
+ outputFile.WriteBytes(EncodeImage(DATATYPE_RGB565_BE, Thumbnails[0]));
if (HeaderSettings.PrinterModel == 120)
{
@@ -577,19 +524,30 @@ namespace UVtools.Core.FileFormats
outputFile.WriteSerialize(pngPreview);
}
- var layerData = new LayerData[LayerCount];
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ var layerData = new LayerDef[LayerCount];
- Parallel.For(0, LayerCount, layerIndex =>
+ foreach (var batch in BatchLayersIndexes())
{
- if (progress.Token.IsCancellationRequested) return;
- using (var mat = this[layerIndex].LayerMat)
+ Parallel.ForEach(batch, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
+ {
+ layerData[layerIndex] = new LayerDef(this);
+ layerData[layerIndex].Encode(mat);
+ }
+ progress.LockAndIncrement();
+ });
+
+ foreach (var layerIndex in batch)
{
- layerData[layerIndex] = new LayerData(this);
- layerData[layerIndex].Encode(mat);
+ progress.Token.ThrowIfCancellationRequested();
+ outputFile.WriteSerialize(layerData[layerIndex]);
+ layerData[layerIndex].EncodedRle = null; // Free this
}
+ }
- progress.LockAndIncrement();
- });
progress.ItemName = "Saving layers";
progress.ProcessedItems = 0;
@@ -625,44 +583,41 @@ namespace UVtools.Core.FileFormats
}
//}
- int previewSize = (int) (HeaderSettings.PreviewSizeX * HeaderSettings.PreviewSizeY * 2);
- byte[] previewData = new byte[previewSize];
-
-
- uint currentOffset = (uint) Helpers.Serializer.SizeOf(HeaderSettings);
- currentOffset += inputFile.ReadBytes(previewData);
- Thumbnails[0] = PreviewDecode(previewData);
+ var previewSize = HeaderSettings.PreviewSizeX * HeaderSettings.PreviewSizeY * 2;
+ var previewData = inputFile.ReadBytes(previewSize);
+ Thumbnails[0] = DecodeImage(DATATYPE_RGB565_BE, previewData, HeaderSettings.PreviewSizeX, HeaderSettings.PreviewSizeY);
if (HeaderSettings.PrinterModel == 120)
{
var pngPreview = Helpers.Deserialize<LGS120PngPreview>(inputFile);
}
-
-
- var layerData = new LayerData[HeaderSettings.LayerCount];
- progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.LayerCount);
- for (int layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
- {
- progress.Token.ThrowIfCancellationRequested();
- layerData[layerIndex] = Helpers.Deserialize<LayerData>(inputFile);
- layerData[layerIndex].Parent = this;
- }
LayerManager.Init(HeaderSettings.LayerCount);
+ var layerData = new LayerDef[LayerCount];
+
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ foreach (var batch in BatchLayersIndexes())
+ {
+ foreach (var layerIndex in batch)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+
+ layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
+ layerData[layerIndex].Parent = this;
+ }
- Parallel.For(0, LayerCount,
- //new ParallelOptions{MaxDegreeOfParallelism = 1},
- layerIndex =>
+ Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
-
- using var image = layerData[layerIndex].Decode();
- this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
+ using (var mat = layerData[layerIndex].Decode())
+ {
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ }
progress.LockAndIncrement();
});
+ }
LayerManager.RebuildLayersProperties();
}
diff --git a/UVtools.Core/FileFormats/MDLPFile.cs b/UVtools.Core/FileFormats/MDLPFile.cs
index 86da4af..d3516b8 100644
--- a/UVtools.Core/FileFormats/MDLPFile.cs
+++ b/UVtools.Core/FileFormats/MDLPFile.cs
@@ -235,13 +235,6 @@ namespace UVtools.Core.FileFormats
}
public override bool DisplayMirror { get; set; }
-
- public override byte AntiAliasing
- {
- get => 1;
- set { }
- }
-
public override float LayerHeight
{
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
@@ -328,33 +321,24 @@ namespace UVtools.Core.FileFormats
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- byte[][] previews = new byte[2][];
- for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
- {
- previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
- }
+ var previews = new byte[ThumbnailsOriginalSize.Length][];
+
// Previews
Parallel.For(0, previews.Length, previewIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- if (Thumbnails[previewIndex] is null) return;
- var span = Thumbnails[previewIndex].GetDataByteSpan();
- int index = 0;
- for (int i = 0; i < span.Length; i += 3)
+ var encodeLength = ThumbnailsOriginalSize[previewIndex].Area() * 2;
+ if (Thumbnails[previewIndex] is null)
{
- byte b = span[i];
- byte g = span[i + 1];
- byte r = span[i + 2];
-
- ushort rgb15 = (ushort)(((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0));
-
- previews[previewIndex][index++] = (byte)(rgb15 >> 8);
- previews[previewIndex][index++] = (byte)(rgb15 & 0xff);
+ previews[previewIndex] = new byte[encodeLength];
+ return;
}
- if (index != previews[previewIndex].Length)
+ previews[previewIndex] = EncodeImage(DATATYPE_RGB565_BE, Thumbnails[previewIndex]);
+
+ if (encodeLength != previews[previewIndex].Length)
{
- throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {index}");
+ throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {encodeLength}");
}
});
@@ -362,6 +346,7 @@ namespace UVtools.Core.FileFormats
{
Helpers.SerializeWriteFileStream(outputFile, previews[i]);
outputFile.WriteBytes(pageBreak);
+ previews[i] = null;
}
Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
@@ -369,7 +354,7 @@ namespace UVtools.Core.FileFormats
var range = Enumerable.Range(0, (int)LayerCount);
var layerBytes = new List<byte>[LayerCount];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -377,44 +362,47 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
var layer = this[layerIndex];
- using var mat = layer.LayerMat;
- var span = mat.GetDataByteSpan();
+ using (var mat = layer.LayerMat)
+ {
+ var span = mat.GetDataByteSpan();
- layerBytes[layerIndex] = new();
+ layerBytes[layerIndex] = new();
- uint lineCount = 0;
+ uint lineCount = 0;
- for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
- {
- int y = layer.BoundingRectangle.Y;
- int startY = -1;
- for (; y < layer.BoundingRectangle.Bottom; y++)
+ for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++)
{
- int pos = mat.GetPixelPos(x, y);
- if (span[pos] < 128) // Black pixel
+ int y = layer.BoundingRectangle.Y;
+ int startY = -1;
+ for (; y < layer.BoundingRectangle.Bottom; y++)
{
- if (startY == -1) continue; // Keep ignoring
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
- startY = -1;
- lineCount++;
+ int pos = mat.GetPixelPos(x, y);
+ if (span[pos] < 128) // Black pixel
+ {
+ if (startY == -1) continue; // Keep ignoring
+ layerBytes[layerIndex]
+ .AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
+ startY = -1;
+ lineCount++;
+ }
+ else
+ {
+ if (startY >= 0) continue; // Keep sum
+ startY = y;
+ }
}
- else
+
+ if (startY >= 0)
{
- if (startY >= 0) continue; // Keep sum
- startY = y;
+ layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
+ lineCount++;
}
}
- if (startY >= 0)
- {
- layerBytes[layerIndex].AddRange(LayerLine.GetBytes((ushort)startY, (ushort)(y - 1), (ushort)x));
- lineCount++;
- }
+ layerBytes[layerIndex].InsertRange(0, BitExtensions.ToBytesBigEndian(lineCount));
+ layerBytes[layerIndex].AddRange(pageBreak);
}
- layerBytes[layerIndex].InsertRange(0, BitExtensions.ToBytesBigEndian(lineCount));
- layerBytes[layerIndex].AddRange(pageBreak);
-
progress.LockAndIncrement();
});
@@ -454,25 +442,10 @@ namespace UVtools.Core.FileFormats
Parallel.For(0, previews.Length, previewIndex =>
{
- var mat = new Mat(ThumbnailsOriginalSize[previewIndex], DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
-
- int spanIndex = 0;
- for (int i = 0; i < previews[previewIndex].Length; i += 2)
- {
- ushort rgb15 = BitExtensions.ToUShortBigEndian(previews[previewIndex][i], previews[previewIndex][i + 1]);
- byte r = (byte)((rgb15 >> 11) << 3);
- byte g = (byte)((rgb15 >> 5) << 2);
- byte b = (byte)((rgb15 >> 0) << 3);
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- Thumbnails[previewIndex] = mat;
+ Thumbnails[previewIndex] = DecodeImage(DATATYPE_RGB565_BE, previews[previewIndex], ThumbnailsOriginalSize[previewIndex]);
+ previews[previewIndex] = null;
});
-
+
SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(inputFile);
@@ -484,7 +457,7 @@ namespace UVtools.Core.FileFormats
var range = Enumerable.Range(0, (int)LayerCount);
var linesBytes = new byte[LayerCount][];
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
progress.Token.ThrowIfCancellationRequested();
@@ -502,20 +475,22 @@ namespace UVtools.Core.FileFormats
Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var mat = EmguExtensions.InitMat(Resolution);
-
- for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+ using (var mat = EmguExtensions.InitMat(Resolution))
{
- var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]);
- var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]);
- var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]);
-
- CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), EmguExtensions.WhiteColor);
- }
- linesBytes[layerIndex] = null;
+ for (int i = 0; i < linesBytes[layerIndex].Length; i++)
+ {
+ var startY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]);
+ var endY = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i++]);
+ var startX = BitExtensions.ToUShortBigEndian(linesBytes[layerIndex][i++], linesBytes[layerIndex][i]);
+
+ CvInvoke.Line(mat, new Point(startX, startY), new Point(startX, endY), EmguExtensions.WhiteColor);
+ }
+
+ linesBytes[layerIndex] = null;
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ }
progress.LockAndIncrement();
});
diff --git a/UVtools.Core/FileFormats/OSLAFile.cs b/UVtools.Core/FileFormats/OSLAFile.cs
index 0ddd9a8..ef0e6de 100644
--- a/UVtools.Core/FileFormats/OSLAFile.cs
+++ b/UVtools.Core/FileFormats/OSLAFile.cs
@@ -13,12 +13,10 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
using BinarySerialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
-using MoreLinq;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
using UVtools.Core.Operations;
@@ -30,6 +28,7 @@ namespace UVtools.Core.FileFormats
#region Constants
public const string MARKER = "OSLATiCo";
+
#endregion
#region Sub Classes
@@ -209,7 +208,7 @@ namespace UVtools.Core.FileFormats
BoundingRectangleHeight = (uint)layer.BoundingRectangle.Height;
}
- public void SetTo(Layer layer)
+ public void CopyTo(Layer layer)
{
layer.PositionZ = PositionZ;
layer.LiftHeight = LiftHeight;
@@ -376,12 +375,6 @@ namespace UVtools.Core.FileFormats
}
}
- public override byte AntiAliasing
- {
- get => 8;
- set => RaisePropertyChanged();
- }
-
public override float LayerHeight
{
get => HeaderSettings.LayerHeight;
@@ -495,7 +488,7 @@ namespace UVtools.Core.FileFormats
progress.Token.ThrowIfCancellationRequested();
- var bytes = EncodeImage(image, HeaderSettings.PreviewDataType);
+ var bytes = EncodeImage(HeaderSettings.PreviewDataType, image);
if (bytes.Length == 0) continue;
var preview = new Preview
{
@@ -528,18 +521,20 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(HeaderSettings.LayerTableSize * LayerCount, SeekOrigin.Current); // Start of layer data
- var layerHash = new Dictionary<string, uint>();
+ var layersHash = new Dictionary<string, uint>();
- var range = Enumerable.Range(0, (int)LayerCount);
- foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
var layerBytes = new byte[LayerCount][];
Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var mat = this[layerIndex].LayerMat;
- layerBytes[layerIndex] = EncodeImage(mat, HeaderSettings.LayerDataType);
+ using (var mat = this[layerIndex].LayerMat)
+ {
+ layerBytes[layerIndex] = EncodeImage(HeaderSettings.LayerDataType, mat);
+ }
+
progress.LockAndIncrement();
});
@@ -549,7 +544,7 @@ namespace UVtools.Core.FileFormats
// Try to reuse layers
var hash = Helpers.ComputeSHA1Hash(layerBytes[layerIndex]);
- if (layerHash.TryGetValue(hash, out var address))
+ if (layersHash.TryGetValue(hash, out var address))
{
layerDataAddresses[layerIndex] = address;
}
@@ -558,10 +553,10 @@ namespace UVtools.Core.FileFormats
layerDataAddresses[layerIndex] = (uint)outputFile.Position;
outputFile.WriteUIntLittleEndian((uint)layerBytes[layerIndex].Length);
outputFile.WriteBytes(layerBytes[layerIndex]);
- layerHash.Add(hash, layerDataAddresses[layerIndex]);
+ layersHash.Add(hash, layerDataAddresses[layerIndex]);
}
- layerBytes[layerIndex] = null; // Clean
+ layerBytes[layerIndex] = null; // Free this
}
}
@@ -646,7 +641,7 @@ namespace UVtools.Core.FileFormats
var bytes = inputFile.ReadBytes((int)Previews[i].ImageLength);
- Thumbnails[i] = DecodeImage(bytes, HeaderSettings.PreviewDataType, Previews[i].ResolutionX, Previews[i].ResolutionY);
+ Thumbnails[i] = DecodeImage(HeaderSettings.PreviewDataType, bytes, Previews[i].ResolutionX, Previews[i].ResolutionY);
progress++;
}
@@ -680,8 +675,7 @@ namespace UVtools.Core.FileFormats
progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
- var range = Enumerable.Range(0, (int)LayerCount);
- foreach (var batch in MoreEnumerable.Batch(range, Environment.ProcessorCount * 10))
+ foreach (var batch in BatchLayersIndexes())
{
var layerBytes = new byte[LayerCount][];
@@ -696,11 +690,14 @@ namespace UVtools.Core.FileFormats
Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- using var mat = DecodeImage(layerBytes[layerIndex], HeaderSettings.LayerDataType, Resolution);
- var layer = new Layer((uint)layerIndex, mat, this);
- layerDef[layerIndex].SetTo(layer);
- this[layerIndex] = layer;
- layerBytes[layerIndex] = null; // Clean
+ using (var mat = DecodeImage(HeaderSettings.LayerDataType, layerBytes[layerIndex], Resolution))
+ {
+ layerBytes[layerIndex] = null; // Clean
+
+ var layer = new Layer((uint)layerIndex, mat, this);
+ layerDef[layerIndex].CopyTo(layer);
+ this[layerIndex] = layer;
+ }
progress.LockAndIncrement();
});
@@ -761,134 +758,7 @@ namespace UVtools.Core.FileFormats
#region Static Methods
- public static byte[] EncodeImage(Mat mat, string encodeTo)
- {
- encodeTo = encodeTo.ToUpperInvariant();
- if (encodeTo is "PNG" or "JPG" or "JPEG" or "JP2" or "BMP" or "TIF" or "TIFF" or "PPM" or "PMG" or "SR" or "RAS")
- {
- return CvInvoke.Imencode($".{encodeTo.ToLowerInvariant()}", mat);
- }
-
- if (encodeTo is "RGB555" or "RGB565" or "RGB888"
- or "BGR555" or "BGR565" or "BGR888")
- {
- var bytesPerPixel = encodeTo is "RGB888" or "BGR888" ? 3 : 2;
- var bytes = new byte[mat.Width * mat.Height * bytesPerPixel];
- uint index = 0;
- var span = mat.GetDataByteSpan();
- for (int i = 0; i < span.Length;)
- {
- byte b = span[i++];
- byte g;
- byte r;
-
- if (mat.NumberOfChannels == 1) // 8 bit safe-guard
- {
- r = g = b;
- }
- else
- {
- g = span[i++];
- r = span[i++];
- }
-
- if (mat.NumberOfChannels == 4) i++; // skip alpha
-
- switch (encodeTo)
- {
- case "RGB555":
- var rgb555 = (ushort) (((r & 0b11111000) << 7) | ((g & 0b11111000) << 2) | (b >> 3));
- BitExtensions.ToBytesLittleEndian(rgb555, bytes, index);
- index += 2;
- break;
- case "RGB565":
- var rgb565 = (ushort) (((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3));
- BitExtensions.ToBytesLittleEndian(rgb565, bytes, index);
- index += 2;
- break;
- case "RGB888":
- bytes[index++] = r;
- bytes[index++] = g;
- bytes[index++] = b;
- break;
- }
- }
-
- return bytes;
- }
-
- throw new NotSupportedException($"The encode type: {encodeTo} is not supported.");
- }
-
- public static Mat DecodeImage(byte[] bytes, string decodeFrom, Size resolution)
- {
- if (decodeFrom is "PNG" or "JPG" or "JPEG" or "JP2" or "BMP" or "TIF" or "TIFF" or "PPM" or "PMG" or "SR" or "RAS")
- {
- var mat = new Mat();
- CvInvoke.Imdecode(bytes, ImreadModes.AnyColor, mat);
- return mat;
- }
-
- if (decodeFrom is "RGB555" or "RGB565" or "RGB888"
- or "BGR555" or "BGR565" or "BGR888")
- {
- var mat = new Mat(resolution, DepthType.Cv8U, 3);
- var span = mat.GetDataByteSpan();
- var pixel = 0;
- for (int i = 0; i < bytes.Length;)
- {
- switch (decodeFrom)
- {
- case "RGB555":
- ushort rgb555 = BitExtensions.ToUShortLittleEndian(bytes, i);
- span[pixel++] = (byte)((rgb555 & 0b00000000_00011111) << 3); // b
- span[pixel++] = (byte)((rgb555 & 0b00000011_11100000) >> 2); // g
- span[pixel++] = (byte)((rgb555 & 0b01111100_00000000) >> 7); // r
- i += 2;
- break;
- case "RGB565":
- ushort rgb565 = BitExtensions.ToUShortLittleEndian(bytes, i);
- span[pixel++] = (byte)((rgb565 & 0b00000000_00011111) << 3); // b
- span[pixel++] = (byte)((rgb565 & 0b00000111_11100000) >> 3); // g
- span[pixel++] = (byte)((rgb565 & 0b11111000_00000000) >> 8); // r
- i += 2;
- break;
- case "RGB888":
- span[pixel++] = bytes[i + 2]; // b
- span[pixel++] = bytes[i + 1]; // g
- span[pixel++] = bytes[i]; // r
- i += 3;
- break;
- case "BGR555":
- ushort bgr555 = BitExtensions.ToUShortLittleEndian(bytes, i);
- span[pixel++] = (byte)((bgr555 & 0b01111100_00000000) >> 7); // b
- span[pixel++] = (byte)((bgr555 & 0b00000011_11100000) >> 2); // g
- span[pixel++] = (byte)((bgr555 & 0b00000000_00011111) << 3); // r
- i += 2;
- break;
- case "BGR565":
- ushort bgr565 = BitExtensions.ToUShortLittleEndian(bytes, i);
- span[pixel++] = (byte)((bgr565 & 0b11111000_00000000) >> 8); // b
- span[pixel++] = (byte)((bgr565 & 0b00000111_11100000) >> 3); // g
- span[pixel++] = (byte)((bgr565 & 0b00000000_00011111) << 3); // r
- i += 2;
- break;
- case "BGR888":
- span[pixel++] = bytes[i]; // b
- span[pixel++] = bytes[i+1]; // g
- span[pixel++] = bytes[i+2]; // r
- i += 3;
- break;
- }
- }
- return mat;
- }
-
- throw new NotSupportedException($"The decode type: {decodeFrom} is not supported.");
- }
-
- public static Mat DecodeImage(byte[] bytes, string decodeFrom, uint resolutionX = 0, uint resolutionY = 0)
- => DecodeImage(bytes, decodeFrom, new Size((int) resolutionX, (int) resolutionY));
+
#endregion
diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index fc507d3..e0ca04b 100644
--- a/UVtools.Core/FileFormats/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -422,17 +422,17 @@ namespace UVtools.Core.FileFormats
#endregion
#region Layer
- public class LayerData
+ public class LayerDef
{
/// <summary>
/// Gets the build platform Z position for this layer, measured in millimeters.
/// </summary>
- [FieldOrder(0)] public float LayerPositionZ { get; set; }
+ [FieldOrder(0)] public float PositionZ { get; set; }
/// <summary>
/// Gets the exposure time for this layer, in seconds.
/// </summary>
- [FieldOrder(1)] public float LayerExposure { get; set; }
+ [FieldOrder(1)] public float ExposureTime { get; set; }
/// <summary>
/// Gets how long to keep the light off after exposing this layer, in seconds.
@@ -457,21 +457,28 @@ namespace UVtools.Core.FileFormats
[Ignore] public PHZFile Parent { get; set; }
- public LayerData()
+ public LayerDef()
{
}
- public LayerData(PHZFile parent, uint layerIndex)
+ public LayerDef(PHZFile parent, Layer layer)
{
Parent = parent;
- RefreshLayerData(layerIndex);
+ SetFrom(layer);
}
- public void RefreshLayerData(uint layerIndex)
+ public void SetFrom(Layer layer)
{
- LayerPositionZ = Parent[layerIndex].PositionZ;
- LayerExposure = Parent[layerIndex].ExposureTime;
- LightOffDelay = Parent[layerIndex].LightOffDelay;
+ PositionZ = layer.PositionZ;
+ ExposureTime = layer.ExposureTime;
+ LightOffDelay = layer.LightOffDelay;
+ }
+
+ public void CopyTo(Layer layer)
+ {
+ layer.PositionZ = PositionZ;
+ layer.ExposureTime = ExposureTime;
+ layer.LightOffDelay = LightOffDelay;
}
public unsafe Mat Decode(uint layerIndex, bool consumeData = true)
@@ -619,7 +626,7 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(LayerPositionZ)}: {LayerPositionZ}, {nameof(LayerExposure)}: {LayerExposure}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
+ return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
}
}
#endregion
@@ -682,9 +689,7 @@ namespace UVtools.Core.FileFormats
public Preview[] Previews { get; protected internal set; }
- public LayerData[] LayersDefinitions { get; private set; }
-
- public Dictionary<string, LayerData> LayersHash { get; } = new ();
+ public LayerDef[] LayersDefinitions { get; private set; }
public override FileFormatType FileType => FileFormatType.Binary;
@@ -788,11 +793,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => (byte) HeaderSettings.AntiAliasLevelInfo;
- set
- {
- HeaderSettings.AntiAliasLevelInfo = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
+ set => base.AntiAliasing = (byte)(HeaderSettings.AntiAliasLevelInfo = value.Clamp(1, 16));
}
public override float LayerHeight
@@ -979,221 +980,201 @@ namespace UVtools.Core.FileFormats
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
- LayersHash.Clear();
-
/*if (HeaderSettings.EncryptionKey == 0)
{
Random rnd = new Random();
HeaderSettings.EncryptionKey = (uint)rnd.Next(short.MaxValue, int.MaxValue);
}*/
+ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
+ using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
+ outputFile.Seek(Helpers.Serializer.SizeOf(HeaderSettings), SeekOrigin.Begin);
- uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
- LayersDefinitions = new LayerData[HeaderSettings.LayerCount];
- using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
+ for (byte i = 0; i < ThumbnailsCount; i++)
{
- outputFile.Seek((int) currentOffset, SeekOrigin.Begin);
+ var image = Thumbnails[i];
- for (byte i = 0; i < ThumbnailsCount; i++)
- {
- var image = Thumbnails[i];
+ var bytes = Preview.Encode(image);
- var bytes = Preview.Encode(image);
+ if (bytes.Length == 0) continue;
- if (bytes.Length == 0) continue;
+ if (i == (byte) FileThumbnailSize.Small)
+ {
+ HeaderSettings.PreviewSmallOffsetAddress = (uint)outputFile.Position;
+ }
+ else
+ {
+ HeaderSettings.PreviewLargeOffsetAddress = (uint)outputFile.Position;
+ }
- if (i == (byte) FileThumbnailSize.Small)
- {
- HeaderSettings.PreviewSmallOffsetAddress = currentOffset;
- }
- else
- {
- HeaderSettings.PreviewLargeOffsetAddress = currentOffset;
- }
+ Preview preview = new()
+ {
+ ResolutionX = (uint) image.Width,
+ ResolutionY = (uint) image.Height,
+ ImageLength = (uint)bytes.Length,
+ };
- Preview preview = new()
- {
- ResolutionX = (uint) image.Width,
- ResolutionY = (uint) image.Height,
- ImageLength = (uint)bytes.Length,
- };
+ preview.ImageOffset = (uint)(outputFile.Position + Helpers.Serializer.SizeOf(preview));
- currentOffset += (uint) Helpers.Serializer.SizeOf(preview);
- preview.ImageOffset = currentOffset;
+ Helpers.SerializeWriteFileStream(outputFile, preview);
- Helpers.SerializeWriteFileStream(outputFile, preview);
+ outputFile.WriteBytes(bytes);
+ }
- currentOffset += (uint)bytes.Length;
- outputFile.WriteBytes(bytes);
- }
+ if (HeaderSettings.MachineNameSize > 0)
+ {
+ HeaderSettings.MachineNameAddress = (uint)outputFile.Position;
+ var machineBytes = Encoding.ASCII.GetBytes(HeaderSettings.MachineName);
+ outputFile.WriteBytes(machineBytes);
+ }
- if (HeaderSettings.MachineNameSize > 0)
- {
- HeaderSettings.MachineNameAddress = currentOffset;
- var machineBytes = Encoding.ASCII.GetBytes(HeaderSettings.MachineName);
- outputFile.Write(machineBytes, 0, machineBytes.Length);
- currentOffset += (uint)machineBytes.Length;
- }
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ var layersHash = new Dictionary<string, LayerDef>();
+ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
+ HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
+ uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + (uint)Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
- Parallel.For(0, LayerCount, /*new ParallelOptions{MaxDegreeOfParallelism = 1},*/ layerIndex =>
+ foreach (var batch in BatchLayersIndexes())
+ {
+ Parallel.ForEach(batch, layerIndex =>
{
- if(progress.Token.IsCancellationRequested) return;
- LayerData layer = new(this, (uint) layerIndex);
- using (var image = this[layerIndex].LayerMat)
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
{
- layer.Encode(image, (uint) layerIndex);
- LayersDefinitions[layerIndex] = layer;
+ LayersDefinitions[layerIndex] = new LayerDef(this, this[layerIndex]);
+ LayersDefinitions[layerIndex].Encode(mat, (uint)layerIndex);
}
-
progress.LockAndIncrement();
});
- progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
-
- HeaderSettings.LayersDefinitionOffsetAddress = currentOffset;
- uint layerDataCurrentOffset = currentOffset + (uint) Helpers.Serializer.SizeOf(LayersDefinitions[0]) * LayerCount;
- for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ foreach (var layerIndex in batch)
{
progress.Token.ThrowIfCancellationRequested();
- LayerData layerData = LayersDefinitions[layerIndex];
- LayerData layerDataHash = null;
+
+ var layerDef = LayersDefinitions[layerIndex];
+ LayerDef layerDefHash = null;
if (HeaderSettings.EncryptionKey == 0)
{
- string hash = Helpers.ComputeSHA1Hash(layerData.EncodedRle);
- if (LayersHash.TryGetValue(hash, out layerDataHash))
+ string hash = Helpers.ComputeSHA1Hash(layerDef.EncodedRle);
+ if (layersHash.TryGetValue(hash, out layerDefHash))
{
- layerData.DataAddress = layerDataHash.DataAddress;
- layerData.DataSize = layerDataHash.DataSize;
+ layerDef.DataAddress = layerDefHash.DataAddress;
+ layerDef.DataSize = layerDefHash.DataSize;
}
else
{
- LayersHash.Add(hash, layerData);
+ layersHash.Add(hash, layerDef);
}
}
- if (ReferenceEquals(layerDataHash, null))
+ if (layerDefHash is null)
{
- layerData.DataAddress = layerDataCurrentOffset;
+ layerDef.DataAddress = layerDataCurrentOffset;
outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
- layerDataCurrentOffset += outputFile.WriteBytes(layerData.EncodedRle);
+ layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle);
}
- LayersDefinitions[layerIndex] = layerData;
+ outputFile.Seek(layerDefCurrentOffset, SeekOrigin.Begin);
+ layerDefCurrentOffset += Helpers.SerializeWriteFileStream(outputFile, layerDef);
- outputFile.Seek(currentOffset, SeekOrigin.Begin);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData);
- progress++;
+ layerDef.EncodedRle = null; // Free
}
+ }
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- Debug.WriteLine("Encode Results:");
- Debug.WriteLine(HeaderSettings);
- Debug.WriteLine(Previews[0]);
- Debug.WriteLine(Previews[1]);
- Debug.WriteLine("-End-");
- }
+ Debug.WriteLine("Encode Results:");
+ Debug.WriteLine(HeaderSettings);
+ Debug.WriteLine(Previews[0]);
+ Debug.WriteLine(Previews[1]);
+ Debug.WriteLine("-End-");
}
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
- using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
+ using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read);
+ //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
+ //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header))));
+ HeaderSettings = Helpers.Deserialize<Header>(inputFile);
+ if (HeaderSettings.Magic != MAGIC_PHZ)
{
+ throw new FileLoadException("Not a valid PHZ file!", fileFullPath);
+ }
- //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
- //HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header))));
- HeaderSettings = Helpers.Deserialize<Header>(inputFile);
- if (HeaderSettings.Magic != MAGIC_PHZ)
- {
- throw new FileLoadException("Not a valid PHZ file!", fileFullPath);
- }
-
- HeaderSettings.AntiAliasLevel = 1;
-
- progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount);
- Debug.Write("Header -> ");
- Debug.WriteLine(HeaderSettings);
-
- for (byte i = 0; i < ThumbnailsCount; i++)
- {
- uint offsetAddress = i == 0
- ? HeaderSettings.PreviewSmallOffsetAddress
- : HeaderSettings.PreviewLargeOffsetAddress;
- if (offsetAddress == 0) continue;
+ HeaderSettings.AntiAliasLevel = 1;
- inputFile.Seek(offsetAddress, SeekOrigin.Begin);
- Previews[i] = Helpers.Deserialize<Preview>(inputFile);
+ progress.Reset(OperationProgress.StatusDecodePreviews, ThumbnailsCount);
+ Debug.Write("Header -> ");
+ Debug.WriteLine(HeaderSettings);
- Debug.Write($"Preview {i} -> ");
- Debug.WriteLine(Previews[i]);
+ for (byte i = 0; i < ThumbnailsCount; i++)
+ {
+ uint offsetAddress = i == 0
+ ? HeaderSettings.PreviewSmallOffsetAddress
+ : HeaderSettings.PreviewLargeOffsetAddress;
+ if (offsetAddress == 0) continue;
- inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
- byte[] rawImageData = new byte[Previews[i].ImageLength];
- inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength);
+ inputFile.Seek(offsetAddress, SeekOrigin.Begin);
+ Previews[i] = Helpers.Deserialize<Preview>(inputFile);
- Thumbnails[i] = Previews[i].Decode(rawImageData);
- progress++;
- }
+ Debug.Write($"Preview {i} -> ");
+ Debug.WriteLine(Previews[i]);
- if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
- {
- inputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
- byte[] buffer = new byte[HeaderSettings.MachineNameSize];
- inputFile.Read(buffer, 0, (int) HeaderSettings.MachineNameSize);
- HeaderSettings.MachineName = Encoding.ASCII.GetString(buffer);
- }
+ inputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
+ byte[] rawImageData = new byte[Previews[i].ImageLength];
+ inputFile.Read(rawImageData, 0, (int) Previews[i].ImageLength);
+ Thumbnails[i] = Previews[i].Decode(rawImageData);
+ progress++;
+ }
- LayersDefinitions = new LayerData[HeaderSettings.LayerCount];
+ if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
+ {
+ inputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
+ byte[] buffer = new byte[HeaderSettings.MachineNameSize];
+ inputFile.Read(buffer, 0, (int) HeaderSettings.MachineNameSize);
+ HeaderSettings.MachineName = Encoding.ASCII.GetString(buffer);
+ }
- uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
- progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.LayerCount);
+ LayerManager.Init(HeaderSettings.LayerCount);
+ LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
- for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
+ progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
+ foreach (var batch in BatchLayersIndexes())
+ {
+ foreach (var layerIndex in batch)
{
- inputFile.Seek(layerOffset, SeekOrigin.Begin);
- LayerData layerData = Helpers.Deserialize<LayerData>(inputFile);
- layerData.Parent = this;
- LayersDefinitions[layerIndex] = layerData;
-
- layerOffset += (uint) Helpers.Serializer.SizeOf(layerData);
- Debug.Write($"LAYER {layerIndex} -> ");
- Debug.WriteLine(layerData);
-
- layerData.EncodedRle = new byte[layerData.DataSize];
- inputFile.Seek(layerData.DataAddress, SeekOrigin.Begin);
- inputFile.Read(layerData.EncodedRle, 0, (int) layerData.DataSize);
-
- progress++;
progress.Token.ThrowIfCancellationRequested();
- }
- LayerManager.Init(HeaderSettings.LayerCount);
+ var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
+ layerDef.Parent = this;
+ LayersDefinitions[layerIndex] = layerDef;
- progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
+ Debug.Write($"LAYER {layerIndex} -> ");
+ Debug.WriteLine(layerDef);
- Parallel.For(0, LayerCount, layerIndex =>
- {
- if (progress.Token.IsCancellationRequested)
+ inputFile.SeekDoWorkAndRewind(layerDef.DataAddress, () =>
{
- return;
- }
+ layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize);
+ });
+ }
- using (var image = LayersDefinitions[layerIndex].Decode((uint) layerIndex, true))
+ Parallel.ForEach(batch, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = LayersDefinitions[layerIndex].Decode((uint)layerIndex))
{
- this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager)
- {
- PositionZ = LayersDefinitions[layerIndex].LayerPositionZ,
- ExposureTime = LayersDefinitions[layerIndex].LayerExposure,
- LightOffDelay = LayersDefinitions[layerIndex].LightOffDelay,
- };
+ var layer = new Layer((uint)layerIndex, mat, this);
+ LayersDefinitions[layerIndex].CopyTo(layer);
+ this[layerIndex] = layer;
}
progress.LockAndIncrement();
@@ -1219,26 +1200,24 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
- using (var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write))
- {
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+ using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- /*if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
+ /*if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0)
{
outputFile.Seek(HeaderSettings.MachineNameAddress, SeekOrigin.Begin);
byte[] buffer = new byte[HeaderSettings.MachineNameSize];
outputFile.Write(Encoding.ASCII.GetBytes(HeaderSettings.MachineName), 0, (int)HeaderSettings.MachineNameSize);
}*/
- uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
- for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
- {
- LayersDefinitions[layerIndex].RefreshLayerData(layerIndex);
- outputFile.Seek(layerOffset, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex]);
- layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
- }
+ uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
+ for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
+ {
+ LayersDefinitions[layerIndex].SetFrom(this[layerIndex]);
+ outputFile.Seek(layerOffset, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex]);
+ layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
}
}
diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs
index 9e4fb9d..da588cb 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -14,7 +14,6 @@ using System.IO;
using System.Threading.Tasks;
using BinarySerialization;
using Emgu.CV;
-using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
using UVtools.Core.Operations;
@@ -22,21 +21,31 @@ namespace UVtools.Core.FileFormats
{
public class PhotonSFile : FileFormat
{
+ #region Constants
public const byte RLEEncodingLimit = 128;
+ public const ushort RESOLUTION_X = 1440;
+ public const ushort RESOLUTION_Y = 2560;
+
+ public const float DISPLAY_WIDTH = 68.04f;
+ public const float DISPLAY_HEIGHT = 120.96f;
+ public const float MACHINE_Z = 165f;
+
+ #endregion
+
+ #region Members
+
+ private uint _resolutionX = RESOLUTION_X;
+ private uint _resolutionY = RESOLUTION_Y;
+
+ #endregion
+
#region Sub Classes
#region Header
public class Header
{
- public const uint ResolutionX = 1440;
- public const uint ResolutionY = 2560;
-
- public const float DisplayWidth = 68.04f;
- public const float DisplayHeight = 120.96f;
- public const float BuildZ = 165f;
-
public const uint TAG1 = 2;
public const ushort TAG2 = 49;
@@ -78,13 +87,13 @@ namespace UVtools.Core.FileFormats
#region LayerDef
- public class LayerData
+ public class LayerDef
{
[FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint Unknown1 { get; set; } = 44944;
[FieldOrder(1)] [FieldEndianness(Endianness.Big)] public uint Unknown2 { get; set; } = 0;
[FieldOrder(2)] [FieldEndianness(Endianness.Big)] public uint Unknown3 { get; set; } = 0;
- [FieldOrder(3)] [FieldEndianness(Endianness.Big)] public uint ResolutionX { get; set; } = 1440;
- [FieldOrder(4)] [FieldEndianness(Endianness.Big)] public uint ResolutionY { get; set; } = 2560;
+ [FieldOrder(3)] [FieldEndianness(Endianness.Big)] public uint ResolutionX { get; set; } = RESOLUTION_X;
+ [FieldOrder(4)] [FieldEndianness(Endianness.Big)] public uint ResolutionY { get; set; } = RESOLUTION_Y;
[FieldOrder(5)] [FieldEndianness(Endianness.Big)] public uint DataSize { get; set; }
[Ignore] public uint RleDataSize
{
@@ -98,9 +107,19 @@ namespace UVtools.Core.FileFormats
[Ignore] public byte[] EncodedRle { get; set; }
+ public LayerDef()
+ {
+ }
+
+ public LayerDef(Mat mat)
+ {
+ ResolutionX = (uint)mat.Width;
+ ResolutionY = (uint)mat.Height;
+ }
+
public override string ToString()
{
- return $"{nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(DataSize)}: {DataSize}, {nameof(RleDataSize)}: {RleDataSize}, {nameof(Unknown5)}: {Unknown5}, {nameof(EncodedRle)}: {EncodedRle.Length}";
+ return $"{nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(DataSize)}: {DataSize}, {nameof(RleDataSize)}: {RleDataSize}, {nameof(Unknown5)}: {Unknown5}, {nameof(EncodedRle)}: {EncodedRle?.Length}";
}
public unsafe byte[] Encode(Mat mat)
@@ -162,7 +181,7 @@ namespace UVtools.Core.FileFormats
return EncodedRle;
}
- public unsafe Mat Decode(bool consumeRle = true)
+ public Mat Decode(bool consumeRle = true)
{
var mat = EmguExtensions.InitMat(new Size((int) ResolutionX, (int) ResolutionY));
//var matSpan = mat.GetBytePointer();
@@ -259,25 +278,33 @@ namespace UVtools.Core.FileFormats
public override uint ResolutionX
{
- get => Header.ResolutionX;
- set { }
+ get => _resolutionX;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _resolutionX, value)) return;
+ HeaderSettings.XYPixelSize = PixelSizeMax;
+ }
}
public override uint ResolutionY
{
- get => Header.ResolutionY;
- set { }
+ get => _resolutionY;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _resolutionY, value)) return;
+ HeaderSettings.XYPixelSize = PixelSizeMax;
+ }
}
public override float DisplayWidth
{
- get => Header.DisplayWidth;
+ get => DISPLAY_WIDTH;
set { }
}
public override float DisplayHeight
{
- get => Header.DisplayHeight;
+ get => DISPLAY_HEIGHT;
set { }
}
@@ -286,13 +313,7 @@ namespace UVtools.Core.FileFormats
get => true;
set { }
}
-
- public override byte AntiAliasing
- {
- get => 1;
- set { }
- }
-
+
public override float LayerHeight
{
get => (float) Layer.RoundHeight(HeaderSettings.LayerHeight);
@@ -305,7 +326,7 @@ namespace UVtools.Core.FileFormats
public override float MachineZ
{
- get => Header.BuildZ;
+ get => MACHINE_Z;
set { }
}
@@ -409,90 +430,40 @@ namespace UVtools.Core.FileFormats
#endregion
#region Methods
-
- public unsafe byte[] PreviewEncode(Mat mat)
- {
- byte[] bytes = new byte[mat.Width * mat.Height * 2];
- var span = mat.GetBytePointer();
- var imageLength = mat.GetLength();
-
- int index = 0;
- for (int i = 0; i < imageLength; i+=3)
- {
- byte r = span[i + 2]; // 60
- byte g = span[i + 1];
- byte b = span[i];
-
- ushort color = (ushort)(((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3));
-
- bytes[index++] = (byte)color;
- bytes[index++] = (byte)(color >> 8);
- }
-
- if (index != bytes.Length)
- {
- throw new FileLoadException($"Preview encode incomplete encode, expected: {bytes.Length}, encoded: {index}");
- }
-
- return bytes;
- }
-
- public unsafe Mat PreviewDecode(byte[] data)
- {
- Mat mat = new((int)HeaderSettings.PreviewResolutionY, (int)HeaderSettings.PreviewResolutionX, DepthType.Cv8U, 3);
- var span = mat.GetBytePointer();
- int spanIndex = 0;
- for (int i = 0; i < data.Length; i += 2)
- {
- ushort color16 = BitExtensions.ToUShortLittleEndian(data[i], data[i + 1]);
-
- //var r = (byte)((color16 & 0x1F) << 3);
- //var g = (byte)(((color16 >> 5) & 0x3F) << 2);
- //var b = (byte)(((color16 >> 11) & 0x1f) << 3);
- var r = (byte)((color16 << 3) & 0xF8); // Mask: 11111000
- var g = (byte)((color16 >> 3) & 0xFC); // Mask: 11111100
- var b = (byte)((color16 >> 8) & 0xF8); // Mask: 11111000
-
- span[spanIndex++] = b;
- span[spanIndex++] = g;
- span[spanIndex++] = r;
- }
-
- return mat;
- }
-
+
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
//throw new NotSupportedException("PhotonS is read-only format, please use pws instead!");
- //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
outputFile.WriteSerialize(HeaderSettings);
- outputFile.WriteBytes(PreviewEncode(Thumbnails[0]));
+ outputFile.WriteBytes(EncodeImage(DATATYPE_BGR565, Thumbnails[0]));
outputFile.WriteSerialize(LayerSettings);
- var layerData = new LayerData[LayerCount];
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ var layerData = new LayerDef[LayerCount];
- Parallel.For(0, LayerCount, layerIndex =>
+ foreach (var batch in BatchLayersIndexes())
{
- if (progress.Token.IsCancellationRequested) return;
- using (var mat = this[layerIndex].LayerMat)
+ Parallel.ForEach(batch, layerIndex =>
{
- layerData[layerIndex] = new LayerData();
- layerData[layerIndex].Encode(mat);
- }
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
+ {
+ layerData[layerIndex] = new LayerDef(mat);
+ layerData[layerIndex].Encode(mat);
+ }
+ progress.LockAndIncrement();
+ });
- progress.LockAndIncrement();
- });
+ foreach (var layerIndex in batch)
+ {
+ progress.Token.ThrowIfCancellationRequested();
- progress.ItemName = "Saving layers";
- progress.ProcessedItems = 0;
+ outputFile.WriteSerialize(layerData[layerIndex]);
+ outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
- for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
- {
- progress.Token.ThrowIfCancellationRequested();
- outputFile.WriteSerialize(layerData[layerIndex]);
- outputFile.WriteBytes(layerData[layerIndex].EncodedRle);
- progress++;
+ layerData[layerIndex].EncodedRle = null; // Free
+ }
}
Debug.WriteLine("Encode Results:");
@@ -512,43 +483,52 @@ namespace UVtools.Core.FileFormats
int previewSize = (int) (HeaderSettings.PreviewResolutionX * HeaderSettings.PreviewResolutionY * 2);
byte[] previewData = new byte[previewSize];
-
- uint currentOffset = (uint) Helpers.Serializer.SizeOf(HeaderSettings);
- currentOffset += inputFile.ReadBytes(previewData);
- Thumbnails[0] = PreviewDecode(previewData);
+ inputFile.ReadBytes(previewData);
+ Thumbnails[0] = DecodeImage(DATATYPE_BGR565, previewData, HeaderSettings.PreviewResolutionX, HeaderSettings.PreviewResolutionY);
LayerSettings = Helpers.Deserialize<LayerHeader>(inputFile);
- currentOffset += (uint)Helpers.Serializer.SizeOf(LayerSettings);
-
+
Debug.WriteLine(HeaderSettings);
Debug.WriteLine(LayerSettings);
- var layerData = new LayerData[LayerSettings.LayerCount];
- progress.Reset(OperationProgress.StatusGatherLayers, LayerSettings.LayerCount);
+ LayerManager.Init(LayerSettings.LayerCount);
+ var layersDefinitions = new LayerDef[LayerSettings.LayerCount];
- for (int layerIndex = 0; layerIndex < LayerSettings.LayerCount; layerIndex++)
+ progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ foreach (var batch in BatchLayersIndexes())
{
- progress.Token.ThrowIfCancellationRequested();
- layerData[layerIndex] = Helpers.Deserialize<LayerData>(inputFile);
- layerData[layerIndex].EncodedRle = new byte[layerData[layerIndex].RleDataSize];
- currentOffset += inputFile.ReadBytes(layerData[layerIndex].EncodedRle);
- Debug.WriteLine($"Layer {layerIndex} -> {layerData[layerIndex]}");
- }
+ foreach (var layerIndex in batch)
+ {
+ progress.Token.ThrowIfCancellationRequested();
- LayerManager.Init(LayerSettings.LayerCount);
- progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ var layerDef = Helpers.Deserialize<LayerDef>(inputFile);
+ layersDefinitions[layerIndex] = layerDef;
- Parallel.For(0, LayerCount,
- //new ParallelOptions{MaxDegreeOfParallelism = 1},
- layerIndex =>
+ layerDef.EncodedRle = inputFile.ReadBytes(layerDef.RleDataSize);
+
+ Debug.Write($"LAYER {layerIndex} -> ");
+ Debug.WriteLine(layerDef);
+
+ if (layerIndex == 1)
+ {
+ // Auto fix resolution if needed
+ ResolutionX = layersDefinitions[layerIndex].ResolutionX;
+ ResolutionY = layersDefinitions[layerIndex].ResolutionY;
+ }
+ }
+
+ Parallel.ForEach(batch, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
+ using (var mat = layersDefinitions[layerIndex].Decode())
+ {
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ }
- using var image = layerData[layerIndex].Decode();
- this[layerIndex] = new Layer((uint) layerIndex, image, this);
progress.LockAndIncrement();
});
+ }
LayerManager.RebuildLayersProperties();
}
diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
index 0663d91..0a23b7f 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -121,7 +121,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// 18
/// </summary>
- [FieldOrder(4)] public uint Offset1 { get; set; }
+ [FieldOrder(4)] public uint Padding1 { get; set; }
/// <summary>
/// Gets the preview start offset
@@ -132,7 +132,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// 20
/// </summary>
- [FieldOrder(6)] public uint Offset2 { get; set; }
+ [FieldOrder(6)] public uint Padding2 { get; set; }
/// <summary>
/// Gets the layer definition start address
@@ -143,7 +143,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// 28
/// </summary>
- [FieldOrder(8)] public uint Offset3 { get; set; }
+ [FieldOrder(8)] public uint Padding3 { get; set; }
/// <summary>
/// Gets layer image start address
@@ -153,7 +153,7 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(Mark)}: {Mark}, {nameof(Version)}: {Version}, {nameof(AreaNum)}: {AreaNum}, {nameof(HeaderAddress)}: {HeaderAddress}, {nameof(Offset1)}: {Offset1}, {nameof(PreviewAddress)}: {PreviewAddress}, {nameof(Offset2)}: {Offset2}, {nameof(LayerDefinitionAddress)}: {LayerDefinitionAddress}, {nameof(Offset3)}: {Offset3}, {nameof(LayerImageAddress)}: {LayerImageAddress}";
+ return $"{nameof(Mark)}: {Mark}, {nameof(Version)}: {Version}, {nameof(AreaNum)}: {AreaNum}, {nameof(HeaderAddress)}: {HeaderAddress}, {nameof(Padding1)}: {Padding1}, {nameof(PreviewAddress)}: {PreviewAddress}, {nameof(Padding2)}: {Padding2}, {nameof(LayerDefinitionAddress)}: {LayerDefinitionAddress}, {nameof(Padding3)}: {Padding3}, {nameof(LayerImageAddress)}: {LayerImageAddress}";
}
}
#endregion
@@ -341,19 +341,19 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// 88
/// </summary>
- [FieldOrder(19)] public uint Offset1 { get; set; }
+ [FieldOrder(19)] public uint Padding1 { get; set; }
/// <summary>
/// 8C
/// </summary>
- [FieldOrder(20)] public uint Offset2 { get; set; }
+ [FieldOrder(20)] public uint Padding2 { get; set; }
public Header()
{
Section = new SectionHeader(SectionMark, this);
}
- public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(PixelSizeUm)}: {PixelSizeUm}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(LayerExposureTime)}: {LayerExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(VolumeMl)}: {VolumeMl}, {nameof(AntiAliasing)}: {AntiAliasing}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(WeightG)}: {WeightG}, {nameof(Price)}: {Price}, {nameof(PriceCurrencyDec)}: {PriceCurrencyDec}, {nameof(PerLayerOverride)}: {PerLayerOverride}, {nameof(PrintTime)}: {PrintTime}, {nameof(Offset1)}: {Offset1}, {nameof(Offset2)}: {Offset2}";
+ public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(PixelSizeUm)}: {PixelSizeUm}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(LayerExposureTime)}: {LayerExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(VolumeMl)}: {VolumeMl}, {nameof(AntiAliasing)}: {AntiAliasing}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(WeightG)}: {WeightG}, {nameof(Price)}: {Price}, {nameof(PriceCurrencyDec)}: {PriceCurrencyDec}, {nameof(PerLayerOverride)}: {PerLayerOverride}, {nameof(PrintTime)}: {PrintTime}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}";
public void Validate()
{
@@ -382,26 +382,26 @@ namespace UVtools.Core.FileFormats
/// Gets the image width, in pixels.
/// A0
/// </summary>
- [FieldOrder(1)] public uint Width { get; set; } = 224;
+ [FieldOrder(1)] public uint ResolutionX { get; set; } = 224;
/// <summary>
/// Gets the resolution of the image, in dpi.
/// A4
/// </summary>
- [FieldOrder(2)] public uint Resolution { get; set; } = 42;
+ [FieldOrder(2)] public uint DpiResolution { get; set; } = 42;
/// <summary>
/// Gets the image height, in pixels.
/// A8
/// </summary>
- [FieldOrder(3)] public uint Height { get; set; } = 168;
+ [FieldOrder(3)] public uint ResolutionY { get; set; } = 168;
- [FieldOrder(4)] public uint Offset1 { get; set; }
- [FieldOrder(5)] public uint Offset2 { get; set; }
- [FieldOrder(6)] public uint Offset3 { get; set; }
- [FieldOrder(7)] public uint Offset4 { get; set; }
+ [FieldOrder(4)] public uint Unknown1 { get; set; }
+ [FieldOrder(5)] public uint Unknown2 { get; set; }
+ [FieldOrder(6)] public uint Unknown3 { get; set; }
+ [FieldOrder(7)] public uint Unknown4 { get; set; }
- [Ignore] public uint DataSize => Width * Height * 2;
+ [Ignore] public uint DataSize => ResolutionX * ResolutionY * 2;
// little-endian 16bit colors, RGB 565 encoded.
//[FieldOrder(4)] [FieldLength(nameof(Section)+"."+nameof(SectionHeader.Length))]
@@ -412,16 +412,16 @@ namespace UVtools.Core.FileFormats
Section = new SectionHeader(SectionMark, this);
}
- public Preview(uint width, uint height, uint resolution = 42) : this()
+ public Preview(uint resolutionX, uint resolutionY, uint dpiResolution = 42) : this()
{
- Width = width;
- Height = height;
- Resolution = resolution;
+ ResolutionX = resolutionX;
+ ResolutionY = resolutionY;
+ DpiResolution = dpiResolution;
Data = new byte[DataSize];
Section.Length += (uint)Data.Length;
}
- public unsafe Mat Decode(bool consumeData = true)
+ /*public unsafe Mat Decode(bool consumeData = true)
{
Mat image = new(new Size((int) Width, (int) Height), DepthType.Cv8U, 3);
var span = image.GetBytePointer();
@@ -469,10 +469,10 @@ namespace UVtools.Core.FileFormats
return preview;
}
-
+ */
public override string ToString()
{
- return $"{nameof(Section)}: {Section}, {nameof(Width)}: {Width}, {nameof(Resolution)}: {Resolution}, {nameof(Height)}: {Height}, {nameof(Data)}: {Data?.Length ?? 0}";
+ return $"{nameof(Section)}: {Section}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(DpiResolution)}: {DpiResolution}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Data)}: {Data?.Length ?? 0}";
}
public void Validate(int size)
@@ -485,7 +485,7 @@ namespace UVtools.Core.FileFormats
#region Layer
- public class LayerData
+ public class LayerDef
{
public const byte ClassSize = 32;
/// <summary>
@@ -505,38 +505,43 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the exposure time for this layer, in seconds.
/// </summary>
- [FieldOrder(4)]
- public float ExposureTime { get; set; }
+ [FieldOrder(4)] public float ExposureTime { get; set; }
/// <summary>
/// Gets the layer height for this layer, measured in millimeters.
/// </summary>
- [FieldOrder(5)]
- public float LayerHeight { get; set; }
+ [FieldOrder(5)] public float LayerHeight { get; set; }
[FieldOrder(6)] public uint NonZeroPixelCount { get; set; }
- [FieldOrder(7)] public uint Offset1 { get; set; }
+ [FieldOrder(7)] public uint Padding1 { get; set; }
[Ignore] public byte[] EncodedRle { get; set; }
[Ignore] public PhotonWorkshopFile Parent { get; set; }
- public LayerData()
+ public LayerDef()
{
}
- public LayerData(PhotonWorkshopFile parent, uint layerIndex)
+ public LayerDef(PhotonWorkshopFile parent, Layer layer)
{
Parent = parent;
- RefreshLayerData(layerIndex);
+ SetFrom(layer);
+ }
+
+ public void SetFrom(Layer layer)
+ {
+ LayerHeight = layer.LayerHeight;
+ ExposureTime = layer.ExposureTime;
+ LiftHeight = layer.LiftHeight;
+ LiftSpeed = (float) Math.Round(layer.LiftSpeed / 60, 2);
+ NonZeroPixelCount = layer.NonZeroPixelCount;
}
- public void RefreshLayerData(uint layerIndex)
+ public void CopyTo(Layer layer)
{
- LayerHeight = Parent[layerIndex].LayerHeight;
- ExposureTime = Parent[layerIndex].ExposureTime;
- LiftHeight = Parent[layerIndex].LiftHeight;
- LiftSpeed = (float) Math.Round(Parent[layerIndex].LiftSpeed / 60, 2);
- NonZeroPixelCount = Parent[layerIndex].NonZeroPixelCount;
+ layer.ExposureTime = ExposureTime;
+ layer.LiftHeight = LiftHeight;
+ layer.LiftSpeed = (float)Math.Round(LiftSpeed * 60, 2);
}
public Mat Decode(bool consumeData = true)
@@ -681,72 +686,79 @@ namespace UVtools.Core.FileFormats
return rawData.ToArray();
}
- private unsafe Mat DecodePW0()
+ private Mat DecodePW0()
{
- var image = EmguExtensions.InitMat(Parent.Resolution);
- var span = image.GetBytePointer();
- var imageLength = image.GetLength();
+ var mat = EmguExtensions.InitMat(Parent.Resolution);
+ var imageLength = mat.GetLength();
- uint n = 0;
- for (int index = 0; index < EncodedRle.Length; index++)
+ int pixelPos = 0;
+ for (int i = 0; i < EncodedRle.Length; i++)
{
- byte b = EncodedRle[index];
+ byte b = EncodedRle[i];
int code = b >> 4;
- uint reps = (uint) (b & 0xf);
+ int repeat = b & 0xf;
byte color;
switch (code)
{
case 0x0:
- color = 0x00;
- index++;
- //reps = reps * 256 + EncodedRle[index];
- reps = (reps << 8) + EncodedRle[index];
+ color = 0;
+ i++;
+ //reps = reps * 256 + EncodedRle[i];
+ if (i >= EncodedRle.Length)
+ {
+ repeat = imageLength - pixelPos;
+ break;
+ }
+
+ repeat = (repeat << 8) + EncodedRle[i];
break;
case 0xf:
- color = 0xff;
- index++;
- //reps = reps * 256 + EncodedRle[index];
- reps = (reps << 8) + EncodedRle[index];
+ color = 255;
+ i++;
+ //reps = reps * 256 + EncodedRle[i];
+ if (i >= EncodedRle.Length)
+ {
+ repeat = imageLength - pixelPos;
+ break;
+ }
+
+ repeat = (repeat << 8) + EncodedRle[i];
break;
default:
color = (byte) ((code << 4) | code);
+ if (i >= EncodedRle.Length)
+ {
+ repeat = imageLength - pixelPos;
+ }
break;
}
//color &= 0xff;
// We only need to set the non-zero pixels
- if (color != 0)
- {
- for (int i = 0; i < reps; i++)
- {
- span[(int) (n + i)] |= color;
- }
- }
-
- n += reps;
+ mat.FillSpan(ref pixelPos, repeat, color);
- if (n == imageLength)
+ if (pixelPos == imageLength)
{
- //index++;
+ //i++;
break;
}
- if (n > imageLength)
+ if (pixelPos > imageLength)
{
- image.Dispose();
- throw new FileLoadException($"Error image ran off the end: {n - reps}({reps}) of {imageLength}");
+ mat.Dispose();
+ throw new FileLoadException($"Error image ran off the end: {pixelPos - repeat}({repeat}) of {imageLength}");
}
}
- if (n > 0 && n != imageLength)
+ if (pixelPos > 0 && pixelPos != imageLength)
{
- image.Dispose();
- throw new FileLoadException($"Error image ended short: {n} of {imageLength}");
+ mat.Dispose();
+ throw new FileLoadException($"Error image ended short: {pixelPos} of {imageLength}");
}
- return image;
+ return mat;
}
public unsafe byte[] EncodePW0(Mat image)
@@ -840,7 +852,7 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(DataAddress)}: {DataAddress}, {nameof(DataLength)}: {DataLength}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(Offset1)}: {Offset1}, {nameof(EncodedRle)}: {EncodedRle?.Length ?? 0}";
+ return $"{nameof(DataAddress)}: {DataAddress}, {nameof(DataLength)}: {DataLength}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(Padding1)}: {Padding1}, {nameof(EncodedRle)}: {EncodedRle?.Length ?? 0}";
}
}
@@ -858,7 +870,7 @@ namespace UVtools.Core.FileFormats
[FieldOrder(1)] public uint LayerCount { get; set; }
- [Ignore] public LayerData[] Layers { get; set; }
+ [Ignore] public LayerDef[] Layers { get; set; }
public LayerDefinition()
{
@@ -868,19 +880,19 @@ namespace UVtools.Core.FileFormats
public LayerDefinition(uint layerCount) : this()
{
LayerCount = layerCount;
- Layers = new LayerData[layerCount];
- Section.Length += (uint) Helpers.Serializer.SizeOf(new LayerData()) * LayerCount;
+ Layers = new LayerDef[layerCount];
+ Section.Length += (uint) Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
}
[Ignore]
- public LayerData this[uint index]
+ public LayerDef this[uint index]
{
get => Layers[index];
set => Layers[index] = value;
}
[Ignore]
- public LayerData this[int index]
+ public LayerDef this[int index]
{
get => Layers[index];
set => Layers[index] = value;
@@ -888,7 +900,7 @@ namespace UVtools.Core.FileFormats
public void Validate()
{
- Section.Validate(SectionMark, (int) (LayerCount * Helpers.Serializer.SizeOf(new LayerData()) - Helpers.Serializer.SizeOf(Section)), this);
+ Section.Validate(SectionMark, (int) (LayerCount * Helpers.Serializer.SizeOf(new LayerDef()) - Helpers.Serializer.SizeOf(Section)), this);
}
public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(LayerCount)}: {LayerCount}";
@@ -907,8 +919,6 @@ namespace UVtools.Core.FileFormats
public LayerDefinition LayersDefinition { get; protected internal set; } = new();
- public Dictionary<string, LayerData> LayersHash { get; } = new();
-
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
@@ -1054,9 +1064,8 @@ namespace UVtools.Core.FileFormats
get => (byte) HeaderSettings.AntiAliasing;
set
{
- HeaderSettings.AntiAliasing = value.Clamp(1, 16);
+ base.AntiAliasing = (byte)(HeaderSettings.AntiAliasing = value.Clamp(1, 16));
ValidateAntiAliasingLevel();
- RaisePropertyChanged();
}
}
@@ -1272,9 +1281,6 @@ namespace UVtools.Core.FileFormats
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
- LayersHash.Clear();
- LayersDefinition = new LayerDefinition(LayerCount);
-
switch (PrinterModel)
{
case AnyCubicMachine.AnyCubicPhotonS:
@@ -1303,65 +1309,72 @@ namespace UVtools.Core.FileFormats
HeaderSettings.PerLayerOverride = (byte)(LayerManager.AllLayersHaveGlobalParameters ? 0 : 1);
- uint currentOffset = FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings);
+ FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings);
using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
- outputFile.Seek((int) currentOffset, SeekOrigin.Begin);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+ outputFile.Seek((int)FileMarkSettings.HeaderAddress, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
if (CreatedThumbnailsCount > 0)
{
- FileMarkSettings.PreviewAddress = currentOffset;
- Preview preview = Preview.Encode(Thumbnails[0]);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, preview);
- currentOffset += outputFile.WriteBytes(preview.Data);
+ FileMarkSettings.PreviewAddress = (uint)outputFile.Position;
+ //Preview preview = Preview.Encode(Thumbnails[0]);
+ var preview = new Preview((uint)Thumbnails[0].Width, (uint)Thumbnails[0].Height)
+ {
+ Data = EncodeImage(DATATYPE_RGB565, Thumbnails[0])
+ };
+ Helpers.SerializeWriteFileStream(outputFile, preview);
+ outputFile.WriteBytes(preview.Data);
}
- FileMarkSettings.LayerDefinitionAddress = currentOffset;
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ FileMarkSettings.LayerDefinitionAddress = (uint)outputFile.Position;
+ LayersDefinition = new LayerDefinition(LayerCount);
+ Helpers.SerializeWriteFileStream(outputFile, LayersDefinition);
+ uint layerDefOffset = (uint)outputFile.Position;
+ uint layerRleOffset = FileMarkSettings.LayerImageAddress = (uint)(layerDefOffset + Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount);
+ var layersHash = new Dictionary<string, LayerDef>();
- Parallel.For(0, LayerCount, layerIndex =>
+ foreach (var batch in BatchLayersIndexes())
{
- if (progress.Token.IsCancellationRequested) return;
- LayerData layer = new(this, (uint) layerIndex);
- using (var image = this[layerIndex].LayerMat)
+ Parallel.ForEach(batch, layerIndex =>
{
- layer.Encode(image);
- LayersDefinition.Layers[layerIndex] = layer;
- }
- progress.LockAndIncrement();
- });
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = this[layerIndex].LayerMat)
+ {
+ LayersDefinition.Layers[layerIndex] = new LayerDef(this, this[layerIndex]);
+ LayersDefinition.Layers[layerIndex].Encode(mat);
+ }
+ progress.LockAndIncrement();
+ });
- uint offsetLayerRle = FileMarkSettings.LayerImageAddress = (uint) (currentOffset + Helpers.Serializer.SizeOf(LayersDefinition.Section) + LayersDefinition.Section.Length);
+ foreach (var layerIndex in batch)
+ {
+ progress.Token.ThrowIfCancellationRequested();
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, LayersDefinition);
+ var layerDef = LayersDefinition.Layers[layerIndex];
- progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
+ var hash = Helpers.ComputeSHA1Hash(layerDef.EncodedRle);
- foreach (var layer in LayersDefinition.Layers)
- {
- progress.Token.ThrowIfCancellationRequested();
- string hash = Helpers.ComputeSHA1Hash(layer.EncodedRle);
+ if (layersHash.TryGetValue(hash, out var layerDataHash))
+ {
+ layerDef.DataAddress = layerDataHash.DataAddress;
+ layerDef.DataLength = (uint)layerDataHash.EncodedRle.Length;
+ }
+ else
+ {
+ layersHash.Add(hash, layerDef);
- if (LayersHash.TryGetValue(hash, out var layerDataHash))
- {
- layer.DataAddress = layerDataHash.DataAddress;
- layer.DataLength = (uint)layerDataHash.EncodedRle.Length;
- }
- else
- {
- LayersHash.Add(hash, layer);
+ layerDef.DataAddress = layerRleOffset;
- layer.DataAddress = offsetLayerRle;
+ outputFile.Seek(layerRleOffset, SeekOrigin.Begin);
+ layerRleOffset += Helpers.SerializeWriteFileStream(outputFile, layerDef.EncodedRle);
+ }
- outputFile.Seek(offsetLayerRle, SeekOrigin.Begin);
- offsetLayerRle += Helpers.SerializeWriteFileStream(outputFile, layer.EncodedRle);
+ outputFile.Seek(layerDefOffset, SeekOrigin.Begin);
+ layerDefOffset += Helpers.SerializeWriteFileStream(outputFile, layerDef);
}
-
- outputFile.Seek(currentOffset, SeekOrigin.Begin);
- currentOffset += Helpers.SerializeWriteFileStream(outputFile, layer);
-
- progress++;
}
-
+
// Rewind
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, FileMarkSettings);
@@ -1410,7 +1423,8 @@ namespace UVtools.Core.FileFormats
PreviewSettings.Data = new byte[PreviewSettings.DataSize];
inputFile.ReadBytes(PreviewSettings.Data);
- Thumbnails[0] = PreviewSettings.Decode(true);
+ Thumbnails[0] = DecodeImage(DATATYPE_RGB565, PreviewSettings.Data, PreviewSettings.ResolutionX, PreviewSettings.ResolutionY);
+ PreviewSettings.Data = null;
}
inputFile.Seek(FileMarkSettings.LayerDefinitionAddress, SeekOrigin.Begin);
@@ -1420,54 +1434,44 @@ namespace UVtools.Core.FileFormats
Debug.WriteLine(LayersDefinition);
LayerManager.Init(LayersDefinition.LayerCount);
- LayersDefinition.Layers = new LayerData[LayerCount];
-
-
+ LayersDefinition.Layers = new LayerDef[LayerCount];
+
LayersDefinition.Validate();
- for (int i = 0; i < LayerCount; i++)
+ progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ foreach (var batch in BatchLayersIndexes())
{
- LayersDefinition[i] = Helpers.Deserialize<LayerData>(inputFile);
- LayersDefinition[i].Parent = this;
- Debug.WriteLine($"Layer {i}: {LayersDefinition[i]}");
- }
-
- progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
+ foreach (var layerIndex in batch)
+ {
+ progress.Token.ThrowIfCancellationRequested();
- for (int i = 0; i < LayerCount; i++)
- {
- var layer = LayersDefinition[i];
- //layer.Parent = this;
- inputFile.Seek(layer.DataAddress, SeekOrigin.Begin);
- layer.EncodedRle = new byte[layer.DataLength];
- inputFile.ReadBytes(layer.EncodedRle);
-
- progress++;
- progress.Token.ThrowIfCancellationRequested();
- }
+ LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
+ LayersDefinition[layerIndex].Parent = this;
+ Debug.WriteLine($"Layer {layerIndex}: {LayersDefinition[layerIndex]}");
- progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
- Parallel.For(0, LayerCount, layerIndex =>
- {
- if (progress.Token.IsCancellationRequested)
- {
- return;
+ inputFile.SeekDoWorkAndRewind(LayersDefinition[layerIndex].DataAddress, () =>
+ {
+ LayersDefinition[layerIndex].EncodedRle = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength);
+ });
}
- using (var image = LayersDefinition[(uint) layerIndex].Decode())
+ Parallel.ForEach(batch, layerIndex =>
{
- this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager)
+ if (progress.Token.IsCancellationRequested) return;
+ using (var mat = LayersDefinition[layerIndex].Decode())
{
- PositionZ = Layer.RoundHeight(LayersDefinition[(uint)layerIndex].LayerHeight),
- ExposureTime = LayersDefinition[(uint)layerIndex].ExposureTime,
- LiftHeight = LayersDefinition[(uint)layerIndex].LiftHeight,
- LiftSpeed = (float)Math.Round(LayersDefinition[(uint)layerIndex].LiftSpeed * 60, 2),
- };
- }
+ var layer = new Layer((uint)layerIndex, mat, this)
+ {
+ PositionZ = Layer.RoundHeight(LayersDefinition[(uint)layerIndex].LayerHeight),
+ };
+ LayersDefinition[layerIndex].CopyTo(layer);
+ this[layerIndex] = layer;
+ }
- progress.LockAndIncrement();
- });
+ progress.LockAndIncrement();
+ });
+ }
// Fix position z height values
if (LayerCount > 0)
@@ -1508,7 +1512,7 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(FileMarkSettings.LayerDefinitionAddress + Helpers.Serializer.SizeOf(LayersDefinition), SeekOrigin.Begin);
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
- LayersDefinition[layerIndex].RefreshLayerData(layerIndex);
+ LayersDefinition[layerIndex].SetFrom(this[layerIndex]);
Helpers.SerializeWriteFileStream(outputFile, LayersDefinition[layerIndex]);
}
}
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 1d58802..33d7555 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -40,9 +40,18 @@ namespace UVtools.Core.FileFormats
public const string Keyword_BottomLiftSpeed = "BottomLiftSpeed";
public const string Keyword_LiftHeight = "LiftHeight";
public const string Keyword_LiftSpeed = "LiftSpeed";
+ public const string Keyword_BottomLiftHeight2 = "BottomLiftHeight2";
+ public const string Keyword_BottomLiftSpeed2 = "BottomLiftSpeed2";
+ public const string Keyword_LiftHeight2 = "LiftHeight2";
+ public const string Keyword_LiftSpeed2 = "LiftSpeed2";
public const string Keyword_BottomWaitTimeAfterLift = "BottomWaitAfterLift";
public const string Keyword_WaitTimeAfterLift = "WaitAfterLift";
+ public const string Keyword_BottomRetractSpeed = "BottomRetractSpeed";
public const string Keyword_RetractSpeed = "RetractSpeed";
+ public const string Keyword_BottomRetractHeight2 = "BottomRetractHeight2";
+ public const string Keyword_BottomRetractSpeed2 = "BottomRetractSpeed2";
+ public const string Keyword_RetractHeight2 = "RetractHeight2";
+ public const string Keyword_RetractSpeed2 = "RetractSpeed2";
public const string Keyword_BottomLightPWM = "BottomLightPWM";
public const string Keyword_LightPWM = "LightPWM";
#endregion
@@ -652,10 +661,22 @@ namespace UVtools.Core.FileFormats
LiftHeight = LookupCustomValue(Keyword_LiftHeight, DefaultLiftHeight);
LiftSpeed = LookupCustomValue(Keyword_LiftSpeed, DefaultLiftSpeed);
+ BottomLiftHeight2 = LookupCustomValue(Keyword_BottomLiftHeight2, DefaultBottomLiftHeight2);
+ BottomLiftSpeed2 = LookupCustomValue(Keyword_BottomLiftSpeed2, DefaultBottomLiftSpeed2);
+
+ LiftHeight2 = LookupCustomValue(Keyword_LiftHeight2, DefaultLiftHeight2);
+ LiftSpeed2 = LookupCustomValue(Keyword_LiftSpeed2, DefaultLiftSpeed2);
+
BottomWaitTimeAfterLift = LookupCustomValue(Keyword_BottomWaitTimeAfterLift, 0f);
WaitTimeAfterLift = LookupCustomValue(Keyword_WaitTimeAfterLift, 0f);
+ BottomRetractSpeed = LookupCustomValue(Keyword_BottomRetractSpeed, DefaultBottomRetractSpeed);
RetractSpeed = LookupCustomValue(Keyword_RetractSpeed, DefaultRetractSpeed);
+
+ BottomRetractHeight2 = LookupCustomValue(Keyword_BottomRetractHeight2, DefaultBottomRetractHeight2);
+ RetractHeight2 = LookupCustomValue(Keyword_RetractHeight2, DefaultRetractHeight2);
+ BottomRetractSpeed2 = LookupCustomValue(Keyword_BottomRetractSpeed2, DefaultBottomRetractSpeed2);
+ RetractSpeed2 = LookupCustomValue(Keyword_RetractSpeed2, DefaultRetractSpeed2);
BottomLightPWM = LookupCustomValue(Keyword_BottomLightPWM, DefaultLightPWM);
LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM);
});
@@ -664,7 +685,7 @@ namespace UVtools.Core.FileFormats
progress.ItemCount = LayerCount;
- foreach (ZipArchiveEntry entity in inputFile.Entries)
+ foreach (var entity in inputFile.Entries)
{
if (!entity.Name.EndsWith(".png")) continue;
if (entity.Name.StartsWith("thumbnail"))
diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs
index c97c286..7ae70da 100644
--- a/UVtools.Core/FileFormats/UVJFile.cs
+++ b/UVtools.Core/FileFormats/UVJFile.cs
@@ -216,12 +216,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => JsonSettings.Properties.AntiAliasLevel;
- set
- {
- JsonSettings.Properties.AntiAliasLevel = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
-
+ set => base.AntiAliasing = JsonSettings.Properties.AntiAliasLevel = value.Clamp(1, 16);
}
public override float LayerHeight
@@ -363,7 +358,7 @@ namespace UVtools.Core.FileFormats
{
LiftHeight = layer.LiftHeight,
LiftSpeed = layer.LiftSpeed,
- RetractHeight = layer.LiftHeight+1,
+ RetractHeight = layer.LiftHeight,
RetractSpeed = layer.RetractSpeed,
LightOffTime = layer.LightOffDelay,
LightOnTime = layer.ExposureTime,
@@ -372,7 +367,7 @@ namespace UVtools.Core.FileFormats
});
}
- using ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create);
+ using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create);
outputFile.PutFileContent(FileConfigName, JsonConvert.SerializeObject(JsonSettings, Formatting.Indented), ZipArchiveMode.Create);
if (CreatedThumbnailsCount > 0)
@@ -407,7 +402,7 @@ namespace UVtools.Core.FileFormats
using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
{
var entry = inputFile.GetEntry(FileConfigName);
- if (ReferenceEquals(entry, null))
+ if (entry is null)
{
Clear();
throw new FileLoadException($"{FileConfigName} not found", fileFullPath);
@@ -418,21 +413,19 @@ namespace UVtools.Core.FileFormats
LayerManager.Init(JsonSettings.Properties.Size.Layers);
entry = inputFile.GetEntry(FilePreviewTinyName);
- if (!ReferenceEquals(entry, null))
+ if (entry is not null)
{
- using (Stream stream = entry.Open())
- {
- Mat image = new();
- CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
- Thumbnails[0] = image;
- stream.Close();
- }
+ using var stream = entry.Open();
+ Mat image = new();
+ CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
+ Thumbnails[0] = image;
+ stream.Close();
}
entry = inputFile.GetEntry(FilePreviewHugeName);
if (entry is not null)
{
- using Stream stream = entry.Open();
+ using var stream = entry.Open();
Mat image = new();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[1] = image;
@@ -482,10 +475,8 @@ namespace UVtools.Core.FileFormats
}
- using (var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update))
- {
- outputFile.PutFileContent(FileConfigName, JsonConvert.SerializeObject(JsonSettings, Formatting.Indented), ZipArchiveMode.Update);
- }
+ using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update);
+ outputFile.PutFileContent(FileConfigName, JsonConvert.SerializeObject(JsonSettings, Formatting.Indented), ZipArchiveMode.Update);
//Decode(FileFullPath, progress);
}
diff --git a/UVtools.Core/FileFormats/VDAFile.cs b/UVtools.Core/FileFormats/VDAFile.cs
index bba398b..0deabf9 100644
--- a/UVtools.Core/FileFormats/VDAFile.cs
+++ b/UVtools.Core/FileFormats/VDAFile.cs
@@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
@@ -152,7 +153,7 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
- new(typeof(VDAFile), "vda.zip", "Voxeldance Additive Zip")
+ new(typeof(VDAFile), "zip", "Voxeldance Additive Zip")
};
public override uint ResolutionX
@@ -247,11 +248,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => ManifestFile.Machines.AntiAliasing;
- set
- {
- ManifestFile.Machines.AntiAliasing = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
+ set => base.AntiAliasing = ManifestFile.Machines.AntiAliasing = value.Clamp(1, 16);
}
public override float LayerHeight
@@ -286,6 +283,24 @@ namespace UVtools.Core.FileFormats
#region Methods
+ public override bool CanProcess(string fileFullPath)
+ {
+ if(!base.CanProcess(fileFullPath)) return false;
+
+ try
+ {
+ using var zip = ZipFile.Open(fileFullPath, ZipArchiveMode.Read);
+ if (zip.Entries.Any(entry => entry.Name.EndsWith(".xml"))) return true;
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ }
+
+
+ return false;
+ }
+
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create);
diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs
index 2b3790d..df2030b 100644
--- a/UVtools.Core/FileFormats/VDTFile.cs
+++ b/UVtools.Core/FileFormats/VDTFile.cs
@@ -288,12 +288,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => ManifestFile.AdvancedParameters.AntialasingLevel;
- set
- {
- ManifestFile.AdvancedParameters.AntialasingLevel = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
-
+ set => base.AntiAliasing = ManifestFile.AdvancedParameters.AntialasingLevel = value.Clamp(1, 16);
}
public override float LayerHeight
@@ -370,18 +365,18 @@ namespace UVtools.Core.FileFormats
set => base.BottomLiftHeight = ManifestFile.Print.BottomLiftHeight = (float)Math.Round(value, 2);
}
- public override float LiftHeight
- {
- get => ManifestFile.Print.LiftHeight;
- set => base.LiftHeight = ManifestFile.Print.LiftHeight = (float)Math.Round(value, 2);
- }
-
public override float BottomLiftSpeed
{
get => ManifestFile.Print.BottomLiftSpeed;
set => base.BottomLiftSpeed = ManifestFile.Print.BottomLiftSpeed = (float)Math.Round(value, 2);
}
+ public override float LiftHeight
+ {
+ get => ManifestFile.Print.LiftHeight;
+ set => base.LiftHeight = ManifestFile.Print.LiftHeight = (float)Math.Round(value, 2);
+ }
+
public override float LiftSpeed
{
get => ManifestFile.Print.LiftSpeed;
@@ -394,18 +389,18 @@ namespace UVtools.Core.FileFormats
set => base.BottomLiftHeight2 = ManifestFile.Print.BottomLiftHeight2 = (float)Math.Round(value, 2);
}
- public override float LiftHeight2
- {
- get => ManifestFile.Print.LiftHeight2;
- set => base.LiftHeight2 = ManifestFile.Print.LiftHeight2 = (float)Math.Round(value, 2);
- }
-
public override float BottomLiftSpeed2
{
get => ManifestFile.Print.BottomLiftSpeed2;
set => base.BottomLiftSpeed2 = ManifestFile.Print.BottomLiftSpeed2 = (float)Math.Round(value, 2);
}
+ public override float LiftHeight2
+ {
+ get => ManifestFile.Print.LiftHeight2;
+ set => base.LiftHeight2 = ManifestFile.Print.LiftHeight2 = (float)Math.Round(value, 2);
+ }
+
public override float LiftSpeed2
{
get => ManifestFile.Print.LiftSpeed2;
@@ -438,21 +433,29 @@ namespace UVtools.Core.FileFormats
public override float BottomRetractHeight2
{
get => ManifestFile.Print.BottomRetractHeight2;
- set => base.BottomRetractHeight2 = ManifestFile.Print.BottomRetractHeight2 = (float)Math.Round(value, 2);
- }
-
- public override float RetractHeight2
- {
- get => ManifestFile.Print.RetractHeight2;
- set => base.RetractHeight2 = ManifestFile.Print.RetractHeight2 = (float)Math.Round(value, 2);
+ set
+ {
+ value = Math.Clamp((float)Math.Round(value, 2), 0, BottomRetractHeightTotal);
+ base.BottomRetractHeight2 = ManifestFile.Print.BottomRetractHeight2 = value;
+ }
}
-
+
public override float BottomRetractSpeed2
{
get => ManifestFile.Print.BottomRetractSpeed2;
set => base.BottomRetractSpeed2 = ManifestFile.Print.BottomRetractSpeed2 = (float)Math.Round(value, 2);
}
+ public override float RetractHeight2
+ {
+ get => ManifestFile.Print.RetractHeight2;
+ set
+ {
+ value = Math.Clamp((float)Math.Round(value, 2), 0, RetractHeightTotal);
+ base.RetractHeight2 = ManifestFile.Print.RetractHeight2 = value;
+ }
+ }
+
public override float RetractSpeed2
{
get => ManifestFile.Print.RetractSpeed2;
@@ -523,11 +526,11 @@ namespace UVtools.Core.FileFormats
public void RebuildVDTLayers()
{
ManifestFile.CreateDateTime = DateTime.UtcNow.ToString("u");
- var layers = new VDTLayer[LayerCount];
+ ManifestFile.Layers = new VDTLayer[LayerCount];
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var layer = this[layerIndex];
- layers[layerIndex] = new VDTLayer
+ ManifestFile.Layers[layerIndex] = new VDTLayer
{
PositionZ = layer.PositionZ,
LightOffDelay = layer.LightOffDelay,
@@ -545,8 +548,6 @@ namespace UVtools.Core.FileFormats
LightPWM = layer.LightPWM
};
}
-
- ManifestFile.Layers = layers;
}
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index db06f9e..9b25c50 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -292,11 +292,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => ManifestFile.Profile.Slice.AntiAliasing;
- set
- {
- ManifestFile.Profile.Slice.AntiAliasing = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
+ set => base.AntiAliasing = ManifestFile.Profile.Slice.AntiAliasing = value.Clamp(1, 16);
}
public override float LayerHeight
diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index 9a397df..72027f4 100644
--- a/UVtools.Core/FileFormats/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -216,12 +216,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => UserSettings.AntiAliasing;
- set
- {
- UserSettings.AntiAliasing = value.Clamp(1, 16);
- RaisePropertyChanged();
- }
-
+ set => base.AntiAliasing = UserSettings.AntiAliasing = value.Clamp(1, 16);
}
public override float LayerHeight
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index 9d5d156..63c4547 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -761,7 +761,6 @@ namespace UVtools.Core.GCode
"\r\n"
;*/
- float positionZ = 0;
var layerBlock = new GCodeLayer(slicerFile);
using var reader = new StringReader(gcode);
diff --git a/UVtools.Core/Helpers.cs b/UVtools.Core/Helpers.cs
index 53c8b90..905b972 100644
--- a/UVtools.Core/Helpers.cs
+++ b/UVtools.Core/Helpers.cs
@@ -101,9 +101,9 @@ namespace UVtools.Core
public static void SwapVariables<T>(ref T var1, ref T var2)
{
- var backup = var1;
- var1 = var2;
- var2 = backup;
+ (var1, var2) = (var2, var1);
}
+
+ public static float BrightnessToPercent(byte brightness, byte roundPlates = 2) => (float)Math.Round(brightness * 100 / 255f, roundPlates);
}
}
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index 456cec5..be20025 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -144,7 +144,7 @@ namespace UVtools.Core
get => _positionZ;
set
{
- if (!RaiseAndSetIfChanged(ref _positionZ, value)) return;
+ if (!RaiseAndSetIfChanged(ref _positionZ, RoundHeight(value))) return;
RaisePropertyChanged(nameof(LayerHeight));
}
}
@@ -160,7 +160,7 @@ namespace UVtools.Core
get => _waitTimeBeforeCure;
set
{
- if (!RaiseAndSetIfChanged(ref _waitTimeBeforeCure, value)) return;
+ if (!RaiseAndSetIfChanged(ref _waitTimeBeforeCure, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -174,7 +174,7 @@ namespace UVtools.Core
set
{
if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
- if(!RaiseAndSetIfChanged(ref _exposureTime, value)) return;
+ if(!RaiseAndSetIfChanged(ref _exposureTime, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -189,7 +189,7 @@ namespace UVtools.Core
get => _waitTimeAfterCure;
set
{
- if (!RaiseAndSetIfChanged(ref _waitTimeAfterCure, value)) return;
+ if (!RaiseAndSetIfChanged(ref _waitTimeAfterCure, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -203,7 +203,7 @@ namespace UVtools.Core
set
{
if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay);
- if(!RaiseAndSetIfChanged(ref _lightOffDelay, value)) return;
+ if(!RaiseAndSetIfChanged(ref _lightOffDelay, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -214,10 +214,10 @@ namespace UVtools.Core
/// </summary>
public float LiftHeightTotal
{
- get => (float)Math.Round(_liftHeight + _liftHeight2);
+ get => (float)Math.Round(_liftHeight + _liftHeight2, 2);
set
{
- LiftHeight = value;
+ LiftHeight = (float)Math.Round(value, 2);
LiftHeight2 = 0;
}
}
@@ -231,7 +231,7 @@ namespace UVtools.Core
set
{
if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
- if(!RaiseAndSetIfChanged(ref _liftHeight, value)) return;
+ if(!RaiseAndSetIfChanged(ref _liftHeight, (float)Math.Round(value, 2))) return;
RaisePropertyChanged(nameof(LiftHeightTotal));
RetractHeight2 = _retractHeight2; // Sanitize
SlicerFile?.UpdatePrintTimeQueued();
@@ -247,7 +247,7 @@ namespace UVtools.Core
set
{
if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
- if(!RaiseAndSetIfChanged(ref _liftSpeed, value)) return;
+ if(!RaiseAndSetIfChanged(ref _liftSpeed, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -261,7 +261,7 @@ namespace UVtools.Core
set
{
if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftHeight2, SlicerFile.LiftHeight2);
- if (!RaiseAndSetIfChanged(ref _liftHeight2, value)) return;
+ if (!RaiseAndSetIfChanged(ref _liftHeight2, (float)Math.Round(value, 2))) return;
RaisePropertyChanged(nameof(LiftHeightTotal));
RetractHeight2 = _retractHeight2; // Sanitize
SlicerFile?.UpdatePrintTimeQueued();
@@ -277,7 +277,7 @@ namespace UVtools.Core
set
{
if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
- if (!RaiseAndSetIfChanged(ref _liftSpeed2, value)) return;
+ if (!RaiseAndSetIfChanged(ref _liftSpeed2, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -287,7 +287,7 @@ namespace UVtools.Core
get => _waitTimeAfterLift;
set
{
- if (!RaiseAndSetIfChanged(ref _waitTimeAfterLift, value)) return;
+ if (!RaiseAndSetIfChanged(ref _waitTimeAfterLift, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -300,7 +300,7 @@ namespace UVtools.Core
/// <summary>
/// Gets the retract height in mm
/// </summary>
- public float RetractHeight => (float)Math.Round(LiftHeightTotal - _retractHeight2);
+ public float RetractHeight => (float)Math.Round(LiftHeightTotal - _retractHeight2, 2);
/// <summary>
/// Gets the speed in mm/min for the retracts
@@ -311,7 +311,7 @@ namespace UVtools.Core
set
{
if (value <= 0) value = SlicerFile.RetractSpeed;
- if(!RaiseAndSetIfChanged(ref _retractSpeed, value)) return;
+ if(!RaiseAndSetIfChanged(ref _retractSpeed, (float)Math.Round(value, 2))) return;
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -391,9 +391,10 @@ namespace UVtools.Core
private set
{
if (ParentLayerManager?.SlicerFile is null) return;
+ //var globalMilliliters = SlicerFile.MaterialMilliliters - _materialMilliliters;
if (value <= 0)
{
- value = (float) Math.Round(ParentLayerManager.SlicerFile.PixelArea * ParentLayerManager.SlicerFile.LayerHeight * NonZeroPixelCount / 1000, 4);
+ value = (float) Math.Round(ParentLayerManager.SlicerFile.PixelArea * ParentLayerManager.SlicerFile.LayerHeight * NonZeroPixelCount / 1000f, 4);
}
if(!RaiseAndSetIfChanged(ref _materialMilliliters, value)) return;
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index ccd1305..3afa268 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -128,7 +128,8 @@ namespace UVtools.Core.Operations
private decimal _featuresHeight = 1;
private decimal _featuresMargin = 2m;
- private ushort _staircaseThickness = 40;
+ private ushort _staircaseThicknessPx = 40;
+ private decimal _staircaseThicknessMm = 2;
private bool _holesEnabled = false;
private CalibrateExposureFinderShapes _holeShape = CalibrateExposureFinderShapes.Square;
@@ -485,12 +486,22 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _featuresMargin, Math.Round(value, 2));
}
- public ushort StaircaseThickness
+ public ushort StaircaseThicknessPx
{
- get => _staircaseThickness;
- set => RaiseAndSetIfChanged(ref _staircaseThickness, value);
+ get => _staircaseThicknessPx;
+ set => RaiseAndSetIfChanged(ref _staircaseThicknessPx, value);
}
+ public decimal StaircaseThicknessMm
+ {
+ get => _staircaseThicknessMm;
+ set => RaiseAndSetIfChanged(ref _staircaseThicknessMm, value);
+ }
+
+ public ushort StaircaseThickness => _unitOfMeasure == CalibrateExposureFinderMeasures.Pixels
+ ? _staircaseThicknessPx
+ : (ushort)(_staircaseThicknessMm * Yppmm);
+
public bool CounterTrianglesEnabled
{
get => _counterTrianglesEnabled;
@@ -664,7 +675,7 @@ namespace UVtools.Core.Operations
{
if (string.IsNullOrWhiteSpace(mmStr)) continue;
if (!decimal.TryParse(mmStr, out var mm)) continue;
- var mmPx = (int)(mm * Xppmm);
+ var mmPx = (int)(mm * Yppmm);
if (mmPx is <= 0 or > 500) continue;
if (bars.Contains(mmPx)) continue;
bars.Add(mmPx);
@@ -1186,7 +1197,7 @@ namespace UVtools.Core.Operations
private bool Equals(OperationCalibrateExposureFinder other)
{
- return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThickness == other._staircaseThickness && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleBrightnessGenEmulatedAALevel == other._multipleBrightnessGenEmulatedAALevel && _multipleBrightnessGenExposureFractions == other._multipleBrightnessGenExposureFractions && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _multipleExposuresBaseLayersPrintMode == other._multipleExposuresBaseLayersPrintMode && _multipleExposuresBaseLayersCustomExposure == other._multipleExposuresBaseLayersCustomExposure && _differentSettingsForSamePositionedLayers == other._differentSettingsForSamePositionedLayers && _samePositionedLayersLiftHeightEnabled == other._samePositionedLayersLiftHeightEnabled && _samePositionedLayersLiftHeight == other._samePositionedLayersLiftHeight && _samePositionedLayersLightOffDelayEnabled == other._samePositionedLayersLightOffDelayEnabled && _samePositionedLayersLightOffDelay == other._samePositionedLayersLightOffDelay && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers;
+ return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThicknessPx == other._staircaseThicknessPx && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleBrightnessGenEmulatedAALevel == other._multipleBrightnessGenEmulatedAALevel && _multipleBrightnessGenExposureFractions == other._multipleBrightnessGenExposureFractions && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _multipleExposuresBaseLayersPrintMode == other._multipleExposuresBaseLayersPrintMode && _multipleExposuresBaseLayersCustomExposure == other._multipleExposuresBaseLayersCustomExposure && _differentSettingsForSamePositionedLayers == other._differentSettingsForSamePositionedLayers && _samePositionedLayersLiftHeightEnabled == other._samePositionedLayersLiftHeightEnabled && _samePositionedLayersLiftHeight == other._samePositionedLayersLiftHeight && _samePositionedLayersLightOffDelayEnabled == other._samePositionedLayersLightOffDelayEnabled && _samePositionedLayersLightOffDelay == other._samePositionedLayersLightOffDelay && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers;
}
public override bool Equals(object obj)
@@ -1213,7 +1224,7 @@ namespace UVtools.Core.Operations
hashCode.Add(_baseHeight);
hashCode.Add(_featuresHeight);
hashCode.Add(_featuresMargin);
- hashCode.Add(_staircaseThickness);
+ hashCode.Add(_staircaseThicknessPx);
hashCode.Add(_holesEnabled);
hashCode.Add((int) _holeShape);
hashCode.Add((int) _unitOfMeasure);
@@ -1353,6 +1364,7 @@ namespace UVtools.Core.Operations
int featuresMarginX = (int)(Xppmm * _featuresMargin);
int featuresMarginY = (int)(Yppmm * _featuresMargin);
+ ushort startCaseThickness = StaircaseThickness;
int holePanelWidth = holes.Length > 0 ? featuresMarginX * 2 + holes[^1] : 0;
int holePanelHeight = GetHolesHeight(holes);
@@ -1360,8 +1372,8 @@ namespace UVtools.Core.Operations
int bulleyesDiameter = GetBullsEyeMaxDiameter(bulleyes);
int bulleyesPanelDiameter = GetBullsEyeMaxPanelDiameter(bulleyes);
int bulleyesRadius = bulleyesDiameter / 2;
- int yLeftMaxSize = _staircaseThickness + featuresMarginY + Math.Max(barsPanelHeight, textSize.Width) + bulleyesPanelDiameter;
- int yRightMaxSize = _staircaseThickness + holePanelHeight + featuresMarginY * 2;
+ int yLeftMaxSize = startCaseThickness + featuresMarginY + Math.Max(barsPanelHeight, textSize.Width) + bulleyesPanelDiameter;
+ int yRightMaxSize = startCaseThickness + holePanelHeight + featuresMarginY * 2;
int xSize = featuresMarginX;
int ySize = TextMarkingSpacing + featuresMarginY;
@@ -1431,10 +1443,10 @@ namespace UVtools.Core.Operations
int yPos = 0;
// Print staircase
- if (isPreview && _staircaseThickness > 0)
+ if (isPreview && startCaseThickness > 0)
{
CvInvoke.Rectangle(layers[1],
- new Rectangle(0, 0, layers[1].Size.Width-holePanelWidth, _staircaseThickness),
+ new Rectangle(0, 0, layers[1].Size.Width-holePanelWidth, startCaseThickness),
EmguExtensions.WhiteColor, -1, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected);
}
@@ -1442,7 +1454,7 @@ namespace UVtools.Core.Operations
for (var layerIndex = 0; layerIndex < layers.Length; layerIndex++)
{
var layer = layers[layerIndex];
- yPos = featuresMarginY + _staircaseThickness;
+ yPos = featuresMarginY + startCaseThickness;
for (int i = 0; i < holes.Length; i++)
{
var diameter = holes[i];
@@ -1547,7 +1559,7 @@ namespace UVtools.Core.Operations
// Print Zebra bars
if (bars.Length > 0)
{
- int yStartPos = _staircaseThickness + featuresMarginY;
+ int yStartPos = startCaseThickness + featuresMarginY;
int xStartPos = xPos;
yPos = yStartPos + _barFenceThickness / 2 + _barFenceOffset;
xPos += _barFenceThickness / 2 + _barFenceOffset;
@@ -1587,7 +1599,7 @@ namespace UVtools.Core.Operations
if (!textSize.IsEmpty)
{
CvInvoke.Rotate(layers[1], layers[1], RotateFlags.Rotate90CounterClockwise);
- CvInvoke.PutText(layers[1], _text, new Point(_staircaseThickness + featuresMarginX, layers[1].Height - barsPanelWidth - featuresMarginX * (barsPanelWidth > 0 ? 2 : 1)), _textFont, _textScale, EmguExtensions.WhiteColor, _textThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected);
+ CvInvoke.PutText(layers[1], _text, new Point(startCaseThickness + featuresMarginY, layers[1].Height - barsPanelWidth - featuresMarginX * (barsPanelWidth > 0 ? 2 : 1)), _textFont, _textScale, EmguExtensions.WhiteColor, _textThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected);
CvInvoke.Rotate(layers[1], layers[1], RotateFlags.Rotate90Clockwise);
}
@@ -1998,6 +2010,7 @@ namespace UVtools.Core.Operations
int currentY = topBottomMarginPx;
int featuresMarginX = (int)(Xppmm * _featuresMargin);
int featuresMarginY = (int)(Yppmm * _featuresMargin);
+ ushort startCaseThickness = StaircaseThickness;
var holes = Holes;
int holePanelWidth = holes.Length > 0 ? featuresMarginX * 2 + holes[^1] : 0;
@@ -2073,7 +2086,7 @@ namespace UVtools.Core.Operations
layers[isBaseLayer ? 0 : 1].CopyTo(matRoi);
- if (!isBaseLayer && _staircaseThickness > 0)
+ if (!isBaseLayer && startCaseThickness > 0)
{
int staircaseWidthIncrement = (int) Math.Ceiling(staircaseWidth / (_featuresHeight / layerHeight-1));
int staircaseLayer = layerCountOnHeight - firstFeatureLayer - 1;
@@ -2081,7 +2094,7 @@ namespace UVtools.Core.Operations
if (staircaseWidthForLayer >= 0 && layerCountOnHeight != lastLayer)
{
CvInvoke.Rectangle(matRoi,
- new Rectangle(staircaseWidth - staircaseWidthForLayer, 0, staircaseWidthForLayer, _staircaseThickness),
+ new Rectangle(staircaseWidth - staircaseWidthForLayer, 0, staircaseWidthForLayer, startCaseThickness),
EmguExtensions.WhiteColor, -1,
_enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected);
}
diff --git a/UVtools.Core/Operations/OperationPixelArithmetic.cs b/UVtools.Core/Operations/OperationPixelArithmetic.cs
index ff1ca0e..10f360c 100644
--- a/UVtools.Core/Operations/OperationPixelArithmetic.cs
+++ b/UVtools.Core/Operations/OperationPixelArithmetic.cs
@@ -8,8 +8,11 @@
using System;
using System.ComponentModel;
+using System.Diagnostics;
+using System.Drawing;
using System.Text;
using System.Threading.Tasks;
+using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
@@ -21,12 +24,40 @@ namespace UVtools.Core.Operations
[Serializable]
public class OperationPixelArithmetic : Operation
{
+ #region Subclasses
+ class StringMatrix
+ {
+ public string Text { get; }
+ public Matrix<byte> Pattern { get; set; }
+
+ public StringMatrix(string text)
+ {
+ Text = text;
+ }
+ }
+ #endregion
+
#region Members
private PixelArithmeticOperators _operator = PixelArithmeticOperators.Set;
+ private PixelArithmeticApplyMethod _applyMethod = PixelArithmeticApplyMethod.Model;
+ private uint _wallThicknessStart = 20;
+ private uint _wallThicknessEnd = 20;
+ private bool _wallChamfer;
private byte _value = byte.MaxValue;
+ private bool _usePattern;
private ThresholdType _thresholdType = ThresholdType.Binary;
private byte _thresholdMaxValue = 255;
- private bool _affectBackPixels;
+ private ushort _patternAlternatePerLayersNumber = 1;
+ private bool _patternInvert;
+ private string _patternText;
+ private string _patternTextAlternate;
+ private Matrix<byte> _pattern;
+ private Matrix<byte> _patternAlternate;
+ private byte _patternGenMinBrightness;
+ private byte _patternGenBrightness = 128;
+ private byte _patternGenInfillThickness = 10;
+ private byte _patternGenInfillSpacing = 20;
+
#endregion
@@ -66,6 +97,20 @@ namespace UVtools.Core.Operations
[Description("Discard Region: in the selected ROI or masks")]
DiscardRegion
}
+
+ public enum PixelArithmeticApplyMethod : byte
+ {
+ [Description("All: Apply to all pixels within the layer")]
+ All,
+ [Description("Model: Apply only to model pixels")]
+ Model,
+ [Description("Model inner: Apply only to model pixels within a margin from walls")]
+ ModelInner,
+ [Description("Model walls: Apply only to model walls with a set thickness")]
+ ModelWalls,
+ //[Description("Model walls minimum: Apply only to model walls where walls must have at least a minimum set thickness")]
+ //ModelWallsMinimum
+ }
#endregion
#region Overrides
@@ -76,14 +121,16 @@ namespace UVtools.Core.Operations
public override string ConfirmationText =>
$"arithmetic {_operator}" +
- (ValueEnabled ? $"={_value}" : string.Empty) +
+ (ValueEnabled && !_usePattern ? $"={_value}" : string.Empty) +
+ (_usePattern && IsUsePatternVisible ? " with pattern" : string.Empty) +
(_operator is PixelArithmeticOperators.Threshold ? $"/{_thresholdMaxValue}" : string.Empty)
+ $" layers from {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressTitle =>
$"Arithmetic {_operator}"+
- (ValueEnabled ? $"={_value}" : string.Empty)
- +$" layers from {LayerIndexStart} through {LayerIndexEnd}";
+ (ValueEnabled && !_usePattern ? $"={_value}" : string.Empty) +
+ (_usePattern && IsUsePatternVisible ? " with pattern" : string.Empty) +
+ $" layers from {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressAction => "Calculated layers";
@@ -117,12 +164,76 @@ namespace UVtools.Core.Operations
sb.AppendLine("Can't divide by 0.");
}
+ if (_applyMethod is PixelArithmeticApplyMethod.ModelWalls //or PixelArithmeticApplyMethod.ModelWallsMinimum
+ && (
+ (_wallChamfer && _wallThicknessStart == 0 && _wallThicknessEnd == 0) ||
+ (!_wallChamfer && _wallThicknessStart == 0)
+ )
+ )
+ {
+ sb.AppendLine("The current wall settings will have no effect.");
+ }
+
+ if (_usePattern && IsUsePatternVisible)
+ {
+ var stringMatrix = new[]
+ {
+ new StringMatrix(PatternText),
+ new StringMatrix(PatternTextAlternate),
+ };
+
+ foreach (var item in stringMatrix)
+ {
+ if (string.IsNullOrWhiteSpace(item.Text)) continue;
+ var lines = item.Text.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
+ for (var row = 0; row < lines.Length; row++)
+ {
+ var bytes = lines[row].Split(' ');
+ if (row == 0)
+ {
+ item.Pattern = new Matrix<byte>(lines.Length, bytes.Length);
+ }
+ else
+ {
+ if (item.Pattern.Cols != bytes.Length)
+ {
+ sb.AppendLine($"Row {row + 1} have invalid number of pixels, the pattern must have equal pixel count per line, per defined on line 1");
+ return sb.ToString();
+ }
+ }
+
+ for (int col = 0; col < bytes.Length; col++)
+ {
+ if (byte.TryParse(bytes[col], out var value))
+ {
+ item.Pattern[row, col] = (byte)(_patternInvert ? byte.MaxValue - value : value);
+ }
+ else
+ {
+ sb.AppendLine($"{bytes[col]} is a invalid number, use values from 0 to 255");
+ return sb.ToString();
+ }
+ }
+ }
+ }
+
+ _pattern = stringMatrix[0].Pattern;
+ _patternAlternate = stringMatrix[1].Pattern;
+
+ if (_pattern is null && _patternAlternate is null)
+ {
+ sb.AppendLine("Either even or odd pattern must contain a valid matrix.");
+ return sb.ToString();
+ }
+ }
+
return sb.ToString();
}
public override string ToString()
{
- var result = $"[{_operator}: {_value}] [ABP: {_affectBackPixels}]"
+ var result = $"[{_operator}: {_value}] [Apply: {_applyMethod}] " +
+ $"[Pattern: {_usePattern}]"
+ LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
@@ -138,11 +249,55 @@ namespace UVtools.Core.Operations
{
if(!RaiseAndSetIfChanged(ref _operator, value)) return;
RaisePropertyChanged(nameof(ValueEnabled));
+ RaisePropertyChanged(nameof(IsUsePatternVisible));
RaisePropertyChanged(nameof(ThresholdEnabled));
- RaisePropertyChanged(nameof(AffectBackPixelsEnabled));
+ RaisePropertyChanged(nameof(IsApplyMethodEnabled));
+ }
+ }
+
+ public bool IsApplyMethodEnabled =>
+ _operator is not (PixelArithmeticOperators.KeepRegion or PixelArithmeticOperators.DiscardRegion);
+
+ public PixelArithmeticApplyMethod ApplyMethod
+ {
+ get => _applyMethod;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _applyMethod, value)) return;
+ RaisePropertyChanged(nameof(IsWallSettingVisible));
}
}
+ public bool IsWallSettingVisible => _applyMethod is PixelArithmeticApplyMethod.ModelInner or PixelArithmeticApplyMethod.ModelWalls; //or PixelArithmeticApplyMethod.ModelWallsMinimum;
+
+ public uint WallThickness
+ {
+ get => _wallThicknessStart;
+ set
+ {
+ WallThicknessStart = value;
+ WallThicknessEnd = value;
+ }
+ }
+
+ public uint WallThicknessStart
+ {
+ get => _wallThicknessStart;
+ set => RaiseAndSetIfChanged(ref _wallThicknessStart, value);
+ }
+
+ public uint WallThicknessEnd
+ {
+ get => _wallThicknessEnd;
+ set => RaiseAndSetIfChanged(ref _wallThicknessEnd, value);
+ }
+
+ public bool WallChamfer
+ {
+ get => _wallChamfer;
+ set => RaiseAndSetIfChanged(ref _wallChamfer, value);
+ }
+
public byte Value
{
get => _value;
@@ -163,6 +318,19 @@ namespace UVtools.Core.Operations
and not PixelArithmeticOperators.DiscardRegion
;
+ public bool IsUsePatternVisible => _operator
+ is not PixelArithmeticOperators.Threshold
+ and not PixelArithmeticOperators.BitwiseNot
+ and not PixelArithmeticOperators.KeepRegion
+ and not PixelArithmeticOperators.DiscardRegion
+ ;
+
+ public bool UsePattern
+ {
+ get => _usePattern;
+ set => RaiseAndSetIfChanged(ref _usePattern, value);
+ }
+
public ThresholdType ThresholdType
{
get => _thresholdType;
@@ -177,13 +345,7 @@ namespace UVtools.Core.Operations
public bool ThresholdEnabled => _operator is PixelArithmeticOperators.Threshold;
- public bool AffectBackPixels
- {
- get => _affectBackPixels;
- set => RaiseAndSetIfChanged(ref _affectBackPixels, value);
- }
-
- public bool AffectBackPixelsEnabled => _operator
+ /*public bool AffectBackPixelsEnabled => _operator
is not PixelArithmeticOperators.Subtract
and not PixelArithmeticOperators.Multiply
and not PixelArithmeticOperators.Divide
@@ -192,7 +354,75 @@ namespace UVtools.Core.Operations
and not PixelArithmeticOperators.KeepRegion
and not PixelArithmeticOperators.DiscardRegion
and not PixelArithmeticOperators.Threshold
- ;
+ ;*/
+
+ public ushort PatternAlternatePerLayersNumber
+ {
+ get => _patternAlternatePerLayersNumber;
+ set => RaiseAndSetIfChanged(ref _patternAlternatePerLayersNumber, value);
+ }
+
+ public bool PatternInvert
+ {
+ get => _patternInvert;
+ set => RaiseAndSetIfChanged(ref _patternInvert, value);
+ }
+
+ public string PatternText
+ {
+ get => _patternText;
+ set => RaiseAndSetIfChanged(ref _patternText, value);
+ }
+
+ public string PatternTextAlternate
+ {
+ get => _patternTextAlternate;
+ set => RaiseAndSetIfChanged(ref _patternTextAlternate, value);
+ }
+
+ [XmlIgnore]
+ public Matrix<byte> Pattern
+ {
+ get => _pattern;
+ set => RaiseAndSetIfChanged(ref _pattern, value);
+ }
+
+ [XmlIgnore]
+ public Matrix<byte> PatternAlternate
+ {
+ get => _patternAlternate;
+ set => RaiseAndSetIfChanged(ref _patternAlternate, value);
+ }
+
+ public byte PatternGenMinBrightness
+ {
+ get => _patternGenMinBrightness;
+ set => RaiseAndSetIfChanged(ref _patternGenMinBrightness, value);
+ }
+
+ public byte PatternGenBrightness
+ {
+ get => _patternGenBrightness;
+ set
+ {
+ RaiseAndSetIfChanged(ref _patternGenBrightness, value);
+ RaisePropertyChanged(nameof(PatternGenBrightnessPercent));
+ }
+ }
+
+ public float PatternGenBrightnessPercent => Helpers.BrightnessToPercent(_patternGenBrightness);
+
+ public byte PatternGenInfillThickness
+ {
+ get => _patternGenInfillThickness;
+ set => RaiseAndSetIfChanged(ref _patternGenInfillThickness, value);
+ }
+
+ public byte PatternGenInfillSpacing
+ {
+ get => _patternGenInfillSpacing;
+ set => RaiseAndSetIfChanged(ref _patternGenInfillSpacing, value);
+ }
#endregion
@@ -208,26 +438,237 @@ namespace UVtools.Core.Operations
protected override bool ExecuteInternally(OperationProgress progress)
{
- var tempMat = GetTempMat();
+ Mat patternMat = null;
+ Mat patternAlternateMat = null;
+ Mat patternMatMask = null;
+ Mat patternAlternateMatMask = null;
+ var anchor = new Point(-1, -1);
+ var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+
+
+ if (_usePattern && IsUsePatternVisible)
+ {
+ if (_pattern is null)
+ {
+ _pattern = new Matrix<byte>(2, 2)
+ {
+ [0, 0] = 0,
+ [0, 1] = 127,
+ [1, 0] = 127,
+ [1, 1] = 0,
+ };
+
+ _patternAlternate ??= new Matrix<byte>(2, 2)
+ {
+ [0, 0] = 127,
+ [0, 1] = 0,
+ [1, 0] = 0,
+ [1, 1] = 127,
+ };
+ }
+
+ _patternAlternate ??= _pattern;
+
+ using var blankMat = new Mat(SlicerFile.Resolution, DepthType.Cv8U, 1);
+ patternMat = blankMat.NewBlank();
+ patternAlternateMat = blankMat.NewBlank();
+ var target = GetRoiOrDefault(blankMat);
+
+ CvInvoke.Repeat(_pattern, target.Rows / _pattern.Rows + 1, target.Cols / _pattern.Cols + 1, patternMat);
+ CvInvoke.Repeat(_patternAlternate, target.Rows / _patternAlternate.Rows + 1, target.Cols / _patternAlternate.Cols + 1, patternAlternateMat);
+
+ patternMatMask = new Mat(patternMat, new Rectangle(0, 0, target.Width, target.Height));
+ patternAlternateMatMask = new Mat(patternAlternateMat, new Rectangle(0, 0, target.Width, target.Height));
+
+ /*if (_patternInvert)
+ {
+ CvInvoke.BitwiseNot(patternMatMask, patternMatMask);
+ CvInvoke.BitwiseNot(patternAlternateMatMask, patternAlternateMatMask);
+ }*/
+ }
+ else if (_operator is not PixelArithmeticOperators.BitwiseNot
+ and not PixelArithmeticOperators.KeepRegion
+ and not PixelArithmeticOperators.DiscardRegion)
+ {
+ patternMatMask = EmguExtensions.InitMat(HaveROI ? ROI.Size : SlicerFile.Resolution, new MCvScalar(_value));
+ }
+
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using (var mat = SlicerFile[layerIndex].LayerMat)
{
- Execute(mat, tempMat);
+ //Execute(mat, tempMat);
+
+ using var original = mat.Clone();
+ var originalRoi = GetRoiOrDefault(original);
+ var target = GetRoiOrDefault(mat);
+ Mat tempMat;
+
+ if (_usePattern && IsUsePatternVisible)
+ {
+ tempMat = IsNormalPattern((uint)layerIndex) ? patternMatMask : patternAlternateMatMask;
+ }
+ else
+ {
+ tempMat = patternMatMask;
+ }
+
+ Mat applyMask;
+
+ int wallThickness = LayerManager.MutateGetIterationChamfer(
+ (uint)layerIndex,
+ LayerIndexStart,
+ LayerIndexEnd,
+ (int)_wallThicknessStart,
+ (int)_wallThicknessEnd,
+ _wallChamfer
+ );
+
+ switch (_applyMethod)
+ {
+ case PixelArithmeticApplyMethod.All:
+ applyMask = null;
+ break;
+ case PixelArithmeticApplyMethod.Model:
+ applyMask = target;
+ break;
+ case PixelArithmeticApplyMethod.ModelInner:
+ applyMask = wallThickness <= 0 ? target : new Mat();
+ CvInvoke.Erode(target, applyMask, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ break;
+ case PixelArithmeticApplyMethod.ModelWalls:
+ {
+ if (wallThickness <= 0) // No effect, skip
+ {
+ progress.LockAndIncrement();
+ return;
+ }
+
+ using var erode = new Mat();
+ applyMask = target.Clone();
+ CvInvoke.Erode(target, erode, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ applyMask.SetTo(EmguExtensions.BlackColor, erode);
+ break;
+ }
+ /*case PixelArithmeticApplyMethod.ModelWallsMinimum:
+ {
+ if (wallThickness <= 0) // No effect, skip
+ {
+ progress.LockAndIncrement();
+ return;
+ }
+
+ using var erode = new Mat();
+ using var erodeInv = new Mat();
+ applyMask = target.Clone();
+ target.Save($"D:\\wallmin\\original{layerIndex}.png");
+ CvInvoke.Erode(target, erode, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ erode.Save($"D:\\wallmin\\erode{layerIndex}.png");
+ CvInvoke.Dilate(erode, erode, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ erode.Save($"D:\\wallmin\\dilate{layerIndex}.png");
+ //CvInvoke.BitwiseXor(target, erode, applyMask);
+ //applyMask.Save($"D:\\wallmin\\bitwiseXor{layerIndex}.png");
+ CvInvoke.BitwiseNot(erode, erodeInv);
+ erodeInv.Save($"D:\\wallmin\\erodeInv{layerIndex}.png");
+ CvInvoke.BitwiseXor(target, erode, erode, erodeInv);
+ erode.Save($"D:\\wallmin\\BitwiseXor{layerIndex}.png");
+ applyMask.SetTo(EmguExtensions.BlackColor, erode);
+ applyMask.Save($"D:\\wallmin\\applymask{layerIndex}.png");
+ break;
+ }*/
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ switch (_operator)
+ {
+ case PixelArithmeticOperators.Set:
+ tempMat.CopyTo(target, applyMask);
+ break;
+ case PixelArithmeticOperators.Add:
+ CvInvoke.Add(target, tempMat, target, applyMask);
+ break;
+ case PixelArithmeticOperators.Subtract:
+ CvInvoke.Subtract(target, tempMat, target, applyMask);
+ break;
+ case PixelArithmeticOperators.Multiply:
+ CvInvoke.Multiply(target, tempMat, target);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ case PixelArithmeticOperators.Divide:
+ CvInvoke.Divide(target, tempMat, target);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ /*case PixelArithmeticOperators.Exponential:
+ CvInvoke.Pow(target, _value, tempMat);
+ if(!_affectBackPixels) ApplyMask(original, mat, original);
+ break;*/
+ case PixelArithmeticOperators.Minimum:
+ CvInvoke.Min(target, tempMat, target);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ case PixelArithmeticOperators.Maximum:
+ CvInvoke.Max(target, tempMat, target);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ case PixelArithmeticOperators.BitwiseNot:
+ CvInvoke.BitwiseNot(target, target, applyMask);
+ break;
+ case PixelArithmeticOperators.BitwiseAnd:
+ CvInvoke.BitwiseAnd(target, tempMat, target, applyMask);
+ break;
+ case PixelArithmeticOperators.BitwiseOr:
+ CvInvoke.BitwiseOr(target, tempMat, target, applyMask);
+ break;
+ case PixelArithmeticOperators.BitwiseXor:
+ CvInvoke.BitwiseXor(target, tempMat, target, applyMask);
+ break;
+ case PixelArithmeticOperators.Threshold:
+ CvInvoke.Threshold(target, target, _value, _thresholdMaxValue, _thresholdType);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ case PixelArithmeticOperators.AbsDiff:
+ CvInvoke.AbsDiff(target, tempMat, target);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
+ break;
+ case PixelArithmeticOperators.KeepRegion:
+ {
+ using var targetClone = target.Clone();
+ original.SetTo(EmguExtensions.BlackColor);
+ mat.SetTo(EmguExtensions.BlackColor);
+ targetClone.CopyTo(target);
+ break;
+ }
+ case PixelArithmeticOperators.DiscardRegion:
+ target.SetTo(EmguExtensions.BlackColor);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+
+ ApplyMask(original, target);
+
SlicerFile[layerIndex].LayerMat = mat;
+
+ if (applyMask is not null && !ReferenceEquals(applyMask, target)) applyMask.Dispose();
}
progress.LockAndIncrement();
});
- tempMat?.Dispose();
+ patternMat?.Dispose();
+ patternAlternateMat?.Dispose();
return !progress.Token.IsCancellationRequested;
}
- public override bool Execute(Mat mat, params object[] arguments)
+ public bool IsNormalPattern(uint layerIndex) => layerIndex / _patternAlternatePerLayersNumber % 2 == 0;
+
+ public bool IsAlternatePattern(uint layerIndex) => !IsNormalPattern(layerIndex);
+
+ /*public override bool Execute(Mat mat, params object[] arguments)
{
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
@@ -244,16 +685,47 @@ namespace UVtools.Core.Operations
needDispose = true;
}
+ Mat applyMask;
+ var anchor = new Point(-1, -1);
+ var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+ int wallThickness = LayerManager.MutateGetIterationChamfer(
+ layerIndex,
+ LayerIndexStart,
+ LayerIndexEnd,
+ (int)_wallThicknessStart,
+ (int)_wallThicknessEnd,
+ _wallChamfer
+ );
+
+ switch (_applyMethod)
+ {
+ case PixelArithmeticApplyMethod.All:
+ applyMask = null;
+ break;
+ case PixelArithmeticApplyMethod.Model:
+ applyMask = target.Clone();
+ break;
+ case PixelArithmeticApplyMethod.ModelInner:
+ CvInvoke.Erode(target, applyMask, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ applyMask = target;
+ break;
+ case PixelArithmeticApplyMethod.ModelWalls:
+ applyMask = target;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
switch (_operator)
{
case PixelArithmeticOperators.Set:
- tempMat.CopyTo(target, _affectBackPixels ? null : target);
+ tempMat.CopyTo(target, applyMask);
break;
case PixelArithmeticOperators.Add:
- CvInvoke.Add(target, tempMat, target, _affectBackPixels ? null : target);
+ CvInvoke.Add(target, tempMat, target, applyMask);
break;
case PixelArithmeticOperators.Subtract:
- CvInvoke.Subtract(target, tempMat, target, _affectBackPixels ? null : target);
+ CvInvoke.Subtract(target, tempMat, target, applyMask);
break;
case PixelArithmeticOperators.Multiply:
CvInvoke.Multiply(target, tempMat, target);
@@ -261,36 +733,36 @@ namespace UVtools.Core.Operations
case PixelArithmeticOperators.Divide:
CvInvoke.Divide(target, tempMat, target);
break;
- /*case PixelArithmeticOperators.Exponential:
- CvInvoke.Pow(target, _value, tempMat);
- if(!_affectBackPixels) ApplyMask(original, mat, original);
- break;*/
+ //case PixelArithmeticOperators.Exponential:
+ // CvInvoke.Pow(target, _value, tempMat);
+ // if(!_affectBackPixels) ApplyMask(original, mat, original);
+ // break;
case PixelArithmeticOperators.Minimum:
CvInvoke.Min(target, tempMat, target);
- if (!_affectBackPixels) ApplyMask(original, target, original);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(original, target, original);
break;
case PixelArithmeticOperators.Maximum:
CvInvoke.Max(target, tempMat, target);
- if (!_affectBackPixels) ApplyMask(original, target, original);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(original, target, original);
break;
case PixelArithmeticOperators.BitwiseNot:
- CvInvoke.BitwiseNot(target, target);
+ CvInvoke.BitwiseNot(target, target, applyMask);
break;
case PixelArithmeticOperators.BitwiseAnd:
- CvInvoke.BitwiseAnd(target, tempMat, target);
+ CvInvoke.BitwiseAnd(target, tempMat, target, applyMask);
break;
case PixelArithmeticOperators.BitwiseOr:
- CvInvoke.BitwiseOr(target, tempMat, target, _affectBackPixels ? null : target);
+ CvInvoke.BitwiseOr(target, tempMat, target, applyMask);
break;
case PixelArithmeticOperators.BitwiseXor:
- CvInvoke.BitwiseXor(target, tempMat, target, _affectBackPixels ? null : target);
+ CvInvoke.BitwiseXor(target, tempMat, target, applyMask);
break;
case PixelArithmeticOperators.Threshold:
CvInvoke.Threshold(target, target, _value, _thresholdMaxValue, _thresholdType);
break;
case PixelArithmeticOperators.AbsDiff:
CvInvoke.AbsDiff(target, tempMat, target);
- if (!_affectBackPixels) ApplyMask(original, target, original);
+ if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(original, target, original);
break;
case PixelArithmeticOperators.KeepRegion:
{
@@ -315,16 +787,33 @@ namespace UVtools.Core.Operations
}
return true;
- }
+ }*/
public Mat GetTempMat() => _operator
is not PixelArithmeticOperators.BitwiseNot
and not PixelArithmeticOperators.KeepRegion
and not PixelArithmeticOperators.DiscardRegion ? EmguExtensions.InitMat(HaveROI ? ROI.Size : SlicerFile.Resolution, new MCvScalar(_value)) : null;
+ public void PresetPixelDimming()
+ {
+ Operator = PixelArithmeticOperators.Subtract;
+ ApplyMethod = PixelArithmeticApplyMethod.ModelInner;
+ WallThickness = 20;
+ WallChamfer = false;
+ UsePattern = true;
+ }
+
+ public void PresetPixelLightening()
+ {
+ PresetPixelDimming();
+ Operator = PixelArithmeticOperators.Add;
+ }
+
public void PresetStripAntiAliasing()
{
Operator = PixelArithmeticOperators.Threshold;
+ ApplyMethod = PixelArithmeticApplyMethod.All;
+ UsePattern = false;
Value = 127;
ThresholdMaxValue = 255;
ThresholdType = ThresholdType.Binary;
@@ -335,13 +824,329 @@ namespace UVtools.Core.Operations
Value = 128;
}
+ public unsafe void LoadPatternFromImage(Mat mat, bool isAlternatePattern = false)
+ {
+ var result = new string[mat.Height];
+ var span = mat.GetBytePointer();
+ Parallel.For(0, mat.Height, y =>
+ {
+ result[y] = string.Empty;
+ var pixelPos = mat.GetPixelPos(0, y);
+ for (int x = 0; x < mat.Width; x++)
+ {
+ result[y] += $"{span[pixelPos++]} ";
+ }
+
+ result[y] = result[y].Trim();
+ });
+
+ StringBuilder sb = new();
+ foreach (var s in result)
+ {
+ sb.AppendLine(s);
+ }
+
+ if (isAlternatePattern)
+ {
+ PatternTextAlternate = sb.ToString();
+ }
+ else
+ {
+ PatternText = sb.ToString();
+ }
+ }
+
+ public void LoadPatternFromImage(string filepath, bool isAlternatePattern = false)
+ {
+ try
+ {
+ using var mat = CvInvoke.Imread(filepath, ImreadModes.Grayscale);
+ LoadPatternFromImage(mat, isAlternatePattern);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ }
+
+ }
+
+
+ public void GeneratePattern(string pattern)
+ {
+ if (pattern == "Chessboard")
+ {
+ PatternText = string.Format(
+ "{0} {1}{2}" +
+ "{1} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{1} {0}{2}" +
+ "{0} {1}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ return;
+ }
+
+ if (pattern == "Sparse")
+ {
+ PatternText = string.Format(
+ "{1} {0} {0} {0}{2}" +
+ "{0} {0} {1} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {1} {0}{2}" +
+ "{1} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Crosses")
+ {
+ PatternText = string.Format(
+ "{1} {0} {1} {0}{2}" +
+ "{0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0}{2}" +
+ "{0} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {0} {0}{2}" +
+ "{1} {0} {1} {0}{2}" +
+ "{0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Strips")
+ {
+ PatternText = string.Format(
+ "{1}{2}" +
+ "{0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0}{2}" +
+ "{1}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Pyramid")
+ {
+ PatternText = string.Format(
+ "{0} {0} {1} {0} {0} {0}{2}" +
+ "{0} {1} {0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0} {1} {0}{2}" +
+ "{0} {0} {0} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {1} {0} {1} {0} {1}{2}" +
+ "{0} {0} {1} {0} {1} {0}{2}" +
+ "{0} {0} {0} {1} {0} {0}{2}" +
+ "{0} {0} {0} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Rhombus")
+ {
+ PatternText = string.Format(
+ "{0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0}{2}" +
+ "{0} {1} {0} {0}{2}" +
+ "{0} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {0} {0}{2}" +
+ "{0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0}{2}" +
+ "{0} {1} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Hearts")
+ {
+ PatternText = string.Format(
+ "{0} {1} {0} {1} {0} {0}{2}" +
+ "{1} {0} {1} {0} {1} {0}{2}" +
+ "{1} {0} {0} {0} {1} {0}{2}" +
+ "{0} {1} {0} {1} {0} {0}{2}" +
+ "{0} {0} {1} {0} {0} {0}{2}" +
+ "{0} {0} {0} {0} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {0} {0} {0} {0}{2}" +
+ "{0} {0} {1} {0} {1} {0}{2}" +
+ "{0} {1} {0} {1} {0} {1}{2}" +
+ "{0} {1} {0} {0} {0} {1}{2}" +
+ "{0} {0} {1} {0} {1} {0}{2}" +
+ "{0} {0} {0} {1} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Slashes")
+ {
+ PatternText = string.Format(
+ "{1} {0} {0}{2}" +
+ "{0} {1} {0}{2}" +
+ "{0} {0} {1}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {1}{2}" +
+ "{0} {1} {0}{2}" +
+ "{1} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Waves")
+ {
+ PatternText = string.Format(
+ "{1} {0} {0}{2}" +
+ "{0} {0} {1}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+
+ PatternTextAlternate = string.Format(
+ "{0} {0} {1}{2}" +
+ "{1} {0} {0}"
+ , _patternGenMinBrightness, _patternGenBrightness, "\n");
+ return;
+ }
+
+ if (pattern == "Solid")
+ {
+ PatternText = _patternGenBrightness.ToString();
+ PatternTextAlternate = null;
+ return;
+ }
+ }
+
+ public void GenerateInfill(string pattern)
+ {
+ if (pattern == "Rectilinear")
+ {
+ PatternText = ($"255\n".Repeat(_patternGenInfillSpacing) + $"0\n".Repeat(_patternGenInfillThickness)).Trim('\n', '\r');
+ PatternTextAlternate = null;
+ return;
+ }
+
+ if (pattern == "Square grid")
+ {
+ var p1 = "255 ".Repeat(_patternGenInfillSpacing) + "0 ".Repeat(_patternGenInfillThickness);
+ p1 = p1.Trim() + "\n";
+ p1 += p1.Repeat(_patternGenInfillThickness);
+
+
+ var p2 = "0 ".Repeat(_patternGenInfillSpacing) + "0 ".Repeat(_patternGenInfillThickness);
+ p2 = p2.Trim() + '\n';
+ p2 += p2.Repeat(_patternGenInfillThickness);
+
+ p2 = p2.Trim('\n', '\r');
+
+ PatternText = p1 + p2;
+ PatternTextAlternate = null;
+ return;
+ }
+
+ if (pattern == "Waves")
+ {
+ var p1 = string.Empty;
+ var pos = 0;
+ for (sbyte dir = 1; dir >= -1; dir -= 2)
+ {
+ while (pos >= 0 && pos <= _patternGenInfillSpacing)
+ {
+ p1 += "255 ".Repeat(pos);
+ p1 += "0 ".Repeat(_patternGenInfillThickness);
+ p1 += "255 ".Repeat(_patternGenInfillSpacing - pos);
+ p1 = p1.Trim() + '\n';
+
+ pos += dir;
+ }
+
+ pos--;
+ }
+
+ PatternText = p1.Trim('\n', '\r');
+ PatternTextAlternate = null;
+ return;
+ }
+
+ if (pattern == "Lattice")
+ {
+ var p1 = string.Empty;
+ var p2 = string.Empty;
+
+ var zeros = Math.Max(0, _patternGenInfillSpacing - _patternGenInfillThickness * 2);
+
+ // Pillar
+ for (int i = 0; i < _patternGenInfillThickness; i++)
+ {
+ p1 += "0 ".Repeat(_patternGenInfillThickness);
+ p1 += "255 ".Repeat(zeros);
+ p1 += "0 ".Repeat(_patternGenInfillThickness);
+ p1 = p1.Trim() + '\n';
+ }
+
+ for (int i = 0; i < zeros; i++)
+ {
+ p1 += "255 ".Repeat(_patternGenInfillSpacing);
+ p1 = p1.Trim() + '\n';
+ }
+
+ for (int i = 0; i < _patternGenInfillThickness; i++)
+ {
+ p1 += "0 ".Repeat(_patternGenInfillThickness);
+ p1 += "255 ".Repeat(zeros);
+ p1 += "0 ".Repeat(_patternGenInfillThickness);
+ p1 = p1.Trim() + '\n';
+ }
+
+ // Square
+ for (int i = 0; i < _patternGenInfillThickness; i++)
+ {
+ p2 += "0 ".Repeat(_patternGenInfillSpacing);
+ p2 = p2.Trim() + '\n';
+ }
+
+ for (int i = 0; i < zeros; i++)
+ {
+ p2 += "0 ".Repeat(_patternGenInfillThickness);
+ p2 += "255 ".Repeat(zeros);
+ p2 += "0 ".Repeat(_patternGenInfillThickness);
+ p2 = p2.Trim() + '\n';
+ }
+
+ for (int i = 0; i < _patternGenInfillThickness; i++)
+ {
+ p2 += "0 ".Repeat(_patternGenInfillSpacing);
+ p2 = p2.Trim() + '\n';
+ }
+
+
+
+ PatternText = p1.Trim('\n', '\r');
+ PatternTextAlternate = p2.Trim('\n', '\r'); ;
+ return;
+ }
+ }
+
#endregion
#region Equality
protected bool Equals(OperationPixelArithmetic other)
{
- return _operator == other._operator && _value == other._value && _thresholdType == other._thresholdType && _thresholdMaxValue == other._thresholdMaxValue && _affectBackPixels == other._affectBackPixels;
+ return _operator == other._operator && _applyMethod == other._applyMethod && _wallThicknessStart == other._wallThicknessStart && _wallThicknessEnd == other._wallThicknessEnd && _wallChamfer == other._wallChamfer && _value == other._value && _usePattern == other._usePattern && _thresholdType == other._thresholdType && _thresholdMaxValue == other._thresholdMaxValue && _patternAlternatePerLayersNumber == other._patternAlternatePerLayersNumber && _patternInvert == other._patternInvert && _patternText == other._patternText && _patternTextAlternate == other._patternTextAlternate && _patternGenMinBrightness == other._patternGenMinBrightness && _patternGenBrightness == other._patternGenBrightness && _patternGenInfillThickness == other._patternGenInfillThickness && _patternGenInfillSpacing == other._patternGenInfillSpacing;
}
public override bool Equals(object obj)
@@ -349,12 +1154,30 @@ namespace UVtools.Core.Operations
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
- return Equals((OperationPixelArithmetic) obj);
+ return Equals((OperationPixelArithmetic)obj);
}
public override int GetHashCode()
{
- return HashCode.Combine((int) _operator, _value, (int) _thresholdType, _thresholdMaxValue, _affectBackPixels);
+ var hashCode = new HashCode();
+ hashCode.Add((int)_operator);
+ hashCode.Add((int)_applyMethod);
+ hashCode.Add(_wallThicknessStart);
+ hashCode.Add(_wallThicknessEnd);
+ hashCode.Add(_wallChamfer);
+ hashCode.Add(_value);
+ hashCode.Add(_usePattern);
+ hashCode.Add((int)_thresholdType);
+ hashCode.Add(_thresholdMaxValue);
+ hashCode.Add(_patternAlternatePerLayersNumber);
+ hashCode.Add(_patternInvert);
+ hashCode.Add(_patternText);
+ hashCode.Add(_patternTextAlternate);
+ hashCode.Add(_patternGenMinBrightness);
+ hashCode.Add(_patternGenBrightness);
+ hashCode.Add(_patternGenInfillThickness);
+ hashCode.Add(_patternGenInfillSpacing);
+ return hashCode.ToHashCode();
}
#endregion
diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs
index d2eac35..97df8bd 100644
--- a/UVtools.Core/Operations/OperationPixelDimming.cs
+++ b/UVtools.Core/Operations/OperationPixelDimming.cs
@@ -36,6 +36,7 @@ namespace UVtools.Core.Operations
#endregion
#region Members
+ private bool _lighteningPixels;
private uint _wallThicknessStart = 10;
private uint _wallThicknessEnd = 10;
private bool _wallsOnly;
@@ -48,6 +49,7 @@ namespace UVtools.Core.Operations
private byte _brightness = 127;
private ushort _infillGenThickness = 10;
private ushort _infillGenSpacing = 20;
+
#endregion
#region Overrides
@@ -140,7 +142,8 @@ namespace UVtools.Core.Operations
#region Constructor
- public OperationPixelDimming() { }
+ public OperationPixelDimming()
+ { }
public OperationPixelDimming(FileFormat slicerFile) : base(slicerFile) { }
@@ -148,6 +151,12 @@ namespace UVtools.Core.Operations
#region Properties
+ public bool LighteningPixels
+ {
+ get => _lighteningPixels;
+ set => RaiseAndSetIfChanged(ref _lighteningPixels, value);
+ }
+
public uint WallThickness
{
get => _wallThicknessStart;
@@ -227,7 +236,7 @@ namespace UVtools.Core.Operations
}
}
- public decimal BrightnessPercent => Math.Round(_brightness * 100 / 255M, 2);
+ public float BrightnessPercent => (float)Math.Round(_brightness * 100 / 255f, 2);
public ushort InfillGenThickness
@@ -248,7 +257,7 @@ namespace UVtools.Core.Operations
protected bool Equals(OperationPixelDimming other)
{
- return _wallThicknessStart == other._wallThicknessStart && _wallThicknessEnd == other._wallThicknessEnd && _wallsOnly == other._wallsOnly && _chamfer == other._chamfer && _alternatePatternPerLayers == other._alternatePatternPerLayers && _patternText == other._patternText && _alternatePatternText == other._alternatePatternText && _brightness == other._brightness && _infillGenThickness == other._infillGenThickness && _infillGenSpacing == other._infillGenSpacing;
+ return _lighteningPixels == other._lighteningPixels && _wallThicknessStart == other._wallThicknessStart && _wallThicknessEnd == other._wallThicknessEnd && _wallsOnly == other._wallsOnly && _chamfer == other._chamfer && _alternatePatternPerLayers == other._alternatePatternPerLayers && _patternText == other._patternText && _alternatePatternText == other._alternatePatternText && _brightness == other._brightness && _infillGenThickness == other._infillGenThickness && _infillGenSpacing == other._infillGenSpacing;
}
public override bool Equals(object obj)
@@ -256,12 +265,13 @@ namespace UVtools.Core.Operations
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
- return Equals((OperationPixelDimming) obj);
+ return Equals((OperationPixelDimming)obj);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
+ hashCode.Add(_lighteningPixels);
hashCode.Add(_wallThicknessStart);
hashCode.Add(_wallThicknessEnd);
hashCode.Add(_wallsOnly);
@@ -673,29 +683,30 @@ namespace UVtools.Core.Operations
using Mat erode = new();
- using Mat diff = new();
+ //using Mat diff = new();
var original = mat.Clone();
+ var originalRoi = GetRoiOrDefault(original);
var target = GetRoiOrDefault(mat);
using var mask = GetMask(mat);
CvInvoke.Erode(target, erode, kernel, anchor, wallThickness, BorderType.Reflect101, default);
-
- if (_wallsOnly)
+
+ if (_lighteningPixels)
{
- CvInvoke.Subtract(target, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target);
- //CvInvoke.BitwiseAnd(diff, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target, mask);
- CvInvoke.Add(erode, target, target);
+ CvInvoke.Add(target, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target, _wallsOnly ? target : erode);
}
else
{
- //CvInvoke.Subtract(target, erode, diff);
- //CvInvoke.BitwiseAnd(erode, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target, mask);
- //CvInvoke.Add(target, diff, target, mask);
- CvInvoke.Subtract(target, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target, erode);
+ CvInvoke.Subtract(target, IsNormalPattern(layerIndex) ? patternMask : alternatePatternMask, target, _wallsOnly ? target : erode);
+ }
+
+ if (_wallsOnly)
+ {
+ originalRoi.CopyTo(target, erode);
}
- ApplyMask(original, target, mask);
+ ApplyMask(originalRoi, target, mask);
return true;
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index dfd68ff..b808a40 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>2.18.1</Version>
+ <Version>2.19.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs
index c5199fe..badd7bf 100644
--- a/UVtools.WPF/App.axaml.cs
+++ b/UVtools.WPF/App.axaml.cs
@@ -127,6 +127,25 @@ namespace UVtools.WPF
}
}
+ public static bool SelectFileOnExplorer(string filePath)
+ {
+ if (!File.Exists(filePath))
+ {
+ return false;
+ }
+
+ if (OperatingSystem.IsWindows())
+ {
+ StartProcess("explorer.exe", $"/select,\"{filePath}\"");
+ }
+ else
+ {
+ StartProcess(Path.GetDirectoryName(filePath));
+ }
+
+ return true;
+ }
+
public static void OpenBrowser(string url)
{
try
diff --git a/UVtools.WPF/Assets/Icons/folder-open-16x16.png b/UVtools.WPF/Assets/Icons/folder-open-16x16.png
new file mode 100644
index 0000000..f47b011
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/folder-open-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml
index 82863cf..885987f 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml
@@ -190,178 +190,175 @@
</Grid>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="{Binding Operation.ErodeObjects, StringFormat=Morph - Erode [\{0\} objects]}"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
-
- <StackPanel>
- <Grid
- Margin="0,10,0,0"
- RowDefinitions="Auto,10,Auto"
- ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,30,Auto,10,Auto"
- >
-
- <CheckBox Grid.Row="0" Grid.Column="2"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.IsErodeEnabled}"
- Content="Enable"/>
-
-
- <TextBlock Grid.Row="2" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Iterations range:"/>
-
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- IsEnabled="{Binding Operation.IsErodeEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="30"
- Value="{Binding Operation.ErodeStartIteration}"/>
-
-
- <TextBlock Grid.Row="2" Grid.Column="4"
- VerticalAlignment="Center"
- Text="-"/>
-
- <NumericUpDown Grid.Row="2" Grid.Column="6"
-
- IsEnabled="{Binding Operation.IsErodeEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="30"
- Value="{Binding Operation.ErodeEndIteration}"/>
-
- <TextBlock Grid.Row="2" Grid.Column="8"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="2" Grid.Column="10"
- VerticalAlignment="Center"
- Text="Step increment(s):"/>
-
- <NumericUpDown Grid.Row="2" Grid.Column="12"
-
- IsEnabled="{Binding Operation.IsErodeEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="20"
- Value="{Binding Operation.ErodeIterationSteps}"/>
-
- </Grid>
-
- <Border
- Margin="0,10,0,0">
- <Expander>
- <Expander.Header>
- <TextBlock Text="Kernel - Advanced options (Click to expand)"
- FontWeight="Bold"
- Cursor="Hand"
- />
- </Expander.Header>
- <controls:KernelControl
- Name="KernelCtrl"
- Margin="0,10,0,0"
- />
- </Expander>
- </Border>
-
- </StackPanel>
-
- </Expander>
- </Border>
-
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="{Binding Operation.DimmingObjects, StringFormat=Wall dimming [\{0\} objects]}"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
-
- <Grid
- Margin="0,10,0,0"
- RowDefinitions="Auto,10,Auto,10,Auto,5,Auto"
- ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,20,Auto,10,Auto"
- >
-
- <CheckBox Grid.Row="0" Grid.Column="2"
- Grid.ColumnSpan="11"
+
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="{Binding Operation.ErodeObjects, StringFormat=Morph - Erode [\{0\} objects]}"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
+
+ <StackPanel>
+ <Grid
+
+ RowDefinitions="Auto,10,Auto"
+ ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,30,Auto,10,Auto"
+ >
+
+ <CheckBox Grid.Row="0" Grid.Column="2"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.IsErodeEnabled}"
+ Content="Enable"/>
+
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
- IsChecked="{Binding Operation.IsDimmingEnabled}"
- Content="Enable - Requires a compatible anti-aliased file format and printer"/>
+ Text="Iterations range:"/>
+
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+
+ IsEnabled="{Binding Operation.IsErodeEnabled}"
+ Increment="1"
+ Minimum="1"
+ Maximum="30"
+ Value="{Binding Operation.ErodeStartIteration}"/>
+
+
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="-"/>
+
+ <NumericUpDown Grid.Row="2" Grid.Column="6"
+
+ IsEnabled="{Binding Operation.IsErodeEnabled}"
+ Increment="1"
+ Minimum="1"
+ Maximum="30"
+ Value="{Binding Operation.ErodeEndIteration}"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="8"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="Step increment(s):"/>
+
+ <NumericUpDown Grid.Row="2" Grid.Column="12"
+
+ IsEnabled="{Binding Operation.IsErodeEnabled}"
+ Increment="1"
+ Minimum="1"
+ Maximum="20"
+ Value="{Binding Operation.ErodeIterationSteps}"/>
+
+ </Grid>
+
+ <Border
+ Margin="0,10,0,0">
+ <Expander>
+ <Expander.Header>
+ <TextBlock Text="Kernel - Advanced options (Click to expand)"
+ FontWeight="Bold"
+ Cursor="Hand"
+ />
+ </Expander.Header>
+ <controls:KernelControl
+ Name="KernelCtrl"
+ Margin="0,10,0,0"
+ />
+ </Expander>
+ </Border>
- <TextBlock Grid.Row="2" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Wall thickness:"/>
+ </StackPanel>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- IsEnabled="{Binding Operation.IsDimmingEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="255"
- Value="{Binding Operation.DimmingWallThickness}"/>
+ </Expander>
- <TextBlock Grid.Row="2" Grid.Column="4"
- VerticalAlignment="Center"
- Text="px"/>
+
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="{Binding Operation.DimmingObjects, StringFormat=Wall dimming [\{0\} objects]}"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
+ <Grid
+ RowDefinitions="Auto,10,Auto,10,Auto,5,Auto"
+ ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,20,Auto,10,Auto"
+ >
- <TextBlock Grid.Row="4" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Brightness range:"/>
+ <CheckBox Grid.Row="0" Grid.Column="2"
+ Grid.ColumnSpan="11"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.IsDimmingEnabled}"
+ Content="Enable - Requires a compatible anti-aliased file format and printer"/>
- <NumericUpDown Grid.Row="4" Grid.Column="2"
-
- IsEnabled="{Binding Operation.IsDimmingEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="254"
- Value="{Binding Operation.DimmingStartBrightness}"/>
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Wall thickness:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+
+ IsEnabled="{Binding Operation.IsDimmingEnabled}"
+ Increment="1"
+ Minimum="1"
+ Maximum="255"
+ Value="{Binding Operation.DimmingWallThickness}"/>
- <TextBlock Grid.Row="4" Grid.Column="4"
- VerticalAlignment="Center"
- HorizontalAlignment="Center"
- Text="-"/>
-
- <NumericUpDown Grid.Row="4" Grid.Column="6"
-
- IsEnabled="{Binding Operation.IsDimmingEnabled}"
- Increment="1"
- Minimum="2"
- Maximum="254"
- Value="{Binding Operation.DimmingEndBrightness}"/>
-
- <TextBlock Grid.Row="4" Grid.Column="10"
- VerticalAlignment="Center"
- Text="Step increment(s):"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"/>
- <NumericUpDown Grid.Row="4" Grid.Column="12"
-
- IsEnabled="{Binding Operation.IsDimmingEnabled}"
- Increment="1"
- Minimum="2"
- Maximum="254"
- Value="{Binding Operation.DimmingBrightnessSteps}"/>
- <TextBlock Grid.Row="6" Grid.Column="2"
- VerticalAlignment="Center"
- HorizontalAlignment="Center"
- Text="{Binding Operation.DimmingStartBrightnessPercent, StringFormat=(\{0\}%)}"/>
- <TextBlock Grid.Row="6" Grid.Column="6"
- VerticalAlignment="Center"
- HorizontalAlignment="Center"
- Text="{Binding Operation.DimmingEndBrightnessPercent, StringFormat=(\{0\}%)}"/>
- </Grid>
+ <TextBlock Grid.Row="4" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Brightness range:"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="2"
+
+ IsEnabled="{Binding Operation.IsDimmingEnabled}"
+ Increment="1"
+ Minimum="1"
+ Maximum="254"
+ Value="{Binding Operation.DimmingStartBrightness}"/>
+
+
+ <TextBlock Grid.Row="4" Grid.Column="4"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Text="-"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="6"
+
+ IsEnabled="{Binding Operation.IsDimmingEnabled}"
+ Increment="1"
+ Minimum="2"
+ Maximum="254"
+ Value="{Binding Operation.DimmingEndBrightness}"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="Step increment(s):"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="12"
+
+ IsEnabled="{Binding Operation.IsDimmingEnabled}"
+ Increment="1"
+ Minimum="2"
+ Maximum="254"
+ Value="{Binding Operation.DimmingBrightnessSteps}"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="2"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Text="{Binding Operation.DimmingStartBrightnessPercent, StringFormat=(\{0\}%)}"/>
+ <TextBlock Grid.Row="6" Grid.Column="6"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Text="{Binding Operation.DimmingEndBrightnessPercent, StringFormat=(\{0\}%)}"/>
+ </Grid>
- </Expander>
- </Border>
+ </Expander>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
index 2ffeb4b..7061e5d 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
@@ -7,811 +7,812 @@
<Grid ColumnDefinitions="Auto,10,380">
<StackPanel Spacing="10">
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Common properties"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
-
- <Grid
- RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
- ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
-
- <TextBlock
- Grid.Row="0" Grid.Column="0"
- VerticalAlignment="Center"
- ToolTip.Tip="The printer display width. Required to calculate the pixels per mm."
- Text="Display width:"/>
- <NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="0.1"
- Minimum="0"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.DisplayWidth}"/>
- <TextBlock Grid.Row="0" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="0" Grid.Column="6"
- VerticalAlignment="Center"
- ToolTip.Tip="The printer display height. Required to calculate the pixels per mm."
- Text="Display height:"/>
- <NumericUpDown Grid.Row="0" Grid.Column="8"
- Increment="0.1"
- Minimum="0"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.DisplayHeight}"/>
- <TextBlock Grid.Row="0" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="2" Grid.Column="0"
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Common properties"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
+
+ <Grid
+ RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
+
+ <TextBlock
+ Grid.Row="0" Grid.Column="0"
+ VerticalAlignment="Center"
+ ToolTip.Tip="The printer display width. Required to calculate the pixels per mm."
+ Text="Display width:"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+
+ Increment="0.1"
+ Minimum="0"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.DisplayWidth}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ VerticalAlignment="Center"
+ ToolTip.Tip="The printer display height. Required to calculate the pixels per mm."
+ Text="Display height:"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="8"
+ Increment="0.1"
+ Minimum="0"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.DisplayHeight}"/>
+ <TextBlock Grid.Row="0" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ IsEnabled="{Binding !Operation.PatternModel}"
+ VerticalAlignment="Center"
+ Text="Layer height:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
IsEnabled="{Binding !Operation.PatternModel}"
- VerticalAlignment="Center"
- Text="Layer height:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
- IsEnabled="{Binding !Operation.PatternModel}"
- Increment="0.01"
- Minimum="0.01"
- Maximum="0.30"
- FormatString="F3"
- Value="{Binding Operation.LayerHeight}"/>
- <TextBlock Grid.Row="2" Grid.Column="4"
- IsEnabled="{Binding !Operation.PatternModel}"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="2" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Bottom layers:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="8"
-
- Increment="1"
- Minimum="1"
- Maximum="1000"
- Value="{Binding Operation.BottomLayers}"/>
- <TextBlock Grid.Row="2" Grid.Column="8"
- VerticalAlignment="Center"
- Text="{Binding Operation.BottomHeight, StringFormat=\{0:F3\}mm}"/>
-
- <TextBlock Grid.Row="4" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Bottom exposure:"/>
- <NumericUpDown Grid.Row="4" Grid.Column="2"
-
- Increment="0.5"
- Minimum="0.1"
- Maximum="200"
- FormatString="F2"
- Value="{Binding Operation.BottomExposure}"/>
- <TextBlock Grid.Row="4" Grid.Column="4"
- VerticalAlignment="Center"
- Text="s"/>
-
- <TextBlock Grid.Row="4" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Normal exposure:"/>
- <NumericUpDown Grid.Row="4" Grid.Column="8"
-
- Increment="0.5"
- Minimum="0.1"
- Maximum="200"
- FormatString="F2"
- Value="{Binding Operation.NormalExposure}"/>
- <TextBlock Grid.Row="4" Grid.Column="10"
- VerticalAlignment="Center"
- Text="s"/>
-
- <TextBlock Grid.Row="6" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Top/bottom margin:"/>
- <NumericUpDown Grid.Row="6" Grid.Column="2"
-
- Increment="0.5"
- Minimum="0"
- Maximum="1000"
- Value="{Binding Operation.TopBottomMargin}"/>
- <TextBlock Grid.Row="6" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="6" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Left/right margin:"/>
- <NumericUpDown Grid.Row="6" Grid.Column="8"
-
- Increment="0.5"
- Minimum="0"
- Maximum="1000"
- Value="{Binding Operation.LeftRightMargin}"/>
- <TextBlock Grid.Row="6" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="8" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Part margin:"/>
- <NumericUpDown Grid.Row="8" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="10000"
- Value="{Binding Operation.PartMargin}"/>
- <TextBlock Grid.Row="8" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="10" Grid.Column="0"
- VerticalAlignment="Center"
- ToolTip.Tip="Chamfer the bottom and top layers"
- Text="Chamfer layers:"/>
- <NumericUpDown Grid.Row="10" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="255"
- IsEnabled="{Binding Operation.ChamferModel}"
- Value="{Binding Operation.ChamferLayers}"/>
-
- <TextBlock Grid.Row="10" Grid.Column="6"
- VerticalAlignment="Center"
- ToolTip.Tip="Erode bottom iterations to counter the elephant foot"
- Text="Erode bottom iter.:"/>
- <NumericUpDown Grid.Row="10" Grid.Column="8"
-
- Increment="1"
- Minimum="0"
- Maximum="255"
- Value="{Binding Operation.ErodeBottomIterations}"/>
-
- <CheckBox Grid.Row="12" Grid.Column="2" Grid.ColumnSpan="5"
- VerticalAlignment="Center"
- IsEnabled="{Binding !Operation.PatternModel}"
- IsChecked="{Binding Operation.EnableAntiAliasing}"
- Content="Enable Anti-Aliasing"/>
-
- <CheckBox Grid.Row="12" Grid.Column="8"
- Grid.ColumnSpan="3"
- IsEnabled="{Binding !Operation.PatternModel}"
- ToolTip.Tip="Most of the printers requires a mirror output to print with the correct orientation"
- IsChecked="{Binding Operation.MirrorOutput}"
- Content="Mirror output" />
-
- </Grid>
- </Expander>
- </Border>
-
- <Border BorderBrush="Black" BorderThickness="1" Padding="5"
- IsVisible="{Binding !Operation.PatternModel}">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Object configuration"
- FontWeight="Bold"
- Cursor="Hand"/>
-
- </Expander.Header>
-
- <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
- ColumnDefinitions="Auto,10,Auto,5,Auto,20,Auto,10,Auto,5,Auto,20,Auto,10,Auto,5,Auto">
- <TextBlock Grid.Row="0" Grid.Column="0"
- Text="Base height:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="0.5"
- Minimum="0.3"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.BaseHeight}"/>
- <TextBlock Grid.Row="0" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="0" Grid.Column="6"
- Text="Features height:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="8"
-
- Increment="0.5"
- Minimum="0.5"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.FeaturesHeight}"/>
- <TextBlock Grid.Row="0" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="0" Grid.Column="12"
- Text="Features margin:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="14"
-
- Increment="0.5"
- Minimum="0"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.FeaturesMargin}"/>
- <TextBlock Grid.Row="0" Grid.Column="16"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="2" Grid.Column="0"
- ToolTip.Tip="Creates an incremental stair at top from left to right that goes up to the top layer"
- Text="Staircase:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="65535"
- Value="{Binding Operation.StaircaseThickness}"/>
- <TextBlock Grid.Row="2" Grid.Column="4"
- VerticalAlignment="Center"
- Text="px"/>
-
- <CheckBox Grid.Row="4" Grid.Column="0"
- Grid.ColumnSpan="17"
- FontWeight="Bold"
- Content="Pin (positive) / holes (negative):"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.HolesEnabled}"/>
-
- <TextBlock Grid.Row="6" Grid.Column="0"
- IsEnabled="{Binding Operation.HolesEnabled}"
- Text="Shape:"
- VerticalAlignment="Center"/>
-
- <ComboBox Grid.Row="6" Grid.Column="2"
- IsEnabled="{Binding Operation.HolesEnabled}"
- HorizontalAlignment="Stretch"
- Items="{Binding Operation.ShapesItems}"
- SelectedItem="{Binding Operation.HoleShape}"/>
-
- <TextBlock Grid.Row="6" Grid.Column="6"
- Text="Unit of measure:"
- VerticalAlignment="Center"/>
-
- <ComboBox Grid.Row="6" Grid.Column="8"
- HorizontalAlignment="Stretch"
- Items="{Binding Operation.MeasuresItems}"
- SelectedItem="{Binding Operation.UnitOfMeasure}"/>
-
-
- <TextBlock Grid.Row="8" Grid.Column="0"
- IsEnabled="{Binding Operation.HolesEnabled}"
- Text="Diameters:"
- ToolTip.Tip="Diameters separated by a comma (,).
+ Increment="0.01"
+ Minimum="0.01"
+ Maximum="0.30"
+ FormatString="F3"
+ Value="{Binding Operation.LayerHeight}"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ IsEnabled="{Binding !Operation.PatternModel}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Bottom layers:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="8"
+
+ Increment="1"
+ Minimum="1"
+ Maximum="1000"
+ Value="{Binding Operation.BottomLayers}"/>
+ <TextBlock Grid.Row="2" Grid.Column="8"
+ VerticalAlignment="Center"
+ Text="{Binding Operation.BottomHeight, StringFormat=\{0:F3\}mm}"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Bottom exposure:"/>
+ <NumericUpDown Grid.Row="4" Grid.Column="2"
+
+ Increment="0.5"
+ Minimum="0.1"
+ Maximum="200"
+ FormatString="F2"
+ Value="{Binding Operation.BottomExposure}"/>
+ <TextBlock Grid.Row="4" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="s"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Normal exposure:"/>
+ <NumericUpDown Grid.Row="4" Grid.Column="8"
+
+ Increment="0.5"
+ Minimum="0.1"
+ Maximum="200"
+ FormatString="F2"
+ Value="{Binding Operation.NormalExposure}"/>
+ <TextBlock Grid.Row="4" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="s"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Top/bottom margin:"/>
+ <NumericUpDown Grid.Row="6" Grid.Column="2"
+
+ Increment="0.5"
+ Minimum="0"
+ Maximum="1000"
+ Value="{Binding Operation.TopBottomMargin}"/>
+ <TextBlock Grid.Row="6" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Left/right margin:"/>
+ <NumericUpDown Grid.Row="6" Grid.Column="8"
+
+ Increment="0.5"
+ Minimum="0"
+ Maximum="1000"
+ Value="{Binding Operation.LeftRightMargin}"/>
+ <TextBlock Grid.Row="6" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="8" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Part margin:"/>
+ <NumericUpDown Grid.Row="8" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="10000"
+ Value="{Binding Operation.PartMargin}"/>
+ <TextBlock Grid.Row="8" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="10" Grid.Column="0"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Chamfer the bottom and top layers"
+ Text="Chamfer layers:"/>
+ <NumericUpDown Grid.Row="10" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="255"
+ IsEnabled="{Binding Operation.ChamferModel}"
+ Value="{Binding Operation.ChamferLayers}"/>
+
+ <TextBlock Grid.Row="10" Grid.Column="6"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Erode bottom iterations to counter the elephant foot"
+ Text="Erode bottom iter.:"/>
+ <NumericUpDown Grid.Row="10" Grid.Column="8"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="255"
+ Value="{Binding Operation.ErodeBottomIterations}"/>
+
+ <CheckBox Grid.Row="12" Grid.Column="2" Grid.ColumnSpan="5"
+ VerticalAlignment="Center"
+ IsEnabled="{Binding !Operation.PatternModel}"
+ IsChecked="{Binding Operation.EnableAntiAliasing}"
+ Content="Enable Anti-Aliasing"/>
+
+ <CheckBox Grid.Row="12" Grid.Column="8"
+ Grid.ColumnSpan="3"
+ IsEnabled="{Binding !Operation.PatternModel}"
+ ToolTip.Tip="Most of the printers requires a mirror output to print with the correct orientation"
+ IsChecked="{Binding Operation.MirrorOutput}"
+ Content="Mirror output" />
+
+ </Grid>
+ </Expander>
+
+ <Expander IsExpanded="True" IsVisible="{Binding !Operation.PatternModel}">
+ <Expander.Header>
+ <TextBlock Text="Object configuration"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+
+ </Expander.Header>
+
+ <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,Auto,5,Auto,20,Auto,10,Auto,5,Auto,20,Auto,10,Auto,5,Auto">
+ <TextBlock Grid.Row="0" Grid.Column="0"
+ Text="Base height:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+
+ Increment="0.5"
+ Minimum="0.3"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.BaseHeight}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ Text="Features height:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="8"
+
+ Increment="0.5"
+ Minimum="0.5"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.FeaturesHeight}"/>
+ <TextBlock Grid.Row="0" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="12"
+ Text="Features margin:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="14"
+
+ Increment="0.5"
+ Minimum="0"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.FeaturesMargin}"/>
+ <TextBlock Grid.Row="0" Grid.Column="16"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ ToolTip.Tip="Creates an incremental stair at top from left to right that goes up to the top layer"
+ Text="Staircase:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ Increment="1"
+ Minimum="0"
+ Maximum="65535"
+ Value="{Binding Operation.StaircaseThicknessPx}"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ Increment="1"
+ Minimum="0"
+ Maximum="500"
+ Value="{Binding Operation.StaircaseThicknessMm}"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ Text="px"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="6"
+ Text="Unit of measure:"
+ VerticalAlignment="Center"/>
+
+ <ComboBox Grid.Row="2" Grid.Column="8"
+ HorizontalAlignment="Stretch"
+ Items="{Binding Operation.MeasuresItems}"
+ SelectedItem="{Binding Operation.UnitOfMeasure}"/>
+
+ <CheckBox Grid.Row="4" Grid.Column="0"
+ Grid.ColumnSpan="17"
+ FontWeight="Bold"
+ Content="Pin (positive) / holes (negative):"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.HolesEnabled}"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="0"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ Text="Shape:"
+ VerticalAlignment="Center"/>
+
+ <ComboBox Grid.Row="6" Grid.Column="2"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ HorizontalAlignment="Stretch"
+ Items="{Binding Operation.ShapesItems}"
+ SelectedItem="{Binding Operation.HoleShape}"/>
+
+
+ <TextBlock Grid.Row="8" Grid.Column="0"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ Text="Diameters:"
+ ToolTip.Tip="Diameters separated by a comma (,).
&#x0a;Order doesn't matter.
&#x0a;Values are pixel square, eg: 3 = 3x3 = 9 pixel hole"
- VerticalAlignment="Center"/>
-
- <TextBox Grid.Row="8" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.HolesEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.HoleDiametersMm}"/>
-
- <TextBox Grid.Row="8" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.HolesEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.HoleDiametersPx}"/>
-
- <TextBlock Grid.Row="8" Grid.Column="16"
- IsEnabled="{Binding Operation.HolesEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="8" Grid.Column="16"
- IsEnabled="{Binding Operation.HolesEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <CheckBox Grid.Row="10" Grid.Column="0"
- Grid.ColumnSpan="17"
- FontWeight="Bold"
- Content="Zebra bars:"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.BarsEnabled}"/>
-
-
- <TextBlock Grid.Row="12" Grid.Column="0"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Bar spacing:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="12" Grid.Column="2"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Increment="0.5"
- Minimum="0.01"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.BarSpacing}"/>
- <TextBlock Grid.Row="12" Grid.Column="4"
+ VerticalAlignment="Center"/>
+
+ <TextBox Grid.Row="8" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.HoleDiametersMm}"/>
+
+ <TextBox Grid.Row="8" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.HoleDiametersPx}"/>
+
+ <TextBlock Grid.Row="8" Grid.Column="16"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="8" Grid.Column="16"
+ IsEnabled="{Binding Operation.HolesEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <CheckBox Grid.Row="10" Grid.Column="0"
+ Grid.ColumnSpan="17"
+ FontWeight="Bold"
+ Content="Zebra bars:"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.BarsEnabled}"/>
+
+
+ <TextBlock Grid.Row="12" Grid.Column="0"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Bar spacing:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="12" Grid.Column="2"
IsEnabled="{Binding Operation.BarsEnabled}"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="12" Grid.Column="6"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Bar length:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="12" Grid.Column="8"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Increment="0.5"
- Minimum="0.01"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.BarLength}"/>
- <TextBlock Grid.Row="12" Grid.Column="10"
+ Increment="0.5"
+ Minimum="0.01"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.BarSpacing}"/>
+ <TextBlock Grid.Row="12" Grid.Column="4"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="12" Grid.Column="6"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Bar length:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="12" Grid.Column="8"
IsEnabled="{Binding Operation.BarsEnabled}"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="12" Grid.Column="12"
+ Increment="0.5"
+ Minimum="0.01"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.BarLength}"/>
+ <TextBlock Grid.Row="12" Grid.Column="10"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="12" Grid.Column="12"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Vertical splitter:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="12" Grid.Column="14"
IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Vertical splitter:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="12" Grid.Column="14"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Increment="1"
- Minimum="-128"
- Maximum="127"
- Value="{Binding Operation.BarVerticalSplitter}"/>
- <TextBlock Grid.Row="10" Grid.Column="16"
+ Increment="1"
+ Minimum="-128"
+ Maximum="127"
+ Value="{Binding Operation.BarVerticalSplitter}"/>
+ <TextBlock Grid.Row="10" Grid.Column="16"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="14" Grid.Column="0"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Fence thick:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="14" Grid.Column="2"
IsEnabled="{Binding Operation.BarsEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="14" Grid.Column="0"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Fence thick:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="14" Grid.Column="2"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Increment="2"
- Minimum="0"
- Maximum="255"
- Value="{Binding Operation.BarFenceThickness}"/>
- <TextBlock Grid.Row="14" Grid.Column="4"
- IsEnabled="{Binding Operation.BarsEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="14" Grid.Column="6"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Fence offset:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="14" Grid.Column="8"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Increment="1"
- Minimum="-128"
- Maximum="127"
- Value="{Binding Operation.BarFenceOffset}"/>
- <TextBlock Grid.Row="14" Grid.Column="10"
+ Increment="2"
+ Minimum="0"
+ Maximum="255"
+ Value="{Binding Operation.BarFenceThickness}"/>
+ <TextBlock Grid.Row="14" Grid.Column="4"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="14" Grid.Column="6"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Fence offset:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="14" Grid.Column="8"
IsEnabled="{Binding Operation.BarsEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="16" Grid.Column="0"
- IsEnabled="{Binding Operation.BarsEnabled}"
- Text="Thicknesses:"
- VerticalAlignment="Center"/>
-
- <TextBox Grid.Row="16" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.BarsEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.BarThicknessesMm}"/>
-
- <TextBox Grid.Row="16" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.BarsEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.BarThicknessesPx}"/>
- <TextBlock Grid.Row="16" Grid.Column="16"
- IsEnabled="{Binding Operation.BarsEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="mm"/>
- <TextBlock Grid.Row="16" Grid.Column="16"
- IsEnabled="{Binding Operation.BarsEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <CheckBox Grid.Row="18" Grid.Column="0"
- Grid.ColumnSpan="17"
- FontWeight="Bold"
- Content="Text:"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.TextEnabled}"/>
-
- <TextBlock Grid.Row="20" Grid.Column="0"
- IsEnabled="{Binding Operation.TextEnabled}"
- Text="Font:"
- VerticalAlignment="Center"/>
- <ComboBox Grid.Row="20" Grid.Column="2"
- IsEnabled="{Binding Operation.TextEnabled}"
- Grid.ColumnSpan="3"
- VerticalAlignment="Center"
- HorizontalAlignment="Stretch"
- Items="{Binding Operation.TextFonts}"
- SelectedItem="{Binding Operation.TextFont}"/>
-
- <TextBlock Grid.Row="20" Grid.Column="6"
+ Increment="1"
+ Minimum="-128"
+ Maximum="127"
+ Value="{Binding Operation.BarFenceOffset}"/>
+ <TextBlock Grid.Row="14" Grid.Column="10"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="16" Grid.Column="0"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ Text="Thicknesses:"
+ VerticalAlignment="Center"/>
+
+ <TextBox Grid.Row="16" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.BarThicknessesMm}"/>
+
+ <TextBox Grid.Row="16" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.BarThicknessesPx}"/>
+ <TextBlock Grid.Row="16" Grid.Column="16"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+ <TextBlock Grid.Row="16" Grid.Column="16"
+ IsEnabled="{Binding Operation.BarsEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <CheckBox Grid.Row="18" Grid.Column="0"
+ Grid.ColumnSpan="17"
+ FontWeight="Bold"
+ Content="Text:"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.TextEnabled}"/>
+
+ <TextBlock Grid.Row="20" Grid.Column="0"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Text="Font:"
+ VerticalAlignment="Center"/>
+ <ComboBox Grid.Row="20" Grid.Column="2"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Grid.ColumnSpan="3"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Stretch"
+ Items="{Binding Operation.TextFonts}"
+ SelectedItem="{Binding Operation.TextFont}"/>
+
+ <TextBlock Grid.Row="20" Grid.Column="6"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Text="Text scale:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="20" Grid.Column="8"
IsEnabled="{Binding Operation.TextEnabled}"
- Text="Text scale:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="20" Grid.Column="8"
- IsEnabled="{Binding Operation.TextEnabled}"
- Increment="0.5"
- Minimum="0.1"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.TextScale}"/>
- <TextBlock Grid.Row="20" Grid.Column="10"
- IsEnabled="{Binding Operation.TextEnabled}"
- VerticalAlignment="Center"
- Text="x"/>
-
- <TextBlock Grid.Row="20" Grid.Column="12"
- IsEnabled="{Binding Operation.TextEnabled}"
- Text="Text thickness:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="20" Grid.Column="14"
- IsEnabled="{Binding Operation.TextEnabled}"
- Increment="1"
- Minimum="1"
- Maximum="255"
- Value="{Binding Operation.TextThickness}"/>
- <TextBlock Grid.Row="20" Grid.Column="16"
+ Increment="0.5"
+ Minimum="0.1"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.TextScale}"/>
+ <TextBlock Grid.Row="20" Grid.Column="10"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ VerticalAlignment="Center"
+ Text="x"/>
+
+ <TextBlock Grid.Row="20" Grid.Column="12"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Text="Text thickness:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="20" Grid.Column="14"
IsEnabled="{Binding Operation.TextEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="22" Grid.Column="0"
- IsEnabled="{Binding Operation.TextEnabled}"
- Text="Text:"
- VerticalAlignment="Center"/>
-
- <TextBox Grid.Row="22" Grid.Column="2"
- IsEnabled="{Binding Operation.TextEnabled}"
- Grid.ColumnSpan="13"
- Text="{Binding Operation.Text}"/>
-
- <CheckBox Grid.Row="24" Grid.Column="0"
- Grid.ColumnSpan="17"
- FontWeight="Bold"
- Content="Bullseye:"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.BullsEyeEnabled}"/>
-
-
- <TextBlock Grid.Row="26" Grid.Column="0"
- Text="Configuration:"
+ Increment="1"
+ Minimum="1"
+ Maximum="255"
+ Value="{Binding Operation.TextThickness}"/>
+ <TextBlock Grid.Row="20" Grid.Column="16"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="22" Grid.Column="0"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Text="Text:"
+ VerticalAlignment="Center"/>
+
+ <TextBox Grid.Row="22" Grid.Column="2"
+ IsEnabled="{Binding Operation.TextEnabled}"
+ Grid.ColumnSpan="13"
+ Text="{Binding Operation.Text}"/>
+
+ <CheckBox Grid.Row="24" Grid.Column="0"
+ Grid.ColumnSpan="17"
+ FontWeight="Bold"
+ Content="Bullseye:"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.BullsEyeEnabled}"/>
+
+
+ <TextBlock Grid.Row="26" Grid.Column="0"
+ Text="Configuration:"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ ToolTip.Tip="Diameter:Thickness, ..."
+ VerticalAlignment="Center"/>
+
+ <TextBox Grid.Row="26" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.BullsEyeConfigurationMm}"/>
+
+ <TextBox Grid.Row="26" Grid.Column="2"
+ Grid.ColumnSpan="13"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ Text="{Binding Operation.BullsEyeConfigurationPx}"/>
+ <TextBlock Grid.Row="26" Grid.Column="16"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="mm"/>
+ <TextBlock Grid.Row="26" Grid.Column="16"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="28" Grid.Column="0"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ Text="Fence thick:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="28" Grid.Column="2"
IsEnabled="{Binding Operation.BullsEyeEnabled}"
- ToolTip.Tip="Diameter:Thickness, ..."
- VerticalAlignment="Center"/>
-
- <TextBox Grid.Row="26" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.BullsEyeConfigurationMm}"/>
-
- <TextBox Grid.Row="26" Grid.Column="2"
- Grid.ColumnSpan="13"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- Text="{Binding Operation.BullsEyeConfigurationPx}"/>
- <TextBlock Grid.Row="26" Grid.Column="16"
+ Increment="2"
+ Minimum="0"
+ Maximum="255"
+ Value="{Binding Operation.BullsEyeFenceThickness}"/>
+ <TextBlock Grid.Row="28" Grid.Column="4"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="28" Grid.Column="6"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ Text="Fence offset:"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="28" Grid.Column="8"
IsEnabled="{Binding Operation.BullsEyeEnabled}"
- IsVisible="{Binding Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="mm"/>
- <TextBlock Grid.Row="26" Grid.Column="16"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- IsVisible="{Binding !Operation.IsUnitOfMeasureMm}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="28" Grid.Column="0"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- Text="Fence thick:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="28" Grid.Column="2"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- Increment="2"
- Minimum="0"
- Maximum="255"
- Value="{Binding Operation.BullsEyeFenceThickness}"/>
- <TextBlock Grid.Row="28" Grid.Column="4"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <TextBlock Grid.Row="28" Grid.Column="6"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- Text="Fence offset:"
- HorizontalAlignment="Right"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="28" Grid.Column="8"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- Increment="1"
- Minimum="-128"
- Maximum="127"
- Value="{Binding Operation.BullsEyeFenceOffset}"/>
- <TextBlock Grid.Row="28" Grid.Column="10"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
-
- <CheckBox Grid.Row="28" Grid.Column="12"
- Grid.ColumnSpan="5"
- Content="Invert quadrants"
- VerticalAlignment="Center"
- IsEnabled="{Binding Operation.BullsEyeEnabled}"
- IsChecked="{Binding Operation.BullsEyeInvertQuadrants}"/>
-
-
- <CheckBox Grid.Row="30" Grid.Column="0"
- Grid.ColumnSpan="17"
- FontWeight="Bold"
- Content="Counter triangles:"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.CounterTrianglesEnabled}"/>
-
-
- <TextBlock Grid.Row="32" Grid.Column="0"
- Text="Tip Offset:"
+ Increment="1"
+ Minimum="-128"
+ Maximum="127"
+ Value="{Binding Operation.BullsEyeFenceOffset}"/>
+ <TextBlock Grid.Row="28" Grid.Column="10"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <CheckBox Grid.Row="28" Grid.Column="12"
+ Grid.ColumnSpan="5"
+ Content="Invert quadrants"
+ VerticalAlignment="Center"
+ IsEnabled="{Binding Operation.BullsEyeEnabled}"
+ IsChecked="{Binding Operation.BullsEyeInvertQuadrants}"/>
+
+
+ <CheckBox Grid.Row="30" Grid.Column="0"
+ Grid.ColumnSpan="17"
+ FontWeight="Bold"
+ Content="Counter triangles:"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.CounterTrianglesEnabled}"/>
+
+
+ <TextBlock Grid.Row="32" Grid.Column="0"
+ Text="Tip Offset:"
+ IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
+ VerticalAlignment="Center"/>
+
+ <NumericUpDown Grid.Row="32" Grid.Column="2"
IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
- VerticalAlignment="Center"/>
+ Increment="1"
+ Minimum="-128"
+ Maximum="127"
+ Value="{Binding Operation.CounterTrianglesTipOffset}"/>
- <NumericUpDown Grid.Row="32" Grid.Column="2"
- IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
- Increment="1"
- Minimum="-128"
- Maximum="127"
- Value="{Binding Operation.CounterTrianglesTipOffset}"/>
+ <TextBlock Grid.Row="32" Grid.Column="4"
+ IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
+ VerticalAlignment="Center"
+ Text="px"/>
- <TextBlock Grid.Row="32" Grid.Column="4"
- IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
- VerticalAlignment="Center"
- Text="px"/>
+ <CheckBox Grid.Row="32" Grid.Column="6"
+ Grid.ColumnSpan="5"
+ IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
+ Content="Fence the triangles"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.CounterTrianglesFence}"/>
- <CheckBox Grid.Row="32" Grid.Column="6"
- Grid.ColumnSpan="5"
- IsEnabled="{Binding Operation.CounterTrianglesEnabled}"
- Content="Fence the triangles"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.CounterTrianglesFence}"/>
+ </Grid>
- </Grid>
+ </Expander>
- </Expander>
- </Border>
-
- <Border BorderBrush="Black"
- BorderThickness="1"
- Padding="5">
- <Expander IsExpanded="False">
- <Expander.Header>
- <StackPanel Orientation="Horizontal" Cursor="Hand">
- <TextBlock Text="Multiple brightness"
- IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
- FontWeight="Bold"/>
- <TextBlock Text="Multiple brightness/exposures with emulated AntiAliasing and time fractions"
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- FontWeight="Bold"/>
- </StackPanel>
- </Expander.Header>
+ <Expander IsExpanded="False">
+ <Expander.Header>
+ <StackPanel Orientation="Horizontal" Cursor="Hand">
+ <TextBlock Text="Multiple brightness"
+ IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
+ FontWeight="Bold"/>
+ <TextBlock Text="Multiple brightness/exposures with emulated AntiAliasing and time fractions"
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ FontWeight="Bold"/>
+ </StackPanel>
- <StackPanel Spacing="10">
+ </Expander.Header>
+
+ <StackPanel Spacing="10">
- <TextBlock
- Text="Only printers able to do Anti-Aliasing and enabled on file can support this.
+ <TextBlock
+ Text="Only printers able to do Anti-Aliasing and enabled on file can support this.
&#x0a;Make sure your is supported or else it can print a full white or full black model.
&#x0a;Also take into consideration some printers/formats have fixed usable AA levels and all in between will be threshold, study this first.
&#x0a;When using this section, always set the exposure time to the highest time you want to test.
&#x0a;If your printer is able to do 'Multiple exposures times per layer', please use that method instead of this (More accurate and AA threshold free)."/>
- <TextBlock
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- TextWrapping="Wrap"
- FontWeight="Bold"
- Text="Note: This file format uses time fractions to emulate AntiAliasing.
+ <TextBlock
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ TextWrapping="Wrap"
+ FontWeight="Bold"
+ Text="Note: This file format uses time fractions to emulate AntiAliasing.
&#x0a;This can be used to replace the 'Multiple exposures' sections and print multiple models at once at different timings.
&#x0a;However you can't set the object time, instead fractions of the main exposure must be used.
&#x0a;The brightness table will tell you the expected exposure time of each object."/>
- <CheckBox
- Content="Enable - For advanced users only!"
- IsChecked="{Binding Operation.MultipleBrightness}"/>
+ <CheckBox
+ Content="Enable - For advanced users only!"
+ IsChecked="{Binding Operation.MultipleBrightness}"/>
- <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
- ColumnDefinitions="Auto,10,200,5,Auto,20,Auto,10,Auto,5,Auto,5,Auto"
- IsEnabled="{Binding Operation.MultipleBrightness}">
+ <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,200,5,Auto,20,Auto,10,Auto,5,Auto,5,Auto"
+ IsEnabled="{Binding Operation.MultipleBrightness}">
- <TextBlock Grid.Row="0" Grid.Column="0"
- ToolTip.Tip="Do not change brightness from the selected layers. Full brightness of 255 is applied to the skip layers."
- Text="Exclude from:"
- VerticalAlignment="Center"/>
- <ComboBox Grid.Row="0" Grid.Column="2"
- VerticalAlignment="Center"
- HorizontalAlignment="Stretch"
- Items="{Binding Operation.MultipleBrightnessExcludeFromItems}"
- SelectedItem="{Binding Operation.MultipleBrightnessExcludeFrom}"/>
- <TextBlock Grid.Row="0" Grid.Column="4"
- Text="layers"
- VerticalAlignment="Center"/>
+ <TextBlock Grid.Row="0" Grid.Column="0"
+ ToolTip.Tip="Do not change brightness from the selected layers. Full brightness of 255 is applied to the skip layers."
+ Text="Exclude from:"
+ VerticalAlignment="Center"/>
+ <ComboBox Grid.Row="0" Grid.Column="2"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Stretch"
+ Items="{Binding Operation.MultipleBrightnessExcludeFromItems}"
+ SelectedItem="{Binding Operation.MultipleBrightnessExcludeFrom}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ Text="layers"
+ VerticalAlignment="Center"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
+ ToolTip.Tip="Append a brightness level to the list by giving a desired exposure time. Supplied time must be lower than the common exposure time or you need to increase it on the common 'Normal Exposure'."
+ Text="Generate by exposure time:"
+ VerticalAlignment="Center"/>
- <TextBlock Grid.Row="0" Grid.Column="6"
+ <NumericUpDown Grid.Row="0" Grid.Column="8"
IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
- ToolTip.Tip="Append a brightness level to the list by giving a desired exposure time. Supplied time must be lower than the common exposure time or you need to increase it on the common 'Normal Exposure'."
- Text="Generate by exposure time:"
- VerticalAlignment="Center"/>
+ Increment="0.10"
+ Minimum="0.10"
+ Maximum="{Binding Operation.NormalExposure}"
+ FormatString="F2"
+ Value="{Binding Operation.MultipleBrightnessGenExposureTime}"/>
- <NumericUpDown Grid.Row="0" Grid.Column="8"
- IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
- Increment="0.10"
- Minimum="0.10"
- Maximum="{Binding Operation.NormalExposure}"
- FormatString="F2"
- Value="{Binding Operation.MultipleBrightnessGenExposureTime}"/>
+ <TextBlock Grid.Row="0" Grid.Column="10"
+ IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
+ Text="s"
+ VerticalAlignment="Center"/>
- <TextBlock Grid.Row="0" Grid.Column="10"
- IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
- Text="s"
- VerticalAlignment="Center"/>
+ <Button
+ Grid.Row="0" Grid.Column="12" VerticalContentAlignment="Center"
+ IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ Command="{Binding BrightnessExposureGenAdd}">
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Image Source="/Assets/Icons/plus-16x16.png"/>
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Add"/>
+ </StackPanel>
+ </Button>
- <Button
- Grid.Row="0" Grid.Column="12" VerticalContentAlignment="Center"
- IsVisible="{Binding !SlicerFile.IsAntiAliasingEmulated}"
- HorizontalContentAlignment="Center"
- VerticalAlignment="Stretch"
- Command="{Binding BrightnessExposureGenAdd}">
- <StackPanel Orientation="Horizontal" Spacing="10">
- <Image Source="/Assets/Icons/plus-16x16.png"/>
- <TextBlock
- VerticalAlignment="Center"
- Text="Add"/>
- </StackPanel>
- </Button>
-
- <TextBlock Grid.Row="2" Grid.Column="0"
- Text="Brightnesses:"
- ToolTip.Tip="From 1-255, where 1 is almost black and 255 is full white. No half numbers are allowed."
- VerticalAlignment="Center"/>
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ Text="Brightnesses:"
+ ToolTip.Tip="From 1-255, where 1 is almost black and 255 is full white. No half numbers are allowed."
+ VerticalAlignment="Center"/>
- <TextBox Grid.Row="2" Grid.Column="2"
- Grid.ColumnSpan="11"
- Text="{Binding Operation.MultipleBrightnessValues}"/>
+ <TextBox Grid.Row="2" Grid.Column="2"
+ Grid.ColumnSpan="11"
+ Text="{Binding Operation.MultipleBrightnessValues}"/>
- <!--
- <TextBlock Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3"
+ <!--
+ <TextBlock Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3"
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ FontWeight="Bold"
+ Text="Emulated AntiAliasing with time fractions"
+ VerticalAlignment="Center"/>
+ !-->
+
+ <TextBlock Grid.Row="4" Grid.Column="0"
IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- FontWeight="Bold"
- Text="Emulated AntiAliasing with time fractions"
+ ToolTip.Tip="AntiAliasing level to set on file.
+&#x0a;This value is used to set the maximum available time fractions on the next field.
+&#x0a;Lower levels have larger time windows, while higher levels allow lower time windows (Recommended)."
+ Text="AntiAliasing:"
VerticalAlignment="Center"/>
- !-->
- <TextBlock Grid.Row="4" Grid.Column="0"
+ <NumericUpDown Grid.Row="4" Grid.Column="2"
IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- ToolTip.Tip="AntiAliasing level to set on file.
-&#x0a;This value is used to set the maximum available time fractions on the next field.
-&#x0a;Lower levels have larger time windows, while higher levels allow lower time windows (Recommended)."
- Text="AntiAliasing:"
- VerticalAlignment="Center"/>
+ Increment="2"
+ Minimum="2"
+ Maximum="{Binding Operation.MaximumAntiAliasing}"
+ Value="{Binding Operation.MultipleBrightnessGenEmulatedAALevel}"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="4"
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ Text="x"
+ VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="4" Grid.Column="2"
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- Increment="2"
- Minimum="2"
- Maximum="{Binding Operation.MaximumAntiAliasing}"
- Value="{Binding Operation.MultipleBrightnessGenEmulatedAALevel}"/>
- <TextBlock Grid.Row="4" Grid.Column="4"
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- Text="x"
- VerticalAlignment="Center"/>
+ <TextBlock Grid.Row="4" Grid.Column="6"
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ ToolTip.Tip="Amount of fractions from the main exposure: 2 to 16"
+ Text="Generate by time fractions:"
+ VerticalAlignment="Center"/>
+
+ <NumericUpDown Grid.Row="4" Grid.Column="8"
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ Increment="1"
+ Minimum="2"
+ Maximum="{Binding Operation.MultipleBrightnessGenEmulatedAALevel}"
+ Value="{Binding Operation.MultipleBrightnessGenExposureFractions}"/>
- <TextBlock Grid.Row="4" Grid.Column="6"
+ <TextBlock Grid.Row="4" Grid.Column="10"
IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- ToolTip.Tip="Amount of fractions from the main exposure: 2 to 16"
- Text="Generate by time fractions:"
+ Text="÷"
VerticalAlignment="Center"/>
-
- <NumericUpDown Grid.Row="4" Grid.Column="8"
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- Increment="1"
- Minimum="2"
- Maximum="{Binding Operation.MultipleBrightnessGenEmulatedAALevel}"
- Value="{Binding Operation.MultipleBrightnessGenExposureFractions}"/>
+ <!--<Button
+ IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
+ Grid.Row="4" Grid.Column="12" VerticalContentAlignment="Center"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ Command="{Binding Operation.GenerateBrightnessExposureFractions}">
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Image Source="/Assets/Icons/refresh-16x16.png"/>
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Gen"/>
+ </StackPanel>
+ </Button>
+ !-->
+ </Grid>
- <TextBlock Grid.Row="4" Grid.Column="10"
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- Text="÷"
- VerticalAlignment="Center"/>
+
+ <DataGrid
+ Name="BrightnessTable"
+ CanUserReorderColumns="True"
+ CanUserResizeColumns="True"
+ CanUserSortColumns="True"
+ GridLinesVisibility="Horizontal"
+ IsReadOnly="True"
+ ClipboardCopyMode="IncludeHeader"
+ VerticalAlignment="Stretch"
+ Margin="0,-10,0,0"
+ IsEnabled="{Binding Operation.MultipleBrightness}"
+ Items="{Binding Operation.MultipleBrightnessTable}">
+ <DataGrid.Columns>
+ <DataGridTextColumn Header="Brightness"
+ Binding="{Binding Brightness}"
+ Width="Auto" />
+ <DataGridTextColumn Header="Percent (%)"
+ Binding="{Binding BrightnessPercent}"
+ Width="Auto" />
+ <DataGridTextColumn Header="Bottom exposure (s)"
+ Binding="{Binding BottomExposure}"
+ Width="Auto" />
+ <DataGridTextColumn Header="Exposure (s)"
+ Binding="{Binding Exposure}"
+ Width="Auto" />
+ </DataGrid.Columns>
- <!--<Button
- IsVisible="{Binding SlicerFile.IsAntiAliasingEmulated}"
- Grid.Row="4" Grid.Column="12" VerticalContentAlignment="Center"
- HorizontalContentAlignment="Center"
- VerticalAlignment="Stretch"
- Command="{Binding Operation.GenerateBrightnessExposureFractions}">
- <StackPanel Orientation="Horizontal" Spacing="10">
- <Image Source="/Assets/Icons/refresh-16x16.png"/>
- <TextBlock
- VerticalAlignment="Center"
- Text="Gen"/>
- </StackPanel>
- </Button>
- !-->
- </Grid>
+ </DataGrid>
+
+
+
+ </StackPanel>
+ </Expander>
-
- <DataGrid
- Name="BrightnessTable"
- CanUserReorderColumns="True"
- CanUserResizeColumns="True"
- CanUserSortColumns="True"
- GridLinesVisibility="Horizontal"
- IsReadOnly="True"
- ClipboardCopyMode="IncludeHeader"
- VerticalAlignment="Stretch"
- Margin="0,-10,0,0"
- IsEnabled="{Binding Operation.MultipleBrightness}"
- Items="{Binding Operation.MultipleBrightnessTable}">
- <DataGrid.Columns>
- <DataGridTextColumn Header="Brightness"
- Binding="{Binding Brightness}"
- Width="Auto" />
- <DataGridTextColumn Header="Percent (%)"
- Binding="{Binding BrightnessPercent}"
- Width="Auto" />
- <DataGridTextColumn Header="Bottom exposure (s)"
- Binding="{Binding BottomExposure}"
- Width="Auto" />
- <DataGridTextColumn Header="Exposure (s)"
- Binding="{Binding Exposure}"
- Width="Auto" />
- </DataGrid.Columns>
-
- </DataGrid>
-
-
-
- </StackPanel>
- </Expander>
- </Border>
-
- <Border BorderBrush="Black"
- BorderThickness="1"
- Padding="5">
- <Border.IsVisible>
- <MultiBinding Converter="{x:Static BoolConverters.And}">
- <Binding Path="CanSupportPerLayerSettings"/>
- <Binding Path="!Operation.PatternModel"/>
- </MultiBinding>
- </Border.IsVisible>
<Expander IsExpanded="False">
- <Expander.Header>
+ <Expander.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="CanSupportPerLayerSettings"/>
+ <Binding Path="!Operation.PatternModel"/>
+ </MultiBinding>
+ </Expander.IsVisible>
+ <Expander.Header>
<TextBlock Text="Multiple layer height"
FontWeight="Bold"
Cursor="Hand"/>
@@ -821,7 +822,7 @@
<StackPanel Spacing="10">
<TextBlock Text="Only few printers support this, make sure your is supported or else it will print a malformed model.
-&#x0a;After this, do not apply any modification which reconstruct the z positions of the layers."/>
+ &#x0a;After this, do not apply any modification which reconstruct the z positions of the layers."/>
<CheckBox
Content="Enable - For advanced users only!"
@@ -873,13 +874,8 @@
</StackPanel>
</Expander>
- </Border>
- <Border BorderBrush="Black"
- BorderThickness="1"
- Padding="5"
- IsVisible="{Binding CanSupportPerLayerSettings}">
- <Expander IsExpanded="True">
+ <Expander IsExpanded="True" IsVisible="{Binding CanSupportPerLayerSettings}">
<Expander.Header>
<TextBlock Text="Multiple exposures"
FontWeight="Bold"
@@ -1208,13 +1204,8 @@
</StackPanel>
</Expander>
- </Border>
- <Border BorderBrush="Black"
- BorderThickness="1"
- Padding="5"
- IsVisible="{Binding Operation.CanPatternModel}">
- <Expander IsExpanded="False">
+ <Expander IsExpanded="False" IsVisible="{Binding Operation.CanPatternModel}">
<Expander.Header>
<TextBlock Text="Pattern loaded model"
FontWeight="Bold"
@@ -1286,7 +1277,6 @@
</StackPanel>
</Expander>
- </Border>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml
index 64dd735..ef5ecdd 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml
@@ -2,11 +2,11 @@
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="800" d:DesignHeight="450" Width="500"
x:Class="UVtools.WPF.Controls.Calibrators.CalibrateExternalTestsControl">
<Grid
RowDefinitions="Auto,Auto,Auto"
- ColumnDefinitions="400">
+ ColumnDefinitions="*">
<Button Grid.Row="0"
Padding="5"
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateGrayscaleControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateGrayscaleControl.axaml
index a8de317..f97755e 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateGrayscaleControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateGrayscaleControl.axaml
@@ -160,16 +160,17 @@
</Grid>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <StackPanel>
- <TextBlock FontWeight="Bold">
- <TextBlock.Text>
- <MultiBinding StringFormat="Pie settings [{0} divisions with {1:F2}º steps]">
- <Binding Path="Operation.Divisions"/>
- <Binding Path="Operation.AngleStep"/>
- </MultiBinding>
- </TextBlock.Text>
- </TextBlock>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock FontWeight="Bold">
+ <TextBlock.Text>
+ <MultiBinding StringFormat="Pie settings [{0} divisions with {1:F2}º steps]">
+ <Binding Path="Operation.Divisions"/>
+ <Binding Path="Operation.AngleStep"/>
+ </MultiBinding>
+ </TextBlock.Text>
+ </TextBlock>
+ </Expander.Header>
<Grid
Margin="0,10,0,0"
@@ -236,6 +237,7 @@
<CheckBox Grid.Row="4" Grid.Column="6" Grid.ColumnSpan="7"
VerticalAlignment="Center"
+ Margin="10,0,0,0"
Content="Enable center hole relief"
IsChecked="{Binding Operation.EnableCenterHoleRelief}"/>
@@ -309,8 +311,7 @@
VerticalAlignment="Center"
Text="px"/>
</Grid>
- </StackPanel>
- </Border>
+ </Expander>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateStressTowerControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateStressTowerControl.axaml
index d93cbf8..ac36835 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateStressTowerControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateStressTowerControl.axaml
@@ -7,281 +7,277 @@
<StackPanel Spacing="10">
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 1 - Common properties"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 1 - Common properties"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
- <Grid
- RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
- ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
+ <Grid
+ RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
- <TextBlock
- Grid.Row="0" Grid.Column="0"
- VerticalAlignment="Center"
- ToolTip.Tip="The printer display width. Required to calculate the pixels per mm."
- Text="Display width:"/>
- <NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="0.1"
- Minimum="0"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.DisplayWidth}"/>
- <TextBlock Grid.Row="0" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock
+ Grid.Row="0" Grid.Column="0"
+ VerticalAlignment="Center"
+ ToolTip.Tip="The printer display width. Required to calculate the pixels per mm."
+ Text="Display width:"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+
+ Increment="0.1"
+ Minimum="0"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.DisplayWidth}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="0" Grid.Column="6"
- VerticalAlignment="Center"
- ToolTip.Tip="The printer display height. Required to calculate the pixels per mm."
- Text="Display height:"/>
- <NumericUpDown Grid.Row="0" Grid.Column="8"
-
- Increment="0.1"
- Minimum="0"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.DisplayHeight}"/>
- <TextBlock Grid.Row="0" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ VerticalAlignment="Center"
+ ToolTip.Tip="The printer display height. Required to calculate the pixels per mm."
+ Text="Display height:"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="8"
+
+ Increment="0.1"
+ Minimum="0"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.DisplayHeight}"/>
+ <TextBlock Grid.Row="0" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="2" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Layer height:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- Increment="0.01"
- Minimum="0.01"
- Maximum="0.30"
- FormatString="F3"
- Value="{Binding Operation.LayerHeight}"
- />
- <TextBlock Grid.Row="2" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Layer height:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+
+ Increment="0.01"
+ Minimum="0.01"
+ Maximum="0.30"
+ FormatString="F3"
+ Value="{Binding Operation.LayerHeight}"
+ />
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="2" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Bottom layers:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="8"
-
- Increment="1"
- Minimum="1"
- Maximum="1000"
- Value="{Binding Operation.BottomLayers}"/>
- <TextBlock Grid.Row="2" Grid.Column="8"
- VerticalAlignment="Center"
- Text="{Binding Operation.BottomHeight, StringFormat=\{0:F3\}mm}"/>
+ <TextBlock Grid.Row="2" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Bottom layers:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="8"
+
+ Increment="1"
+ Minimum="1"
+ Maximum="1000"
+ Value="{Binding Operation.BottomLayers}"/>
+ <TextBlock Grid.Row="2" Grid.Column="8"
+ VerticalAlignment="Center"
+ Text="{Binding Operation.BottomHeight, StringFormat=\{0:F3\}mm}"/>
- <TextBlock Grid.Row="4" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Bottom exposure:"/>
- <NumericUpDown Grid.Row="4" Grid.Column="2"
-
- Increment="0.5"
- Minimum="0.1"
- Maximum="200"
- FormatString="F2"
- Value="{Binding Operation.BottomExposure}"/>
- <TextBlock Grid.Row="4" Grid.Column="4"
- VerticalAlignment="Center"
- Text="s"/>
+ <TextBlock Grid.Row="4" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Bottom exposure:"/>
+ <NumericUpDown Grid.Row="4" Grid.Column="2"
+
+ Increment="0.5"
+ Minimum="0.1"
+ Maximum="200"
+ FormatString="F2"
+ Value="{Binding Operation.BottomExposure}"/>
+ <TextBlock Grid.Row="4" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="s"/>
- <TextBlock Grid.Row="4" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Normal exposure:"/>
- <NumericUpDown Grid.Row="4" Grid.Column="8"
-
- Increment="0.5"
- Minimum="0.1"
- Maximum="200"
- FormatString="F2"
- Value="{Binding Operation.NormalExposure}"/>
- <TextBlock Grid.Row="4" Grid.Column="10"
- VerticalAlignment="Center"
- Text="s"/>
+ <TextBlock Grid.Row="4" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Normal exposure:"/>
+ <NumericUpDown Grid.Row="4" Grid.Column="8"
+
+ Increment="0.5"
+ Minimum="0.1"
+ Maximum="200"
+ FormatString="F2"
+ Value="{Binding Operation.NormalExposure}"/>
+ <TextBlock Grid.Row="4" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="s"/>
- <TextBlock Grid.Row="6" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Base height:"/>
- <NumericUpDown Grid.Row="6" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.BaseHeight}"/>
- <TextBlock Grid.Row="6" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock Grid.Row="6" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Base height:"/>
+ <NumericUpDown Grid.Row="6" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.BaseHeight}"/>
+ <TextBlock Grid.Row="6" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="6" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Base diameter:"/>
- <NumericUpDown Grid.Row="6" Grid.Column="8"
-
- Increment="1"
- Minimum="1"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.BaseDiameter}"/>
- <TextBlock Grid.Row="6" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock Grid.Row="6" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Base diameter:"/>
+ <NumericUpDown Grid.Row="6" Grid.Column="8"
+
+ Increment="1"
+ Minimum="1"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.BaseDiameter}"/>
+ <TextBlock Grid.Row="6" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="8" Grid.Column="0"
- VerticalAlignment="Center"
- Text="Ceil height:"/>
- <NumericUpDown Grid.Row="8" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="100"
- FormatString="F2"
- Value="{Binding Operation.CeilHeight}"/>
- <TextBlock Grid.Row="8" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
-
- <TextBlock Grid.Row="8" Grid.Column="6"
- VerticalAlignment="Center"
- Text="Body height:"/>
- <NumericUpDown Grid.Row="8" Grid.Column="8"
-
- Increment="1"
- Minimum="0"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.BodyHeight}"/>
- <TextBlock Grid.Row="8" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
+ <TextBlock Grid.Row="8" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Ceil height:"/>
+ <NumericUpDown Grid.Row="8" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="100"
+ FormatString="F2"
+ Value="{Binding Operation.CeilHeight}"/>
+ <TextBlock Grid.Row="8" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+
+ <TextBlock Grid.Row="8" Grid.Column="6"
+ VerticalAlignment="Center"
+ Text="Body height:"/>
+ <NumericUpDown Grid.Row="8" Grid.Column="8"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.BodyHeight}"/>
+ <TextBlock Grid.Row="8" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <StackPanel Grid.Row="10" Grid.Column="6"
- VerticalAlignment="Center"
- Spacing="0">
- <TextBlock
- FontWeight="Bold"
- Text="Total layers:"/>
- <TextBlock
- FontWeight="Bold"
- Text="Total height:"/>
- </StackPanel>
+ <StackPanel Grid.Row="10" Grid.Column="6"
+ VerticalAlignment="Center"
+ Spacing="0">
+ <TextBlock
+ FontWeight="Bold"
+ Text="Total layers:"/>
+ <TextBlock
+ FontWeight="Bold"
+ Text="Total height:"/>
+ </StackPanel>
- <StackPanel Grid.Row="10" Grid.Column="8"
- VerticalAlignment="Center"
- Spacing="0">
- <TextBlock
- FontWeight="Bold"
- Text="{Binding Operation.LayerCount}"/>
+ <StackPanel Grid.Row="10" Grid.Column="8"
+ VerticalAlignment="Center"
+ Spacing="0">
+ <TextBlock
+ FontWeight="Bold"
+ Text="{Binding Operation.LayerCount}"/>
- <TextBlock
- FontWeight="Bold"
- Text="{Binding Operation.TotalHeight, StringFormat=\{0:F3\}mm}"/>
+ <TextBlock
+ FontWeight="Bold"
+ Text="{Binding Operation.TotalHeight, StringFormat=\{0:F3\}mm}"/>
- </StackPanel>
+ </StackPanel>
-
+
- <TextBlock Grid.Row="10" Grid.Column="0"
- VerticalAlignment="Center"
- ToolTip.Tip="Chamfer the bottom layers"
- Text="Chamfer layers:"/>
- <NumericUpDown Grid.Row="10" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="255"
- IsEnabled="{Binding Operation.ChamferModel}"
- Value="{Binding Operation.ChamferLayers}"/>
+ <TextBlock Grid.Row="10" Grid.Column="0"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Chamfer the bottom layers"
+ Text="Chamfer layers:"/>
+ <NumericUpDown Grid.Row="10" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="255"
+ IsEnabled="{Binding Operation.ChamferModel}"
+ Value="{Binding Operation.ChamferLayers}"/>
- <CheckBox Grid.Row="12" Grid.Column="2" Grid.ColumnSpan="5"
- VerticalAlignment="Center"
- IsChecked="{Binding Operation.EnableAntiAliasing}"
- Content="Enable Anti-Aliasing"/>
+ <CheckBox Grid.Row="12" Grid.Column="2" Grid.ColumnSpan="5"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Operation.EnableAntiAliasing}"
+ Content="Enable Anti-Aliasing"/>
- <CheckBox Grid.Row="12" Grid.Column="8"
- Grid.ColumnSpan="3"
- ToolTip.Tip="Most of the printers requires a mirror output to print with the correct orientation"
- IsChecked="{Binding Operation.MirrorOutput}"
- Content="Mirror output" />
+ <CheckBox Grid.Row="12" Grid.Column="8"
+ Grid.ColumnSpan="3"
+ ToolTip.Tip="Most of the printers requires a mirror output to print with the correct orientation"
+ IsChecked="{Binding Operation.MirrorOutput}"
+ Content="Mirror output" />
- </Grid>
- </Expander>
- </Border>
+ </Grid>
+ </Expander>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Outer Spirals"
- FontWeight="Bold"
- Cursor="Hand"/>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Outer Spirals"
+ FontWeight="Bold"
+ Cursor="Hand"/>
- </Expander.Header>
+ </Expander.Header>
- <Grid RowDefinitions="Auto,5,Auto"
- ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
+ <Grid RowDefinitions="Auto,5,Auto"
+ ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
- <TextBlock Grid.Row="0" Grid.Column="0"
- Text="Number of spirals:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="1"
- Minimum="1"
- Maximum="10"
- Value="{Binding Operation.Spirals}"/>
+ <TextBlock Grid.Row="0" Grid.Column="0"
+ Text="Number of spirals:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+
+ Increment="1"
+ Minimum="1"
+ Maximum="10"
+ Value="{Binding Operation.Spirals}"/>
- <TextBlock Grid.Row="0" Grid.Column="6"
- VerticalAlignment="Center"
- ToolTip.Tip="Clockwise: All spirals turn clockwise.
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Clockwise: All spirals turn clockwise.
&#x0a;Alternate: Each spiral turn into opposite direction.
&#x0a;Both: Each spiral will turn in both directions, clockwise and counter-clockwise."
- Text="Spiral direction:"/>
- <ComboBox Grid.Row="0" Grid.Column="8"
- Items="{Binding Operation.SpiralDirectionsItems}"
- SelectedItem="{Binding Operation.SpiralDirection}"
- HorizontalAlignment="Stretch"/>
+ Text="Spiral direction:"/>
+ <ComboBox Grid.Row="0" Grid.Column="8"
+ Items="{Binding Operation.SpiralDirectionsItems}"
+ SelectedItem="{Binding Operation.SpiralDirection}"
+ HorizontalAlignment="Stretch"/>
- <TextBlock Grid.Row="2" Grid.Column="0"
- Text="Spiral diameter:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- Increment="1"
- Minimum="0.1"
- Maximum="10000"
- FormatString="F2"
- Value="{Binding Operation.SpiralDiameter}"/>
- <TextBlock Grid.Row="2" Grid.Column="4"
- Text="mm"
- VerticalAlignment="Center"/>
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ Text="Spiral diameter:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0.1"
+ Maximum="10000"
+ FormatString="F2"
+ Value="{Binding Operation.SpiralDiameter}"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ Text="mm"
+ VerticalAlignment="Center"/>
- <TextBlock Grid.Row="2" Grid.Column="6"
- Text="Step angle:"
- ToolTip.Tip="Spirals will turn this angle per layer."
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="8"
-
- Increment="1"
- Minimum="0.01"
- Maximum="359.99"
- FormatString="F2"
- Value="{Binding Operation.SpiralAngleStepPerLayer}"/>
- <TextBlock Grid.Row="2" Grid.Column="10"
- Text="º/layer"
- VerticalAlignment="Center"/>
+ <TextBlock Grid.Row="2" Grid.Column="6"
+ Text="Step angle:"
+ ToolTip.Tip="Spirals will turn this angle per layer."
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="8"
+
+ Increment="1"
+ Minimum="0.01"
+ Maximum="359.99"
+ FormatString="F2"
+ Value="{Binding Operation.SpiralAngleStepPerLayer}"/>
+ <TextBlock Grid.Row="2" Grid.Column="10"
+ Text="º/layer"
+ VerticalAlignment="Center"/>
- </Grid>
- </Expander>
- </Border>
+ </Grid>
+ </Expander>
</StackPanel>
</UserControl>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateToleranceControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateToleranceControl.axaml
index 7e0c6ef..22516d2 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateToleranceControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateToleranceControl.axaml
@@ -7,7 +7,6 @@
<Grid ColumnDefinitions="Auto,10,380">
<StackPanel Spacing="10">
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
<Expander IsExpanded="True">
<Expander.Header>
<TextBlock Text="Step 1 - Common properties"
@@ -241,174 +240,164 @@
</Grid>
</Expander>
- </Border>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 2 - Female part"
- FontWeight="Bold"
- Cursor="Hand"/>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 2 - Female part"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+
+ </Expander.Header>
+
+ <Grid RowDefinitions="Auto,5,Auto"
+ ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
+
+
+ <TextBlock Grid.Row="0" Grid.Column="0"
+ Text="Diameter:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+
+ Increment="1.0"
+ Minimum="2"
+ Maximum="1000"
+ FormatString="F2"
+ Value="{Binding Operation.FemaleDiameter}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="6"
+ Text="Hole diameter:"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="8"
+
+ Increment="1.0"
+ Minimum="2"
+ Maximum="1000"
+ FormatString="F2"
+ Value="{Binding Operation.FemaleHoleDiameter}"/>
+ <TextBlock Grid.Row="0" Grid.Column="10"
+ VerticalAlignment="Center"
+ Text="mm"/>
- </Expander.Header>
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ Text="Expected:"
+ FontWeight="Bold"
+ VerticalAlignment="Center"/>
- <Grid RowDefinitions="Auto,5,Auto"
- ColumnDefinitions="Auto,10,170,5,Auto,20,Auto,10,170,5,Auto">
+ <TextBlock Grid.Row="2" Grid.Column="2"
+ Text="{Binding Operation.FemaleDiameterRealXSize, StringFormat=\{0:F2\}mm}"
+ FontWeight="Bold"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="8"
+ Text="{Binding Operation.FemaleHoleDiameterRealXSize, StringFormat=\{0:F2\}mm}"
+ FontWeight="Bold"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center"/>
+ </Grid>
+
+ </Expander>
+
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 3 - Male parts"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+
+ </Expander.Header>
+
+ <Grid RowDefinitions="Auto,10,Auto"
+ ColumnDefinitions="Auto,10,Auto,5,Auto,20,Auto,10,150,5,Auto,20,Auto,10,150,5,Auto">
<TextBlock Grid.Row="0" Grid.Column="0"
- Text="Diameter:"
+ Text="Thinner models:"
VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="1.0"
- Minimum="2"
- Maximum="1000"
- FormatString="F2"
- Value="{Binding Operation.FemaleDiameter}"/>
- <TextBlock Grid.Row="0" Grid.Column="4"
- VerticalAlignment="Center"
- Text="mm"/>
-
+
+ Increment="1"
+ Minimum="0"
+ Maximum="1000"
+ Value="{Binding Operation.MaleThinnerModels}"/>
<TextBlock Grid.Row="0" Grid.Column="6"
- Text="Hole diameter:"
+ Text="-Offset:"
VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="0" Grid.Column="8"
- Increment="1.0"
- Minimum="2"
- Maximum="1000"
+ Increment="0.01"
+ Minimum="-1000"
+ Maximum="0"
FormatString="F2"
- Value="{Binding Operation.FemaleHoleDiameter}"/>
+ Value="{Binding Operation.MaleThinnerOffset}"/>
<TextBlock Grid.Row="0" Grid.Column="10"
VerticalAlignment="Center"
Text="mm"/>
- <TextBlock Grid.Row="2" Grid.Column="0"
- Text="Expected:"
- FontWeight="Bold"
+ <TextBlock Grid.Row="0" Grid.Column="12"
+ Text="-Step:"
VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="14"
+
+ Increment="0.01"
+ Minimum="-1000"
+ Maximum="-0.01"
+ FormatString="F2"
+ Value="{Binding Operation.MaleThinnerStep}"/>
+ <TextBlock Grid.Row="0" Grid.Column="16"
+ VerticalAlignment="Center"
+ Text="mm"/>
- <TextBlock Grid.Row="2" Grid.Column="2"
- Text="{Binding Operation.FemaleDiameterRealXSize, StringFormat=\{0:F2\}mm}"
- FontWeight="Bold"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- <TextBlock Grid.Row="2" Grid.Column="8"
- Text="{Binding Operation.FemaleHoleDiameterRealXSize, StringFormat=\{0:F2\}mm}"
- FontWeight="Bold"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- </Grid>
-
- </Expander>
- </Border>
-
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 3 - Male parts"
- FontWeight="Bold"
- Cursor="Hand"/>
-
- </Expander.Header>
-
- <Grid RowDefinitions="Auto,10,Auto"
- ColumnDefinitions="Auto,10,Auto,5,Auto,20,Auto,10,150,5,Auto,20,Auto,10,150,5,Auto">
-
-
- <TextBlock Grid.Row="0" Grid.Column="0"
- Text="Thinner models:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="1000"
- Value="{Binding Operation.MaleThinnerModels}"/>
- <TextBlock Grid.Row="0" Grid.Column="6"
- Text="-Offset:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="8"
-
- Increment="0.01"
- Minimum="-1000"
- Maximum="0"
- FormatString="F2"
- Value="{Binding Operation.MaleThinnerOffset}"/>
- <TextBlock Grid.Row="0" Grid.Column="10"
- VerticalAlignment="Center"
- Text="mm"/>
-
- <TextBlock Grid.Row="0" Grid.Column="12"
- Text="-Step:"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="0" Grid.Column="14"
-
- Increment="0.01"
- Minimum="-1000"
- Maximum="-0.01"
- FormatString="F2"
- Value="{Binding Operation.MaleThinnerStep}"/>
- <TextBlock Grid.Row="0" Grid.Column="16"
- VerticalAlignment="Center"
- Text="mm"/>
-
-
- <TextBlock Grid.Row="2" Grid.Column="0"
- Text="Thicker models:"
- IsEnabled="{Binding !Operation.FuseParts}"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="2"
-
- Increment="1"
- Minimum="0"
- Maximum="1000"
- IsEnabled="{Binding !Operation.FuseParts}"
- Value="{Binding Operation.MaleThickerModels}"/>
- <TextBlock Grid.Row="2" Grid.Column="6"
- Text="+Offset:"
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ Text="Thicker models:"
+ IsEnabled="{Binding !Operation.FuseParts}"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+
+ Increment="1"
+ Minimum="0"
+ Maximum="1000"
IsEnabled="{Binding !Operation.FuseParts}"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="8"
-
- Increment="0.01"
- Minimum="0"
- Maximum="1000"
- FormatString="F2"
- IsEnabled="{Binding !Operation.FuseParts}"
- Value="{Binding Operation.MaleThickerOffset}"/>
- <TextBlock Grid.Row="2" Grid.Column="10"
- VerticalAlignment="Center"
+ Value="{Binding Operation.MaleThickerModels}"/>
+ <TextBlock Grid.Row="2" Grid.Column="6"
+ Text="+Offset:"
+ IsEnabled="{Binding !Operation.FuseParts}"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="8"
+
+ Increment="0.01"
+ Minimum="0"
+ Maximum="1000"
+ FormatString="F2"
IsEnabled="{Binding !Operation.FuseParts}"
- Text="mm"/>
-
- <TextBlock Grid.Row="2" Grid.Column="12"
- Text="+Step:"
- IsEnabled="{Binding !Operation.FuseParts}"
- VerticalAlignment="Center"/>
- <NumericUpDown Grid.Row="2" Grid.Column="14"
-
- Increment="0.01"
- Minimum="0.01"
- Maximum="1000"
- IsEnabled="{Binding !Operation.FuseParts}"
- FormatString="F2"
- Value="{Binding Operation.MaleThickerStep}"/>
- <TextBlock Grid.Row="2" Grid.Column="16"
- VerticalAlignment="Center"
+ Value="{Binding Operation.MaleThickerOffset}"/>
+ <TextBlock Grid.Row="2" Grid.Column="10"
+ VerticalAlignment="Center"
+ IsEnabled="{Binding !Operation.FuseParts}"
+ Text="mm"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="12"
+ Text="+Step:"
+ IsEnabled="{Binding !Operation.FuseParts}"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="14"
+
+ Increment="0.01"
+ Minimum="0.01"
+ Maximum="1000"
IsEnabled="{Binding !Operation.FuseParts}"
- Text="mm"/>
-
-
-
-
- </Grid>
-
- </Expander>
- </Border>
+ FormatString="F2"
+ Value="{Binding Operation.MaleThickerStep}"/>
+ <TextBlock Grid.Row="2" Grid.Column="16"
+ VerticalAlignment="Center"
+ IsEnabled="{Binding !Operation.FuseParts}"
+ Text="mm"/>
+ </Grid>
+ </Expander>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateXYZAccuracyControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateXYZAccuracyControl.axaml
index d95b166..c2ddb1a 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateXYZAccuracyControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateXYZAccuracyControl.axaml
@@ -7,13 +7,12 @@
<Grid ColumnDefinitions="Auto,10,380">
<StackPanel Spacing="10">
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 1: Generate and print test model"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 1: Generate and print test model"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
<Grid
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
@@ -376,15 +375,13 @@
</Grid>
</Expander>
- </Border>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 2: Validate the printed model with your measures"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 2: Validate the printed model with your measures"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
<StackPanel Spacing="10">
@@ -482,17 +479,15 @@
</StackPanel>
</Expander>
- </Border>
- <Border BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="True">
- <Expander.Header>
- <TextBlock Text="Step 3: Save a resize profile with the results"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
+ <Expander IsExpanded="True">
+ <Expander.Header>
+ <TextBlock Text="Step 3: Save a resize profile with the results"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
- <Grid ColumnDefinitions="Auto,10,*,5,Auto,5,Auto">
+ <Grid ColumnDefinitions="Auto,10,440,5,Auto,5,Auto">
<TextBlock VerticalAlignment="Center"
Text="Profile name:"/>
<TextBox Grid.Column="2" VerticalAlignment="Center"
@@ -511,7 +506,6 @@
</Button>
</Grid>
</Expander>
- </Border>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Helpers.cs b/UVtools.WPF/Controls/Helpers.cs
index ed5d288..bcf5973 100644
--- a/UVtools.WPF/Controls/Helpers.cs
+++ b/UVtools.WPF/Controls/Helpers.cs
@@ -24,8 +24,11 @@ namespace UVtools.WPF.Controls
"bmp",
"jpeg",
"jpg",
+ "jp2",
"tif",
"tiff",
+ "sr",
+ "ras",
}
},
};
diff --git a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
index 868a47c..683b3f9 100644
--- a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml
@@ -62,20 +62,18 @@
</Grid>
- <Border
- Margin="0,10,0,0" >
- <Expander>
- <Expander.Header>
- <TextBlock Text="Kernel - Advanced options (Click to expand)"
- FontWeight="Bold"
- Cursor="Hand"/>
- </Expander.Header>
- <uc:KernelControl
- Name="KernelCtrl"
- Margin="0,10,0,0"
- />
- </Expander>
- </Border>
+
+ <Expander Margin="0,10,0,0">
+ <Expander.Header>
+ <TextBlock Text="Kernel - Advanced options (Click to expand)"
+ FontWeight="Bold"
+ Cursor="Hand"/>
+ </Expander.Header>
+ <uc:KernelControl
+ Name="KernelCtrl"
+ Margin="0,10,0,0"
+ />
+ </Expander>
</StackPanel>
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml b/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml
index c4ca28e..40788d1 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml
@@ -6,7 +6,7 @@
x:Class="UVtools.WPF.Controls.Tools.ToolPixelArithmeticControl">
<StackPanel Spacing="10">
- <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto"
+ <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
ColumnDefinitions="Auto,10,Auto,20,Auto,10,Auto,20,Auto,10,Auto">
<TextBlock Grid.Row="0" Grid.Column="0"
@@ -21,11 +21,62 @@
<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
+ IsEnabled="{Binding Operation.IsApplyMethodEnabled}"
+ Text="Apply to:"/>
+
+ <ComboBox Grid.Row="2" Grid.Column="2"
+ Grid.ColumnSpan="9"
+ Width="610"
+ IsEnabled="{Binding Operation.IsApplyMethodEnabled}"
+ Items="{Binding Operation.ApplyMethod, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
+ SelectedItem="{Binding Operation.ApplyMethod, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
+
+ <TextBlock Grid.Row="4" Grid.Column="0"
+ VerticalAlignment="Center"
+ IsVisible="{Binding Operation.IsWallSettingVisible}"
+ Text="Wall thickness:"/>
+
+
+ <StackPanel Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="9"
+ IsVisible="{Binding Operation.IsWallSettingVisible}"
+ Spacing="10" Orientation="Horizontal">
+ <NumericUpDown
+ Minimum="0"
+ Maximum="1000"
+ Width="80"
+ Value="{Binding Operation.WallThicknessStart}"/>
+
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="To:"
+ IsEnabled="{Binding Operation.WallChamfer}"/>
+
+ <NumericUpDown
+ Minimum="0"
+ Maximum="1000"
+ Width="80"
+ Value="{Binding Operation.WallThicknessEnd}"
+ IsEnabled="{Binding Operation.WallChamfer}"/>
+
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="px"
+ IsEnabled="{Binding Operation.WallChamfer}"/>
+
+ <CheckBox
+ Margin="10,0,0,0"
+ Content="Chamfer walls"
+ ToolTip.Tip="Allow the number of walls pixels to be gradually varied as the operation progresses from the starting layer to the ending layer."
+ IsChecked="{Binding Operation.WallChamfer}"/>
+ </StackPanel>
+
+ <TextBlock Grid.Row="6" Grid.Column="0"
+ VerticalAlignment="Center"
IsVisible="{Binding Operation.ValueEnabled}"
IsEnabled="{Binding Operation.ValueEnabled}"
Text="Brightness:"/>
- <StackPanel Grid.Row="2" Grid.Column="2"
+ <StackPanel Grid.Row="6" Grid.Column="2"
VerticalAlignment="Center"
Orientation="Horizontal" Spacing="5"
IsVisible="{Binding Operation.ValueEnabled}"
@@ -34,40 +85,43 @@
<NumericUpDown
Minimum="0"
Maximum="255"
+ IsEnabled="{Binding !Operation.UsePattern}"
Value="{Binding Operation.Value}"/>
<TextBlock VerticalAlignment="Center"
+ IsEnabled="{Binding !Operation.UsePattern}"
Text="{Binding Operation.ValuePercent, StringFormat={}{0}%}"/>
- </StackPanel>
+ <CheckBox
+ Margin="20,0,0,0"
+ IsVisible="{Binding Operation.IsUsePatternVisible}"
+ IsChecked="{Binding Operation.UsePattern}"
+ Content="Use a pattern instead of fixed brightness"/>
- <CheckBox Grid.Row="2" Grid.Column="4"
- Content="Affect empty/black pixels"
- IsVisible="{Binding Operation.AffectBackPixelsEnabled}"
- IsChecked="{Binding Operation.AffectBackPixels}"/>
+ </StackPanel>
- <TextBlock Grid.Row="2" Grid.Column="4"
+ <TextBlock Grid.Row="6" Grid.Column="4"
VerticalAlignment="Center"
HorizontalAlignment="Right"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Text="Max.:"/>
- <NumericUpDown Grid.Row="2" Grid.Column="6"
+ <NumericUpDown Grid.Row="6" Grid.Column="6"
Minimum="0"
Maximum="255"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Value="{Binding Operation.ThresholdMaxValue}"/>
- <TextBlock Grid.Row="2" Grid.Column="8"
+ <TextBlock Grid.Row="6" Grid.Column="8"
VerticalAlignment="Center"
HorizontalAlignment="Right"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Text="Threshold:"/>
- <ComboBox Grid.Row="2" Grid.Column="10"
+ <ComboBox Grid.Row="6" Grid.Column="10"
Width="130"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
@@ -75,14 +129,22 @@
SelectedItem="{Binding Operation.ThresholdType, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
- <TextBlock Grid.Row="4" Grid.Column="0"
+ <TextBlock Grid.Row="8" Grid.Column="0"
VerticalAlignment="Center"
Text="Presets:"/>
- <StackPanel Grid.Row="4" Grid.Column="2"
+ <StackPanel Grid.Row="8" Grid.Column="2"
Grid.ColumnSpan="9"
VerticalAlignment="Center"
Orientation="Horizontal" Spacing="5">
+ <Button
+ Command="{Binding Operation.PresetPixelDimming}"
+ Content="Pixel dimming"/>
+
+ <Button
+ Command="{Binding Operation.PresetPixelLightening}"
+ Content="Pixel lightening"/>
+
<Button
Command="{Binding Operation.PresetStripAntiAliasing}"
Content="Strip anti-aliasing"/>
@@ -94,6 +156,271 @@
</StackPanel>
</Grid>
+
+ <Border>
+ <Border.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="Operation.IsUsePatternVisible" />
+ <Binding Path="Operation.UsePattern"/>
+ </MultiBinding>
+ </Border.IsVisible>
+
+ <StackPanel Spacing="10">
+
+ <TextBlock Text="Pattern:" FontWeight="Bold"/>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Alternate the pattern every:"/>
+ <NumericUpDown
+ Minimum="1"
+ Maximum="65535"
+ Width="150"
+ Value="{Binding Operation.PatternAlternatePerLayersNumber}"/>
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="layers"/>
+
+ <CheckBox
+ Margin="20,0,0,0"
+ IsChecked="{Binding Operation.PatternInvert}"
+ ToolTip.Tip="If enabled, it will invert the pattern before apply, that is: 255 - {value}"
+ Content="Invert the pattern when processing the pixels"/>
+ </StackPanel>
+
+
+ <Grid
+ RowDefinitions="Auto,200,10,Auto"
+ ColumnDefinitions="450,10,450">
+
+ <Button Grid.Row="0" Grid.Column="0"
+ Content="Load pattern from image"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Command="{Binding LoadPatternFromImage}"
+ CommandParameter="False"/>
+
+ <TextBox
+ Grid.Row="1" Grid.Column="0"
+ AcceptsReturn="True"
+ Watermark="Pattern"
+ UseFloatingWatermark="True"
+ TextWrapping="NoWrap"
+ Text="{Binding Operation.PatternText}"/>
+
+ <Button Grid.Row="0" Grid.Column="2"
+ Content="Load alternate pattern from image"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Command="{Binding LoadPatternFromImage}"
+ CommandParameter="True"/>
+ <TextBox
+ Grid.Row="1" Grid.Column="2"
+ AcceptsReturn="True"
+ Watermark="Alternate pattern (Optional)"
+ UseFloatingWatermark="True"
+ TextWrapping="NoWrap"
+ Text="{Binding Operation.PatternTextAlternate}"/>
+
+ <Border
+ Grid.Row="3" Grid.Column="0"
+ BorderBrush="LightGray"
+ BorderThickness="1"
+ Padding="5">
+
+ <StackPanel Spacing="10">
+ <TextBlock FontWeight="Bold" Text="Pattern generator"/>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Brightness:"/>
+
+ <NumericUpDown
+ Minimum="0"
+ Maximum="255"
+ Value="{Binding Operation.PatternGenMinBrightness}"/>
+
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="-"/>
+
+ <NumericUpDown
+ Minimum="0"
+ Maximum="255"
+ Value="{Binding Operation.PatternGenBrightness}"/>
+
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="{Binding Operation.PatternGenBrightnessPercent, StringFormat=(\{0\}%)}"/>
+ </StackPanel>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Button
+ Padding="10"
+ Content="Chessboard"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Chessboard"
+ />
+ <Button
+ Padding="10"
+ Content="Sparse"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Sparse"
+ />
+ <Button
+ Padding="10"
+ Content="Crosses"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Crosses"
+ />
+ <Button
+ Padding="10"
+ Content="Strips"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Strips"
+ />
+ </StackPanel>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Button
+ Padding="10"
+ Content="Pyramid"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Pyramid"
+ />
+
+ <Button
+ Padding="10"
+ Content="Rhombus"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Rhombus"
+ />
+ <Button
+ Padding="10"
+ Content="Waves"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Waves"
+ />
+ <Button
+ Padding="10"
+ Content="Slashes"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Slashes"
+ />
+ </StackPanel>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Button
+ Padding="10"
+ Content="Hearts"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Hearts"
+ />
+ <Button
+ Padding="10"
+ Content="Solid"
+ Width="100"
+ Command="{Binding Operation.GeneratePattern}"
+ CommandParameter="Solid"
+ />
+ </StackPanel>
+
+ </StackPanel>
+ </Border>
+
+ <Border
+ Grid.Row="3"
+ Grid.Column="2"
+ BorderBrush="LightGray"
+ BorderThickness="1"
+ Padding="5"
+ >
+
+ <StackPanel Spacing="10">
+ <TextBlock FontWeight="Bold" Text="Infill generator"/>
+
+ <TextBlock
+ TextWrapping="Wrap"
+ Text="Warning: This function can generate a large number of resin traps. (Use with caution)"/>
+
+ <Grid RowDefinitions="Auto,10,Auto"
+ ColumnDefinitions="Auto,10,150,5,Auto">
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Thickness:"/>
+ <NumericUpDown
+ Grid.Row="0" Grid.Column="2"
+ Minimum="5"
+ Maximum="10000"
+ Value="{Binding Operation.PatternGenInfillThickness}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Spacing:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ Minimum="5"
+ Maximum="10000"
+ Value="{Binding Operation.PatternGenInfillSpacing}"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"/>
+
+ </Grid>
+
+ <StackPanel Orientation="Horizontal" Spacing="10">
+ <Button
+ Padding="10"
+ Content="Rectilinear"
+ Width="100"
+ Command="{Binding Operation.GenerateInfill}"
+ CommandParameter="Rectilinear"
+ />
+ <Button
+ Padding="10"
+ Content="Square grid"
+ Width="100"
+ Command="{Binding Operation.GenerateInfill}"
+ CommandParameter="Square grid"
+ />
+ <Button
+ Padding="10"
+ Content="Waves"
+ Width="100"
+ Command="{Binding Operation.GenerateInfill}"
+ CommandParameter="Waves"
+ />
+ <Button
+ Padding="10"
+ Content="Lattice"
+ Width="100"
+ Command="{Binding Operation.GenerateInfill}"
+ CommandParameter="Lattice"
+ />
+ </StackPanel>
+ </StackPanel>
+ </Border>
+
+ </Grid>
+
+ </StackPanel>
+ </Border>
+
</StackPanel>
</UserControl>
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml.cs
index bc151a4..84e1f68 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPixelArithmeticControl.axaml.cs
@@ -1,3 +1,4 @@
+using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using UVtools.Core.Operations;
@@ -11,11 +12,25 @@ namespace UVtools.WPF.Controls.Tools
BaseOperation = new OperationPixelArithmetic(SlicerFile);
if (!ValidateSpawn()) return;
InitializeComponent();
+
+ Operation.GeneratePattern("Chessboard");
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
+
+ public async void LoadPatternFromImage(bool isAlternatePattern = false)
+ {
+ var dialog = new OpenFileDialog
+ {
+ AllowMultiple = false,
+ Filters = Helpers.ImagesFileFilter,
+ };
+ var files = await dialog.ShowAsync(ParentWindow);
+ if (files is null || files.Length == 0) return;
+ Operation.LoadPatternFromImage(files[0], isAlternatePattern);
+ }
}
}
diff --git a/UVtools.WPF/MainWindow.Information.cs b/UVtools.WPF/MainWindow.Information.cs
index 60563ce..8082ea0 100644
--- a/UVtools.WPF/MainWindow.Information.cs
+++ b/UVtools.WPF/MainWindow.Information.cs
@@ -7,12 +7,9 @@
*/
using System;
using System.Collections;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Diagnostics;
using System.Globalization;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Text;
using Avalonia;
@@ -20,7 +17,6 @@ using Avalonia.Controls;
using Avalonia.Input;
using MessageBox.Avalonia.Enums;
using UVtools.Core;
-using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
using UVtools.WPF.Extensions;
using UVtools.WPF.Structures;
@@ -137,8 +133,8 @@ namespace UVtools.WPF
}
}
- public bool ThumbnailCanGoPrevious => SlicerFile is { } && _visibleThumbnailIndex > 1;
- public bool ThumbnailCanGoNext => SlicerFile is { } && _visibleThumbnailIndex < SlicerFile.CreatedThumbnailsCount;
+ public bool ThumbnailCanGoPrevious => SlicerFile is not null && _visibleThumbnailIndex > 1;
+ public bool ThumbnailCanGoNext => SlicerFile is not null && _visibleThumbnailIndex < SlicerFile.CreatedThumbnailsCount;
public void ThumbnailGoPrevious()
{
@@ -167,7 +163,7 @@ namespace UVtools.WPF
public async void OnClickThumbnailSave()
{
if (SlicerFile is null) return;
- if (ReferenceEquals(SlicerFile.Thumbnails[_visibleThumbnailIndex - 1], null))
+ if (SlicerFile.Thumbnails[_visibleThumbnailIndex - 1] is null)
{
return; // This should never happen!
}
@@ -189,7 +185,7 @@ namespace UVtools.WPF
public async void OnClickThumbnailImport()
{
if (_visibleThumbnailIndex <= 0) return;
- if (ReferenceEquals(SlicerFile.Thumbnails[_visibleThumbnailIndex - 1], null))
+ if (SlicerFile.Thumbnails[_visibleThumbnailIndex - 1] is null)
{
return; // This should never happen!
}
@@ -203,8 +199,21 @@ namespace UVtools.WPF
var filepath = await dialog.ShowAsync(this);
if (filepath is null || filepath.Length <= 0) return;
- int i = (int)(_visibleThumbnailIndex - 1);
- SlicerFile.SetThumbnail(i, filepath[0]);
+ uint i = _visibleThumbnailIndex - 1;
+ SlicerFile.SetThumbnail((int)i, filepath[0]);
+ //VisibleThumbnailImage = SlicerFile.Thumbnails[i].ToBitmap();
+ SlicerFile.RequireFullEncode = true;
+ CanSave = true;
+ }
+
+ public void RefreshThumbnail()
+ {
+ if (_visibleThumbnailIndex <= 0) return;
+ uint i = _visibleThumbnailIndex - 1;
+ if (SlicerFile.Thumbnails?[i] is null)
+ {
+ return;
+ }
VisibleThumbnailImage = SlicerFile.Thumbnails[i].ToBitmap();
}
#endregion
@@ -228,32 +237,30 @@ namespace UVtools.WPF
try
{
- using (TextWriter tw = new StreamWriter(file))
+ using TextWriter tw = new StreamWriter(file);
+ foreach (var config in SlicerFile.Configs)
{
- foreach (var config in SlicerFile.Configs)
+ var type = config.GetType();
+ tw.WriteLine($"[{type.Name}]");
+ foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
- var type = config.GetType();
- tw.WriteLine($"[{type.Name}]");
- foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ if (property.Name.Equals("Item")) continue;
+ var value = property.GetValue(config);
+ switch (value)
{
- if (property.Name.Equals("Item")) continue;
- var value = property.GetValue(config);
- switch (value)
- {
- case null:
- continue;
- case IList list:
- tw.WriteLine($"{property.Name} = {list.Count}");
- break;
- default:
- tw.WriteLine($"{property.Name} = {value}");
- break;
- }
+ case null:
+ continue;
+ case IList list:
+ tw.WriteLine($"{property.Name} = {list.Count}");
+ break;
+ default:
+ tw.WriteLine($"{property.Name} = {value}");
+ break;
}
- tw.WriteLine();
}
- tw.Close();
+ tw.WriteLine();
}
+ tw.Close();
}
catch (Exception e)
{
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index e078ba6..0dadac8 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -22,12 +22,12 @@
HotKey="Ctrl+O" InputGesture="Ctrl+O"
Command="{Binding MenuFileOpenClicked}">
<MenuItem.Icon>
- <Image Source="\Assets\Icons\open-16x16.png"/>
+ <Image Source="\Assets\Icons\file-import-16x16.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Name="MainMenu.File.OpenNewWindow" Header="Open in _new window" HotKey="Ctrl+Shift+O" InputGesture="Ctrl+Shift+O" Command="{Binding MenuFileOpenNewWindowClicked}">
<MenuItem.Icon>
- <Image Source="\Assets\Icons\open-16x16.png"/>
+ <Image Source="\Assets\Icons\file-import-16x16.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem
@@ -82,10 +82,16 @@
<Image Source="\Assets\Icons\flask-16x16.png"/>
</MenuItem.Icon>
</MenuItem>
-
+
+ <MenuItem Name="MainMenu.File.OpenCurrentFileFolder" Header="Open current file fo_lder" HotKey="Ctrl+Shift+L" InputGesture="Ctrl+Shift+L" IsEnabled="{Binding IsFileLoaded}" Command="{Binding MenuFileOpenCurrentFileFolderClicked}">
+ <MenuItem.Icon>
+ <Image Source="\Assets\Icons\folder-open-16x16.png"/>
+ </MenuItem.Icon>
+ </MenuItem>
+
<MenuItem
Name="MainMenu.File.Extract"
- Header="_Extract" HotKey="Ctrl+E" InputGesture="Ctrl+E"
+ Header="_Extract file contents" HotKey="Ctrl+E" InputGesture="Ctrl+E"
IsEnabled="{Binding IsFileLoaded}"
Command="{Binding ExtractFile}">
<MenuItem.Icon>
@@ -103,7 +109,7 @@
<Image Source="\Assets\Icons\convert-16x16.png"/>
</MenuItem.Icon>
</MenuItem>
-
+
<Separator/>
<MenuItem
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index e83107a..d195a4a 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -155,7 +155,7 @@ namespace UVtools.WPF
Tag = new OperationPixelArithmetic(),
Icon = new Avalonia.Controls.Image
{
- Source = new Bitmap(App.GetAsset("/Assets/Icons/square-root-16x16.png"))
+ Source = new Bitmap(App.GetAsset("/Assets/Icons/pixel-16x16.png"))
}
},
new()
@@ -166,14 +166,14 @@ namespace UVtools.WPF
Source = new Bitmap(App.GetAsset("/Assets/Icons/mask-16x16.png"))
}
},
- new()
+ /*new()
{
Tag = new OperationPixelDimming(),
Icon = new Avalonia.Controls.Image
{
Source = new Bitmap(App.GetAsset("/Assets/Icons/pixel-16x16.png"))
}
- },
+ },*/
new()
{
Tag = new OperationLightBleedCompensation(),
@@ -745,6 +745,12 @@ namespace UVtools.WPF
public void MenuFileOpenClicked() => OpenFile();
public void MenuFileOpenNewWindowClicked() => OpenFile(true);
+ public void MenuFileOpenCurrentFileFolderClicked()
+ {
+ if (!IsFileLoaded) return;
+ App.SelectFileOnExplorer(SlicerFile.FileFullPath);
+ }
+
public async void MenuFileSaveClicked()
{
if (!CanSave) return;
@@ -1148,9 +1154,8 @@ namespace UVtools.WPF
SlicerFile.CanUseBottomLightOffDelay &&
(Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.BottomLightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero))
{
- if (SlicerFile is ChituboxFile chituboxFile &&
- chituboxFile.HeaderSettings.Version >= 4 &&
- (chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0))
+ if ((SlicerFile.CanUseAnyWaitTimeBeforeCure || SlicerFile.CanUseAnyWaitTimeAfterCure || SlicerFile.CanUseAnyWaitTimeAfterLift) &&
+ (SlicerFile.BottomWaitTimeBeforeCure > 0 || SlicerFile.BottomWaitTimeAfterCure > 0 || SlicerFile.BottomWaitTimeAfterLift > 0))
{
// Ignore this automation
}
@@ -1175,9 +1180,8 @@ namespace UVtools.WPF
SlicerFile.CanUseLightOffDelay &&
(Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.LightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero))
{
- if (SlicerFile is ChituboxFile chituboxFile &&
- chituboxFile.HeaderSettings.Version >= 4 &&
- (chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0))
+ if ((SlicerFile.CanUseAnyWaitTimeBeforeCure || SlicerFile.CanUseAnyWaitTimeAfterCure || SlicerFile.CanUseAnyWaitTimeAfterLift) &&
+ (SlicerFile.WaitTimeBeforeCure > 0 || SlicerFile.WaitTimeAfterCure > 0 || SlicerFile.WaitTimeAfterLift > 0))
{
// Ignore this automation
}
@@ -1218,6 +1222,8 @@ namespace UVtools.WPF
if(fileFormat is ImageFile) continue;
foreach (var fileExtension in fileFormat.FileExtensions)
{
+ if(!fileExtension.IsVisibleOnConvertMenu) continue;
+
var menuItem = new MenuItem
{
Header = fileExtension.Description,
@@ -1315,6 +1321,16 @@ namespace UVtools.WPF
SelectedTabItem = TabIssues;
}
}
+
+ SlicerFile.PropertyChanged += SlicerFileOnPropertyChanged;
+ }
+
+ private void SlicerFileOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(SlicerFile.Thumbnails))
+ {
+ RefreshThumbnail();
+ }
}
private async void ShowProgressWindow(string title, bool canCancel = true)
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index dc8e4e7..6d6bc26 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>2.18.1</Version>
+ <Version>2.19.0</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -24,11 +24,11 @@
<NoWarn>1701;1702;</NoWarn>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Avalonia" Version="0.10.6" />
+ <PackageReference Include="Avalonia" Version="0.10.7" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
- <PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.6" />
- <PackageReference Include="Avalonia.Desktop" Version="0.10.6" />
- <PackageReference Include="Avalonia.Diagnostics" Version="0.10.6" />
+ <PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.7" />
+ <PackageReference Include="Avalonia.Desktop" Version="0.10.7" />
+ <PackageReference Include="Avalonia.Diagnostics" Version="0.10.7" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.3.4721" />
<PackageReference Include="MessageBox.Avalonia" Version="1.5.1" />
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.6" />
diff --git a/UVtools.WPF/Windows/MaterialManagerWindow.axaml b/UVtools.WPF/Windows/MaterialManagerWindow.axaml
index 52908af..30873e4 100644
--- a/UVtools.WPF/Windows/MaterialManagerWindow.axaml
+++ b/UVtools.WPF/Windows/MaterialManagerWindow.axaml
@@ -77,8 +77,7 @@
</Border>
- <Border Grid.Row="1" BorderBrush="Black" BorderThickness="1" Padding="5">
- <Expander IsExpanded="False">
+ <Expander Grid.Row="1" IsExpanded="False">
<Expander.Header>
<TextBlock Text="Add new material"
FontWeight="Bold"
@@ -170,7 +169,6 @@
Text="units"/>
</Grid>
</Expander>
- </Border>
<TextBlock Grid.Row="2"
VerticalAlignment="Center" FontWeight="Bold"
diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
index 80d1a66..b63f068 100644
--- a/UVtools.WPF/Windows/SettingsWindow.axaml.cs
+++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
@@ -63,7 +63,7 @@ namespace UVtools.WPF.Windows
{
FileFormat.AllSlicerFiles.Replace("*", string.Empty)
};
- fileFormats.AddRange(from format in FileFormat.AvailableFormats from extension in format.FileExtensions select $"{extension.Description} (.{extension.Extension})");
+ fileFormats.AddRange(from format in FileFormat.AvailableFormats from extension in format.FileExtensions where extension.IsVisibleOnFileFilters select $"{extension.Description} (.{extension.Extension})");
FileOpenDialogFilters = fileFormats.ToArray();
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
index f7ffdfa..5d2438f 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml.cs
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -725,6 +725,8 @@ namespace UVtools.WPF.Windows
}, TimeSpan.FromMilliseconds(1));
}
+
+
public void FitToSize()
{
SizeToContent = SizeToContent.Manual;
diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1
index 218e9b5..4985e72 100644
--- a/build/CreateRelease.WPF.ps1
+++ b/build/CreateRelease.WPF.ps1
@@ -32,10 +32,10 @@ Set-Location $PSScriptRoot\..
####################################
### Configuration ###
####################################
-#$enableMSI = $true
-$buildOnly = 'win-x64'
+$enableMSI = $true
+#$buildOnly = 'win-x64'
#$buildOnly = 'linux-x64'
-#$enableNugetPublish = $true
+$enableNugetPublish = $true
# Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
$deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch