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/FileFormats/CXDLPFile.cs')
-rw-r--r--UVtools.Core/FileFormats/CXDLPFile.cs703
1 files changed, 703 insertions, 0 deletions
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
new file mode 100644
index 0000000..2e680a3
--- /dev/null
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -0,0 +1,703 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+// https://github.com/cbiffle/catibo/blob/master/doc/cbddlp-ctb.adoc
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BinarySerialization;
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
+using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
+
+namespace UVtools.Core.FileFormats
+{
+ public class CXDLPFile : FileFormat
+ {
+ #region Constants
+ private const byte HEADER_SIZE = 9; // CXSW3DV2
+ private const string HEADER_VALUE = "CXSW3DV2";
+
+
+ private const uint SlicerInfoAddress = 4 + HEADER_SIZE + 6 + 290 * 290 * 4 + 116 * 116 * 2 + 6;
+ #endregion
+
+ #region Sub Classes
+ #region Header
+ public sealed class Header
+ {
+ /// <summary>
+ /// Gets the size of the header
+ /// </summary>
+ [FieldOrder(0)]
+ [FieldEndianness(Endianness.Big)]
+ public uint HeaderSize { get; set; } = HEADER_SIZE;
+
+ /// <summary>
+ /// Gets the header name
+ /// </summary>
+ [FieldOrder(1)]
+ [FieldLength(HEADER_SIZE)]
+ [SerializeAs(SerializedType.TerminatedString)]
+ public string HeaderValue { get; set; } = HEADER_VALUE;
+
+ /// <summary>
+ /// Gets the number of records in the layer table
+ /// </summary>
+ [FieldOrder(2)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort LayerCount { get; set; }
+
+ /// <summary>
+ /// Gets the printer resolution along X axis, in pixels. This information is critical to correctly decoding layer images.
+ /// </summary>
+ [FieldOrder(3)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort ResolutionX { get; set; }
+
+ /// <summary>
+ /// Gets the printer resolution along Y axis, in pixels. This information is critical to correctly decoding layer images.
+ /// </summary>
+ [FieldOrder(4)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort ResolutionY { get; set; }
+
+ public void Validate()
+ {
+ if (HeaderSize != HEADER_SIZE || HeaderValue != HEADER_VALUE)
+ {
+ throw new FileLoadException("Not a valid CXDLP file!");
+ }
+ }
+ }
+
+ #endregion
+
+ #region SlicerInfo
+ // Address: 363337
+ public sealed class SlicerInfo
+ {
+ [FieldOrder(0)]
+ [FieldEndianness(Endianness.Big)]
+ public uint DisplayWidthDataSize { get; set; } = 20;
+
+ [FieldOrder(1)]
+ [FieldLength(nameof(DisplayWidthDataSize))]
+ public byte[] DisplayWidth { get; set; }
+
+ [FieldOrder(2)]
+ [FieldEndianness(Endianness.Big)]
+ public uint DisplayHeightDataSize { get; set; } = 20;
+
+ [FieldOrder(3)]
+ [FieldLength(nameof(DisplayHeightDataSize))]
+ public byte[] DisplayHeight { get; set; }
+
+ [FieldOrder(4)]
+ [FieldEndianness(Endianness.Big)]
+ public uint LayerHeightDataSize { get; set; } = 16;
+
+ [FieldOrder(5)]
+ [FieldLength(nameof(LayerHeightDataSize))]
+ public byte[] LayerHeight { get; set; }
+
+ [FieldOrder(6)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort ExposureTime { get; set; }
+
+ [FieldOrder(7)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort LightOffDelay { get; set; }
+
+ [FieldOrder(8)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort BottomExposureTime { get; set; }
+
+ [FieldOrder(9)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort BottomLayers { get; set; }
+
+ [FieldOrder(10)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort BottomLiftHeight { get; set; }
+
+ [FieldOrder(11)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort BottomLiftSpeed { get; set; }
+
+ [FieldOrder(12)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort LiftHeight { get; set; }
+
+ [FieldOrder(13)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort LiftSpeed { get; set; }
+
+ [FieldOrder(14)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort RetractSpeed { get; set; }
+
+ [FieldOrder(15)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort BottomLightPWM { get; set; } = 255;
+
+ [FieldOrder(16)]
+ [FieldEndianness(Endianness.Big)]
+ public ushort LightPWM { get; set; } = 255;
+ }
+ #endregion
+
+ #region Layer Def
+
+ public sealed class PreLayer
+ {
+ [FieldOrder(0)]
+ [FieldEndianness(Endianness.Big)]
+ public uint Unknown { get; set; }
+
+ public PreLayer()
+ {
+ }
+
+ public PreLayer(uint unknown)
+ {
+ Unknown = unknown;
+ }
+ }
+
+ public sealed class LayerDef
+ {
+ [FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint Unknown { get; set; }
+ [FieldOrder(1)] [FieldEndianness(Endianness.Big)] public uint LineCount { get; set; }
+ [FieldOrder(2)] [FieldCount(nameof(LineCount))] public LayerLine[] Lines { get; set; }
+ [FieldOrder(3)] public PageBreak PageBreak { get; set; } = new();
+
+ public LayerDef() { }
+
+ public LayerDef(uint unknown, uint lineCount, LayerLine[] lines)
+ {
+ Unknown = unknown;
+ LineCount = lineCount;
+ Lines = lines;
+ }
+ }
+
+ public sealed class LayerLine
+ {
+ public const byte CoordinateCount = 5;
+ [FieldOrder(0)] [FieldCount(CoordinateCount)] public byte[] Coordinates { get; set; } = new byte[CoordinateCount];
+ //[FieldOrder(0)] [FieldEndianness(Endianness.Big)] [FieldBitLength(13)] public ushort StartY { get; set; }
+ //[FieldOrder(1)] [FieldEndianness(Endianness.Big)] [FieldBitLength(13)] public ushort EndY { get; set; }
+ //[FieldOrder(2)] [FieldEndianness(Endianness.Big)] [FieldBitLength(14)] public ushort StartX { get; set; }
+ [FieldOrder(1)] public byte Gray { get; set; }
+
+ [Ignore] public ushort StartY => (ushort) ((((Coordinates[0] << 8) + Coordinates[1]) >> 3) & 0x1FFF); // 13 bits
+
+ [Ignore] public ushort EndY => (ushort)((((Coordinates[1] << 16) + (Coordinates[2] << 8) + Coordinates[3]) >> 6) & 0x1FFF); // 13 bits
+
+ [Ignore] public ushort StartX => (ushort)(((Coordinates[3] << 8) + Coordinates[4]) & 0x3FFF); // 14 bits
+ [Ignore] public ushort Length => (ushort) (EndY - StartY);
+
+ public LayerLine() { }
+
+ public LayerLine(ushort startY, ushort endY, ushort startX, byte gray)
+ {
+ Coordinates[0] = (byte) ((startY >> 5) & 0xFF);
+ Coordinates[1] = (byte) (((startY << 3) + (endY >> 10)) & 0xFF);
+ Coordinates[2] = (byte) ((endY >> 2) & 0xFF);
+ Coordinates[3] = (byte)(((endY << 6) + (startX >> 8)) & 0xFF);
+ Coordinates[4] = (byte) startX;
+ /*StartY = startY;
+ EndY = endY;
+ StartX = startX;*/
+ Gray = gray;
+ }
+ }
+
+ public sealed class PageBreak
+ {
+ [FieldOrder(0)] public byte Line { get; set; } = 0x0D;
+ [FieldOrder(1)] public byte Break { get; set; } = 0x0A;
+ }
+
+ #endregion
+
+ #region Footer
+ public sealed class Footer
+ {
+ /// <summary>
+ /// Gets the size of the header
+ /// </summary>
+ [FieldOrder(0)]
+ [FieldEndianness(Endianness.Big)]
+ public uint FooterSize { get; set; } = HEADER_SIZE;
+
+ /// <summary>
+ /// Gets the header name
+ /// </summary>
+ [FieldOrder(1)]
+ [FieldLength(HEADER_SIZE)]
+ [SerializeAs(SerializedType.TerminatedString)]
+ public string FooterValue { get; set; } = HEADER_VALUE;
+
+ [FieldOrder(2)]
+ public uint Unknown { get; set; } = 7;
+
+ public void Validate()
+ {
+ if (FooterSize != HEADER_SIZE || FooterValue != HEADER_VALUE)
+ {
+ throw new FileLoadException("Not a valid CXDLP file!");
+ }
+ }
+ }
+ #endregion
+
+ #endregion
+
+ #region Properties
+
+ public Header HeaderSettings { get; protected internal set; } = new();
+ public SlicerInfo SlicerInfoSettings { get; protected internal set; } = new();
+ public Footer FooterSettings { get; protected internal set; } = new();
+
+ public override FileFormatType FileType => FileFormatType.Binary;
+
+ public override FileExtension[] FileExtensions { get; } = {
+ new("cxdlp", "Creality CXDLP"),
+ };
+
+ public override PrintParameterModifier[] PrintParameterModifiers { get; } =
+ {
+ PrintParameterModifier.BottomLayerCount,
+ PrintParameterModifier.BottomExposureSeconds,
+ PrintParameterModifier.ExposureSeconds,
+
+ PrintParameterModifier.BottomLiftHeight,
+ PrintParameterModifier.BottomLiftSpeed,
+ PrintParameterModifier.LiftHeight,
+ PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.LightOffDelay,
+
+ PrintParameterModifier.BottomLightPWM,
+ PrintParameterModifier.LightPWM,
+ };
+
+ public override Size[] ThumbnailsOriginalSize { get; } =
+ {
+ new(116, 116),
+ new(290, 290),
+ new(290, 290)
+ };
+
+ public override uint ResolutionX
+ {
+ get => HeaderSettings.ResolutionX;
+ set
+ {
+ HeaderSettings.ResolutionX = (ushort) value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint ResolutionY
+ {
+ get => HeaderSettings.ResolutionY;
+ set
+ {
+ HeaderSettings.ResolutionY = (ushort) value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float DisplayWidth
+ {
+ get => float.Parse(SlicerInfoSettings.DisplayWidth.Where(b => b != 0).Aggregate(string.Empty, (current, b) => current + System.Convert.ToChar(b)));
+ set
+ {
+ string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
+ SlicerInfoSettings.DisplayWidthDataSize = (uint)(str.Length * 2);
+ var data = new byte[SlicerInfoSettings.DisplayWidthDataSize];
+ for (var i = 0; i < str.Length; i++)
+ {
+ data[i * 2] = System.Convert.ToByte(str[i]);
+ }
+
+ SlicerInfoSettings.DisplayWidth = data;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float DisplayHeight
+ {
+ get => float.Parse(SlicerInfoSettings.DisplayHeight.Where(b => b != 0).Aggregate(string.Empty, (current, b) => current + System.Convert.ToChar(b)));
+ set
+ {
+ string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
+ SlicerInfoSettings.DisplayHeightDataSize = (uint)(str.Length * 2);
+ var data = new byte[SlicerInfoSettings.DisplayHeightDataSize];
+ for (var i = 0; i < str.Length; i++)
+ {
+ data[i * 2] = System.Convert.ToByte(str[i]);
+ }
+
+ SlicerInfoSettings.DisplayHeight = data;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override byte AntiAliasing
+ {
+ get => 8;
+ set {}
+ }
+
+ public override float LayerHeight
+ {
+ get => float.Parse(SlicerInfoSettings.LayerHeight.Where(b => b != 0).Aggregate(string.Empty, (current, b) => current + System.Convert.ToChar(b)));
+ set
+ {
+ string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture);
+ SlicerInfoSettings.LayerHeightDataSize = (uint)(str.Length * 2);
+ var data = new byte[SlicerInfoSettings.LayerHeightDataSize];
+ for (var i = 0; i < str.Length; i++)
+ {
+ data[i * 2] = System.Convert.ToByte(str[i]);
+ }
+
+ SlicerInfoSettings.LayerHeight = data;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint LayerCount
+ {
+ get => base.LayerCount;
+ set => base.LayerCount = HeaderSettings.LayerCount = (ushort) base.LayerCount;
+ }
+
+ public override ushort BottomLayerCount
+ {
+ get => SlicerInfoSettings.BottomLayers;
+ set => base.BottomLayerCount = SlicerInfoSettings.BottomLayers = value;
+ }
+
+ public override float BottomExposureTime
+ {
+ get => SlicerInfoSettings.BottomExposureTime;
+ set => base.BottomExposureTime = SlicerInfoSettings.BottomExposureTime = (ushort) value;
+ }
+
+ public override float ExposureTime
+ {
+ get => SlicerInfoSettings.ExposureTime;
+ set => base.ExposureTime = SlicerInfoSettings.ExposureTime = (ushort) value;
+ }
+
+ public override float BottomLiftHeight
+ {
+ get => SlicerInfoSettings.BottomLiftHeight;
+ set => base.BottomLiftHeight = SlicerInfoSettings.BottomLiftHeight = (ushort) value;
+ }
+
+ public override float LiftHeight
+ {
+ get => SlicerInfoSettings.LiftHeight;
+ set => base.LiftHeight = SlicerInfoSettings.LiftHeight = (ushort)value;
+ }
+
+ public override float BottomLiftSpeed
+ {
+ get => SlicerInfoSettings.BottomLiftSpeed;
+ set => base.BottomLiftSpeed = SlicerInfoSettings.BottomLiftSpeed = (ushort)value;
+ }
+
+ public override float LiftSpeed
+ {
+ get => SlicerInfoSettings.LiftSpeed;
+ set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)value;
+ }
+
+ public override float RetractSpeed
+ {
+ get => SlicerInfoSettings.RetractSpeed;
+ set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)value;
+ }
+
+ public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay;
+
+ public override float LightOffDelay
+ {
+ get => SlicerInfoSettings.LightOffDelay;
+ set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value;
+ }
+
+ public override byte BottomLightPWM
+ {
+ get => (byte) SlicerInfoSettings.BottomLightPWM;
+ set => base.BottomLightPWM = (byte) (SlicerInfoSettings.BottomLightPWM = value);
+ }
+
+ public override byte LightPWM
+ {
+ get => (byte)SlicerInfoSettings.LightPWM;
+ set => base.LightPWM = (byte) (SlicerInfoSettings.LightPWM = value);
+ }
+
+ public override object[] Configs => new object[] { HeaderSettings, SlicerInfoSettings, FooterSettings };
+
+ #endregion
+
+ #region Constructors
+ #endregion
+
+ #region Methods
+
+ protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
+ {
+ using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
+
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
+ var pageBreak = new PageBreak();
+
+ byte[][] previews = new byte[ThumbnailsOriginalSize.Length][];
+ for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
+ {
+ previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
+ }
+ // Previews
+ Parallel.For(0, previews.Length, previewIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ if (Thumbnails[previewIndex] is null) return;
+ var span = Thumbnails[previewIndex].GetPixelSpanByte();
+ int index = 0;
+ for (int i = 0; i < span.Length; i += 3)
+ {
+ 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);
+ }
+
+ if (index != previews[previewIndex].Length)
+ {
+ throw new FileLoadException($"Preview encode incomplete encode, expected: {previews[previewIndex].Length}, encoded: {index}");
+ }
+ });
+
+ for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
+ {
+ Helpers.SerializeWriteFileStream(outputFile, previews[i]);
+ Helpers.SerializeWriteFileStream(outputFile, pageBreak);
+ }
+ Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
+
+ progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
+ var preLayers = new PreLayer[LayerCount];
+ var layerDefs = new LayerDef[LayerCount];
+
+ for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ var layer = this[layerIndex];
+ preLayers[layerIndex] = new(layer.NonZeroPixelCount);
+ }
+ Helpers.SerializeWriteFileStream(outputFile, preLayers);
+ Helpers.SerializeWriteFileStream(outputFile, pageBreak);
+
+ Parallel.For(0, LayerCount, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ List<LayerLine> layerLines = new();
+ var layer = this[layerIndex];
+ using var mat = layer.LayerMat;
+ var span = mat.GetPixelSpanByte();
+
+ 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++)
+ {
+ int pos = mat.GetPixelPos(x, y);
+ byte color = span[pos];
+
+ if (lastColor == color && color != 0) continue;
+
+ if (startY >= 0)
+ {
+ layerLines.Add(new LayerLine((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
+ }
+
+ startY = color == 0 ? -1 : y;
+
+ lastColor = color;
+ }
+
+ if (startY >= 0)
+ {
+ layerLines.Add(new LayerLine((ushort)startY, (ushort)(y - 1), (ushort)x, lastColor));
+ }
+ }
+
+ layerDefs[layerIndex] = new LayerDef(layer.NonZeroPixelCount, (uint)layerLines.Count, layerLines.ToArray());
+
+ progress.LockAndIncrement();
+ });
+
+ progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
+ for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ Helpers.SerializeWriteFileStream(outputFile, layerDefs[layerIndex]);
+ progress++;
+ }
+
+ Helpers.SerializeWriteFileStream(outputFile, FooterSettings);
+
+ Debug.WriteLine("Encode Results:");
+ Debug.WriteLine(HeaderSettings);
+ Debug.WriteLine("-End-");
+ }
+
+ protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
+ {
+ using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read);
+ HeaderSettings = Helpers.Deserialize<Header>(inputFile);
+ HeaderSettings.Validate();
+
+ byte[][] previews = new byte[ThumbnailsOriginalSize.Length][];
+ for (int i = 0; i < ThumbnailsOriginalSize.Length; i++)
+ {
+ previews[i] = new byte[ThumbnailsOriginalSize[i].Area() * 2];
+ inputFile.ReadBytes(previews[i]);
+ inputFile.Seek(2, SeekOrigin.Current);
+ }
+
+ Parallel.For(0, previews.Length, previewIndex =>
+ {
+ var mat = new Mat(ThumbnailsOriginalSize[previewIndex], DepthType.Cv8U, 3);
+ var span = mat.GetPixelSpanByte();
+
+ 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;
+ });
+
+
+ SlicerInfoSettings = Helpers.Deserialize<SlicerInfo>(inputFile);
+
+ LayerManager.Init(HeaderSettings.LayerCount);
+ progress.ItemCount = LayerCount;
+ var preLayers = new PreLayer[LayerCount];
+ for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ preLayers[layerIndex] = Helpers.Deserialize<PreLayer>(inputFile);
+ }
+
+ inputFile.Seek(2, SeekOrigin.Current);
+ var layerDefs = new LayerDef[LayerCount];
+ for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ layerDefs[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
+ progress++;
+ }
+
+ /*using TextWriter file = new StreamWriter("D:\\dump.txt");
+ for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ file.WriteLine($"Layer: {layerIndex}");
+ for (int lineIndex = 0; lineIndex < layerDefs[layerIndex].LineCount; lineIndex++)
+ {
+ file.WriteLine($"\tLine: {lineIndex}");
+ var line = layerDefs[layerIndex].Lines[lineIndex];
+ file.WriteLine($"\t\tb1: {line.Coordinates[0]}");
+ file.WriteLine($"\t\tb2: {line.Coordinates[1]}");
+ file.WriteLine($"\t\tb3: {line.Coordinates[2]}");
+ file.WriteLine($"\t\tb4: {line.Coordinates[3]}");
+ file.WriteLine($"\t\tb5: {line.Coordinates[4]}");
+ file.WriteLine($"\t\tstartY: {line.StartY}");
+ file.WriteLine($"\t\tendY: {line.EndY}");
+ file.WriteLine($"\t\tstartX: {line.StartX}");
+ file.WriteLine($"\t\tgray: {line.Gray}");
+ }
+ }
+ file.Close();*/
+
+ progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+ Parallel.For(0, LayerCount, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ using var mat = EmguExtensions.InitMat(Resolution);
+ foreach (var line in layerDefs[layerIndex].Lines)
+ {
+ CvInvoke.Line(mat, new Point(line.StartX, line.StartY), new Point(line.StartX, line.EndY), new MCvScalar(line.Gray));
+ }
+
+ this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ progress.LockAndIncrement();
+ });
+
+ FooterSettings = Helpers.Deserialize<Footer>(inputFile);
+ FooterSettings.Validate();
+ }
+
+ public override void SaveAs(string filePath = null, OperationProgress progress = null)
+ {
+ if (RequireFullEncode)
+ {
+ if (!string.IsNullOrEmpty(filePath))
+ {
+ FileFullPath = filePath;
+ }
+ Encode(FileFullPath, progress);
+ return;
+ }
+
+ if (!string.IsNullOrEmpty(filePath))
+ {
+ File.Copy(FileFullPath, filePath, true);
+ FileFullPath = filePath;
+ }
+
+ using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
+ outputFile.Seek(SlicerInfoAddress, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings);
+ }
+
+ #endregion
+ }
+}