From 9ef6ab40894f079d8a560628fc05b41e9a13df43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sun, 1 Jan 2023 20:24:19 +0000 Subject: [PATCH] Add support for Anet N7 Modify file format to accept multiple anet printers with different resolutions. --- UVtools.Core/FileFormats/AnetFile.cs | 159 +++++++++++++++------------ 1 file changed, 90 insertions(+), 69 deletions(-) diff --git a/UVtools.Core/FileFormats/AnetFile.cs b/UVtools.Core/FileFormats/AnetFile.cs index a80e161..9b82507 100644 --- a/UVtools.Core/FileFormats/AnetFile.cs +++ b/UVtools.Core/FileFormats/AnetFile.cs @@ -13,11 +13,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; +using System.Linq; using System.Threading.Tasks; using UVtools.Core.Converters; using UVtools.Core.Extensions; using UVtools.Core.Layers; using UVtools.Core.Operations; +using UVtools.Core.Printer; namespace UVtools.Core.FileFormats; @@ -30,12 +32,19 @@ public sealed class AnetFile : FileFormat { #region Constants - public const ushort RESOLUTION_X = 1440; - public const ushort RESOLUTION_Y = 2560; + public const ushort RESOLUTION_N4_X = 1440; + public const ushort RESOLUTION_N4_Y = 2560; - public const float DISPLAY_WIDTH = 68.04f; - public const float DISPLAY_HEIGHT = 120.96f; - public const float MACHINE_Z = 135f; + public const float DISPLAY_N4_WIDTH = 68.04f; + public const float DISPLAY_N4_HEIGHT = 120.96f; + public const float MACHINE_N4_Z = 135f; + + public const ushort RESOLUTION_N7_X = 2560; + public const ushort RESOLUTION_N7_Y = 1600; + + public const float DISPLAY_N7_WIDTH = 192f; + public const float DISPLAY_N7_HEIGHT = 120f; + public const float MACHINE_N7_Z = 300f; /// /// Printer uses incorrect BMP header for preview image so we need to use it as-is instead of generating. @@ -44,13 +53,13 @@ public sealed class AnetFile : FileFormat #endregion - #region Members + #region Enums - private uint _resolutionX = RESOLUTION_X; - private uint _resolutionY = RESOLUTION_Y; - - private float _displayWidth = DISPLAY_WIDTH; - private float _displayHeight = DISPLAY_HEIGHT; + public enum AnetPrinter : byte + { + N4, + N7 + } #endregion @@ -58,7 +67,7 @@ public sealed class AnetFile : FileFormat #region Header - public class Header + public class AnetHeader { [FieldOrder(0)][FieldEndianness(Endianness.Big)] public int VersionLength { get; set; } = 2; [FieldOrder(1)][FieldEncoding("UTF-16BE")][FieldLength(nameof(VersionLength))] public string Version { get; set; } = "3"; @@ -155,10 +164,11 @@ public sealed class AnetFile : FileFormat } } - if (mat.Width != RESOLUTION_X || mat.Height != RESOLUTION_Y) + // Format does not have a global resolution field but supports multiple resolutions + /*if (mat.Width != RESOLUTION_X || mat.Height != RESOLUTION_Y) { throw new ArgumentException($"Anet N4 support only {RESOLUTION_X}x{RESOLUTION_Y} image, got {mat.Width}x{mat.Height}"); - } + }*/ WhitePixelsCount = 0; uint singleColorLength = 0; @@ -205,7 +215,7 @@ public sealed class AnetFile : FileFormat return EncodedRle; } - public Mat Decode(bool consumeRle = true) + public Mat Decode(out uint resolutionX, out uint resolutionY, bool consumeRle = true) { uint GetBits(uint pos, uint count = 1) { @@ -231,10 +241,10 @@ public sealed class AnetFile : FileFormat throw new IndexOutOfRangeException($"Incorrect RLE data size {EncodedRle.Length * 8}, except {BitsCount} bits."); } - uint rleWidth = GetBits(0, 16); - uint rleHeight = GetBits(16, 16); + resolutionX = GetBits(0, 16); + resolutionY = GetBits(16, 16); - var mat = EmguExtensions.InitMat(new Size((int)rleWidth, (int)rleHeight)); + var mat = EmguExtensions.InitMat(new Size((int)resolutionX, (int)resolutionY)); var imageLength = mat.GetLength(); byte brightness = (byte)((GetBits(32) == 1) ? 0xff : 0x0); @@ -261,11 +271,15 @@ public sealed class AnetFile : FileFormat #region Properties - public Header HeaderSettings { get; private set; } = new(); + public AnetHeader HeaderSettings { get; private set; } = new(); + public override FileFormatType FileType => FileFormatType.Binary; + public override string ConvertMenuGroup => "Anet"; + public override FileExtension[] FileExtensions { get; } = { new(typeof(AnetFile), "n4", "Anet N4"), + new(typeof(AnetFile), "n7", "Anet N7"), }; public override SpeedUnit FormatSpeedUnit => SpeedUnit.MillimetersPerSecond; @@ -283,48 +297,6 @@ public sealed class AnetFile : FileFormat public override Size[]? ThumbnailsOriginalSize { get; } = { new(260, 140) }; - public override uint ResolutionX - { - get => _resolutionX; - set - { - if (!RaiseAndSetIfChanged(ref _resolutionX, value)) return; - if(value != RESOLUTION_X) throw new ArgumentException($"Anet N4 support only {RESOLUTION_X}x{RESOLUTION_Y} image, got {ResolutionX}x{ResolutionY}"); - HeaderSettings.XYPixelSize = PixelSizeMax; - } - } - - public override uint ResolutionY - { - get => _resolutionY; - set - { - if (!RaiseAndSetIfChanged(ref _resolutionY, value)) return; - if (value != RESOLUTION_Y) throw new ArgumentException($"Anet N4 support only {RESOLUTION_X}x{RESOLUTION_Y} image, got {ResolutionX}x{ResolutionY}"); - HeaderSettings.XYPixelSize = PixelSizeMax; - } - } - - public override float DisplayWidth - { - get => _displayWidth; - set - { - if (!RaiseAndSetIfChanged(ref _displayWidth, value)) return; - HeaderSettings.XYPixelSize = PixelSizeMax; - } - } - - public override float DisplayHeight - { - get => _displayHeight; - set - { - if (!RaiseAndSetIfChanged(ref _displayHeight, value)) return; - HeaderSettings.XYPixelSize = PixelSizeMax; - } - } - public override FlipDirection DisplayMirror { get => FlipDirection.Horizontally; @@ -409,21 +381,53 @@ public sealed class AnetFile : FileFormat } } - public override string MachineName => "Anet N4"; - public override object[] Configs => new object[] { HeaderSettings }; + public AnetPrinter PrinterModel + { + get + { + if (FileEndsWith(".n4")) + { + return AnetPrinter.N4; + } + + if (FileEndsWith(".n7")) + { + return AnetPrinter.N7; + } + + return AnetPrinter.N4; + } + } + #endregion #region Constructors - public AnetFile() - { - MachineZ = MACHINE_Z; - } + + public AnetFile() { } #endregion #region Methods + protected override void OnBeforeEncode(bool isPartialEncode) + { + switch (PrinterModel) + { + case AnetPrinter.N4: + if (ResolutionX != RESOLUTION_N4_X || ResolutionY != RESOLUTION_N4_Y) + throw new ArgumentException($"Anet N4 support only {RESOLUTION_N4_X}x{RESOLUTION_N4_Y} image, got {ResolutionX}x{ResolutionY}"); + break; + case AnetPrinter.N7: + if (ResolutionX != RESOLUTION_N7_X || ResolutionY != RESOLUTION_N7_Y) + throw new ArgumentException($"Anet N7 support only {RESOLUTION_N7_X}x{RESOLUTION_N7_Y} image, got {ResolutionX}x{ResolutionY}"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(PrinterModel), FileExtension); + } + HeaderSettings.XYPixelSize = PixelSizeMax; + } + protected override void EncodeInternally(OperationProgress progress) { using var outputFile = new FileStream(TemporaryOutputFileFullPath, FileMode.Create, FileAccess.Write); @@ -479,7 +483,7 @@ public sealed class AnetFile : FileFormat protected override void DecodeInternally(OperationProgress progress) { using var inputFile = new FileStream(FileFullPath!, FileMode.Open, FileAccess.Read); - HeaderSettings = Helpers.Deserialize
(inputFile); + HeaderSettings = Helpers.Deserialize(inputFile); if (HeaderSettings.Version is not "3") { throw new FileLoadException($"Not a valid N4 file: Version doesn't match, got {HeaderSettings.Version} instead of 3)", FileFullPath); @@ -524,7 +528,24 @@ public sealed class AnetFile : FileFormat { Parallel.ForEach(batch, CoreSettings.GetParallelOptions(progress), layerIndex => { - using var mat = layersDefinitions[layerIndex].Decode(); + using var mat = layersDefinitions[layerIndex].Decode(out var resolutionX, out var resolutionY); + if (layerIndex == 0) // Set file resolution from first layer RLE. Figure out other properties after that + { + ResolutionX = resolutionX; + ResolutionY = resolutionY; + + var machine = Machine.Machines.FirstOrDefault(machine => + machine.Brand == PrinterBrand.Anet && machine.ResolutionX == resolutionX && + machine.ResolutionY == resolutionY); + + if (machine is not null) + { + DisplayWidth = machine.DisplayWidth; + DisplayHeight = machine.DisplayHeight; + MachineZ = machine.MachineZ; + MachineName = machine.Name; + } + } _layers[layerIndex] = new Layer((uint)layerIndex, mat, this); progress.LockAndIncrement(); });