mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
57f077f444
- **File formats:** - (Add) OSF (Vlare Open File Format) - (Fix) CTB Encrypted: Bottom Retract Height for TSMC was constraining incorrectly with the normal total retract height - (Fix) CWS: Only issue `;<Slice>` command when the exposure is about to happen (#514) - **GCode:** - (Add) Command `CommandWaitSyncDelay` for movement wait sync delay instead of depending on G4 wait command - (Fix) Wrong parsing and set of wait times when using a wait after lift / wait before retract - (Improvement) Auto update: Make sure the download url exists before attempt the download, if not, instead it will prompt for manual download and update - (Improvement) MacOS: Remove `com.apple.quarantine` flag from the auto downloaded files - (Upgrade) .NET from 6.0.7 to 6.0.8 - (Upgrade) AvaloniaUI from 0.10.17 to 0.10.18
634 lines
20 KiB
C#
634 lines
20 KiB
C#
/*
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* Version 3, 19 November 2007
|
|
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
* Everyone is permitted to copy and distribute verbatim copies
|
|
* of this license document, but changing it is not allowed.
|
|
*/
|
|
|
|
using BinarySerialization;
|
|
using Emgu.CV;
|
|
using Emgu.CV.CvEnum;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using UVtools.Core.Converters;
|
|
using UVtools.Core.Extensions;
|
|
using UVtools.Core.Layers;
|
|
using UVtools.Core.Operations;
|
|
|
|
namespace UVtools.Core.FileFormats;
|
|
|
|
public class LGSFile : FileFormat
|
|
{
|
|
#region Sub Classes
|
|
|
|
#region Header
|
|
|
|
public class Header
|
|
{
|
|
public const string NameValue = "Longer3D";
|
|
|
|
/// <summary>
|
|
/// Gets the model name
|
|
/// </summary>
|
|
[FieldOrder(0)] [FieldLength(8)] public string Name { get; set; } = NameValue; // 0x00:
|
|
[FieldOrder(1)] public uint Uint_08 { get; set; } = 1; // 0x08: 0xff000001 ?
|
|
[FieldOrder(2)] public uint Uint_0c { get; set; } = 1; // 0x0c: 1 ?
|
|
[FieldOrder(3)] public uint PrinterModel { get; set; } = 30; // 10, 30, 120, 4000 (4k), 4500 (4k mono)
|
|
[FieldOrder(4)] public uint Uint_14 { get; set; } = 0; // 0x14: 0 ?
|
|
[FieldOrder(5)] public uint MagicKey { get; set; } = 34; // 0x18: 34
|
|
[FieldOrder(6)] public float PixelPerMmX { get; set; } = 15.404f;
|
|
[FieldOrder(7)] public float PixelPerMmY { get; set; } = 4.866f;
|
|
[FieldOrder(8)] public float ResolutionX { get; set; }
|
|
[FieldOrder(9)] public float ResolutionY { get; set; }
|
|
[FieldOrder(10)] public float LayerHeight { get; set; }
|
|
[FieldOrder(11)] public float ExposureTimeMs { get; set; }
|
|
[FieldOrder(12)] public float BottomExposureTimeMs { get; set; }
|
|
[FieldOrder(13)] public float Float_38 { get; set; } = 10; // 0x38: 10
|
|
[FieldOrder(14)] public float LightOffDelayMs { get; set; } = 2000;
|
|
[FieldOrder(15)] public float BottomLightOffDelayMs { get; set; }
|
|
[FieldOrder(16)] public float BottomHeight { get; set; }
|
|
[FieldOrder(17)] public float Float_48 { get; set; } = 0.6f; // 0x48: 0.6
|
|
[FieldOrder(18)] public float BottomLiftHeight { get; set; } = 4;
|
|
[FieldOrder(19)] public float LiftHeight { get; set; }
|
|
[FieldOrder(20)] public float LiftSpeed { get; set; } = 150;
|
|
[FieldOrder(21)] public float LiftSpeed_ { get; set; } = 150;
|
|
[FieldOrder(22)] public float BottomLiftSpeed { get; set; } = 90;
|
|
[FieldOrder(23)] public float BottomLiftSpeed_ { get; set; } = 90;
|
|
[FieldOrder(24)] public float Float_64 { get; set; } = 5; // 0x64: 5?
|
|
[FieldOrder(25)] public float Float_68 { get; set; } = 60; // 0x68: 60?
|
|
[FieldOrder(26)] public float Float_6c { get; set; } = 10; // 0x6c: 10?
|
|
[FieldOrder(27)] public float Float_70 { get; set; } = 600; // 0x70: 600?
|
|
[FieldOrder(28)] public float Float_74 { get; set; } = 600; // 0x70: 600?
|
|
[FieldOrder(29)] public float Float_78 { get; set; } = 2; // 0x78: 2?
|
|
[FieldOrder(30)] public float Float_7c { get; set; } = 0.2f; // 0x7c: 0.2?
|
|
[FieldOrder(31)] public float Float_80 { get; set; } = 60; // 0x80: 60?
|
|
[FieldOrder(32)] public float Float_84 { get; set; } = 1; // 0x84: 1?
|
|
[FieldOrder(33)] public float Float_88 { get; set; } = 6; // 0x88: 6?
|
|
[FieldOrder(34)] public float Float_8c { get; set; } = 150; // 0x8c: 150 ?
|
|
[FieldOrder(35)] public float Float_90 { get; set; } = 1001; // 0x90: 1001 ?
|
|
[FieldOrder(36)] public float MachineZ { get; set; } = 140;// 0x94: 140 for lgs10, 170 for lgs30, 150 for lgs120, 190 for lgs4k
|
|
[FieldOrder(37)] public uint Uint_98 { get; set; } // 0x98: 0 ?
|
|
[FieldOrder(38)] public uint Uint_9c { get; set; } // 0x9c: 0 ?
|
|
[FieldOrder(39)] public uint Uint_a0 { get; set; } // 0xa0: 0 ?
|
|
[FieldOrder(40)] public uint LayerCount { get; set; }
|
|
[FieldOrder(41)] public uint Uint_a8 { get; set; } = 4; // 0xa8: 4 ?
|
|
[FieldOrder(42)] public uint PreviewSizeX { get; set; } = 120;
|
|
[FieldOrder(43)] public uint PreviewSizeY { get; set; } = 150;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LGS120PngPreview
|
|
|
|
public class LGS120PngPreview
|
|
{
|
|
public const ushort ResolutionX = 1200;
|
|
public const ushort ResolutionY = 1600;
|
|
|
|
[FieldOrder(0)] public uint DataSize { get; set; }
|
|
|
|
[FieldOrder(1)]
|
|
[FieldLength(nameof(DataSize))]
|
|
public byte[] PngBytes { get; set; } = null!;
|
|
|
|
[FieldOrder(2)] public ushort Padding { get; set; }
|
|
|
|
public void Encode(Mat mat)
|
|
{
|
|
mat ??= EmguExtensions.InitMat(new Size(ResolutionX, ResolutionY), 3);
|
|
|
|
if (mat.Width != ResolutionX || mat.Height != ResolutionY)
|
|
{
|
|
using var resizeMat = new Mat();
|
|
CvInvoke.Resize(mat, resizeMat, new Size(ResolutionX, ResolutionY));
|
|
PngBytes = resizeMat.GetPngByes();
|
|
}
|
|
else
|
|
{
|
|
PngBytes = mat.GetPngByes();
|
|
}
|
|
}
|
|
|
|
public Mat Decode(bool consumeRle = true)
|
|
{
|
|
var mat = new Mat();
|
|
CvInvoke.Imdecode(PngBytes, ImreadModes.AnyColor, mat);
|
|
if (consumeRle)
|
|
PngBytes = null!;
|
|
return mat;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LayerData
|
|
|
|
public class LayerDef
|
|
{
|
|
[Ignore] public LGSFile Parent { get; set; } = null!;
|
|
|
|
[FieldOrder(0)]
|
|
public uint DataSize { get; set; }
|
|
|
|
[FieldOrder(1)]
|
|
[FieldLength(nameof(DataSize))]
|
|
public byte[] EncodedRle { get; set; } = null!;
|
|
|
|
public LayerDef() { }
|
|
|
|
public LayerDef(LGSFile parent)
|
|
{
|
|
Parent = parent;
|
|
}
|
|
|
|
public unsafe byte[] Encode(Mat mat)
|
|
{
|
|
List<byte> rawData = new();
|
|
List<byte> chunk = new();
|
|
|
|
if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
|
|
{
|
|
CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90Clockwise);
|
|
}
|
|
|
|
var spanMat = mat.GetBytePointer();
|
|
var imageLength = mat.GetLength();
|
|
|
|
uint span = 0;
|
|
byte lc = 0;
|
|
|
|
void addSpan(){
|
|
chunk.Clear();
|
|
for (; span > 0; span >>= 4) {
|
|
chunk.Insert(0, (byte)((byte)(span & 0xf) | (lc & 0xf0)));
|
|
}
|
|
rawData.AddRange(chunk.ToArray());
|
|
}
|
|
|
|
for (int i = 0; i < imageLength; i++)
|
|
{
|
|
byte c = (byte) (spanMat[i] & 0xf0);
|
|
|
|
if (c == lc)
|
|
{
|
|
span++;
|
|
}
|
|
else
|
|
{
|
|
addSpan();
|
|
span = 1;
|
|
}
|
|
|
|
lc = c;
|
|
}
|
|
|
|
addSpan();
|
|
EncodedRle = rawData.ToArray();
|
|
DataSize = (uint) EncodedRle.Length;
|
|
|
|
if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
|
|
{
|
|
CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90CounterClockwise);
|
|
}
|
|
|
|
return EncodedRle;
|
|
}
|
|
|
|
public Mat Decode(bool consumeRle = true)
|
|
{
|
|
// lgs10/30 -------->
|
|
// lgs120/4k From Y bottom to top Y
|
|
var mat = EmguExtensions.InitMat(Parent.HeaderSettings.PrinterModel is 4000 or 4500 ? Parent.Resolution.Exchange() : Parent.Resolution);
|
|
//var matSpan = mat.GetBytePointer();
|
|
var imageLength = mat.GetLength();
|
|
|
|
int pixelPos = 0;
|
|
|
|
for (var i = 0; i < EncodedRle.Length; i++)
|
|
{
|
|
var b = EncodedRle[i];
|
|
byte colorNibble = (byte)(b >> 4);
|
|
byte color = (byte)(colorNibble << 4 | colorNibble);
|
|
int repeat = b & 0xf;
|
|
|
|
while (i + 1 < EncodedRle.Length && (EncodedRle[i + 1] >> 4) == colorNibble)
|
|
{
|
|
i++;
|
|
repeat = (repeat << 4) | (EncodedRle[i] & 0xf);
|
|
}
|
|
|
|
if (pixelPos >= imageLength)
|
|
{
|
|
throw new FileLoadException($"Too much buffer, expected: {imageLength}, got: {pixelPos}");
|
|
}
|
|
|
|
mat.FillSpan(ref pixelPos, repeat, color);
|
|
|
|
//if (repeat <= 0) continue;
|
|
/*while (repeat-- > 0)
|
|
{
|
|
matSpan[pixel++] = color;
|
|
}*/
|
|
|
|
}
|
|
|
|
if (pixelPos != imageLength)
|
|
{
|
|
throw new FileLoadException($"Incomplete buffer, expected: {imageLength}, got: {pixelPos}");
|
|
}
|
|
|
|
if (consumeRle)
|
|
EncodedRle = null!;
|
|
|
|
if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
|
|
{
|
|
CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90CounterClockwise);
|
|
}
|
|
|
|
return mat;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public Header HeaderSettings { get; protected internal set; } = new();
|
|
public override FileFormatType FileType => FileFormatType.Binary;
|
|
|
|
public override FileExtension[] FileExtensions { get; } = {
|
|
new (typeof(LGSFile), "lgs", "Longer Orange 10 (LGS)"),
|
|
new (typeof(LGSFile), "lgs30", "Longer Orange 30 (LGS30)"),
|
|
new (typeof(LGSFile), "lgs120", "Longer Orange 120 (LGS120)"),
|
|
new (typeof(LGSFile), "lgs4k", "Longer Orange 4k (LGS4K)"),
|
|
};
|
|
|
|
public override PrintParameterModifier[]? PrintParameterModifiers { get; } =
|
|
{
|
|
PrintParameterModifier.BottomLayerCount,
|
|
|
|
PrintParameterModifier.BottomLightOffDelay,
|
|
PrintParameterModifier.LightOffDelay,
|
|
|
|
PrintParameterModifier.BottomExposureTime,
|
|
PrintParameterModifier.ExposureTime,
|
|
|
|
PrintParameterModifier.BottomLiftHeight,
|
|
PrintParameterModifier.BottomLiftSpeed,
|
|
PrintParameterModifier.LiftHeight,
|
|
PrintParameterModifier.LiftSpeed,
|
|
|
|
};
|
|
|
|
public override Size[]? ThumbnailsOriginalSize { get; } = {new(120, 150)};
|
|
|
|
public override uint ResolutionX
|
|
{
|
|
get => (uint) HeaderSettings.ResolutionX;
|
|
set
|
|
{
|
|
HeaderSettings.ResolutionX = value;
|
|
RaisePropertyChanged();
|
|
}
|
|
}
|
|
|
|
public override uint ResolutionY
|
|
{
|
|
get => (uint)HeaderSettings.ResolutionY;
|
|
set
|
|
{
|
|
HeaderSettings.ResolutionY = value;
|
|
RaisePropertyChanged();
|
|
}
|
|
}
|
|
|
|
public override float Xppmm
|
|
{
|
|
get => HeaderSettings.PixelPerMmX > 0 ? HeaderSettings.PixelPerMmX : base.Xppmm;
|
|
set
|
|
{
|
|
HeaderSettings.PixelPerMmX = value;
|
|
base.Xppmm = value;
|
|
}
|
|
}
|
|
|
|
public override float Yppmm
|
|
{
|
|
get => HeaderSettings.PixelPerMmY > 0 ? HeaderSettings.PixelPerMmY : base.Yppmm;
|
|
set
|
|
{
|
|
HeaderSettings.PixelPerMmY = value;
|
|
base.Yppmm = value;
|
|
}
|
|
}
|
|
|
|
public override float DisplayWidth
|
|
{
|
|
get => ResolutionX / HeaderSettings.PixelPerMmX;
|
|
set { }
|
|
}
|
|
|
|
public override float DisplayHeight
|
|
{
|
|
get => ResolutionY / HeaderSettings.PixelPerMmY;
|
|
set { }
|
|
}
|
|
|
|
public override float MachineZ
|
|
{
|
|
get => HeaderSettings.MachineZ > 0 ? HeaderSettings.MachineZ : base.MachineZ;
|
|
set => base.MachineZ = HeaderSettings.MachineZ = (float)Math.Round(value, 2);
|
|
}
|
|
|
|
public override FlipDirection DisplayMirror
|
|
{
|
|
get => FlipDirection.Horizontally;
|
|
set { }
|
|
}
|
|
|
|
public override float LayerHeight
|
|
{
|
|
get => HeaderSettings.LayerHeight;
|
|
set
|
|
{
|
|
HeaderSettings.LayerHeight = Layer.RoundHeight(value);
|
|
RaisePropertyChanged();
|
|
}
|
|
}
|
|
|
|
public override uint LayerCount
|
|
{
|
|
get => base.LayerCount;
|
|
set => base.LayerCount = HeaderSettings.LayerCount = base.LayerCount;
|
|
}
|
|
|
|
public override ushort BottomLayerCount
|
|
{
|
|
get => (ushort) (HeaderSettings.BottomHeight / LayerHeight);
|
|
set
|
|
{
|
|
HeaderSettings.BottomHeight = value * LayerHeight;
|
|
base.BottomLayerCount = value;
|
|
}
|
|
}
|
|
|
|
public override float BottomLightOffDelay
|
|
{
|
|
get => TimeConverter.MillisecondsToSeconds(HeaderSettings.BottomLightOffDelayMs);
|
|
set
|
|
{
|
|
HeaderSettings.BottomLightOffDelayMs = TimeConverter.SecondsToMilliseconds(value);
|
|
base.BottomLightOffDelay = value;
|
|
}
|
|
}
|
|
|
|
public override float LightOffDelay
|
|
{
|
|
get => TimeConverter.MillisecondsToSeconds(HeaderSettings.LightOffDelayMs);
|
|
set
|
|
{
|
|
HeaderSettings.LightOffDelayMs = TimeConverter.SecondsToMilliseconds(value);
|
|
base.LightOffDelay = value;
|
|
}
|
|
}
|
|
|
|
public override float BottomWaitTimeBeforeCure
|
|
{
|
|
get => base.BottomWaitTimeBeforeCure;
|
|
set
|
|
{
|
|
SetBottomLightOffDelay(value);
|
|
base.BottomWaitTimeBeforeCure = value;
|
|
}
|
|
}
|
|
|
|
public override float WaitTimeBeforeCure
|
|
{
|
|
get => base.WaitTimeBeforeCure;
|
|
set
|
|
{
|
|
SetNormalLightOffDelay(value);
|
|
base.WaitTimeBeforeCure = value;
|
|
}
|
|
}
|
|
|
|
public override float BottomExposureTime
|
|
{
|
|
get => TimeConverter.MillisecondsToSeconds(HeaderSettings.BottomExposureTimeMs);
|
|
set
|
|
{
|
|
HeaderSettings.BottomExposureTimeMs = TimeConverter.SecondsToMilliseconds(value);
|
|
base.BottomExposureTime = value;
|
|
}
|
|
}
|
|
|
|
public override float ExposureTime
|
|
{
|
|
get => TimeConverter.MillisecondsToSeconds(HeaderSettings.ExposureTimeMs);
|
|
set
|
|
{
|
|
HeaderSettings.ExposureTimeMs = TimeConverter.SecondsToMilliseconds(value);
|
|
base.ExposureTime = value;
|
|
}
|
|
}
|
|
|
|
public override float BottomLiftHeight
|
|
{
|
|
get => HeaderSettings.BottomLiftHeight;
|
|
set => base.BottomLiftHeight = HeaderSettings.BottomLiftHeight = value;
|
|
}
|
|
|
|
public override float LiftHeight
|
|
{
|
|
get => HeaderSettings.LiftHeight;
|
|
set => base.LiftHeight = HeaderSettings.LiftHeight = value;
|
|
}
|
|
|
|
public override float BottomLiftSpeed
|
|
{
|
|
get => HeaderSettings.BottomLiftSpeed;
|
|
set => base.BottomLiftSpeed = HeaderSettings.BottomLiftSpeed = HeaderSettings.BottomLiftSpeed_ = value;
|
|
}
|
|
|
|
public override float LiftSpeed
|
|
{
|
|
get => HeaderSettings.LiftSpeed;
|
|
set => base.LiftSpeed = HeaderSettings.LiftSpeed = HeaderSettings.LiftSpeed_ = value;
|
|
}
|
|
|
|
public override float BottomRetractSpeed => RetractSpeed;
|
|
|
|
public override float RetractSpeed => LiftSpeed;
|
|
|
|
/*public override float PrintTime => 0;
|
|
|
|
public override float UsedMaterial => 0;
|
|
|
|
public override float MaterialCost => 0;
|
|
|
|
public override string MaterialName => "Unknown";
|
|
public override string MachineName => null;*/
|
|
|
|
|
|
public override object[] Configs => new object[] { HeaderSettings };
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
public LGSFile()
|
|
{
|
|
}
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
protected override void EncodeInternally(OperationProgress progress)
|
|
{
|
|
if (FileEndsWith(".lgs")) // Longer Orange 10
|
|
{
|
|
MachineZ = 140;
|
|
HeaderSettings.PrinterModel = 10;
|
|
}
|
|
else if (FileEndsWith(".lgs30")) // Longer Orange 30
|
|
{
|
|
MachineZ = 170;
|
|
HeaderSettings.PrinterModel = 30;
|
|
}
|
|
else if (FileEndsWith(".lgs120")) // Longer Orange 120
|
|
{
|
|
MachineZ = 150;
|
|
HeaderSettings.PrinterModel = 120;
|
|
}
|
|
else if (FileEndsWith(".lgs4k")) // Longer Orange 4K & Mono
|
|
{
|
|
MachineZ = 190;
|
|
if(HeaderSettings.PrinterModel is not 4000 and not 4500) HeaderSettings.PrinterModel = 4500;
|
|
}
|
|
|
|
//uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
|
|
using (var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write))
|
|
{
|
|
outputFile.WriteSerialize(HeaderSettings);
|
|
outputFile.WriteBytes(EncodeImage(DATATYPE_RGB565_BE, Thumbnails[0]!));
|
|
|
|
if (HeaderSettings.PrinterModel == 120)
|
|
{
|
|
// Insert PNG here
|
|
var mat = GetThumbnail(true);
|
|
var pngPreview = new LGS120PngPreview();
|
|
pngPreview.Encode(mat!);
|
|
outputFile.WriteSerialize(pngPreview);
|
|
}
|
|
|
|
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
|
|
var layerData = new LayerDef[LayerCount];
|
|
|
|
foreach (var batch in BatchLayersIndexes())
|
|
{
|
|
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
|
{
|
|
using (var mat = this[layerIndex].LayerMat)
|
|
{
|
|
layerData[layerIndex] = new LayerDef(this);
|
|
layerData[layerIndex].Encode(mat);
|
|
}
|
|
progress.LockAndIncrement();
|
|
});
|
|
|
|
foreach (var layerIndex in batch)
|
|
{
|
|
progress.ThrowIfCancellationRequested();
|
|
outputFile.WriteSerialize(layerData[layerIndex]);
|
|
layerData[layerIndex].EncodedRle = null!; // Free this
|
|
}
|
|
}
|
|
|
|
|
|
progress.ItemName = "Saving layers";
|
|
progress.ProcessedItems = 0;
|
|
|
|
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
|
{
|
|
progress.ThrowIfCancellationRequested();
|
|
outputFile.WriteSerialize(layerData[layerIndex]);
|
|
progress++;
|
|
}
|
|
}
|
|
|
|
Debug.WriteLine("Encode Results:");
|
|
Debug.WriteLine(HeaderSettings);
|
|
Debug.WriteLine("-End-");
|
|
}
|
|
|
|
protected override void DecodeInternally(OperationProgress progress)
|
|
{
|
|
using var inputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Read);
|
|
HeaderSettings = Helpers.Deserialize<Header>(inputFile);
|
|
if (HeaderSettings.Name != Header.NameValue)
|
|
{
|
|
throw new FileLoadException("Not a valid LGS file!", FileFullPath);
|
|
}
|
|
|
|
//if (HeaderSettings.PrinterModel is 10 or 30 or 120)
|
|
//{
|
|
// Fix inconsistencies found of different version of plugin and slicers
|
|
if (ResolutionX > ResolutionY)
|
|
{
|
|
(ResolutionX, ResolutionY) = (ResolutionY, ResolutionX);
|
|
}
|
|
//}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial);
|
|
var layerData = new LayerDef[LayerCount];
|
|
|
|
if (DecodeType == FileDecodeType.Full)
|
|
{
|
|
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
|
|
foreach (var batch in BatchLayersIndexes())
|
|
{
|
|
foreach (var layerIndex in batch)
|
|
{
|
|
progress.ThrowIfCancellationRequested();
|
|
|
|
layerData[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
|
layerData[layerIndex].Parent = this;
|
|
}
|
|
|
|
Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex =>
|
|
{
|
|
using var mat = layerData[layerIndex].Decode();
|
|
_layers[layerIndex] = new Layer((uint)layerIndex, mat, this);
|
|
|
|
progress.LockAndIncrement();
|
|
});
|
|
}
|
|
}
|
|
|
|
RebuildLayersProperties();
|
|
}
|
|
|
|
protected override void PartialSaveInternally(OperationProgress progress)
|
|
{
|
|
using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Open, FileAccess.Write);
|
|
outputFile.Seek(0, SeekOrigin.Begin);
|
|
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
|
|
}
|
|
|
|
#endregion
|
|
} |