mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
Pre0.2 commit
This commit is contained in:
+535
-95
@@ -5,165 +5,605 @@
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using BinarySerialization;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Advanced;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
public class CbddlpFile : FileFormat
|
||||
{
|
||||
const uint SPI_FILE_MAGIC_BASE = 0x12FD0000;
|
||||
const int SPECIAL_BIT = 1 << 1;
|
||||
const int SPECIAL_BIT_MASK = ~SPECIAL_BIT;
|
||||
#region Constants
|
||||
private const uint SPI_FILE_MAGIC_BASE = 0x12FD0019;
|
||||
private const int SPECIAL_BIT = 1 << 1;
|
||||
private const int SPECIAL_BIT_MASK = ~SPECIAL_BIT;
|
||||
private const ushort REPEATRGB15MASK = (1 << 5);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct Header
|
||||
private const byte RLE8EncodingLimit = 125;
|
||||
private const ushort RLE16EncodingLimit = 0x1000;
|
||||
#endregion
|
||||
|
||||
#region Sub Classes
|
||||
#region Header
|
||||
public class Header
|
||||
{
|
||||
public uint Magic;
|
||||
public uint Version;
|
||||
public float BedSizeX;
|
||||
public float BedSizeY;
|
||||
public float BedSizeZ;
|
||||
public uint Unknown1;
|
||||
public uint Unknown2;
|
||||
public uint Unknown3;
|
||||
public float LayerHeightMilimeter;
|
||||
public float LayerExposureSeconds;
|
||||
public float BottomExposureSeconds;
|
||||
public float LayerOffTime;
|
||||
public uint BottomLayersCount;
|
||||
public uint ResolutionX;
|
||||
public uint ResolutionY;
|
||||
public uint PreviewOneOffsetAddress;
|
||||
public uint LayersDefinitionOffsetAddress;
|
||||
public uint LayerCount;
|
||||
public uint PreviewTwoOffsetAddress;
|
||||
public uint PrintTime;
|
||||
public uint ProjectorType;
|
||||
public uint PrintParametersOffsetAddress;
|
||||
public uint PrintParametersSize;
|
||||
public uint AntiAliasLevel;
|
||||
public ushort LightPWM;
|
||||
public ushort BottomLightPWM;
|
||||
public uint Padding1;
|
||||
public uint Padding2;
|
||||
public uint Padding3;
|
||||
|
||||
[FieldOrder(0)] public uint Magic { get; set; } // 00
|
||||
[FieldOrder(1)] public uint Version { get; set; } // 04
|
||||
[FieldOrder(2)] public float BedSizeX { get; set; } // 08
|
||||
[FieldOrder(3)] public float BedSizeY { get; set; } // 12
|
||||
[FieldOrder(4)] public float BedSizeZ { get; set; } // 20
|
||||
[FieldOrder(5)] public uint Unknown1 { get; set; }
|
||||
[FieldOrder(6)] public uint Unknown2 { get; set; }
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public float LayerHeightMilimeter { get; set; } // 20
|
||||
[FieldOrder(9)] public float LayerExposureSeconds { get; set; } // 24: Layer exposure (in seconds)
|
||||
[FieldOrder(10)] public float BottomExposureSeconds { get; set; } // 28: Bottom layers exporsure (in seconds)
|
||||
[FieldOrder(11)] public float LayerOffTime { get; set; } // 2c: Layer off time (in seconds)
|
||||
[FieldOrder(12)] public uint BottomLayersCount { get; set; } // 30: Number of bottom layers
|
||||
[FieldOrder(13)] public uint ResolutionX { get; set; } // 34:
|
||||
[FieldOrder(14)] public uint ResolutionY { get; set; } // 38:
|
||||
[FieldOrder(15)] public uint PreviewOneOffsetAddress { get; set; }// 3c: Offset of the high-res preview
|
||||
[FieldOrder(16)] public uint LayersDefinitionOffsetAddress { get; set; }// 40: Offset of the layer definitions
|
||||
[FieldOrder(17)] public uint LayerCount { get; set; } // 44:
|
||||
[FieldOrder(18)] public uint PreviewTwoOffsetAddress { get; set; }// 48: Offset of the low-rew preview
|
||||
[FieldOrder(19)] public uint PrintTime { get; set; } // 4c: In seconds
|
||||
[FieldOrder(20)] public uint ProjectorType { get; set; } // 0 = CAST, 1 = LCD_X_MIRROR
|
||||
[FieldOrder(21)] public uint PrintParametersOffsetAddress { get; set; } // 54:
|
||||
[FieldOrder(22)] public uint PrintParametersSize { get; set; } // 58:
|
||||
[FieldOrder(23)] public uint AntiAliasLevel { get; set; } // 5c:
|
||||
[FieldOrder(24)] public ushort LightPWM { get; set; } // 60:
|
||||
[FieldOrder(25)] public ushort BottomLightPWM { get; set; } // 62:
|
||||
[FieldOrder(26)] public uint Padding1 { get; set; }
|
||||
[FieldOrder(27)] public uint Padding2 { get; set; }
|
||||
[FieldOrder(28)] public uint Padding3 { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(Magic)}: {Magic}, {nameof(Version)}: {Version}, {nameof(BedSizeX)}: {BedSizeX}, {nameof(BedSizeY)}: {BedSizeY}, {nameof(BedSizeZ)}: {BedSizeZ}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(LayerHeightMilimeter)}: {LayerHeightMilimeter}, {nameof(LayerExposureSeconds)}: {LayerExposureSeconds}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(LayerOffTime)}: {LayerOffTime}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(PreviewOneOffsetAddress)}: {PreviewOneOffsetAddress}, {nameof(LayersDefinitionOffsetAddress)}: {LayersDefinitionOffsetAddress}, {nameof(LayerCount)}: {LayerCount}, {nameof(PreviewTwoOffsetAddress)}: {PreviewTwoOffsetAddress}, {nameof(PrintTime)}: {PrintTime}, {nameof(ProjectorType)}: {ProjectorType}, {nameof(PrintParametersOffsetAddress)}: {PrintParametersOffsetAddress}, {nameof(PrintParametersSize)}: {PrintParametersSize}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(LightPWM)}: {LightPWM}, {nameof(BottomLightPWM)}: {BottomLightPWM}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct PrintParameters
|
||||
#region PrintParameters
|
||||
public class PrintParameters
|
||||
{
|
||||
public float BottomLiftHeight;
|
||||
public float BottomLiftSpeed;
|
||||
public float LiftHeight;
|
||||
public float LiftingSpeed;
|
||||
public float RetractSpeed;
|
||||
public float VolumeMl;
|
||||
public float WeightG;
|
||||
public float CostDollars;
|
||||
public float BottomLightOffDelay;
|
||||
public float LightOffDelay;
|
||||
public uint BottomLayerCount;
|
||||
public uint P1;
|
||||
public uint P2;
|
||||
public uint P3;
|
||||
public uint P4;
|
||||
[FieldOrder(0)] public float BottomLiftHeight { get; set; }
|
||||
[FieldOrder(1)] public float BottomLiftSpeed { get; set; }
|
||||
[FieldOrder(2)] public float LiftHeight { get; set; }
|
||||
[FieldOrder(3)] public float LiftingSpeed { get; set; }
|
||||
[FieldOrder(4)] public float RetractSpeed { get; set; }
|
||||
[FieldOrder(5)] public float VolumeMl { get; set; }
|
||||
[FieldOrder(6)] public float WeightG { get; set; }
|
||||
[FieldOrder(7)] public float CostDollars { get; set; }
|
||||
[FieldOrder(8)] public float BottomLightOffDelay { get; set; }
|
||||
[FieldOrder(9)] public float LightOffDelay { get; set; }
|
||||
[FieldOrder(10)] public uint BottomLayerCount { get; set; }
|
||||
[FieldOrder(11)] public uint P1 { get; set; }
|
||||
[FieldOrder(12)] public uint P2 { get; set; }
|
||||
[FieldOrder(13)] public uint P3 { get; set; }
|
||||
[FieldOrder(14)] public uint P4 { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(BottomLiftHeight)}: {BottomLiftHeight}, {nameof(BottomLiftSpeed)}: {BottomLiftSpeed}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftingSpeed)}: {LiftingSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(VolumeMl)}: {VolumeMl}, {nameof(WeightG)}: {WeightG}, {nameof(CostDollars)}: {CostDollars}, {nameof(BottomLightOffDelay)}: {BottomLightOffDelay}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(BottomLayerCount)}: {BottomLayerCount}, {nameof(P1)}: {P1}, {nameof(P2)}: {P2}, {nameof(P3)}: {P3}, {nameof(P4)}: {P4}";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct Layer
|
||||
#region MachineInfo
|
||||
|
||||
public class MachineInfo
|
||||
{
|
||||
public float LayerPositionZ;
|
||||
public float LayerExposure;
|
||||
public float LayerOffTimeSeconds;
|
||||
public uint DataAddress;
|
||||
public uint DataSize;
|
||||
public uint Unknown1;
|
||||
public uint Unknown2;
|
||||
public uint Unknown3;
|
||||
public uint Unknown4;
|
||||
[FieldOrder(0)] public uint d1 { get; set; }
|
||||
[FieldOrder(1)] public uint d2 { get; set; }
|
||||
[FieldOrder(2)] public uint d3 { get; set; }
|
||||
[FieldOrder(3)] public uint d4 { get; set; }
|
||||
[FieldOrder(4)] public uint d5 { get; set; }
|
||||
[FieldOrder(5)] public uint d6 { get; set; }
|
||||
[FieldOrder(6)] public uint d7 { get; set; }
|
||||
[FieldOrder(7)] public uint MachineNameAddress { get; set; }
|
||||
[FieldOrder(8)] public uint MachineNameSize { get; set; }
|
||||
[FieldOrder(9)] public uint d8 { get; set; }
|
||||
[FieldOrder(10)] public uint d9 { get; set; }
|
||||
[FieldOrder(11)] public uint d10 { get; set; }
|
||||
[FieldOrder(12)] public uint d11 { get; set; }
|
||||
[FieldOrder(13)] public uint d12 { get; set; }
|
||||
[FieldOrder(14)] public uint d13 { get; set; }
|
||||
[FieldOrder(15)] public uint d14 { get; set; }
|
||||
[FieldOrder(16)] public uint d15 { get; set; }
|
||||
[FieldOrder(17)] public uint d16 { get; set; }
|
||||
[FieldOrder(18)] public uint d17 { get; set; }
|
||||
|
||||
[FieldOrder(19)] [FieldLength(nameof(MachineNameSize))]
|
||||
public string MachineName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(d1)}: {d1}, {nameof(d2)}: {d2}, {nameof(d3)}: {d3}, {nameof(d4)}: {d4}, {nameof(d5)}: {d5}, {nameof(d6)}: {d6}, {nameof(d7)}: {d7}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(d8)}: {d8}, {nameof(d9)}: {d9}, {nameof(d10)}: {d10}, {nameof(d11)}: {d11}, {nameof(d12)}: {d12}, {nameof(d13)}: {d13}, {nameof(d14)}: {d14}, {nameof(d15)}: {d15}, {nameof(d16)}: {d16}, {nameof(d17)}: {d17}, {nameof(MachineName)}: {MachineName}";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preview
|
||||
public class Preview
|
||||
{
|
||||
[FieldOrder(0)] public uint ResolutionX { get; set; }
|
||||
[FieldOrder(1)] public uint ResolutionY { get; set; }
|
||||
[FieldOrder(2)] public uint ImageOffset { get; set; }
|
||||
[FieldOrder(3)] public uint ImageLength { 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; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(ImageOffset)}: {ImageOffset}, {nameof(ImageLength)}: {ImageLength}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Layer
|
||||
public class Layer
|
||||
{
|
||||
[FieldOrder(0)] public float LayerPositionZ { get; set; }
|
||||
[FieldOrder(1)] public float LayerExposure { get; set; }
|
||||
[FieldOrder(2)] public float LayerOffTimeSeconds { get; set; }
|
||||
[FieldOrder(3)] public uint DataAddress { get; set; }
|
||||
[FieldOrder(4)] public uint DataSize { get; set; }
|
||||
[FieldOrder(5)] public uint Unknown1 { get; set; }
|
||||
[FieldOrder(6)] public uint Unknown2 { get; set; }
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public uint Unknown4 { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(LayerPositionZ)}: {LayerPositionZ}, {nameof(LayerExposure)}: {LayerExposure}, {nameof(LayerOffTimeSeconds)}: {LayerOffTimeSeconds}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public Header HeaderSettings { get; private set; }
|
||||
public PrintParameters PrintParametersSettings { get; private set; }
|
||||
#endregion
|
||||
|
||||
public List<Layer> Layers { get; } = new List<Layer>();
|
||||
#region Properties
|
||||
|
||||
public FileStream InputFile { get; private set; }
|
||||
public FileStream OutputFile { get; private set; }
|
||||
public Header HeaderSettings { get; protected internal set; }
|
||||
public PrintParameters PrintParametersSettings { get; protected internal set; }
|
||||
|
||||
public override string FileExtension { get; } = "cbddlp";
|
||||
public override string FileExtensionName { get; } = "Chitubox DLP Files";
|
||||
public override void Load(string fileFullPath)
|
||||
public MachineInfo MachineInfoSettings { get; protected internal set; }
|
||||
//public string MachineName { get; protected internal set; }
|
||||
|
||||
public Preview[] Previews { get; protected internal set; }
|
||||
|
||||
public Layer[,] Layers { get; private set; }
|
||||
|
||||
private uint CurrentOffset { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public CbddlpFile()
|
||||
{
|
||||
FileValidation(fileFullPath);
|
||||
FileFullPath = fileFullPath;
|
||||
Previews = new Preview[ThumbnailsCount];
|
||||
}
|
||||
#endregion
|
||||
|
||||
Layers.Clear();
|
||||
#region Overrides
|
||||
|
||||
BinaryReader binReader = new BinaryReader(File.Open(FileFullPath, FileMode.Open));
|
||||
public override string FileFullPath { get; protected set; }
|
||||
|
||||
public override FileExtension[] ValidFiles { get; } = {
|
||||
new FileExtension("cbddlp", "Chitubox DLP Files"),
|
||||
};
|
||||
public override byte ThumbnailsCount { get; } = 2;
|
||||
public override Image<Rgba32>[] Thumbnails { get; protected internal set; }
|
||||
|
||||
public override void BeginEncode(string fileFullPath)
|
||||
{
|
||||
CurrentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
|
||||
Layers = new Layer[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel];
|
||||
OutputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write);
|
||||
|
||||
HeaderSettings.Magic = SPI_FILE_MAGIC_BASE;
|
||||
//HeaderSettings.PreviewOneOffsetAddress = CurrentOffset;
|
||||
HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
|
||||
|
||||
Helpers.SerializeWriteFileStream(OutputFile, HeaderSettings);
|
||||
|
||||
//OutputFile.Seek((int)HeaderSettings.PreviewOneOffsetAddress, SeekOrigin.Begin);
|
||||
|
||||
HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(binReader);
|
||||
if (HeaderSettings.Magic != (SPI_FILE_MAGIC_BASE | 0x19))
|
||||
|
||||
/*for (int i = 0; i < ThumbnailsCount; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
{
|
||||
HeaderSettings.PreviewTwoOffsetAddress = CurrentOffset;
|
||||
}
|
||||
var image = Thumbnails[i];
|
||||
Preview preview = new Preview {ResolutionX = (uint)image.Width, ResolutionY = (uint)image.Height};
|
||||
List<byte> rawData = new List<byte>();
|
||||
|
||||
Rgba32 color;
|
||||
byte nrOfColor = 0;
|
||||
Rgba32? prevColor = null;
|
||||
|
||||
for (int y = 0; y < image.Height; y++)
|
||||
{
|
||||
Span<Rgba32> pixelRowSpan = image.GetPixelRowSpan(y);
|
||||
for (int x = 0; x < image.Width; x++)
|
||||
{
|
||||
color = pixelRowSpan[x];
|
||||
if (prevColor == null) prevColor = color;
|
||||
bool isLastPixel = x == (image.Width - 1) && y == (image.Height - 1);
|
||||
if (color == prevColor && nrOfColor < 0x0FFF && !isLastPixel)
|
||||
{
|
||||
nrOfColor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
byte R = prevColor.Value.R;
|
||||
byte G = prevColor.Value.G;
|
||||
byte B = prevColor.Value.B;
|
||||
byte X = nrOfColor > 1 ? (byte)1 : (byte)0;
|
||||
|
||||
|
||||
// build 2 or 4 bytes (depending on X
|
||||
// The color (R,G,B) of a pixel spans 2 bytes (little endian) and
|
||||
// each color component is 5 bits: RRRRR GGG GG X BBBBB
|
||||
R = (byte)Math.Round(R / 255f * 31f);
|
||||
G = (byte)Math.Round(G / 255f * 31f);
|
||||
B = (byte)Math.Round(B / 255f * 31f);
|
||||
|
||||
byte encValue0 = (byte)(R << 3 | G >> 2);
|
||||
byte encValue1 = (byte) (((G & 0b00000011) << 6) | X << 5 | B);
|
||||
rawData.Add(encValue0);
|
||||
rawData.Add(encValue1);
|
||||
if (X == 1)
|
||||
{
|
||||
nrOfColor--;
|
||||
// write one less than nr of pixels
|
||||
byte encValue2 = (byte)(nrOfColor >> 8);
|
||||
byte encValue3 = (byte)(nrOfColor & 0b000000011111111);
|
||||
// seems like nr bytes pixels have 0011 as start
|
||||
encValue2 = (byte)(encValue2 | 0b00110000);
|
||||
rawData.Add(encValue2);
|
||||
rawData.Add(encValue3);
|
||||
}
|
||||
|
||||
prevColor = color;
|
||||
nrOfColor = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
preview.ImageLength = (uint)rawData.Count;
|
||||
CurrentOffset += (uint)Helpers.Serializer.SizeOf(preview);
|
||||
preview.ImageOffset = CurrentOffset;
|
||||
|
||||
Previews[i] = preview;
|
||||
|
||||
using (MemoryStream stream = Helpers.Serialize(preview))
|
||||
{
|
||||
OutputFile.Write(stream.GetBuffer());
|
||||
}
|
||||
|
||||
OutputFile.Write(rawData.ToArray());
|
||||
|
||||
CurrentOffset += (uint)rawData.Count;
|
||||
}
|
||||
*/
|
||||
|
||||
if (HeaderSettings.Version == 2)
|
||||
{
|
||||
HeaderSettings.PrintParametersOffsetAddress = CurrentOffset;
|
||||
|
||||
Helpers.SerializeWriteFileStream(OutputFile, PrintParametersSettings);
|
||||
|
||||
CurrentOffset += (uint) (Helpers.Serializer.SizeOf(PrintParametersSettings) +
|
||||
Helpers.Serializer.SizeOf(MachineInfoSettings) -
|
||||
MachineInfoSettings.MachineNameSize);
|
||||
|
||||
MachineInfoSettings.MachineNameAddress = CurrentOffset;
|
||||
|
||||
Helpers.SerializeWriteFileStream(OutputFile, MachineInfoSettings);
|
||||
|
||||
CurrentOffset += MachineInfoSettings.MachineNameSize;
|
||||
}
|
||||
|
||||
HeaderSettings.LayersDefinitionOffsetAddress = CurrentOffset;
|
||||
}
|
||||
|
||||
public override void InsertLayerImageEncode(Image<Gray8> image, uint layerIndex)
|
||||
{
|
||||
Layer layer = new Layer();
|
||||
List<byte> rawData = new List<byte>();
|
||||
|
||||
byte color = 0;
|
||||
byte black = 0;
|
||||
byte white = 1;
|
||||
|
||||
byte nrOfColor = 0;
|
||||
byte prevColor = byte.MaxValue;
|
||||
|
||||
for (int y = 0; y < image.Height; y++)
|
||||
{
|
||||
Span<Gray8> pixelRowSpan = image.GetPixelRowSpan(y);
|
||||
for (int x = 0; x < image.Width; x++)
|
||||
{
|
||||
color = pixelRowSpan[x].PackedValue < 128 ? black : white;
|
||||
if (prevColor == byte.MaxValue) prevColor = color;
|
||||
bool isLastPixel = x == (image.Width - 1) && y == (image.Height - 1);
|
||||
|
||||
if (color == prevColor && nrOfColor< 0x7D && !isLastPixel)
|
||||
{
|
||||
nrOfColor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte encValue = (byte)((prevColor << 7) | nrOfColor); // push color (B/W) to highest bit and repetitions to lowest 7 bits.
|
||||
rawData.Add(encValue);
|
||||
prevColor = color;
|
||||
nrOfColor = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurrentOffset += (uint)Helpers.Serializer.SizeOf(layer);
|
||||
|
||||
layer.DataAddress = CurrentOffset;
|
||||
layer.DataSize = (uint)rawData.Count;
|
||||
layer.LayerPositionZ = layerIndex * HeaderSettings.LayerHeightMilimeter;
|
||||
layer.LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? PrintParametersSettings.BottomLightOffDelay : PrintParametersSettings.LightOffDelay;
|
||||
layer.LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds;
|
||||
Layers[layerIndex, 0] = layer;
|
||||
|
||||
Helpers.SerializeWriteFileStream(OutputFile, layer);
|
||||
Helpers.WriteFileStream(OutputFile, rawData.ToArray());
|
||||
|
||||
CurrentOffset += (uint)rawData.Count;
|
||||
}
|
||||
|
||||
public override void EndEncode()
|
||||
{
|
||||
|
||||
OutputFile.Seek(0, SeekOrigin.Begin);
|
||||
Helpers.SerializeWriteFileStream(OutputFile, HeaderSettings);
|
||||
|
||||
OutputFile.Close();
|
||||
OutputFile.Dispose();
|
||||
|
||||
Debug.WriteLine("Encode Results:");
|
||||
Debug.WriteLine(HeaderSettings);
|
||||
Debug.WriteLine(Previews[0]);
|
||||
Debug.WriteLine(Previews[1]);
|
||||
Debug.WriteLine(PrintParametersSettings);
|
||||
Debug.WriteLine(MachineInfoSettings);
|
||||
Debug.WriteLine("-End-");
|
||||
}
|
||||
|
||||
public override void Decode(string fileFullPath)
|
||||
{
|
||||
DecodeInternal(fileFullPath);
|
||||
|
||||
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 != SPI_FILE_MAGIC_BASE)
|
||||
{
|
||||
throw new FileLoadException("Not a valid CBDDLP file!", fileFullPath);
|
||||
}
|
||||
|
||||
Debug.WriteLine(HeaderSettings);
|
||||
|
||||
if (HeaderSettings.Version == 2)
|
||||
if (HeaderSettings.Version == 1 || HeaderSettings.AntiAliasLevel == 0)
|
||||
{
|
||||
binReader.BaseStream.Seek(HeaderSettings.PrintParametersOffsetAddress, SeekOrigin.Begin);
|
||||
PrintParametersSettings = Helpers.ByteToType<CbddlpFile.PrintParameters>(binReader);
|
||||
Debug.WriteLine(PrintParametersSettings);
|
||||
HeaderSettings.AntiAliasLevel = 1;
|
||||
}
|
||||
|
||||
uint aaLevel = HeaderSettings.Version == 1 ? 1 : HeaderSettings.AntiAliasLevel;
|
||||
FileFullPath = fileFullPath;
|
||||
|
||||
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
|
||||
for (int image = 1; image <= HeaderSettings.AntiAliasLevel; image++)
|
||||
|
||||
Debug.Write("Header -> ");
|
||||
Debug.WriteLine(HeaderSettings);
|
||||
|
||||
for (byte i = 0; i < ThumbnailsCount; i++)
|
||||
{
|
||||
if (HeaderSettings.AntiAliasLevel > 1) Debug.WriteLine("Image GROUP " + image + "----");
|
||||
for (int i = 0; i < HeaderSettings.LayerCount; i++)
|
||||
{
|
||||
binReader.BaseStream.Seek(layerOffset, SeekOrigin.Begin);
|
||||
Layer layer = Helpers.ByteToType<CbddlpFile.Layer>(binReader);
|
||||
Layers.Add(layer);
|
||||
uint offsetAddress = i == 0 ? HeaderSettings.PreviewOneOffsetAddress : HeaderSettings.PreviewTwoOffsetAddress;
|
||||
if(offsetAddress == 0) continue;
|
||||
|
||||
layerOffset += (uint)Marshal.SizeOf((object)layer);
|
||||
Debug.WriteLine("LAYER " + i);
|
||||
Debug.WriteLine(layer);
|
||||
InputFile.Seek(offsetAddress, SeekOrigin.Begin);
|
||||
Previews[i] = Helpers.Deserialize<Preview>(InputFile);
|
||||
|
||||
Debug.Write($"Preview {i} -> ");
|
||||
Debug.WriteLine(Previews[i]);
|
||||
|
||||
Thumbnails[i] = new Image<Rgba32>((int)Previews[i].ResolutionX, (int)Previews[i].ResolutionY);
|
||||
|
||||
InputFile.Seek(Previews[i].ImageOffset, SeekOrigin.Begin);
|
||||
byte[] rawImageData = new byte[Previews[i].ImageLength];
|
||||
InputFile.Read(rawImageData, 0, (int)Previews[i].ImageLength);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
for (int n = 0; n < Previews[i].ImageLength; n++)
|
||||
{
|
||||
uint dot = (uint)(rawImageData[n] & 0xFF | ((rawImageData[++n] & 0xFF) << 8));
|
||||
//uint color = ((dot & 0xF800) << 8) | ((dot & 0x07C0) << 5) | ((dot & 0x001F) << 3);
|
||||
byte red = (byte)(((dot >> 11) & 0x1F) << 3);
|
||||
byte green = (byte)(((dot >> 6) & 0x1F) << 3);
|
||||
byte blue = (byte)((dot & 0x1F) << 3);
|
||||
int repeat = 1;
|
||||
if ((dot & 0x0020) == 0x0020)
|
||||
{
|
||||
repeat += rawImageData[++n] & 0xFF | ((rawImageData[++n] & 0x0F) << 8);
|
||||
}
|
||||
|
||||
|
||||
for (int j = 0; j < repeat; j++)
|
||||
{
|
||||
Thumbnails[i][x, y] = new Rgba32(red, green, blue, 255);
|
||||
x++;
|
||||
|
||||
if (x == Previews[i].ResolutionX)
|
||||
{
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binReader.Close();
|
||||
binReader.Dispose();
|
||||
if (HeaderSettings.Version == 2 && HeaderSettings.PrintParametersOffsetAddress > 0)
|
||||
{
|
||||
InputFile.Seek(HeaderSettings.PrintParametersOffsetAddress, SeekOrigin.Begin);
|
||||
PrintParametersSettings = Helpers.Deserialize<PrintParameters>(InputFile);
|
||||
Debug.Write("Print Parameters -> ");
|
||||
Debug.WriteLine(PrintParametersSettings);
|
||||
|
||||
MachineInfoSettings = Helpers.Deserialize<MachineInfo>(InputFile);
|
||||
Debug.Write("Machine Info -> ");
|
||||
Debug.WriteLine(MachineInfoSettings);
|
||||
|
||||
/*InputFile.BaseStream.Seek(MachineInfoSettings.MachineNameAddress, SeekOrigin.Begin);
|
||||
byte[] bytes = InputFile.ReadBytes((int)MachineInfoSettings.MachineNameSize);
|
||||
MachineName = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
Debug.WriteLine($"{nameof(MachineName)}: {MachineName}");*/
|
||||
}
|
||||
|
||||
Layers = new Layer[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel];
|
||||
|
||||
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
|
||||
Image<Gray8> image = new Image<Gray8>((int)HeaderSettings.BedSizeX, (int)HeaderSettings.BedSizeY);
|
||||
|
||||
|
||||
for (uint aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
Debug.WriteLine($"-Image GROUP {aaIndex}-");
|
||||
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
|
||||
{
|
||||
InputFile.Seek(layerOffset, SeekOrigin.Begin);
|
||||
Layer layer = Helpers.Deserialize<Layer>(InputFile);
|
||||
Layers[layerIndex, aaIndex] = layer;
|
||||
//Layers.Add(layer);
|
||||
|
||||
layerOffset += (uint)Helpers.Serializer.SizeOf(layer);
|
||||
Debug.Write($"LAYER {layerIndex} -> ");
|
||||
Debug.WriteLine(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Image<Gray8> GetLayerImage(uint layerIndex)
|
||||
{
|
||||
if (layerIndex >= HeaderSettings.LayerCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"Layer {layerIndex} doesn't exists, out of bounds.");
|
||||
}
|
||||
|
||||
Image<Gray8> image = new Image<Gray8>((int)HeaderSettings.ResolutionX, (int)HeaderSettings.ResolutionY);
|
||||
|
||||
for (uint aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
Layer layer = Layers[layerIndex, aaIndex];
|
||||
InputFile.Seek(layer.DataAddress, SeekOrigin.Begin);
|
||||
byte[] rawImageData = new byte[(int)layer.DataSize];
|
||||
InputFile.Read(rawImageData, 0, (int)layer.DataSize);
|
||||
uint x = 0;
|
||||
uint y = 0;
|
||||
|
||||
foreach (byte rle in rawImageData)
|
||||
{
|
||||
// From each byte retrieve color (highest bit) and number of pixels of that color (lowest 7 bits)
|
||||
uint length = (uint)(rle & 0x7F); // turn highest bit of
|
||||
bool color = (rle & 0x80) == 0x80; // only read 1st bit
|
||||
|
||||
uint x2 = (uint)Math.Min(x + length, HeaderSettings.ResolutionX);
|
||||
|
||||
if (color)
|
||||
{
|
||||
for (uint i = x; i < x2; i++)
|
||||
{
|
||||
image[(int) i, (int) y] = Helpers.Gray8White;
|
||||
}
|
||||
}
|
||||
|
||||
x += length;
|
||||
|
||||
if (x >= HeaderSettings.ResolutionX)
|
||||
{
|
||||
length = x - HeaderSettings.ResolutionX;
|
||||
x = 0;
|
||||
y++;
|
||||
x2 = x + length;
|
||||
|
||||
if (color)
|
||||
{
|
||||
for (uint i = x; i < x2; i++)
|
||||
{
|
||||
image[(int) i, (int) y] = new Gray8(255);
|
||||
}
|
||||
}
|
||||
|
||||
x += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public override float GetHeightFromLayer(uint layerNum)
|
||||
{
|
||||
return HeaderSettings.LayerCount;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
for (byte i = 0; i < ThumbnailsCount; i++)
|
||||
{
|
||||
Previews[i] = new Preview();
|
||||
}
|
||||
|
||||
Layers = null;
|
||||
|
||||
if (!ReferenceEquals(InputFile, null))
|
||||
{
|
||||
InputFile.Close();
|
||||
InputFile.Dispose();
|
||||
}
|
||||
|
||||
if (!ReferenceEquals(OutputFile, null))
|
||||
{
|
||||
OutputFile.Close();
|
||||
OutputFile.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Convert(Type to, string fileFullPath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a file extension for slicer file formats
|
||||
/// </summary>
|
||||
public sealed class FileExtension
|
||||
{
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Gets the extension name without the dot (.)
|
||||
/// </summary>
|
||||
public string Extension { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the extension description
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file filter for open and save dialogs
|
||||
/// </summary>
|
||||
public string Filter => $@"{Description} (*.{Extension})|*.{Extension}";
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension name without the dot (.)</param>
|
||||
/// <param name="description">The extension description</param>
|
||||
public FileExtension(string extension, string description)
|
||||
{
|
||||
Extension = extension;
|
||||
Description = description;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(Extension)}: {Extension}, {nameof(Description)}: {Description}";
|
||||
}
|
||||
|
||||
private bool Equals(FileExtension other)
|
||||
{
|
||||
return Extension == other.Extension;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return ReferenceEquals(this, obj) || obj is FileExtension other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Extension != null ? Extension.GetHashCode() : 0);
|
||||
}
|
||||
|
||||
private sealed class ExtensionEqualityComparer : IEqualityComparer<FileExtension>
|
||||
{
|
||||
public bool Equals(FileExtension x, FileExtension y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.Extension == y.Extension;
|
||||
}
|
||||
|
||||
public int GetHashCode(FileExtension obj)
|
||||
{
|
||||
return (obj.Extension != null ? obj.Extension.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<FileExtension> ExtensionComparer { get; } = new ExtensionEqualityComparer();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,123 @@
|
||||
using System;
|
||||
/*
|
||||
* 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 System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
public abstract class FileFormat : IFileFormat
|
||||
/// <summary>
|
||||
/// Slicer <see cref="FileFormat"/> representation
|
||||
/// </summary>
|
||||
public abstract class FileFormat : IFileFormat, IDisposable
|
||||
{
|
||||
public string FileFullPath { get; protected set; }
|
||||
public abstract string FileExtension { get; }
|
||||
public abstract string FileExtensionName { get; }
|
||||
public abstract void Load(string fileFullPath);
|
||||
/// <summary>
|
||||
/// Gets the input file path loaded into this <see cref="FileFormat"/>
|
||||
/// </summary>
|
||||
public abstract string FileFullPath { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the valid file extensions for this <see cref="FileFormat"/>
|
||||
/// </summary>
|
||||
public abstract FileExtension[] ValidFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the thumbnails count present in this file format
|
||||
/// </summary>
|
||||
public abstract byte ThumbnailsCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the thumbnails for this <see cref="FileFormat"/>
|
||||
/// </summary>
|
||||
public abstract Image<Rgba32>[] Thumbnails { get; protected internal set; }
|
||||
|
||||
protected FileFormat()
|
||||
{
|
||||
Thumbnails = new Image<Rgba32>[ThumbnailsCount];
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return !ReferenceEquals(FileFullPath, null);
|
||||
}
|
||||
|
||||
public abstract void BeginEncode(string fileFullPath);
|
||||
|
||||
public abstract void InsertLayerImageEncode(Image<Gray8> image, uint layerIndex);
|
||||
|
||||
public abstract void EndEncode();
|
||||
|
||||
public abstract void Decode(string fileFullPath);
|
||||
public abstract Image<Gray8> GetLayerImage(uint layerIndex);
|
||||
|
||||
protected void DecodeInternal(string fileFullPath)
|
||||
{
|
||||
Clear();
|
||||
FileValidation(fileFullPath);
|
||||
FileFullPath = fileFullPath;
|
||||
}
|
||||
public abstract float GetHeightFromLayer(uint layerNum);
|
||||
|
||||
public abstract void Clear();
|
||||
|
||||
protected void ClearInternal()
|
||||
{
|
||||
FileFullPath = null;
|
||||
if (!ReferenceEquals(Thumbnails, null))
|
||||
{
|
||||
for (int i = 0; i < ThumbnailsCount; i++)
|
||||
{
|
||||
Thumbnails[i]?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract bool Convert(Type to, string fileFullPath);
|
||||
|
||||
public void FileValidation(string fileFullPath)
|
||||
{
|
||||
if (ReferenceEquals(fileFullPath, null)) throw new ArgumentNullException(nameof(FileFullPath), "fullFilePath can't be null.");
|
||||
if (!File.Exists(fileFullPath)) throw new FileNotFoundException("The specified file does not exists.", fileFullPath);
|
||||
if (!Path.GetExtension(fileFullPath).Equals($".{FileExtension}")) throw new FileLoadException($"The specified file is not valid, can only open {FileExtension} files.", fileFullPath);
|
||||
|
||||
if (IsExtensionValid(fileFullPath, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new FileLoadException($"The specified file is not valid.", fileFullPath);
|
||||
}
|
||||
|
||||
public bool IsExtensionValid(string extension, bool isFilePath = false)
|
||||
{
|
||||
extension = isFilePath ? Path.GetExtension(extension)?.Remove(0, 1) : extension;
|
||||
return ValidFiles.Any(fileExtension => fileExtension.Extension.Equals(extension));
|
||||
}
|
||||
|
||||
public string GetFileFilter()
|
||||
{
|
||||
string result = String.Empty;
|
||||
|
||||
foreach (var fileExt in ValidFiles)
|
||||
{
|
||||
if (!ReferenceEquals(result, string.Empty))
|
||||
{
|
||||
result += '|';
|
||||
}
|
||||
result += fileExt.Filter;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,16 @@
|
||||
*/
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using BinarySerialization;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
public static class Helpers
|
||||
{
|
||||
public static BinarySerializer Serializer { get; } = new BinarySerializer {Endianness = Endianness.Little };
|
||||
public static Gray8 Gray8White { get; } = new Gray8(255);
|
||||
public static T ByteToType<T>(BinaryReader reader)
|
||||
{
|
||||
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
|
||||
@@ -22,5 +27,52 @@ namespace PrusaSL1Reader
|
||||
|
||||
return theStructure;
|
||||
}
|
||||
|
||||
public static byte[] SerializeToBytes<T>(T item)
|
||||
{
|
||||
var formatter = new BinaryFormatter();
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
formatter.Serialize(stream, item);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static MemoryStream Serialize(object value)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
Serializer.Serialize(stream, value);
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(BinaryReader binaryReader)
|
||||
{
|
||||
return Deserialize<T>(binaryReader.BaseStream);
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream)
|
||||
{
|
||||
return Helpers.Serializer.Deserialize<T>(stream);
|
||||
}
|
||||
|
||||
public static int WriteFileStream(FileStream fs, MemoryStream stream, uint offset = 0)
|
||||
{
|
||||
return WriteFileStream(fs, stream.GetBuffer(), offset);
|
||||
}
|
||||
|
||||
public static int WriteFileStream(FileStream fs, byte[] bytes, uint offset = 0)
|
||||
{
|
||||
fs.Write(bytes, 0, bytes.Length);
|
||||
return bytes.Length;
|
||||
}
|
||||
|
||||
public static int SerializeWriteFileStream(FileStream fs, object value, uint offset = 0)
|
||||
{
|
||||
using (MemoryStream stream = Helpers.Serialize(value))
|
||||
{
|
||||
return Helpers.WriteFileStream(fs, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,74 @@
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
/// <summary>
|
||||
/// Slicer file format representation interface
|
||||
/// </summary>
|
||||
public interface IFileFormat
|
||||
{
|
||||
string FileExtension { get; }
|
||||
string FileExtensionName { get; }
|
||||
void Load(string fileFullPath);
|
||||
/// <summary>
|
||||
/// Check if this file is valid to read
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool IsValid();
|
||||
|
||||
/// <summary>
|
||||
/// Begin encode to an output file
|
||||
/// </summary>
|
||||
/// <param name="fileFullPath">Output file</param>
|
||||
void BeginEncode(string fileFullPath);
|
||||
|
||||
/// <summary>
|
||||
/// Insert a layer image to be encoded
|
||||
/// </summary>
|
||||
/// <param name="image"></param>
|
||||
/// <param name="layerIndex"></param>
|
||||
void InsertLayerImageEncode(Image<Gray8> image, uint layerIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Finish the encoding procedure
|
||||
/// </summary>
|
||||
void EndEncode();
|
||||
|
||||
/// <summary>
|
||||
/// Decode a slicer file
|
||||
/// </summary>
|
||||
/// <param name="fileFullPath"></param>
|
||||
void Decode(string fileFullPath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a image from layer
|
||||
/// </summary>
|
||||
/// <param name="layerIndex">The layer index</param>
|
||||
/// <returns>Returns a image</returns>
|
||||
Image<Gray8> GetLayerImage(uint layerIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Get height in mm from layer height
|
||||
/// </summary>
|
||||
/// <param name="layerNum">The layer height</param>
|
||||
/// <returns>The height in mm</returns>
|
||||
float GetHeightFromLayer(uint layerNum);
|
||||
|
||||
/// <summary>
|
||||
/// Clears all definitions and properties, it also dispose valid candidates
|
||||
/// </summary>
|
||||
void Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Converts this file type to another file type
|
||||
/// </summary>
|
||||
/// <param name="to">Target type</param>
|
||||
/// <param name="fileFullPath">Output path file</param>
|
||||
/// <returns>True if convert succeed, otherwise false</returns>
|
||||
bool Convert(Type to, string fileFullPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static object DeserializeFromBytes(byte[] bytes)
|
||||
{
|
||||
var formatter = new BinaryFormatter();
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
return formatter.Deserialize(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,18 @@
|
||||
<PackageProjectUrl>https://github.com/sn4k3/PrusaSL1Viewer</PackageProjectUrl>
|
||||
<PackageIcon></PackageIcon>
|
||||
<RepositoryUrl>https://github.com/sn4k3/PrusaSL1Viewer</RepositoryUrl>
|
||||
<AssemblyVersion>0.1.0.0</AssemblyVersion>
|
||||
<FileVersion>0.1.0.0</FileVersion>
|
||||
<Version>0.1</Version>
|
||||
<AssemblyVersion>0.2.0.0</AssemblyVersion>
|
||||
<FileVersion>0.2.0.0</FileVersion>
|
||||
<Version>0.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE" Link="LICENSE" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BinarySerializer" Version="8.5.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+149
-19
@@ -13,10 +13,13 @@ using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace PrusaSL1Reader
|
||||
{
|
||||
public class SL1File : FileFormat, IDisposable, IEquatable<SL1File>
|
||||
public class SL1File : FileFormat, IEquatable<SL1File>
|
||||
{
|
||||
#region Sub Classes
|
||||
|
||||
@@ -265,7 +268,11 @@ namespace PrusaSL1Reader
|
||||
|
||||
public Statistics Statistics { get; } = new Statistics();
|
||||
|
||||
public List<ZipArchiveEntry> Thumbnails { get; } = new List<ZipArchiveEntry>(2);
|
||||
public override byte ThumbnailsCount { get; } = 2;
|
||||
|
||||
public override Image<Rgba32>[] Thumbnails { get; protected internal set; }
|
||||
|
||||
//public List<ZipArchiveEntry> Thumbnails { get; } = new List<ZipArchiveEntry>(2);
|
||||
public List<ZipArchiveEntry> LayerImages { get; } = new List<ZipArchiveEntry>();
|
||||
|
||||
public uint GetLayerCount => (uint)LayerImages.Count;
|
||||
@@ -292,11 +299,6 @@ namespace PrusaSL1Reader
|
||||
return (FileFullPath != null ? FileFullPath.GetHashCode() : 0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Archive?.Dispose();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(FileFullPath)}: {FileFullPath}, {nameof(MaterialSettings)}: {MaterialSettings}, {nameof(PrintSettings)}: {PrintSettings}, {nameof(OutputConfigSettings)}: {OutputConfigSettings}, {nameof(Statistics)}: {Statistics}, {nameof(GetLayerCount)}: {GetLayerCount}, {nameof(TotalHeight)}: {TotalHeight}";
|
||||
@@ -306,26 +308,42 @@ namespace PrusaSL1Reader
|
||||
|
||||
#region Contructors
|
||||
public SL1File() { }
|
||||
public SL1File(string fileFullPath)
|
||||
public SL1File(string fileFullPath)
|
||||
{
|
||||
Load(fileFullPath);
|
||||
Decode(fileFullPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Functions
|
||||
|
||||
public override string FileExtension { get; } = "sl1";
|
||||
public override string FileExtensionName { get; } = "Prusa SL1 Files";
|
||||
public override string FileFullPath { get; protected set; }
|
||||
|
||||
public override void Load(string fileFullPath)
|
||||
public override FileExtension[] ValidFiles { get; } = {
|
||||
new FileExtension("sl1", "Prusa SL1 Files")
|
||||
};
|
||||
|
||||
private List<Image<Gray8>> images = new List<Image<Gray8>>();
|
||||
|
||||
public override void BeginEncode(string fileFullPath)
|
||||
{
|
||||
FileValidation(fileFullPath);
|
||||
FileFullPath = fileFullPath;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Archive?.Dispose();
|
||||
Thumbnails.Clear();
|
||||
LayerImages.Clear();
|
||||
Statistics.Clear();
|
||||
public override void InsertLayerImageEncode(Image<Gray8> image, uint layerIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void EndEncode()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Decode(string fileFullPath)
|
||||
{
|
||||
DecodeInternal(fileFullPath);
|
||||
|
||||
FileFullPath = fileFullPath;
|
||||
|
||||
PrinterSettings = new Printer();
|
||||
MaterialSettings = new Material();
|
||||
@@ -343,6 +361,7 @@ namespace PrusaSL1Reader
|
||||
};
|
||||
|
||||
Archive = ZipFile.OpenRead(FileFullPath);
|
||||
byte thumbnailIndex = 0;
|
||||
foreach (ZipArchiveEntry entity in Archive.Entries)
|
||||
{
|
||||
if (entity.Name.EndsWith(".ini"))
|
||||
@@ -383,23 +402,134 @@ namespace PrusaSL1Reader
|
||||
{
|
||||
if (entity.Name.StartsWith("thumbnail"))
|
||||
{
|
||||
Thumbnails.Add(entity);
|
||||
using (Stream stream = entity.Open())
|
||||
{
|
||||
Thumbnails[thumbnailIndex] = Image.Load<Rgba32>(stream);
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
thumbnailIndex++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
LayerImages.Add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
Statistics.ExecutionTime.Stop();
|
||||
|
||||
Debug.WriteLine(Statistics);
|
||||
}
|
||||
|
||||
public override Image<Gray8> GetLayerImage(uint layerIndex)
|
||||
{
|
||||
return Image.Load<Gray8>(LayerImages[(int)layerIndex].Open());
|
||||
}
|
||||
|
||||
public override float GetHeightFromLayer(uint layerNum)
|
||||
{
|
||||
return (float)Math.Round(MaterialSettings.InitialLayerHeight + (layerNum - 1) * OutputConfigSettings.LayerHeight, 2);
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
ClearInternal();
|
||||
Archive?.Dispose();
|
||||
LayerImages.Clear();
|
||||
Statistics.Clear();
|
||||
}
|
||||
|
||||
public override bool Convert(Type to, string fileFullPath)
|
||||
{
|
||||
if (!IsValid()) return false;
|
||||
|
||||
if (to == typeof(CbddlpFile))
|
||||
{
|
||||
CbddlpFile file = new CbddlpFile
|
||||
{
|
||||
HeaderSettings = new CbddlpFile.Header
|
||||
{
|
||||
Version = 2,
|
||||
AntiAliasLevel = LookupCustomValue<uint>("AntiAliasLevel", 1),
|
||||
BedSizeX = PrinterSettings.DisplayWidth,
|
||||
BedSizeY = PrinterSettings.DisplayHeight,
|
||||
BedSizeZ = PrinterSettings.MaxPrintHeight,
|
||||
BottomExposureSeconds = MaterialSettings.InitialExposureTime,
|
||||
BottomLayersCount = PrintSettings.FadedLayers,
|
||||
BottomLightPWM = LookupCustomValue<ushort>("BottomLightPWM", 255), // TODO
|
||||
LayerCount = GetLayerCount,
|
||||
LayerExposureSeconds = MaterialSettings.ExposureTime,
|
||||
LayerHeightMilimeter = PrintSettings.LayerHeight,
|
||||
LayerOffTime = LookupCustomValue<float>("LayerOffTime", 0), // TODO
|
||||
LightPWM = LookupCustomValue<ushort>("LightPWM", 255), // TODO
|
||||
PrintTime = (uint) OutputConfigSettings.PrintTime,
|
||||
ProjectorType = PrinterSettings.DisplayMirrorX ? 1u : 0u,
|
||||
ResolutionX = PrinterSettings.DisplayPixelsX,
|
||||
ResolutionY = PrinterSettings.DisplayPixelsY,
|
||||
},
|
||||
PrintParametersSettings = new CbddlpFile.PrintParameters
|
||||
{
|
||||
BottomLayerCount = PrintSettings.FadedLayers,
|
||||
BottomLiftHeight = LookupCustomValue<float>("BottomLiftHeight", 5), // TODO
|
||||
BottomLiftSpeed = LookupCustomValue<float>("BottomLiftSpeed", 60), // TODO
|
||||
BottomLightOffDelay = LookupCustomValue<float>("BottomLightOffDelay", 0), // TODO
|
||||
CostDollars = OutputConfigSettings.UsedMaterial * MaterialSettings.BottleCost /
|
||||
MaterialSettings.BottleVolume,
|
||||
LiftHeight = LookupCustomValue<float>("LiftHeight", 5), // TODO, // TODO
|
||||
LiftingSpeed = LookupCustomValue<float>("LiftingSpeed", 60), // TODO
|
||||
LightOffDelay = LookupCustomValue<float>("LightOffDelay", 0), // TODO
|
||||
RetractSpeed = LookupCustomValue<float>("RetractSpeed", 150), // TODO
|
||||
VolumeMl = OutputConfigSettings.UsedMaterial,
|
||||
WeightG = OutputConfigSettings.UsedMaterial * MaterialSettings.MaterialDensity
|
||||
},
|
||||
Thumbnails = Thumbnails,
|
||||
MachineInfoSettings = new CbddlpFile.MachineInfo()
|
||||
{
|
||||
MachineName = PrinterSettings.PrinterSettingsId,
|
||||
MachineNameSize = (uint)PrinterSettings.PrinterSettingsId.Length
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
file.BeginEncode(fileFullPath);
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < GetLayerCount; layerIndex++)
|
||||
{
|
||||
file.InsertLayerImageEncode(GetLayerImage(layerIndex), layerIndex);
|
||||
}
|
||||
|
||||
file.EndEncode();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T LookupCustomValue<T>(string name, T defaultValue)
|
||||
{
|
||||
string result = string.Empty;
|
||||
name += '_';
|
||||
|
||||
int index = PrinterSettings.PrinterNotes.IndexOf(name, StringComparison.Ordinal);
|
||||
int startIndex = index + name.Length;
|
||||
|
||||
if (index < 0 || PrinterSettings.PrinterNotes.Length < startIndex) return defaultValue;
|
||||
for (int i = startIndex; i < PrinterSettings.PrinterNotes.Length; i++)
|
||||
{
|
||||
char c = PrinterSettings.PrinterNotes[i];
|
||||
if (!Char.IsLetterOrDigit(c) && c != '.')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result += PrinterSettings.PrinterNotes[i];
|
||||
}
|
||||
|
||||
return result.Convert<T>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Functions
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace PrusaSL1Reader
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Upper the first character in a string
|
||||
/// </summary>
|
||||
/// <param name="input">Input string</param>
|
||||
/// <returns>Modified string with fist character upper</returns>
|
||||
public static string FirstCharToUpper(this string input)
|
||||
{
|
||||
switch (input)
|
||||
@@ -23,6 +28,12 @@ namespace PrusaSL1Reader
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string into a target type
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Target type to convert into</typeparam>
|
||||
/// <param name="input">Value</param>
|
||||
/// <returns>Converted value into target type</returns>
|
||||
public static T Convert<T>(this string input)
|
||||
{
|
||||
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
||||
Generated
+14
-2
@@ -56,6 +56,7 @@
|
||||
this.scCenter = new System.Windows.Forms.SplitContainer();
|
||||
this.pbLayer = new System.Windows.Forms.PictureBox();
|
||||
this.pbLayers = new System.Windows.Forms.ProgressBar();
|
||||
this.menuEditConvert = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menu.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
@@ -116,7 +117,8 @@
|
||||
// menuEdit
|
||||
//
|
||||
this.menuEdit.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.menuEditExtract});
|
||||
this.menuEditExtract,
|
||||
this.menuEditConvert});
|
||||
this.menuEdit.Enabled = false;
|
||||
this.menuEdit.Name = "menuEdit";
|
||||
this.menuEdit.Size = new System.Drawing.Size(39, 20);
|
||||
@@ -128,7 +130,7 @@
|
||||
this.menuEditExtract.Image = global::PrusaSL1Viewer.Properties.Resources.Extract_object_16x16;
|
||||
this.menuEditExtract.Name = "menuEditExtract";
|
||||
this.menuEditExtract.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E)));
|
||||
this.menuEditExtract.Size = new System.Drawing.Size(150, 22);
|
||||
this.menuEditExtract.Size = new System.Drawing.Size(181, 22);
|
||||
this.menuEditExtract.Text = "&Extract";
|
||||
this.menuEditExtract.Click += new System.EventHandler(this.MenuItemClicked);
|
||||
//
|
||||
@@ -349,6 +351,15 @@
|
||||
this.pbLayers.Step = 1;
|
||||
this.pbLayers.TabIndex = 6;
|
||||
//
|
||||
// menuEditConvert
|
||||
//
|
||||
this.menuEditConvert.Name = "menuEditConvert";
|
||||
this.menuEditConvert.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt)
|
||||
| System.Windows.Forms.Keys.C)));
|
||||
this.menuEditConvert.Size = new System.Drawing.Size(181, 22);
|
||||
this.menuEditConvert.Text = "&Convert";
|
||||
this.menuEditConvert.Click += new System.EventHandler(this.MenuItemClicked);
|
||||
//
|
||||
// FrmMain
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
@@ -410,6 +421,7 @@
|
||||
private System.Windows.Forms.SplitContainer scCenter;
|
||||
private System.Windows.Forms.PictureBox pbLayer;
|
||||
private System.Windows.Forms.ProgressBar pbLayers;
|
||||
private System.Windows.Forms.ToolStripMenuItem menuEditConvert;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-11
@@ -13,6 +13,7 @@ using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using PrusaSL1Reader;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace PrusaSL1Viewer
|
||||
{
|
||||
@@ -34,7 +35,7 @@ namespace PrusaSL1Viewer
|
||||
#region Events
|
||||
private void sbLayers_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
ShowLayer(sbLayers.Maximum - sbLayers.Value);
|
||||
ShowLayer((uint)(sbLayers.Maximum - sbLayers.Value));
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +47,7 @@ namespace PrusaSL1Viewer
|
||||
using (OpenFileDialog openFile = new OpenFileDialog())
|
||||
{
|
||||
openFile.CheckFileExists = true;
|
||||
openFile.Filter = $@"{Program.SL1File.FileExtensionName} (*.{Program.SL1File.FileExtension})|*.{Program.SL1File.FileExtension}";
|
||||
openFile.Filter = Program.SL1File.GetFileFilter();
|
||||
openFile.FilterIndex = 0;
|
||||
if (openFile.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
@@ -97,13 +98,34 @@ namespace PrusaSL1Viewer
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(sender, menuEditConvert))
|
||||
{
|
||||
using (SaveFileDialog dialog = new SaveFileDialog())
|
||||
{
|
||||
dialog.FileName = Path.GetFileNameWithoutExtension(Program.SL1File.FileFullPath);
|
||||
using (CbddlpFile file = new CbddlpFile())
|
||||
{
|
||||
dialog.Filter = file.GetFileFilter();
|
||||
}
|
||||
|
||||
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
Program.SL1File.Convert(typeof(CbddlpFile), dialog.FileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(sender, menuAboutAbout))
|
||||
{
|
||||
Program.FrmAbout.ShowDialog();
|
||||
}
|
||||
if (ReferenceEquals(sender, menuAboutWebsite))
|
||||
{
|
||||
Process.Start(PrusaSL1Reader.About.Website);
|
||||
Process.Start(About.Website);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,7 +146,7 @@ namespace PrusaSL1Viewer
|
||||
if (ReferenceEquals(files, null)) return;
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (!file.EndsWith($".{Program.SL1File.FileExtension}")) continue;
|
||||
if (!Program.SL1File.IsExtensionValid(file, true)) continue;
|
||||
try
|
||||
{
|
||||
ProcessFile(file);
|
||||
@@ -141,14 +163,14 @@ namespace PrusaSL1Viewer
|
||||
|
||||
void ProcessFile(string fileName)
|
||||
{
|
||||
if (!ReferenceEquals(Program.SL1File, null))
|
||||
/* if (!ReferenceEquals(Program.SL1File, null))
|
||||
{
|
||||
Program.SL1File.Dispose();
|
||||
}
|
||||
}*/
|
||||
|
||||
Program.SL1File.Load(fileName);
|
||||
Program.SL1File.Decode(fileName);
|
||||
|
||||
pbThumbnail.Image = Image.FromStream(Program.SL1File.Thumbnails[0].Open());
|
||||
pbThumbnail.Image = Program.SL1File.Thumbnails[0].ToBitmap();
|
||||
//ShowLayer(0);
|
||||
|
||||
sbLayers.SmallChange = 1;
|
||||
@@ -190,12 +212,15 @@ namespace PrusaSL1Viewer
|
||||
Text = $"{FrmAbout.AssemblyTitle} Version: {FrmAbout.AssemblyVersion} File: {Path.GetFileName(fileName)}";
|
||||
}
|
||||
|
||||
void ShowLayer(int layerNum)
|
||||
void ShowLayer(uint layerNum)
|
||||
{
|
||||
//if(!ReferenceEquals(pbLayer.Image, null))
|
||||
// pbLayer.Image.Dispose(); SLOW! LET GC DO IT
|
||||
pbLayer.Image = Image.FromStream(Program.SL1File.LayerImages[layerNum].Open());
|
||||
pbLayer.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
|
||||
//pbLayer.Image = Image.FromStream(Program.SL1File.LayerImages[layerNum].Open());
|
||||
//pbLayer.Image.RotateFlip(RotateFlipType.Rotate90FlipNone);
|
||||
var image = Program.SL1File.GetLayerImage(layerNum);
|
||||
image.Mutate(x => x.Rotate(RotateMode.Rotate90));
|
||||
pbLayer.Image = image.ToBitmap();
|
||||
|
||||
byte percent = (byte)((layerNum + 1) * 100 / Program.SL1File.GetLayerCount);
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.IO;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Advanced;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace PrusaSL1Viewer
|
||||
{
|
||||
public static class ImageSharpExtensions
|
||||
{
|
||||
public static System.Drawing.Bitmap ToBitmap<TPixel>(this Image<TPixel> image) where TPixel : struct, IPixel<TPixel>
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
var imageEncoder = image.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance);
|
||||
image.Save(memoryStream, imageEncoder);
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return new System.Drawing.Bitmap(memoryStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static Image<TPixel> ToImageSharpImage<TPixel>(this System.Drawing.Bitmap bitmap) where TPixel : struct, IPixel<TPixel>
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return Image.Load<TPixel>(memoryStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using PrusaSL1Reader;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace PrusaSL1Viewer
|
||||
{
|
||||
@@ -33,11 +34,14 @@ namespace PrusaSL1Viewer
|
||||
FrmAbout = new FrmAbout();
|
||||
Application.Run(FrmMain);
|
||||
|
||||
//CbddlpFile file = new CbddlpFile();
|
||||
|
||||
//file.Load(@"D:\Tiago\Desktop\_Coronavirus-v6-HIRES-Supports.cbddlp");
|
||||
|
||||
CbddlpFile file = new CbddlpFile();
|
||||
|
||||
//file.Decode(@"D:\Tiago\Desktop\_Coronavirus-v6-HIRES-Supports_NOAA.cbddlp");
|
||||
//file.Decode(@"D:\Tiago\Desktop\coronanew11.cbddlp");
|
||||
/*file.GetLayerImage(0).Save(@"D:\img0.png");
|
||||
file.GetLayerImage(10).Save(@"D:\img10.png");
|
||||
file.GetLayerImage(20).Save(@"D:\img20.png");
|
||||
file.GetLayerImage(50).Save(@"D:\img50.png");*/
|
||||
|
||||
//LayerPositionZ: 0, LayerExposure: 35, LayerOffTimeSeconds: 0, DataAddress: 283641, DataSize: 30804, Unknown1: 0, Unknown2: 0, Unknown3: 0, Unknown4: 0
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0.0")]
|
||||
[assembly: AssemblyVersion("0.2.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.2.0.0")]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Microsoft.Net.Compilers.Toolset.3.6.0-2.final\build\Microsoft.Net.Compilers.Toolset.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.Toolset.3.6.0-2.final\build\Microsoft.Net.Compilers.Toolset.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -28,6 +29,8 @@
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -54,13 +57,71 @@
|
||||
<ApplicationIcon>PrusaSL1Viewer.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BinarySerializer, Version=8.5.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BinarySerializer.8.5.1\lib\net46\BinarySerializer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SixLabors.Core, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SixLabors.Core.1.0.0-beta0008\lib\netstandard2.0\SixLabors.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SixLabors.ImageSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SixLabors.ImageSharp.1.0.0-beta0007\lib\net472\SixLabors.ImageSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection.TypeExtensions, Version=4.1.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.TypeExtensions.4.7.0\lib\net461\System.Reflection.TypeExtensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0-preview.2.20160.6\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Extensions, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.InteropServices" />
|
||||
<Reference Include="System.Threading.Thread" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
@@ -77,6 +138,7 @@
|
||||
<Compile Include="FrmMain.Designer.cs">
|
||||
<DependentUpon>FrmMain.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ImageSharpExtensions.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<EmbeddedResource Include="FrmAbout.resx">
|
||||
@@ -104,6 +166,7 @@
|
||||
<None Include="..\README.md">
|
||||
<Link>README.md</Link>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
@@ -147,4 +210,10 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.Toolset.3.6.0-2.final\build\Microsoft.Net.Compilers.Toolset.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.Toolset.3.6.0-2.final\build\Microsoft.Net.Compilers.Toolset.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BinarySerializer" version="8.5.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Net.Compilers.Toolset" version="3.6.0-2.final" targetFramework="net48" developmentDependency="true" />
|
||||
<package id="SixLabors.Core" version="1.0.0-beta0008" targetFramework="net48" />
|
||||
<package id="SixLabors.ImageSharp" version="1.0.0-beta0007" targetFramework="net48" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.IO" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
|
||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Reflection.TypeExtensions" version="4.7.0" targetFramework="net48" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Runtime" version="4.3.1" targetFramework="net48" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="5.0.0-preview.2.20160.6" targetFramework="net48" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.1" targetFramework="net48" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net48" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net48" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user