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:
Diffstat (limited to 'UVtools.Core')
-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
30 files changed, 2545 insertions, 1574 deletions
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>