diff --git a/CHANGELOG.md b/CHANGELOG.md index 5603b838..17899d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,44 @@ # Changelog -## ? - v0.4.3 +## 13/06/2020 - v0.5 -* (Add) PWS and PW0 file formats +* (Add) PWS and PW0 file formats (Thanks to Jason McMullan) +* (Add) PrusaSlicer Printer "AnyCubic Photon S" +* (Add) PrusaSlicer Printer "AnyCubic Photon Zero" +* (Add) PrusaSlicer Universal Profiles optimized for non SL1 printers (Import them) * (Add) Open image files as single layer and transform them in grayscale (jpg, jpeg, png, bmp, gif, tga) -* (Add) Shortcut "Home" go to first layer -* (Add) Shortcut "End" go to last layer -* (Add) Shortcut "+" and button go to next layer -* (Add) Shortcut "-" and button go to previous layer -* (Add) Show current layer and height near tracker position +* (Add) Resize mutator +* (Add) Shortcut "F5" to reload current layer preview +* (Add) Shortcut "Home" and button go to first layer +* (Add) Shortcut "End" and button go to last layer +* (Add) Shortcut "+" and button go to next layer +* (Add) Shortcut "-" and button go to previous layer +* (Add) Shortcut "CTRL+Left" go to previous issue if available +* (Add) Shortcut "CTRL+Right" go to next issue if available +* (Add) Shortcut "Delete" to remove selected issues +* (Add) Button to jump to a layer number +* (Add) Show current layer and height near tracker position +* (Add) Auto compute issues when click "Issues" tab for the first time for the open file +* (Add) "AntiAliasing_x" note under PrusaSlicer printer to enable AntiAliasing on supported formats, printers lacking this note are not supported +* (Add) AntiAliasing capable convertions +* (Add) Touching Bounds detection under issues * (Change) Scroll bar to track bar * (Change) Keyword "LiftingSpeed" to "LiftSpeed" under PrusaSlicer notes (Please update printers notes or import them again) * (Change) Keywords For Nova3D Elfin printer under PrusaSlicer notes (Please update printers notes or import them again) * (Change) Keywords For Zortrax Inkspire printer under PrusaSlicer notes (Please update printers notes or import them again) +* (Change) Islands tab to Issues ab +* (Improvement) Much faster photon, cbddlp, cbt and phz file encoding/convert and saves * (Improvement) Much faster layer scroll display * (Improvement) Hide empty items for status bar, ie: if printer don't have them to display -* (Fix) Save layer preview image trigger an error +* (Improvement) Smooth mutators descriptions +* (Improvement) Disallow invalid iteration numbers for smooth mutators +* (Improvement) File reload now reshow current layer after reload +* (Improvement) Some dependecies were updated and ZedGraph removed +* (Fix) AntiAlias decodes for photon and cbddlp +* (Fix) AntiAlias encodes and decodes for cbt +* (Fix) Save the preview thumbnail image trigger an error * (Fix) Implement missing "InheritsCummulative" key to SL1 files +* (Fix) Install print profiles button, two typos and Cancel button doesn't really cancel the operation ## 05/06/2020 - v0.4.2.2 - Beta diff --git a/ImportPrinters.bat b/ImportPrinters.bat deleted file mode 100644 index 1b7bb149..00000000 --- a/ImportPrinters.bat +++ /dev/null @@ -1,36 +0,0 @@ -@echo off -SET DIR=%~dp0 -SET INPUT_DIR=%AppData%\PrusaSlicer\printer -SET OUTPUT_DIR=%~dp0PrusaSlicer\printer - -SET files[0]=EPAX X1.ini -SET files[1]=EPAX X10.ini -SET files[2]=EPAX X133 4K Mono.ini -SET files[3]=EPAX X156 4K Color.ini -SET files[4]=Zortrax Inkspire.ini -SET files[5]=Nova3D Elfin.ini -SET files[6]=AnyCubic Photon.ini -SET files[7]=Elegoo Mars.ini -SET files[8]=Elegoo Mars Saturn.ini -SET files[9]=Peopoly Phenom.ini -SET files[10]=Peopoly Phenom L.ini -SET files[11]=Peopoly Phenom Noir.ini -SET files[12]=QIDI Shadow5.5.ini -SET files[13]=QIDI Shadow6.0 Pro.ini -SET files[14]=Phrozen Shuffle.ini -SET files[15]=Phrozen Shuffle Lite.ini -SET files[16]=Phrozen Shuffle XL.ini -SET files[17]=Phrozen Shuffle 4K.ini -SET files[18]=Phrozen Sonic.ini -SET files[19]=Phrozen Sonic Mini.ini -SET files[20]=Phrozen Transform.ini - -echo PrusaSlicer Printers Instalation -echo This will replace printers, all changes will be discarded -echo %INPUT_DIR% -echo %OUTPUT_DIR% - -for /F "tokens=2 delims==" %%s in ('set files[') do xcopy /y "%INPUT_DIR%\%%s" "%OUTPUT_DIR%" - -REM xcopy /i /e /y %INPUT_DIR% %OUTPUT_DIR% -pause \ No newline at end of file diff --git a/ImportPrusaSlicerData.bat b/ImportPrusaSlicerData.bat new file mode 100644 index 00000000..36faff72 --- /dev/null +++ b/ImportPrusaSlicerData.bat @@ -0,0 +1,54 @@ +@echo off +SET DIR=%~dp0 +SET INPUT_DIR=%AppData%\PrusaSlicer +SET OUTPUT_DIR=%~dp0PrusaSlicer + +SET PRINT_DIR=sla_print +SET PRINTER_DIR=printer + +SET files[0]=EPAX X1.ini +SET files[1]=EPAX X10.ini +SET files[2]=EPAX X133 4K Mono.ini +SET files[3]=EPAX X156 4K Color.ini +SET files[4]=Zortrax Inkspire.ini +SET files[5]=Nova3D Elfin.ini +SET files[6]=AnyCubic Photon.ini +SET files[7]=AnyCubic Photon S.ini +SET files[8]=AnyCubic Photon Zero.ini +SET files[9]=Elegoo Mars.ini +SET files[10]=Elegoo Mars Saturn.ini +SET files[11]=Peopoly Phenom.ini +SET files[12]=Peopoly Phenom L.ini +SET files[13]=Peopoly Phenom Noir.ini +SET files[14]=QIDI Shadow5.5.ini +SET files[15]=QIDI Shadow6.0 Pro.ini +SET files[16]=Phrozen Shuffle.ini +SET files[17]=Phrozen Shuffle Lite.ini +SET files[18]=Phrozen Shuffle XL.ini +SET files[19]=Phrozen Shuffle 4K.ini +SET files[20]=Phrozen Sonic.ini +SET files[21]=Phrozen Sonic Mini.ini +SET files[22]=Phrozen Transform.ini + +echo PrusaSlicer Printers Instalation +echo This will replace printers, all changes will be discarded +echo %INPUT_DIR% +echo %OUTPUT_DIR% + +echo Importing Printers +for /F "tokens=2 delims==" %%s in ('set files[') do xcopy /d /y "%INPUT_DIR%\%PRINTER_DIR%\%%s" "%OUTPUT_DIR%\%PRINTER_DIR%\" + +echo Importing Profiles +xcopy /i /y /d %INPUT_DIR%\%PRINT_DIR% %OUTPUT_DIR%\%PRINT_DIR% + +REM /s Copies directories and subdirectories, unless they are empty. If you omit /s, xcopy works within a single directory. +REM /y Suppresses prompting to confirm that you want to overwrite an existing destination file. +REM /i If Source is a directory or contains wildcards and Destination does not exist, +REM xcopy assumes Destination specifies a directory name and creates a new directory. +REM Then, xcopy copies all specified files into the new directory. +REM By default, xcopy prompts you to specify whether Destination is a file or a directory. +REM /d Copies source files changed on or after the specified date only. +REM If you do not include a MM-DD-YYYY value, xcopy copies all Source files that are newer than existing Destination files. +REM This command-line option allows you to update files that have changed. + +pause \ No newline at end of file diff --git a/PrusaSL1Reader/CWSFile.cs b/PrusaSL1Reader/CWSFile.cs index 9604041c..912965a3 100644 --- a/PrusaSL1Reader/CWSFile.cs +++ b/PrusaSL1Reader/CWSFile.cs @@ -105,7 +105,7 @@ public class Slice public override FileFormatType FileType => FileFormatType.Archive; public override FileExtension[] FileExtensions { get; } = { - new FileExtension("cws", "CWS Files") + new FileExtension("cws", "NovaMaker CWS Files") }; public override Type[] ConvertToFormats { get; } = null; @@ -128,6 +128,7 @@ public class Slice public override uint ResolutionX => SliceSettings.Xres; public override uint ResolutionY => SliceSettings.Yres; + public override byte AntiAliasing => (byte) OutputSettings.AntiAliasingValue; public override float LayerHeight => SliceSettings.Thickness; diff --git a/PrusaSL1Reader/ChituboxFile.cs b/PrusaSL1Reader/ChituboxFile.cs index 45b8e6f7..d11e32c6 100644 --- a/PrusaSL1Reader/ChituboxFile.cs +++ b/PrusaSL1Reader/ChituboxFile.cs @@ -12,6 +12,8 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using BinarySerialization; using PrusaSL1Reader.Extensions; @@ -356,10 +358,106 @@ public class Preview [FieldOrder(6)] public uint Unknown3 { get; set; } [FieldOrder(7)] public uint Unknown4 { get; set; } + public Image Decode(byte[] rawImageData) + { + var image = new Image((int) ResolutionX, (int) ResolutionY); + image.TryGetSinglePixelSpan(out var span); + + int pixel = 0; + for (int n = 0; n < rawImageData.Length; 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++) + { + span[pixel++] = new Rgba32(red, green, blue); + } + } + + return image; + } + 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}"; } + + public byte[] Encode(Image image) + { + List rawData = new List(); + ushort color15 = 0; + uint rep = 0; + + void RleRGB15() + { + switch (rep) + { + case 0: + return; + case 1: + rawData.Add((byte)(color15 & ~REPEATRGB15MASK)); + rawData.Add((byte)((color15 & ~REPEATRGB15MASK) >> 8)); + break; + case 2: + for (int i = 0; i < 2; i++) + { + rawData.Add((byte)(color15 & ~REPEATRGB15MASK)); + rawData.Add((byte)((color15 & ~REPEATRGB15MASK) >> 8)); + } + + break; + default: + rawData.Add((byte)(color15 | REPEATRGB15MASK)); + rawData.Add((byte)((color15 | REPEATRGB15MASK) >> 8)); + rawData.Add((byte)((rep - 1) | 0x3000)); + rawData.Add((byte)(((rep - 1) | 0x3000) >> 8)); + break; + } + } + + for (int y = 0; y < image.Height; y++) + { + Span pixelRowSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + var ncolor15 = + (pixelRowSpan[x].B >> 3) + | ((pixelRowSpan[x].G >> 2) << 5) + | ((pixelRowSpan[x].R >> 3) << 11); + + if (ncolor15 == color15) + { + rep++; + if (rep == RLE16EncodingLimit) + { + RleRGB15(); + rep = 0; + } + } + else + { + RleRGB15(); + color15 = (ushort)ncolor15; + rep = 1; + } + } + } + + RleRGB15(); + + ImageLength = (uint) rawData.Count; + + return rawData.ToArray(); + } } #endregion @@ -397,11 +495,319 @@ public class LayerData [FieldOrder(8)] public uint Unknown4 { get; set; } [Ignore] public byte[] EncodedRle { get; set; } + [Ignore] public ChituboxFile Parent { get; set; } + + public LayerData() + { + } + + public LayerData(ChituboxFile parent, uint layerIndex) + { + Parent = parent; + LayerPositionZ = parent.GetHeightFromLayer(layerIndex); + + LayerOffTimeSeconds = layerIndex < parent.HeaderSettings.BottomLayersCount + ? parent.PrintParametersSettings.BottomLightOffDelay + : parent.PrintParametersSettings.LightOffDelay; + + LayerExposure = layerIndex < parent.HeaderSettings.BottomLayersCount + ? parent.HeaderSettings.BottomExposureSeconds + : parent.HeaderSettings.LayerExposureSeconds; + } + + public Image Decode(uint layerIndex, bool consumeData = true) + { + var image = Parent.IsCbtFile ? DecodeCbtImage(layerIndex) : DecodeCbddlpImage(Parent, layerIndex); + + if (consumeData) + EncodedRle = null; + + return image; + } + + public static Image DecodeCbddlpImage(ChituboxFile parent, uint layerIndex) + { + Image image = new Image((int)parent.HeaderSettings.ResolutionX, (int)parent.HeaderSettings.ResolutionY); + image.TryGetSinglePixelSpan(out var span); + + for (byte bit = 0; bit < parent.AntiAliasing; bit++) + { + var layer = parent.LayersDefinitions[bit, layerIndex]; + + byte bitValue = (byte)(byte.MaxValue / ((1 << parent.AntiAliasing) - 1) * (1 << bit)); + + int n = 0; + for (int index = 0; index < layer.DataSize; index++) + { + // Lower 7 bits is the repeat count for the bit (0..127) + int reps = layer.EncodedRle[index] & 0x7f; + + // We only need to set the non-zero pixels + // High bit is on for white, off for black + if ((layer.EncodedRle[index] & 0x80) != 0) + { + for (int i = 0; i < reps; i++) + { + span[n + i].PackedValue |= bitValue; + } + } + + n += reps; + + if (n == span.Length) + { + break; + } + + if (n > span.Length) + { + throw new FileLoadException("Error image ran off the end"); + } + } + } + + return image; + } + + private Image DecodeCbtImage(uint layerIndex) + { + Image image = new Image((int)Parent.HeaderSettings.ResolutionX, (int)Parent.HeaderSettings.ResolutionY); + image.TryGetSinglePixelSpan(out var span); + + + if (Parent.HeaderSettings.EncryptionKey > 0) + { + KeyRing kr = new KeyRing(Parent.HeaderSettings.EncryptionKey, layerIndex); + EncodedRle = kr.Read(EncodedRle); + } + + int pixel = 0; + for (var n = 0; n < EncodedRle.Length; n++) + { + byte code = EncodedRle[n]; + uint stride = 1; + + if ((code & 0x80) == 0x80) // It's a run + { + code &= 0x7f; // Get the run length + n++; + + var slen = EncodedRle[n]; + + if ((slen & 0x80) == 0) + { + stride = slen; + } + else if ((slen & 0xc0) == 0x80) + { + stride = (uint)(((slen & 0x3f) << 8) + EncodedRle[n + 1]); + n++; + } + else if ((slen & 0xe0) == 0xc0) + { + stride = (uint)(((slen & 0x1f) << 16) + (EncodedRle[n + 1] << 8) + EncodedRle[n + 2]); + n += 2; + } + else if ((slen & 0xf0) == 0xe0) + { + stride = (uint)(((slen & 0xf) << 24) + (EncodedRle[n + 1] << 16) + (EncodedRle[n + 2] << 8) + EncodedRle[n + 3]); + + n += 3; + } + else + { + throw new FileLoadException("Corrupted RLE data"); + } + } + + // Bit extend from 7-bit to 8-bit greymap + if (code != 0) + { + code = (byte)((code << 1) | 1); + } + + if (stride == 0) continue; // Nothing to do + + if (code == 0) // Ignore blacks, spare cycles + { + pixel += (int)stride; + continue; + } + + while (stride-- > 0) + { + span[pixel].PackedValue = code; + pixel++; + } + } + + return image; + } + + public byte[] Encode(Image image, byte aaIndex, uint layerIndex) + { + return Parent.IsCbtFile ? EncodeCbtImage(image, layerIndex) : EncodeCbddlpImage(image, aaIndex); + } + + public byte[] EncodeCbddlpImage(Image image, byte bit) + { + List rawData = new List(); + + bool obit = false; + int rep = 0; + + void AddRep() + { + if (rep <= 0) return; + + byte by = (byte)rep; + + if (obit) + { + by |= 0x80; + //bitsOn += uint(rep) + } + + rawData.Add(by); + } + + for (int y = 0; y < image.Height; y++) + { + Span pixelRowSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + //ngrey:= uint16(r | g | b) + + var nbit = (pixelRowSpan[x].PackedValue & (1 << (8 - Parent.AntiAliasing + bit))) != 0; + + if (nbit == obit) + { + rep++; + + if (rep == RLE8EncodingLimit) + { + AddRep(); + rep = 0; + } + } + else + { + AddRep(); + obit = nbit; + rep = 1; + } + } + } + + // Collect stragglers + AddRep(); + + EncodedRle = rawData.ToArray(); + DataSize = (uint) EncodedRle.Length; + + return EncodedRle; + } + + private byte[] EncodeCbtImage(Image image, uint layerIndex) + { + List rawData = new List(); + byte color = byte.MaxValue >> 1; + uint stride = 0; + + void AddRep() + { + if (stride == 0) + { + return; + } + + if (stride > 1) + { + color |= 0x80; + } + rawData.Add(color); + + if (stride <= 1) + { + // no run needed + return; + } + + if (stride <= 0x7f) + { + rawData.Add((byte)stride); + return; + } + + if (stride <= 0x3fff) + { + rawData.Add((byte)((stride >> 8) | 0x80)); + rawData.Add((byte)stride); + return; + } + + if (stride <= 0x1fffff) + { + rawData.Add((byte)((stride >> 16) | 0xc0)); + rawData.Add((byte)(stride >> 8)); + rawData.Add((byte)stride); + return; + } + + if (stride <= 0xfffffff) + { + rawData.Add((byte)((stride >> 24) | 0xe0)); + rawData.Add((byte)(stride >> 16)); + rawData.Add((byte)(stride >> 8)); + rawData.Add((byte)stride); + } + + } + + + for (int y = 0; y < image.Height; y++) + { + var pixelRowSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + var grey7 = (byte)(pixelRowSpan[x].PackedValue >> 1); + + if (grey7 == color) + { + stride++; + } + else + { + AddRep(); + color = grey7; + stride = 1; + } + } + } + + AddRep(); + + if (Parent.HeaderSettings.EncryptionKey > 0) + { + KeyRing kr = new KeyRing(Parent.HeaderSettings.EncryptionKey, layerIndex); + EncodedRle = kr.Read(rawData).ToArray(); + } + else + { + EncodedRle = rawData.ToArray(); + } + + DataSize = (uint)EncodedRle.Length; + + return EncodedRle; + } 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 @@ -475,11 +881,12 @@ public byte[] Read(byte[] input) public override FileExtension[] FileExtensions { get; } = { new FileExtension("cbddlp", "Chitubox DLP Files"), new FileExtension("ctb", "Chitubox CTB Files"), - new FileExtension("photon", "Photon Files"), + new FileExtension("photon", "Chitubox Photon Files"), }; public override Type[] ConvertToFormats { get; } = { + typeof(PWSFile), typeof(PHZFile), typeof(ZCodexFile), }; @@ -509,6 +916,7 @@ public byte[] Read(byte[] input) public override uint ResolutionX => HeaderSettings.ResolutionX; public override uint ResolutionY => HeaderSettings.ResolutionY; + public override byte AntiAliasing => (byte) HeaderSettings.AntiAliasLevel; public override float LayerHeight => HeaderSettings.LayerHeightMilimeter; @@ -532,6 +940,8 @@ public byte[] Read(byte[] input) public override object[] Configs => new[] { (object)HeaderSettings, PrintParametersSettings, SlicerInfoSettings }; + public byte AntiAliasingSize => (byte) (IsCbddlpFile ? HeaderSettings.AntiAliasLevel : 1); + public bool IsCbddlpFile => HeaderSettings.Magic == MAGIC_CBDDLP; public bool IsCbtFile => HeaderSettings.Magic == MAGIC_CBT; #endregion @@ -580,89 +990,26 @@ public override void Encode(string fileFullPath) } uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings); - LayersDefinitions = new LayerData[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel]; + LayersDefinitions = new LayerData[AntiAliasingSize, HeaderSettings.LayerCount]; using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write)) { outputFile.Seek((int) currentOffset, SeekOrigin.Begin); - List rawData = new List(); - ushort color15 = 0; - uint rep = 0; - - void rleRGB15() - { - switch (rep) - { - case 0: - return; - case 1: - rawData.Add((byte) (color15 & ~REPEATRGB15MASK)); - rawData.Add((byte) ((color15 & ~REPEATRGB15MASK) >> 8)); - break; - case 2: - for (int i = 0; i < 2; i++) - { - rawData.Add((byte) (color15 & ~REPEATRGB15MASK)); - rawData.Add((byte) ((color15 & ~REPEATRGB15MASK) >> 8)); - } - - break; - default: - rawData.Add((byte) (color15 | REPEATRGB15MASK)); - rawData.Add((byte) ((color15 | REPEATRGB15MASK) >> 8)); - rawData.Add((byte) ((rep - 1) | 0x3000)); - rawData.Add((byte) (((rep - 1) | 0x3000) >> 8)); - break; - } - } for (byte i = 0; i < ThumbnailsCount; i++) { var image = Thumbnails[i]; - color15 = 0; - rep = 0; - rawData.Clear(); - - - for (int y = 0; y < image.Height; y++) + Preview preview = new Preview { - Span pixelRowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - - /*var ncolor15 = - (((pixelRowSpan[x].B >> (16 - 5)) & 0x1f)) - | (((pixelRowSpan[x].G >> (16 - 5)) & 0x1f) << 6) - | (((pixelRowSpan[x].R >> (16 - 5)) & 0x1f) << 11);*/ - - var ncolor15 = - (pixelRowSpan[x].B >> 3) - | ((pixelRowSpan[x].G >> 2) << 5) - | ((pixelRowSpan[x].R >> 3) << 11); - - if (ncolor15 == color15) - { - rep++; - if (rep == RLE16EncodingLimit) - { - rleRGB15(); - rep = 0; - } - } - else - { - rleRGB15(); - color15 = (ushort) ncolor15; - rep = 1; - } - } - } + ResolutionX = (uint)image.Width, + ResolutionY = (uint)image.Height, + }; - rleRGB15(); + var previewBytes = preview.Encode(image); - if (rawData.Count == 0) continue; + if (previewBytes.Length == 0) continue; if (i == (byte) FileThumbnailSize.Small) { @@ -674,21 +1021,11 @@ void rleRGB15() } - - Preview preview = new Preview - { - ResolutionX = (uint) image.Width, - ResolutionY = (uint) image.Height, - ImageLength = (uint) rawData.Count, - }; - currentOffset += (uint) Helpers.Serializer.SizeOf(preview); preview.ImageOffset = currentOffset; Helpers.SerializeWriteFileStream(outputFile, preview); - - currentOffset += (uint) rawData.Count; - outputFile.Write(rawData.ToArray(), 0, rawData.Count); + currentOffset += outputFile.WriteBytes(previewBytes); } @@ -708,48 +1045,47 @@ void rleRGB15() } HeaderSettings.LayersDefinitionOffsetAddress = currentOffset; - uint layerDataCurrentOffset = currentOffset + (uint) Helpers.Serializer.SizeOf(new LayerData()) * HeaderSettings.LayerCount * HeaderSettings.AntiAliasLevel; - - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + uint layerDataCurrentOffset = currentOffset + (uint)Helpers.Serializer.SizeOf(new LayerData()) * HeaderSettings.LayerCount * AntiAliasingSize; + + for (byte aaIndex = 0; aaIndex < AntiAliasingSize; aaIndex++) { - for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + Parallel.For(0, LayerCount, layerIndex => { - - LayerData layerData = new LayerData(); - LayerData layerDataHash = null; + LayerData layerData = new LayerData(this, (uint) layerIndex); + LayersDefinitions[aaIndex, layerIndex] = layerData; var image = this[layerIndex].Image; - rawData = IsCbtFile ? EncodeCbtImage(image, layerIndex) : EncodeCbddlpImage(image, aaIndex); + layerData.Encode(image, aaIndex, (uint) layerIndex); + }); - var byteArr = rawData.ToArray(); + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + { + var layerData = LayersDefinitions[aaIndex, layerIndex]; + LayerData layerDataHash = null; if (HeaderSettings.EncryptionKey == 0) { - string hash = Helpers.ComputeSHA1Hash(byteArr); - if (!LayersHash.TryGetValue(hash, out layerDataHash)) + string hash = Helpers.ComputeSHA1Hash(layerData.EncodedRle); + if (LayersHash.TryGetValue(hash, out layerDataHash)) + { + layerData.DataAddress = layerDataHash.DataAddress; + layerData.DataSize = layerDataHash.DataSize; + } + else { LayersHash.Add(hash, layerData); } } - //layer.DataAddress = CurrentOffset + (uint)Helpers.Serializer.SizeOf(layer); - layerData.DataAddress = layerDataHash?.DataAddress ?? layerDataCurrentOffset; - layerData.DataSize = layerDataHash?.DataSize ?? (uint) byteArr.Length; - layerData.LayerPositionZ = layerIndex * HeaderSettings.LayerHeightMilimeter; - layerData.LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount - ? PrintParametersSettings.BottomLightOffDelay - : PrintParametersSettings.LightOffDelay; - layerData.LayerExposure = layerIndex < HeaderSettings.BottomLayersCount - ? HeaderSettings.BottomExposureSeconds - : HeaderSettings.LayerExposureSeconds; - LayersDefinitions[layerIndex, aaIndex] = layerData; - - currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData); + if (ReferenceEquals(layerDataHash, null)) + { + layerData.DataAddress = layerDataCurrentOffset; - if (!ReferenceEquals(layerDataHash, null)) continue; + outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin); + layerDataCurrentOffset += outputFile.WriteBytes(layerData.EncodedRle); + } - outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin); - layerDataCurrentOffset += Helpers.WriteFileStream(outputFile, byteArr); outputFile.Seek(currentOffset, SeekOrigin.Begin); + currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData); } } @@ -769,150 +1105,7 @@ void rleRGB15() } } - private List EncodeCbddlpImage(Image image, byte aalevel) - { - List rawData = new List(); - - bool obit = false; - int rep = 0; - - void AddRep() - { - if (rep <= 0) return; - - byte by = (byte) rep; - - if (obit) - { - by |= 0x80; - //bitsOn += uint(rep) - } - - rawData.Add(by); - } - - for (int y = 0; y < image.Height; y++) - { - Span pixelRowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - //ngrey:= uint16(r | g | b) - - var nbit = (pixelRowSpan[x].PackedValue & (1 << (int)(8 - HeaderSettings.AntiAliasLevel + aalevel))) != 0; - if (nbit == obit) - { - rep++; - - if (rep == RLE8EncodingLimit) - { - AddRep(); - rep = 0; - } - } - else - { - AddRep(); - obit = nbit; - rep = 1; - } - } - } - - // Collect stragglers - AddRep(); - - return rawData; - } - - private List EncodeCbtImage(Image image, uint layerIndex) - { - List rawData = new List(); - byte color = byte.MaxValue >> 1; - uint stride = 0; - - void AddRep() - { - if (stride == 0) - { - return; - } - - if (stride > 1) - { - color |= 0x80; - } - rawData.Add(color); - - if (stride <= 1) - { - // no run needed - return; - } - - if (stride <= 0x7f) - { - rawData.Add((byte) stride); - return; - } - - if (stride <= 0x3fff) - { - rawData.Add((byte) ((stride >> 8) | 0x80)); - rawData.Add((byte)stride); - return; - } - - if (stride <= 0x1fffff) - { - rawData.Add((byte)((stride >> 16) | 0xc0)); - rawData.Add((byte)(stride >> 8)); - rawData.Add((byte)stride); - return; - } - - if (stride <= 0xfffffff) - { - rawData.Add((byte)((stride >> 24) | 0xe0)); - rawData.Add((byte)(stride >> 16)); - rawData.Add((byte)(stride >> 8)); - rawData.Add((byte)stride); - } - - } - - - for (int y = 0; y < image.Height; y++) - { - var pixelRowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - var grey7 = (byte)(pixelRowSpan[x].PackedValue >> 1); - - if (grey7 == color) - { - stride++; - } - else - { - AddRep(); - color = grey7; - stride = 1; - } - } - } - - AddRep(); - - if (HeaderSettings.EncryptionKey > 0) - { - List encodedData = new List(); - KeyRing kr = new KeyRing(HeaderSettings.EncryptionKey, layerIndex); - return kr.Read(rawData); - } - - return rawData; - } public override void Decode(string fileFullPath) { @@ -951,39 +1144,11 @@ public override void Decode(string fileFullPath) Debug.Write($"Preview {i} -> "); Debug.WriteLine(Previews[i]); - Thumbnails[i] = new Image((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++; - } - } - } + Thumbnails[i] = Previews[i].Decode(rawImageData); } //if (HeaderSettings.Version == 2) @@ -1012,19 +1177,20 @@ public override void Decode(string fileFullPath) Debug.WriteLine($"{nameof(MachineName)}: {MachineName}");*/ //} - LayersDefinitions = new LayerData[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel]; + LayersDefinitions = new LayerData[AntiAliasingSize, HeaderSettings.LayerCount]; uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (byte aaIndex = 0; aaIndex < AntiAliasingSize; aaIndex++) { Debug.WriteLine($"-Image GROUP {aaIndex}-"); for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { inputFile.Seek(layerOffset, SeekOrigin.Begin); LayerData layerData = Helpers.Deserialize(inputFile); - LayersDefinitions[layerIndex, aaIndex] = layerData; + layerData.Parent = this; + LayersDefinitions[aaIndex, layerIndex] = layerData; layerOffset += (uint)Helpers.Serializer.SizeOf(layerData); Debug.Write($"LAYER {layerIndex} -> "); @@ -1038,236 +1204,13 @@ public override void Decode(string fileFullPath) LayerManager = new LayerManager(HeaderSettings.LayerCount); - Parallel.For(0, LayerCount, layerIndex => { - var image = IsCbtFile ? DecodeCbtImage((uint) layerIndex) : DecodeCbddlpImage((uint) layerIndex); - this[layerIndex] = new Layer((uint)layerIndex, image); - }); - - /*byte[,][] rleArr = new byte[LayerCount, HeaderSettings.AntiAliasLevel][]; - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - //byte[][] rleArr = new byte[HeaderSettings.AntiAliasLevel][]; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) - { - Layer layer = LayersDefinitions[layerIndex, aaIndex]; - inputFile.Seek(layer.DataAddress, SeekOrigin.Begin); - rleArr[layerIndex, aaIndex] = new byte[(int)layer.DataSize]; - inputFile.Read(rleArr[layerIndex, aaIndex], 0, (int)layer.DataSize); - } - - var image = IsCbtFile ? DecodeCbtImage(rleArr[0], layerIndex) : DecodeCbddlpImage(rleArr, layerIndex); - using (var ms = new MemoryStream()) - { - image.Save(ms, Helpers.PngEncoder); - Layers[layerIndex] = ms.ToArray(); - } - //} - - /*for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - var image = IsCbtFile ? DecodeCbtImage(layerIndex) : DecodeCbddlpImage(layerIndex); - using (var ms = new MemoryStream()) - { - image.Save(ms, Helpers.BmpEncoder); - Layers[layerIndex] = CompressLayer(ms.ToArray()); - } - }*/ - } - - private Image DecodeCbddlpImage(uint layerIndex) - { - Image image = new Image((int)HeaderSettings.ResolutionX, (int)HeaderSettings.ResolutionY); - - for (uint aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) - { - //Layer layer = LayersDefinitions[layerIndex, aaIndex]; - uint x = 0; - uint y = 0; - - foreach (byte rle in LayersDefinitions[layerIndex, aaIndex].EncodedRle) - { - // 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 - - if (length == 0) - { - Debug.WriteLine("Corrupted RLE data."); - continue; - } - - if (!color) // Skip black pixels - { - uint x2 = x + length; - y += x2 / HeaderSettings.ResolutionX; - x = x2 % HeaderSettings.ResolutionX; - continue; - } - - var span = image.GetPixelRowSpan((int)y); - while(length-- > 0) - { - if (x >= HeaderSettings.ResolutionX) - { - y++; - x = 0; - span = image.GetPixelRowSpan((int)y); - } - - span[(int)x] = Helpers.L8White; - x++; - } - } - } - - return image; - } - - private Image DecodeCbtImage(uint layerIndex) - { - Image image = new Image((int)HeaderSettings.ResolutionX, (int)HeaderSettings.ResolutionY); - //Layer layer = LayersDefinitions[layerIndex, 0]; - - uint x = 0; - uint y = 0; - - var rawImageData = LayersDefinitions[layerIndex, 0].EncodedRle; - - if (HeaderSettings.EncryptionKey > 0) + Parallel.For(0, LayerCount, layerIndex => { - KeyRing kr = new KeyRing(HeaderSettings.EncryptionKey, layerIndex); - rawImageData = kr.Read(rawImageData); - } - - for (var n = 0; n < rawImageData.Length; n++) - { - byte code = rawImageData[n]; - uint stride = 1; - - if ((code & 0x80) == 0x80) // It's a run - { - code &= 0x7f; // Get the run length - n++; - - var slen = rawImageData[n]; - - if ((slen & 0x80) == 0) - { - stride = slen; - } - else if ((slen & 0xc0) == 0x80) - { - stride = (uint) (((slen & 0x3f) << 8) + rawImageData[n + 1]); - n++; - } - else if((slen & 0xe0) == 0xc0) - { - stride = (uint) (((slen & 0x1f) << 16) + (rawImageData[n + 1] << 8) + rawImageData[n + 2]); - n += 2; - } - else if((slen & 0xf0) == 0xe0) - { - stride = (uint) (((slen & 0xf) << 24) + (rawImageData[n + 1] << 16) + (rawImageData[n + 2] << 8) + rawImageData[n + 3]); - - n += 3; - } - else - { - Debug.WriteLine("Corrupted RLE data"); - } - } - - // Bit extend from 7-bit to 8-bit greymap - if (code != 0) - { - code = (byte) ((code << 1) | 1); - } - - if(stride == 0) continue; // Nothing to do - - if (code == 0) // Ignore blacks, spare cycles - { - uint x2 = x + stride; - y += x2 / HeaderSettings.ResolutionX; - x = x2 % HeaderSettings.ResolutionX; - continue; - } - - var span = image.GetPixelRowSpan((int)y); - while (stride-- > 0) - { - if (x >= HeaderSettings.ResolutionX) - { - y++; - x = 0; - span = image.GetPixelRowSpan((int)y); - } - - span[(int) x].PackedValue = code; - - x++; - } - } - - return image; - } - - /*public override byte[] GetLayer(uint layerIndex) - { - if (layerIndex >= LayerCount) return null; - if (ReferenceEquals(Layers[layerIndex], null)) - { - var image = GetLayerImage(layerIndex); - using (var ms = new MemoryStream()) - { - image.Save(ms, Helpers.PngEncoder); - Layers[layerIndex] = CompressLayer(ms.ToArray()); - } - } - - return base.GetLayer(layerIndex); + var image = LayersDefinitions[0, layerIndex].Decode((uint) layerIndex); + this[layerIndex] = new Layer((uint)layerIndex, image); + }); } - public override Image GetLayerImage(uint layerIndex) - { - if (layerIndex >= LayerCount) return null; - if (ReferenceEquals(Layers[layerIndex], null)) - { - var image = IsCbtFile ? DecodeCbtImage(layerIndex) : DecodeCbddlpImage(layerIndex); - /*using (var ms = new MemoryStream()) - { - image.Save(ms, Helpers.PngEncoder); - Layers[layerIndex] = CompressLayer(ms.ToArray()); - }*/ - /*if (image.TryGetSinglePixelSpan(out var pixelSpan)) - { - byte[] rgbaBytes = MemoryMarshal.AsBytes(pixelSpan).ToArray(); - using (MemoryStream output = new MemoryStream()) - { - using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal)) - { - dstream.Write(rgbaBytes, 0, rgbaBytes.Length); - } - var byes = output.ToArray(); - } - }*/ - /* return image; - } - - return base.GetLayerImage(layerIndex); - }*/ - - /*public override Image GetLayerImage(uint layerIndex) - { - if (layerIndex >= LayerCount) - { - return null; - //throw new IndexOutOfRangeException($"Layer {layerIndex} doesn't exists, out of bounds."); - } - - return IsCbtFile ? DecodeCbtImage(layerIndex) : DecodeCbddlpImage(layerIndex); - }*/ - public override object GetValueFromPrintParameterModifier(PrintParameterModifier modifier) { var baseValue = base.GetValueFromPrintParameterModifier(modifier); @@ -1292,13 +1235,13 @@ public override bool SetValueFromPrintParameterModifier(PrintParameterModifier m { void UpdateLayers() { - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (byte aaIndex = 0; aaIndex < AntiAliasingSize; aaIndex++) { for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { // Bottom : others - LayersDefinitions[layerIndex, aaIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; - LayersDefinitions[layerIndex, aaIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? PrintParametersSettings.BottomLightOffDelay : PrintParametersSettings.LightOffDelay; + LayersDefinitions[aaIndex, layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; + LayersDefinitions[aaIndex, layerIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? PrintParametersSettings.BottomLightOffDelay : PrintParametersSettings.LightOffDelay; } } } @@ -1410,13 +1353,12 @@ public override void SaveAs(string filePath = null) } uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (byte aaIndex = 0; aaIndex < AntiAliasingSize; aaIndex++) { for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { outputFile.Seek(layerOffset, SeekOrigin.Begin); - Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex, aaIndex]); - layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex, aaIndex]); + layerOffset += Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[aaIndex, layerIndex]); } } outputFile.Close(); @@ -1427,46 +1369,77 @@ public override void SaveAs(string filePath = null) public override bool Convert(Type to, string fileFullPath) { + if (to == typeof(PWSFile)) + { + PWSFile file = new PWSFile + { + LayerManager = LayerManager, + HeaderSettings = + { + ResolutionX = ResolutionX, + ResolutionY = ResolutionY, + LayerHeight = LayerHeight, + LayerExposureTime = LayerExposureTime, + LiftHeight = LiftHeight, + LiftSpeed = LiftSpeed / 60, + RetractSpeed = RetractSpeed / 60, + LayerOffTime = HeaderSettings.LayerOffTime, + BottomLayersCount = InitialLayerCount, + BottomExposureSeconds = InitialExposureTime, + Price = MaterialCost, + Volume = UsedMaterial, + Weight = PrintParametersSettings.WeightG, + AntiAliasing = ValidateAntiAliasingLevel() + } + }; + + file.SetThumbnails(Thumbnails); + file.Encode(fileFullPath); + + return true; + } + if (to == typeof(PHZFile)) { PHZFile file = new PHZFile { - LayerManager = LayerManager + LayerManager = LayerManager, + HeaderSettings = + { + Version = 2, + BedSizeX = HeaderSettings.BedSizeX, + BedSizeY = HeaderSettings.BedSizeY, + BedSizeZ = HeaderSettings.BedSizeZ, + OverallHeightMilimeter = TotalHeight, + BottomExposureSeconds = InitialExposureTime, + BottomLayersCount = InitialLayerCount, + BottomLightPWM = HeaderSettings.BottomLightPWM, + LayerCount = LayerCount, + LayerExposureSeconds = LayerExposureTime, + LayerHeightMilimeter = LayerHeight, + LayerOffTime = HeaderSettings.LayerOffTime, + LightPWM = HeaderSettings.LightPWM, + PrintTime = HeaderSettings.PrintTime, + ProjectorType = HeaderSettings.ProjectorType, + ResolutionX = ResolutionX, + ResolutionY = ResolutionY, + BottomLayerCount = InitialLayerCount, + BottomLiftHeight = PrintParametersSettings.BottomLiftHeight, + BottomLiftSpeed = PrintParametersSettings.BottomLiftSpeed, + BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay, + CostDollars = MaterialCost, + LiftHeight = PrintParametersSettings.LiftHeight, + LiftingSpeed = PrintParametersSettings.LiftingSpeed, + RetractSpeed = PrintParametersSettings.RetractSpeed, + VolumeMl = UsedMaterial, + AntiAliasLevelInfo = ValidateAntiAliasingLevel(), + WeightG = PrintParametersSettings.WeightG, + MachineName = MachineName, + MachineNameSize = (uint)MachineName.Length + } }; - - file.HeaderSettings.Version = 2; - file.HeaderSettings.BedSizeX = HeaderSettings.BedSizeX; - file.HeaderSettings.BedSizeY = HeaderSettings.BedSizeY; - file.HeaderSettings.BedSizeZ = HeaderSettings.BedSizeZ; - file.HeaderSettings.OverallHeightMilimeter = TotalHeight; - file.HeaderSettings.BottomExposureSeconds = InitialExposureTime; - file.HeaderSettings.BottomLayersCount = InitialLayerCount; - file.HeaderSettings.BottomLightPWM = HeaderSettings.BottomLightPWM; - file.HeaderSettings.LayerCount = LayerCount; - file.HeaderSettings.LayerExposureSeconds = LayerExposureTime; - file.HeaderSettings.LayerHeightMilimeter = LayerHeight; - file.HeaderSettings.LayerOffTime = HeaderSettings.LayerOffTime; - file.HeaderSettings.LightPWM = HeaderSettings.LightPWM; - file.HeaderSettings.PrintTime = HeaderSettings.PrintTime; - file.HeaderSettings.ProjectorType = HeaderSettings.ProjectorType; - file.HeaderSettings.ResolutionX = ResolutionX; - file.HeaderSettings.ResolutionY = ResolutionY; - - file.HeaderSettings.BottomLayerCount = InitialLayerCount; - file.HeaderSettings.BottomLiftHeight = PrintParametersSettings.BottomLiftHeight; - file.HeaderSettings.BottomLiftSpeed = PrintParametersSettings.BottomLiftSpeed; - file.HeaderSettings.BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay; - file.HeaderSettings.CostDollars = MaterialCost; - file.HeaderSettings.LiftHeight = PrintParametersSettings.LiftHeight; - file.HeaderSettings.LiftingSpeed = PrintParametersSettings.LiftingSpeed; - file.HeaderSettings.LayerOffTime = HeaderSettings.LayerOffTime; - file.HeaderSettings.RetractSpeed = PrintParametersSettings.RetractSpeed; - file.HeaderSettings.VolumeMl = UsedMaterial; - file.HeaderSettings.WeightG = PrintParametersSettings.WeightG; - - file.HeaderSettings.MachineName = MachineName; - file.HeaderSettings.MachineNameSize = (uint) MachineName.Length; + file.SetThumbnails(Thumbnails); file.Encode(fileFullPath); @@ -1503,7 +1476,7 @@ public override bool Convert(Type to, string fileFullPath) BottomLayerExposureTime = (uint)(InitialExposureTime * 1000), MaterialId = 2, LayerThickness = $"{LayerHeight} mm", - AntiAliasing = 0, + AntiAliasing = (byte)(AntiAliasing > 1 ? 1 : 0), CrossSupportEnabled = 1, ExposureOffTime = (uint) HeaderSettings.LayerOffTime, HollowEnabled = 0, diff --git a/PrusaSL1Reader/Extensions/FileStreamExtensions.cs b/PrusaSL1Reader/Extensions/FileStreamExtensions.cs new file mode 100644 index 00000000..3d1dd61e --- /dev/null +++ b/PrusaSL1Reader/Extensions/FileStreamExtensions.cs @@ -0,0 +1,31 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ + +using System.IO; + +namespace PrusaSL1Reader.Extensions +{ + public static class FileStreamExtensions + { + public static uint ReadBytes(this FileStream fs, byte[] bytes, int offset = 0) + { + return (uint)fs.Read(bytes, offset, bytes.Length); + } + + public static uint WriteStream(this FileStream fs, MemoryStream stream, int offset = 0) + { + return fs.WriteBytes(stream.ToArray(), offset); + } + + public static uint WriteBytes(this FileStream fs, byte[] bytes, int offset = 0) + { + fs.Write(bytes, offset, bytes.Length); + return (uint)bytes.Length; + } + } +} diff --git a/PrusaSL1Reader/Extensions/ObjectExtensions.cs b/PrusaSL1Reader/Extensions/ObjectExtensions.cs deleted file mode 100644 index d7a1d1f8..00000000 --- a/PrusaSL1Reader/Extensions/ObjectExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * GNU AFFERO GENERAL PUBLIC LICENSE - * Version 3, 19 November 2007 - * Copyright (C) 2007 Free Software Foundation, Inc. - * 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.Extensions -{ - public static class ObjectExtensions - { - /// - /// Converts a string into a target type - /// - /// Target type to convert into - /// Value - /// Converted value into target type - public static T Convert(this object input) - { - return StringExtensions.Convert(input.ToString()); - } - - public static object DeserializeFromBytes(byte[] bytes) - { - var formatter = new BinaryFormatter(); - using (var stream = new MemoryStream(bytes)) - { - return formatter.Deserialize(stream); - } - } - } -} diff --git a/PrusaSL1Reader/FileFormat.cs b/PrusaSL1Reader/FileFormat.cs index aa2fb2dd..83a21333 100644 --- a/PrusaSL1Reader/FileFormat.cs +++ b/PrusaSL1Reader/FileFormat.cs @@ -8,7 +8,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -268,6 +267,8 @@ public byte CreatedThumbnailsCount { public abstract uint ResolutionX { get; } public abstract uint ResolutionY { get; } + public bool HaveAntiAliasing => AntiAliasing > 1; + public abstract byte AntiAliasing { get; } public abstract float LayerHeight { get; } @@ -649,6 +650,7 @@ public void Resize(uint startLayerIndex, uint endLayerIndex, float x, float y) image.Mutate(o => o.Resize(width, height)); newImage.Mutate(o => o.DrawImage(image, location, 1f)); + this[layerIndex].Image = newImage; }); @@ -670,6 +672,13 @@ public void Resize(uint startLayerIndex, uint endLayerIndex, float x, float y) }*/ } + public byte ValidateAntiAliasingLevel() + { + if (AntiAliasing < 2) return 1; + if(AntiAliasing % 2 != 0) throw new ArgumentException("AntiAliasing must be multiples of 2, otherwise use 0 or 1 to disable it", nameof(AntiAliasing)); + return AntiAliasing; + } + #endregion } } diff --git a/PrusaSL1Reader/Helpers.cs b/PrusaSL1Reader/Helpers.cs index 6e1c0323..af4a56f5 100644 --- a/PrusaSL1Reader/Helpers.cs +++ b/PrusaSL1Reader/Helpers.cs @@ -74,32 +74,16 @@ public static MemoryStream Serialize(object value) return stream; } - public static T Deserialize(BinaryReader binaryReader) - { - return Deserialize(binaryReader.BaseStream); - } - public static T Deserialize(Stream stream) { return Serializer.Deserialize(stream); } - public static uint WriteFileStream(FileStream fs, MemoryStream stream, uint offset = 0) - { - return WriteFileStream(fs, stream.ToArray(), offset); - } - - public static uint WriteFileStream(FileStream fs, byte[] bytes, uint offset = 0) - { - fs.Write(bytes, 0, bytes.Length); - return (uint)bytes.Length; - } - - public static uint SerializeWriteFileStream(FileStream fs, object value, uint offset = 0) + public static uint SerializeWriteFileStream(FileStream fs, object value, int offset = 0) { using (MemoryStream stream = Helpers.Serialize(value)) { - return WriteFileStream(fs, stream); + return fs.WriteStream(stream, offset); } } @@ -153,10 +137,5 @@ public static bool SetPropertyValue(PropertyInfo attribute, object obj, string v throw new Exception($"Data type '{name}' not recognized, contact developer."); } } - - public static uint CoordinatesToPixelIndex(uint x, uint y, uint width) - { - return y * width + x; - } } } diff --git a/PrusaSL1Reader/IFileFormat.cs b/PrusaSL1Reader/IFileFormat.cs index 3b0016a3..bda39255 100644 --- a/PrusaSL1Reader/IFileFormat.cs +++ b/PrusaSL1Reader/IFileFormat.cs @@ -7,8 +7,6 @@ */ using System; -using System.Drawing; -using System.IO; using System.Text; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -92,6 +90,13 @@ public interface IFileFormat /// uint ResolutionY { get; } + bool HaveAntiAliasing { get; } + + /// + /// Gets the AntiAliasing level + /// + byte AntiAliasing { get; } + /// /// Gets Layer Height in mm /// @@ -330,6 +335,11 @@ public interface IFileFormat /// Y factor void Resize(uint startLayerIndex, uint endLayerIndex, float x, float y); + /// + /// Validate AntiAlias Level + /// + byte ValidateAntiAliasingLevel(); + #endregion } } diff --git a/PrusaSL1Reader/ImageFile.cs b/PrusaSL1Reader/ImageFile.cs index 2bdfe441..8845882b 100644 --- a/PrusaSL1Reader/ImageFile.cs +++ b/PrusaSL1Reader/ImageFile.cs @@ -27,6 +27,7 @@ public class ImageFile : FileFormat public override Size[] ThumbnailsOriginalSize { get; } = null; public override uint ResolutionX => (uint)ImageL8.Width; public override uint ResolutionY => (uint)ImageL8.Height; + public override byte AntiAliasing { get; } = 1; public override float LayerHeight { get; } = 0; public override ushort InitialLayerCount { get; } = 1; public override float InitialExposureTime { get; } = 0; diff --git a/PrusaSL1Reader/LayerManager.cs b/PrusaSL1Reader/LayerManager.cs index 68cbbb4e..3b3fbfb2 100644 --- a/PrusaSL1Reader/LayerManager.cs +++ b/PrusaSL1Reader/LayerManager.cs @@ -6,6 +6,7 @@ * of this license document, but changing it is not allowed. */ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.IO; @@ -18,33 +19,62 @@ namespace PrusaSL1Reader { - #region LayerIsland Class - public class LayerIsland : IEnumerable + #region LayerIssue Class + + public class LayerIssue : IEnumerable { + public enum IssueType : byte + { + Island, + ResinTrap, + TouchingBound, + //HoleSandwich, + } + /// - /// Gets the layer who own this island + /// Gets the parent layer /// - public Layer Owner { get; } + public Layer Layer { get; } - public uint X => (uint) Pixels[0].X; + /// + /// Gets the issue type associated + /// + public IssueType Type { get; } - public uint Y => (uint)Pixels[0].Y; + /// + /// Gets the pixels containing the issue + /// + public Point[] Pixels { get; } - public Point Point => new Point((int) X, (int) Y); + /// + /// Gets the X coordinate for the first point, -1 if doesn't exists + /// + public int X => HaveValidPoint ? Pixels[0].X : -1; /// - /// Gets pixels locations + /// Gets the Y coordinate for the first point, -1 if doesn't exists /// - public Point[] Pixels { get; } + public int Y => HaveValidPoint ? Pixels[0].Y : -1; + + /// + /// Gets the XY point for first point + /// + public Point Point => HaveValidPoint ? Pixels[0] : new Point(-1, -1); /// - /// Gets the number of pixels on this island + /// Gets the number of pixels on this issue /// - public uint Size => (uint) Pixels.Length; + public uint Size => (uint) (Pixels?.Length ?? 0); - public LayerIsland(Layer owner, Point[] pixels) + /// + /// Check if this issue have a valid start point to show + /// + public bool HaveValidPoint => !ReferenceEquals(Pixels, null) && Pixels.Length > 0; + + public LayerIssue(Layer layer, IssueType type, Point[] pixels = null) { - Owner = owner; + Layer = layer; + Type = type; Pixels = pixels; } @@ -52,7 +82,6 @@ public LayerIsland(Layer owner, Point[] pixels) public Point this[int index] => Pixels[index]; - public IEnumerator GetEnumerator() { return ((IEnumerable)Pixels).GetEnumerator(); @@ -62,6 +91,11 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + public override string ToString() + { + return $"{nameof(Type)}: {Type}"; + } } #endregion @@ -225,7 +259,7 @@ public int Compare(Layer x, Layer y) #region Formaters public override string ToString() { - return $"{nameof(Filename)}: {Filename}, {nameof(IsModified)}: {IsModified}"; + return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(IsModified)}: {IsModified}"; } #endregion @@ -252,7 +286,7 @@ public Layer NextLayer() /// https://www.geeksforgeeks.org/find-number-of-islands/ /// /// holding all islands coordinates - public List GetIslandsLocation(uint requiredPixelsToSupportIsland = 5) + public List GetIssues(uint requiredPixelsToSupportIsland = 5) { if (requiredPixelsToSupportIsland == 0) requiredPixelsToSupportIsland = 1; @@ -260,16 +294,10 @@ public List GetIslandsLocation(uint requiredPixelsToSupportIsland = // These arrays are used to // get row and column numbers // of 8 neighbors of a given cell - List result = new List(); + List result = new List(); List pixels = new List(); - if (Index == 0) return result; - sbyte[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 }; - sbyte[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 }; - const uint minPixel = 10; - const uint minPixelForSupportIsland = 200; - int pixelIndex; - uint islandSupportingPixels; + var image = Image; byte[] bytes = null; @@ -288,99 +316,145 @@ public List GetIslandsLocation(uint requiredPixelsToSupportIsland = } } + /*var nextLayerImage = NextLayer()?.Image; + byte[] nextBytes = null; + if (!ReferenceEquals(nextLayerImage, null)) + { + if (nextLayerImage.TryGetSinglePixelSpan(out var nextPixelSpan)) + { + nextBytes = MemoryMarshal.AsBytes(nextPixelSpan).ToArray(); + } + }*/ + // Make a bool array to // mark visited cells. // Initially all cells // are unvisited - bool[,] visited = new bool[image.Height, image.Width]; - - /*bool isSafe() - { - // row number is in range, - // column number is in range - // and value is 1 and not - // yet visited - pixelIndex = y2 * image.Width + x2; - return (y2 >= 0) && (y2 < image.Height) && (x2 >= 0) && (x2 < image.Width) && (bytes[pixelIndex] >= minPixel && !visited[y2, x2]); - }*/ + bool[,] visited = new bool[image.Width, image.Height]; + // Initialize count as 0 and + // traverse through the all + // cells of given matrix + //uint count = 0; - void DFS(int y2, int x2) + // Island checker + sbyte[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 }; + sbyte[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 }; + const uint minPixel = 10; + const uint minPixelForSupportIsland = 200; + int pixelIndex; + uint islandSupportingPixels; + if (Index > 0) { - Queue queue = new Queue(); - queue.Enqueue(new System.Drawing.Point(x2, y2)); - // Mark this cell as visited - visited[y2, x2] = true; - - while (queue.Count > 0) + for (int y = 0; y < image.Height; y++) { - var point = queue.Dequeue(); - y2 = point.Y; - x2 = point.X; - for (byte k = 0; k < 8; k++) + for (int x = 0; x < image.Width; x++) { - //if (isSafe(y2 + rowNbr[k], x2 + colNbr[k])) - var tempy2 = y2 + rowNbr[k]; - var tempx2 = x2 + colNbr[k]; - pixelIndex = tempy2 * image.Width + tempx2; - if (tempy2 >= 0 && - tempy2 < image.Height && - tempx2 >= 0 && tempx2 < image.Width && - bytes[pixelIndex] >= minPixel && - !visited[tempy2, tempx2]) + pixelIndex = y * image.Width + x; + + /*if (bytes[pixelIndex] == 0 && previousBytes?[pixelIndex] == byte.MaxValue && + nextBytes?[pixelIndex] == byte.MaxValue) { - visited[tempy2, tempx2] = true; - point = new Point(tempx2, tempy2); - pixels.Add(point); - queue.Enqueue(point); + result.Add(new LayerIssue(this, LayerIssue.IssueType.HoleSandwich, new []{new Point(x, y)})); + }*/ + + if (bytes[pixelIndex] > minPixel && !visited[x, y]) + { + // If a cell with value 1 is not + // visited yet, then new island + // found, Visit all cells in this + // island and increment island count + pixels.Clear(); + pixels.Add(new Point(x, y)); + islandSupportingPixels = previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0; + - islandSupportingPixels += previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0; - /*if (!presetOnPrevious) + + int x2; + int y2; + + + Queue queue = new Queue(); + queue.Enqueue(new Point(x, y)); + // Mark this cell as visited + visited[x, y] = true; + + while (queue.Count > 0) { - if (previousBytes[pixelIndex] >= minPixelForSupportIsland) presetOnPrevious = true; - }*/ + var point = queue.Dequeue(); + y2 = point.Y; + x2 = point.X; + for (byte k = 0; k < 8; k++) + { + //if (isSafe(y2 + rowNbr[k], x2 + colNbr[k])) + var tempy2 = y2 + rowNbr[k]; + var tempx2 = x2 + colNbr[k]; + pixelIndex = tempy2 * image.Width + tempx2; + if (tempy2 >= 0 && + tempy2 < image.Height && + tempx2 >= 0 && tempx2 < image.Width && + bytes[pixelIndex] >= minPixel && + !visited[tempx2, tempy2]) + { + visited[tempx2, tempy2] = true; + point = new Point(tempx2, tempy2); + pixels.Add(point); + queue.Enqueue(point); + + islandSupportingPixels += previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0; + } + } + } + //count++; + + if (islandSupportingPixels >= requiredPixelsToSupportIsland) + continue; // Not a island, bounding is strong + if (islandSupportingPixels > 0 && pixels.Count < requiredPixelsToSupportIsland && + islandSupportingPixels >= Math.Max(1, pixels.Count / 2)) continue; // Not a island + result.Add(new LayerIssue(this, LayerIssue.IssueType.Island, pixels.ToArray())); } } } } - // Initialize count as 0 and - // travese through the all - // cells of given matrix - //uint count = 0; - for (int y = 0; y < image.Height; ++y) + pixels.Clear(); + + // TouchingBounds Checker + for (int x = 0; x < image.Width; x++) // Check Top and Bottom bounds { - for (int x = 0; x < image.Width; ++x) + if (bytes[x] >= 200) // Top { - pixelIndex = y * image.Width + x; - if (bytes[pixelIndex] > minPixel && !visited[y, x]) - { - // If a cell with value 1 is not - // visited yet, then new island - // found, Visit all cells in this - // island and increment island count - pixels.Clear(); - pixels.Add(new Point(x, y)); - islandSupportingPixels = previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0; - DFS(y, x); - //count++; - - if (islandSupportingPixels >= requiredPixelsToSupportIsland) continue; // Not a island, bounding is strong - if (islandSupportingPixels > 0 && pixels.Count < requiredPixelsToSupportIsland && islandSupportingPixels >= Math.Max(1, pixels.Count / 2)) continue; // Not a island - result.Add(new LayerIsland(this, pixels.ToArray())); - } + pixels.Add(new Point(x, 0)); + } + + if (bytes[image.Width * image.Height - image.Width + x] >= 200) // Bottom + { + pixels.Add(new Point(x, image.Height-1)); } } - return result; - } + for (int y = 0; y < image.Height; y++) // Check Left and Right bounds + { + if (bytes[y * image.Width] >= 200) // Left + { + pixels.Add(new Point(0, y)); + } - /// - /// Count the number of islands on this layer - /// - /// Number of islands - public uint CountIslands => (uint)GetIslandsLocation().Count; + if (bytes[y * image.Width + image.Width - 1] >= 200) // Right + { + pixels.Add(new Point(image.Width-1, y)); + } + } + + if (pixels.Count > 0) + { + result.Add(new LayerIssue(this, LayerIssue.IssueType.TouchingBound, pixels.ToArray())); + } + pixels.Clear(); + + return result; + } public Layer Clone() { @@ -536,15 +610,81 @@ public Layer GetLayer(uint index) return Layers[index]; } - public Dictionary> GetAllIslands() + public SortedDictionary> GetAllIssues() { - var result = new Dictionary>((int) Count); + var result = new SortedDictionary>(); - Parallel.ForEach(this, (layer) => + Parallel.ForEach(this, layer => { - result[layer.Index] = layer.GetIslandsLocation(); + var issues = layer.GetIssues(); + if (issues.Count > 0) + { + result.Add(layer.Index, issues); + } }); + /*const byte minPixel = 50; + sbyte[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 }; + sbyte[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 }; + + int pixelIndex; + for (uint layerindex = 0; layerindex < Count; layerindex++) + { + var image = this[layerindex].Image; + byte[] bytes = null; + if (image.TryGetSinglePixelSpan(out var pixelSpan)) + { + bytes = MemoryMarshal.AsBytes(pixelSpan).ToArray(); + } + + bool[,] visited = new bool[image.Width, image.Height]; + + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + pixelIndex = y * image.Width + x; + if (bytes[pixelIndex] > minPixel && !visited[y, x]) + { + Queue queue = new Queue(); + queue.Enqueue(new Point(x, y)); + // Mark this cell as visited + visited[x, y] = true; + + var x2 = x; + var y2 = y; + + while (queue.Count > 0) + { + var point = queue.Dequeue(); + y2 = point.Y; + x2 = point.X; + for (byte k = 0; k < 8; k++) + { + //if (isSafe(y2 + rowNbr[k], x2 + colNbr[k])) + var tempy2 = y2 + rowNbr[k]; + var tempx2 = x2 + colNbr[k]; + pixelIndex = tempy2 * image.Width + tempx2; + if (tempy2 >= 0 && + tempy2 < image.Height && + tempx2 >= 0 && tempx2 < image.Width && + bytes[pixelIndex] >= minPixel && + !visited[tempx2, tempy2]) + { + visited[tempx2, tempy2] = true; + point = new Point(tempx2, tempy2); + pixels.Add(point); + queue.Enqueue(point); + + islandSupportingPixels += previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0; + } + } + } + } + } + } + }*/ + return result; } diff --git a/PrusaSL1Reader/PHZFile.cs b/PrusaSL1Reader/PHZFile.cs index a33a1ccf..ff7a3859 100644 --- a/PrusaSL1Reader/PHZFile.cs +++ b/PrusaSL1Reader/PHZFile.cs @@ -25,11 +25,8 @@ public class PHZFile : FileFormat { #region Constants private const uint MAGIC_PHZ = 0x9FDA83AE; - private const int SPECIAL_BIT = 1 << 1; - private const int SPECIAL_BIT_MASK = ~SPECIAL_BIT; private const ushort REPEATRGB15MASK = 0x20; - private const byte RLE8EncodingLimit = 125; private const ushort RLE16EncodingLimit = 0x1000; #endregion @@ -244,7 +241,7 @@ public class Header /// /// Gets the parameter used to control encryption. - /// Not totally understood. 0 for cbddlp files, 0xF for ctb files. + /// Not totally understood. 0 for cbddlp files, 0xF for ctb files, 0x1c for phz /// [FieldOrder(45)] public uint EncryptionMode { get; set; } = 28; @@ -256,7 +253,7 @@ public class Header /// /// Gets a number that increments with time or number of models sliced, or both. Zeroing it in output seems to have no effect. Possibly a user tracking bug. /// - [FieldOrder(47)] public uint AntiAliasLevel2 { get; set; } + [FieldOrder(47)] public uint AntiAliasLevelInfo { get; set; } [FieldOrder(48)] public uint SoftwareVersion { get; set; } = 0x01060300; @@ -269,7 +266,7 @@ public class Header public override string ToString() { - return $"{nameof(Magic)}: {Magic}, {nameof(Version)}: {Version}, {nameof(LayerHeightMilimeter)}: {LayerHeightMilimeter}, {nameof(LayerExposureSeconds)}: {LayerExposureSeconds}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(PreviewLargeOffsetAddress)}: {PreviewLargeOffsetAddress}, {nameof(LayersDefinitionOffsetAddress)}: {LayersDefinitionOffsetAddress}, {nameof(LayerCount)}: {LayerCount}, {nameof(PreviewSmallOffsetAddress)}: {PreviewSmallOffsetAddress}, {nameof(PrintTime)}: {PrintTime}, {nameof(ProjectorType)}: {ProjectorType}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(LightPWM)}: {LightPWM}, {nameof(BottomLightPWM)}: {BottomLightPWM}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(OverallHeightMilimeter)}: {OverallHeightMilimeter}, {nameof(BedSizeX)}: {BedSizeX}, {nameof(BedSizeY)}: {BedSizeY}, {nameof(BedSizeZ)}: {BedSizeZ}, {nameof(EncryptionKey)}: {EncryptionKey}, {nameof(BottomLightOffDelay)}: {BottomLightOffDelay}, {nameof(LayerOffTime)}: {LayerOffTime}, {nameof(BottomLayerCount)}: {BottomLayerCount}, {nameof(Padding3)}: {Padding3}, {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(Padding4)}: {Padding4}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(MachineName)}: {MachineName}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(Padding7)}: {Padding7}, {nameof(Padding8)}: {Padding8}, {nameof(Padding9)}: {Padding9}, {nameof(Padding10)}: {Padding10}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevel2)}: {AntiAliasLevel2}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(Padding11)}: {Padding11}, {nameof(Padding12)}: {Padding12}, {nameof(Padding13)}: {Padding13}, {nameof(Padding14)}: {Padding14}, {nameof(Padding15)}: {Padding15}, {nameof(Padding16)}: {Padding16}"; + return $"{nameof(Magic)}: {Magic}, {nameof(Version)}: {Version}, {nameof(LayerHeightMilimeter)}: {LayerHeightMilimeter}, {nameof(LayerExposureSeconds)}: {LayerExposureSeconds}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(PreviewLargeOffsetAddress)}: {PreviewLargeOffsetAddress}, {nameof(LayersDefinitionOffsetAddress)}: {LayersDefinitionOffsetAddress}, {nameof(LayerCount)}: {LayerCount}, {nameof(PreviewSmallOffsetAddress)}: {PreviewSmallOffsetAddress}, {nameof(PrintTime)}: {PrintTime}, {nameof(ProjectorType)}: {ProjectorType}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(LightPWM)}: {LightPWM}, {nameof(BottomLightPWM)}: {BottomLightPWM}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(OverallHeightMilimeter)}: {OverallHeightMilimeter}, {nameof(BedSizeX)}: {BedSizeX}, {nameof(BedSizeY)}: {BedSizeY}, {nameof(BedSizeZ)}: {BedSizeZ}, {nameof(EncryptionKey)}: {EncryptionKey}, {nameof(BottomLightOffDelay)}: {BottomLightOffDelay}, {nameof(LayerOffTime)}: {LayerOffTime}, {nameof(BottomLayerCount)}: {BottomLayerCount}, {nameof(Padding3)}: {Padding3}, {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(Padding4)}: {Padding4}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(MachineName)}: {MachineName}, {nameof(Padding5)}: {Padding5}, {nameof(Padding6)}: {Padding6}, {nameof(Padding7)}: {Padding7}, {nameof(Padding8)}: {Padding8}, {nameof(Padding9)}: {Padding9}, {nameof(Padding10)}: {Padding10}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevelInfo)}: {AntiAliasLevelInfo}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(Padding11)}: {Padding11}, {nameof(Padding12)}: {Padding12}, {nameof(Padding13)}: {Padding13}, {nameof(Padding14)}: {Padding14}, {nameof(Padding15)}: {Padding15}, {nameof(Padding16)}: {Padding16}"; } } #endregion @@ -306,6 +303,101 @@ public class Preview [FieldOrder(6)] public uint Unknown3 { get; set; } [FieldOrder(7)] public uint Unknown4 { get; set; } + public Image Decode(byte[] rawImageData) + { + var image = new Image((int)ResolutionX, (int)ResolutionY); + image.TryGetSinglePixelSpan(out var span); + int pixel = 0; + for (uint n = 0; n < 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++) + { + span[pixel] = new Rgba32(red, green, blue, byte.MaxValue); + pixel++; + } + } + + return image; + } + + public static byte[] Encode(Image image) + { + List rawData = new List(); + ushort color15 = 0; + uint rep = 0; + + void RleRGB15() + { + switch (rep) + { + case 0: + return; + case 1: + rawData.Add((byte)(color15 & ~REPEATRGB15MASK)); + rawData.Add((byte)((color15 & ~REPEATRGB15MASK) >> 8)); + break; + case 2: + for (int i = 0; i < 2; i++) + { + rawData.Add((byte)(color15 & ~REPEATRGB15MASK)); + rawData.Add((byte)((color15 & ~REPEATRGB15MASK) >> 8)); + } + + break; + default: + rawData.Add((byte)(color15 | REPEATRGB15MASK)); + rawData.Add((byte)((color15 | REPEATRGB15MASK) >> 8)); + rawData.Add((byte)((rep - 1) | 0x3000)); + rawData.Add((byte)(((rep - 1) | 0x3000) >> 8)); + break; + } + } + + for (int y = 0; y < image.Height; y++) + { + Span pixelRowSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + var ncolor15 = + (pixelRowSpan[x].B >> 3) + | ((pixelRowSpan[x].G >> 2) << 5) + | ((pixelRowSpan[x].R >> 3) << 11); + + if (ncolor15 == color15) + { + rep++; + if (rep == RLE16EncodingLimit) + { + RleRGB15(); + rep = 0; + } + } + else + { + RleRGB15(); + color15 = (ushort)ncolor15; + rep = 1; + } + } + } + + RleRGB15(); + + return rawData.ToArray(); + } + 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}"; @@ -348,6 +440,157 @@ public class LayerData [Ignore] public byte[] EncodedRle { get; set; } + [Ignore] public PHZFile Parent { get; set; } + + public LayerData() + { + } + + public LayerData(PHZFile parent, uint layerIndex) + { + Parent = parent; + LayerOffTimeSeconds = layerIndex < parent.HeaderSettings.BottomLayersCount ? parent.HeaderSettings.BottomLightOffDelay : parent.HeaderSettings.LayerOffTime; + LayerExposure = layerIndex < Parent.InitialLayerCount ? Parent.HeaderSettings.BottomExposureSeconds : Parent.HeaderSettings.LayerExposureSeconds; + LayerPositionZ = Parent.GetHeightFromLayer(layerIndex); + } + + public Image Decode(uint layerIndex, bool consumeData = true) + { + Image image = new Image((int)Parent.ResolutionX, (int)Parent.ResolutionY); + + + if (Parent.HeaderSettings.EncryptionKey > 0) + { + KeyRing kr = new KeyRing(Parent.HeaderSettings.EncryptionKey, layerIndex); + EncodedRle = kr.Read(EncodedRle); + } + + int limit = image.Width * image.Height; + int index = 0; + byte lastColor = 0; + + image.TryGetSinglePixelSpan(out var span); + + foreach (var code in EncodedRle) + { + if ((code & 0x80) == 0x80) + { + //lastColor = (byte) (code << 1); + // // Convert from 7bpp to 8bpp (extending the last bit) + lastColor = (byte)(((code & 0x7f) << 1) | (code & 1)); + if (lastColor >= 0xfc) + { + // Make 'white' actually white + lastColor = 0xff; + + } + + if (index < limit) + { + span[index].PackedValue = lastColor; + } + else + { + Debug.WriteLine("Corrupted RLE data."); + } + + index++; + } + else + { + for (uint i = 0; i < code; i++) + { + if (index < limit) + { + span[index].PackedValue = lastColor; + } + else + { + Debug.WriteLine("Corrupted RLE data."); + } + index++; + } + } + } + + if (consumeData) + EncodedRle = null; + + return image; + } + + public void Encode(Image image, uint layerIndex) + { + List rawData = new List(); + //byte color = byte.MaxValue >> 1; + byte color = byte.MaxValue; + uint stride = 0; + + void AddRep() + { + rawData.Add((byte)(color | 0x80)); + stride--; + int done = 0; + while (done < stride) + { + int todo = 0x7d; + + if (stride - done < todo) + { + todo = (int)(stride - done); + } + + rawData.Add((byte)(todo)); + + done += todo; + } + } + + int halfWidth = image.Width / 2; + + for (int y = 0; y < image.Height; y++) + { + var pixelRowSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + var grey7 = (byte)((pixelRowSpan[x].PackedValue >> 1) & 0x7f); + if (grey7 > 0x7c) + { + grey7 = 0x7c; + } + + if (color == byte.MaxValue) + { + color = grey7; + stride = 1; + } + else if (grey7 != color || x == halfWidth) + { + AddRep(); + color = grey7; + stride = 1; + } + else + { + stride++; + } + } + + AddRep(); + color = byte.MaxValue; + } + + + if (Parent.HeaderSettings.EncryptionKey > 0) + { + KeyRing kr = new KeyRing(Parent.HeaderSettings.EncryptionKey, layerIndex); + EncodedRle = kr.Read(rawData).ToArray(); + return; + } + + EncodedRle = rawData.ToArray(); + } + 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}"; @@ -413,19 +656,20 @@ public byte[] Read(byte[] input) public Preview[] Previews { get; protected internal set; } - public LayerData[,] LayersDefinitions { get; private set; } + public LayerData[] LayersDefinitions { get; private set; } public Dictionary LayersHash { get; } = new Dictionary(); public override FileFormatType FileType => FileFormatType.Binary; public override FileExtension[] FileExtensions { get; } = { - new FileExtension("phz", "PHZ Files"), + new FileExtension("phz", "Chitubox PHZ Files"), }; public override Type[] ConvertToFormats { get; } = { typeof(ChituboxFile), + typeof(PWSFile), typeof(ZCodexFile), }; @@ -454,6 +698,7 @@ public byte[] Read(byte[] input) public override uint ResolutionX => HeaderSettings.ResolutionX; public override uint ResolutionY => HeaderSettings.ResolutionY; + public override byte AntiAliasing => (byte) HeaderSettings.AntiAliasLevelInfo; public override float LayerHeight => HeaderSettings.LayerHeightMilimeter; @@ -512,83 +757,18 @@ public override void Encode(string fileFullPath) uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings); - LayersDefinitions = new LayerData[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel]; + LayersDefinitions = new LayerData[HeaderSettings.LayerCount]; using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write)) { - outputFile.Seek((int) currentOffset, SeekOrigin.Begin); - List rawData = new List(); - ushort color15 = 0; - uint rep = 0; - - void rleRGB15() - { - switch (rep) - { - case 0: - return; - case 1: - rawData.Add((byte) (color15 & ~REPEATRGB15MASK)); - rawData.Add((byte) ((color15 & ~REPEATRGB15MASK) >> 8)); - break; - case 2: - for (int i = 0; i < 2; i++) - { - rawData.Add((byte) (color15 & ~REPEATRGB15MASK)); - rawData.Add((byte) ((color15 & ~REPEATRGB15MASK) >> 8)); - } - - break; - default: - rawData.Add((byte) (color15 | REPEATRGB15MASK)); - rawData.Add((byte) ((color15 | REPEATRGB15MASK) >> 8)); - rawData.Add((byte) ((rep - 1) | 0x3000)); - rawData.Add((byte) (((rep - 1) | 0x3000) >> 8)); - break; - } - } - for (byte i = 0; i < ThumbnailsCount; i++) { var image = Thumbnails[i]; - color15 = 0; - rep = 0; - rawData.Clear(); - - - for (int y = 0; y < image.Height; y++) - { - Span pixelRowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - var ncolor15 = - (pixelRowSpan[x].B >> 3) - | ((pixelRowSpan[x].G >> 2) << 5) - | ((pixelRowSpan[x].R >> 3) << 11); - - if (ncolor15 == color15) - { - rep++; - if (rep == RLE16EncodingLimit) - { - rleRGB15(); - rep = 0; - } - } - else - { - rleRGB15(); - color15 = (ushort) ncolor15; - rep = 1; - } - } - } - - rleRGB15(); + var bytes = Preview.Encode(image); - if (rawData.Count == 0) continue; + if (bytes.Length == 0) continue; if (i == (byte) FileThumbnailSize.Small) { @@ -605,7 +785,7 @@ void rleRGB15() { ResolutionX = (uint) image.Width, ResolutionY = (uint) image.Height, - ImageLength = (uint) rawData.Count, + ImageLength = (uint)bytes.Length, }; currentOffset += (uint) Helpers.Serializer.SizeOf(preview); @@ -613,13 +793,10 @@ void rleRGB15() Helpers.SerializeWriteFileStream(outputFile, preview); - currentOffset += (uint) rawData.Count; - outputFile.Write(rawData.ToArray(), 0, rawData.Count); + currentOffset += (uint)bytes.Length; + outputFile.WriteBytes(bytes); } - - - HeaderSettings.MachineNameSize = string.IsNullOrWhiteSpace(HeaderSettings.MachineName) ? 0 : (uint)HeaderSettings.MachineName.Length; if (HeaderSettings.MachineNameSize > 0) { HeaderSettings.MachineNameAddress = currentOffset; @@ -628,41 +805,43 @@ void rleRGB15() currentOffset += (uint)machineBytes.Length; } + Parallel.For(0, LayerCount, layerIndex => + { + LayerData layer = new LayerData(this, (uint)layerIndex); + layer.Encode(this[layerIndex].Image, (uint) layerIndex); + LayersDefinitions[layerIndex] = layer; + }); + HeaderSettings.LayersDefinitionOffsetAddress = currentOffset; - uint layerDataCurrentOffset = currentOffset + (uint) Helpers.Serializer.SizeOf(new LayerData()) * HeaderSettings.LayerCount * HeaderSettings.AntiAliasLevel; + uint layerDataCurrentOffset = currentOffset + (uint) Helpers.Serializer.SizeOf(LayersDefinitions[0]) * LayerCount; for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - LayerData layerData = new LayerData(); - LayerData layerDataHash = null; - var image = this[layerIndex].Image; - rawData = EncodePhzImage(image, layerIndex); - - var byteArr = rawData.ToArray(); + LayerData layerData = LayersDefinitions[layerIndex]; if (HeaderSettings.EncryptionKey == 0) { - string hash = Helpers.ComputeSHA1Hash(byteArr); - if (!LayersHash.TryGetValue(hash, out layerDataHash)) + string hash = Helpers.ComputeSHA1Hash(layerData.EncodedRle); + if (LayersHash.TryGetValue(hash, out var layerDataHash)) + { + layerData.DataAddress = layerDataHash.DataAddress; + layerData.DataSize = layerDataHash.DataSize; + } + else { LayersHash.Add(hash, layerData); + layerData.DataAddress = layerDataCurrentOffset; + layerData.DataSize = (uint)layerData.EncodedRle.Length; + + outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin); + layerDataCurrentOffset += outputFile.WriteBytes(layerData.EncodedRle); } } - //layer.DataAddress = CurrentOffset + (uint)Helpers.Serializer.SizeOf(layer); - layerData.DataAddress = layerDataHash?.DataAddress ?? layerDataCurrentOffset; - layerData.DataSize = layerDataHash?.DataSize ?? (uint)byteArr.Length; - layerData.LayerPositionZ = layerIndex * HeaderSettings.LayerHeightMilimeter; - layerData.LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomLightOffDelay : HeaderSettings.LayerOffTime; - layerData.LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; - LayersDefinitions[layerIndex, 0] = layerData; - - currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData); + + LayersDefinitions[layerIndex] = layerData; - if (!ReferenceEquals(layerDataHash, null)) continue; - - outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin); - layerDataCurrentOffset += Helpers.WriteFileStream(outputFile, byteArr); outputFile.Seek(currentOffset, SeekOrigin.Begin); + currentOffset += Helpers.SerializeWriteFileStream(outputFile, layerData); } outputFile.Seek(0, SeekOrigin.Begin); @@ -679,77 +858,6 @@ void rleRGB15() } } - private List EncodePhzImage(Image image, uint layerIndex) - { - List rawData = new List(); - //byte color = byte.MaxValue >> 1; - byte color = byte.MaxValue; - uint stride = 0; - - void AddRep() - { - rawData.Add((byte)(color|0x80)); - stride--; - int done = 0; - while(done < stride) - { - int todo = 0x7d; - - if (stride - done < todo) { - todo = (int)(stride - done); - } - - rawData.Add((byte)(todo)); - - done += todo; - } - } - - int halfWidth = image.Width / 2; - - for (int y = 0; y < image.Height; y++) - { - var pixelRowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - var grey7 = (byte)((pixelRowSpan[x].PackedValue >> 1) & 0x7f); - if (grey7 > 0x7c) - { - grey7 = 0x7c; - } - - if (color == byte.MaxValue) - { - color = grey7; - stride = 1; - } - else if (grey7 != color || x == halfWidth) - { - AddRep(); - color = grey7; - stride = 1; - } - else - { - stride++; - } - } - - AddRep(); - color = byte.MaxValue; - } - - - if (HeaderSettings.EncryptionKey > 0) - { - List encodedData = new List(); - KeyRing kr = new KeyRing(HeaderSettings.EncryptionKey, layerIndex); - return kr.Read(rawData); - } - - return rawData; - } - public override void Decode(string fileFullPath) { base.Decode(fileFullPath); @@ -784,39 +892,11 @@ public override void Decode(string fileFullPath) Debug.Write($"Preview {i} -> "); Debug.WriteLine(Previews[i]); - Thumbnails[i] = new Image((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++; - } - } - } + Thumbnails[i] = Previews[i].Decode(rawImageData); } if (HeaderSettings.MachineNameAddress > 0 && HeaderSettings.MachineNameSize > 0) @@ -828,100 +908,38 @@ public override void Decode(string fileFullPath) } - LayersDefinitions = new LayerData[HeaderSettings.LayerCount, HeaderSettings.AntiAliasLevel]; + LayersDefinitions = new LayerData[HeaderSettings.LayerCount]; uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) - { - Debug.WriteLine($"-Image GROUP {aaIndex}-"); - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - inputFile.Seek(layerOffset, SeekOrigin.Begin); - LayerData layerData = Helpers.Deserialize(inputFile); - LayersDefinitions[layerIndex, aaIndex] = layerData; - - layerOffset += (uint)Helpers.Serializer.SizeOf(layerData); - Debug.Write($"LAYER {layerIndex} -> "); - Debug.WriteLine(layerData); - - layerData.EncodedRle = new byte[layerData.DataSize]; - inputFile.Seek(layerData.DataAddress, SeekOrigin.Begin); - inputFile.Read(layerData.EncodedRle, 0, (int)layerData.DataSize); - } - } - - LayerManager = new LayerManager(HeaderSettings.LayerCount); - Parallel.For(0, LayerCount, layerIndex => { - var image = DecodePhzImage((uint) layerIndex); - this[layerIndex] = new Layer((uint) layerIndex, image); - }); - } - - private Image DecodePhzImage(uint layerIndex) - { - Image image = new Image((int)HeaderSettings.ResolutionX, (int)HeaderSettings.ResolutionY); - var rawImageData = LayersDefinitions[layerIndex, 0].EncodedRle; - - if (HeaderSettings.EncryptionKey > 0) + for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { - KeyRing kr = new KeyRing(HeaderSettings.EncryptionKey, layerIndex); - rawImageData = kr.Read(rawImageData); + inputFile.Seek(layerOffset, SeekOrigin.Begin); + LayerData layerData = Helpers.Deserialize(inputFile); + layerData.Parent = this; + LayersDefinitions[layerIndex] = layerData; + + layerOffset += (uint)Helpers.Serializer.SizeOf(layerData); + Debug.Write($"LAYER {layerIndex} -> "); + Debug.WriteLine(layerData); + + layerData.EncodedRle = new byte[layerData.DataSize]; + inputFile.Seek(layerData.DataAddress, SeekOrigin.Begin); + inputFile.Read(layerData.EncodedRle, 0, (int)layerData.DataSize); } - int limit = image.Width * image.Height; - int index = 0; - byte lastColor = 0; - - image.TryGetSinglePixelSpan(out var span); + LayerManager = new LayerManager(HeaderSettings.LayerCount); - foreach (var code in rawImageData) + Parallel.For(0, LayerCount, layerIndex => { - if ((code & 0x80) == 0x80) - { - //lastColor = (byte) (code << 1); - // // Convert from 7bpp to 8bpp (extending the last bit) - lastColor = (byte) (((code & 0x7f) << 1) | (code & 1)); - if (lastColor >= 0xfc) { - // Make 'white' actually white - lastColor = 0xff; - - } - - if (index < limit) - { - span[index].PackedValue = lastColor; - } - else - { - Debug.WriteLine("Corrupted RLE data."); - } - - index++; - } - else - { - for (uint i = 0; i < code; i++) - { - if (index < limit) - { - span[index].PackedValue = lastColor; - } - else - { - Debug.WriteLine("Corrupted RLE data."); - } - index++; - } - } - } - - return image; + var image = LayersDefinitions[layerIndex].Decode((uint) layerIndex, true); + this[layerIndex] = new Layer((uint) layerIndex, image); + }); } - public override object GetValueFromPrintParameterModifier(PrintParameterModifier modifier) + public override object GetValueFromPrintParameterModifier(PrintParameterModifier modifier) { var baseValue = base.GetValueFromPrintParameterModifier(modifier); if (!ReferenceEquals(baseValue, null)) return baseValue; @@ -945,14 +963,11 @@ public override bool SetValueFromPrintParameterModifier(PrintParameterModifier m { void UpdateLayers() { - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - // Bottom : others - LayersDefinitions[layerIndex, aaIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; - LayersDefinitions[layerIndex, aaIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomLightOffDelay : HeaderSettings.LayerOffTime; - } + // Bottom : others + LayersDefinitions[layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; + LayersDefinitions[layerIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomLightOffDelay : HeaderSettings.LayerOffTime; } } @@ -1062,14 +1077,11 @@ public override void SaveAs(string filePath = null) }*/ uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) { - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - outputFile.Seek(layerOffset, SeekOrigin.Begin); - Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex, aaIndex]); - layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex, aaIndex]); - } + outputFile.Seek(layerOffset, SeekOrigin.Begin); + Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex]); + layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]); } outputFile.Close(); } @@ -1083,42 +1095,79 @@ public override bool Convert(Type to, string fileFullPath) { ChituboxFile file = new ChituboxFile { - LayerManager = LayerManager + LayerManager = LayerManager, + HeaderSettings + = + { + Version = 2, + BedSizeX = HeaderSettings.BedSizeX, + BedSizeY = HeaderSettings.BedSizeY, + BedSizeZ = HeaderSettings.BedSizeZ, + OverallHeightMilimeter = TotalHeight, + BottomExposureSeconds = InitialExposureTime, + BottomLayersCount = InitialLayerCount, + BottomLightPWM = HeaderSettings.BottomLightPWM, + LayerCount = LayerCount, + LayerExposureSeconds = LayerExposureTime, + LayerHeightMilimeter = LayerHeight, + LayerOffTime = HeaderSettings.LayerOffTime, + LightPWM = HeaderSettings.LightPWM, + PrintTime = HeaderSettings.PrintTime, + ProjectorType = HeaderSettings.ProjectorType, + ResolutionX = ResolutionX, + ResolutionY = ResolutionY, + AntiAliasLevel = ValidateAntiAliasingLevel() + }, + PrintParametersSettings = + { + BottomLayerCount = InitialLayerCount, + BottomLiftHeight = HeaderSettings.BottomLiftHeight, + BottomLiftSpeed = HeaderSettings.BottomLiftSpeed, + BottomLightOffDelay = HeaderSettings.BottomLightOffDelay, + CostDollars = MaterialCost, + LiftHeight = HeaderSettings.LiftHeight, + LiftingSpeed = HeaderSettings.LiftingSpeed, + LightOffDelay = HeaderSettings.LayerOffTime, + RetractSpeed = HeaderSettings.RetractSpeed, + VolumeMl = UsedMaterial, + WeightG = HeaderSettings.WeightG + }, + SlicerInfoSettings = {MachineName = MachineName, MachineNameSize = (uint) MachineName.Length} }; - file.HeaderSettings.Version = 2; - file.HeaderSettings.BedSizeX = HeaderSettings.BedSizeX; - file.HeaderSettings.BedSizeY = HeaderSettings.BedSizeY; - file.HeaderSettings.BedSizeZ = HeaderSettings.BedSizeZ; - file.HeaderSettings.OverallHeightMilimeter = TotalHeight; - file.HeaderSettings.BottomExposureSeconds = InitialExposureTime; - file.HeaderSettings.BottomLayersCount = InitialLayerCount; - file.HeaderSettings.BottomLightPWM = HeaderSettings.BottomLightPWM; - file.HeaderSettings.LayerCount = LayerCount; - file.HeaderSettings.LayerExposureSeconds = LayerExposureTime; - file.HeaderSettings.LayerHeightMilimeter = LayerHeight; - file.HeaderSettings.LayerOffTime = HeaderSettings.LayerOffTime; - file.HeaderSettings.LightPWM = HeaderSettings.LightPWM; - file.HeaderSettings.PrintTime = HeaderSettings.PrintTime; - file.HeaderSettings.ProjectorType = HeaderSettings.ProjectorType; - file.HeaderSettings.ResolutionX = ResolutionX; - file.HeaderSettings.ResolutionY = ResolutionY; - - file.PrintParametersSettings.BottomLayerCount = InitialLayerCount; - file.PrintParametersSettings.BottomLiftHeight = HeaderSettings.BottomLiftHeight; - file.PrintParametersSettings.BottomLiftSpeed = HeaderSettings.BottomLiftSpeed; - file.PrintParametersSettings.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay; - file.PrintParametersSettings.CostDollars = MaterialCost; - file.PrintParametersSettings.LiftHeight = HeaderSettings.LiftHeight; - file.PrintParametersSettings.LiftingSpeed = HeaderSettings.LiftingSpeed; - file.PrintParametersSettings.LightOffDelay = HeaderSettings.LayerOffTime; - file.PrintParametersSettings.RetractSpeed = HeaderSettings.RetractSpeed; - file.PrintParametersSettings.VolumeMl = UsedMaterial; - file.PrintParametersSettings.WeightG = HeaderSettings.WeightG; - - file.SlicerInfoSettings.MachineName = MachineName; - file.SlicerInfoSettings.MachineNameSize = (uint)MachineName.Length; + + + + file.SetThumbnails(Thumbnails); + file.Encode(fileFullPath); + + return true; + } + + if (to == typeof(PWSFile)) + { + PWSFile file = new PWSFile + { + LayerManager = LayerManager, + HeaderSettings = + { + ResolutionX = ResolutionX, + ResolutionY = ResolutionY, + LayerHeight = LayerHeight, + LayerExposureTime = LayerExposureTime, + LiftHeight = LiftHeight, + LiftSpeed = LiftSpeed / 60, + RetractSpeed = RetractSpeed / 60, + LayerOffTime = HeaderSettings.LayerOffTime, + BottomLayersCount = InitialLayerCount, + BottomExposureSeconds = InitialExposureTime, + Price = MaterialCost, + Volume = UsedMaterial, + Weight = HeaderSettings.WeightG, + AntiAliasing = ValidateAntiAliasingLevel() + } + }; file.SetThumbnails(Thumbnails); file.Encode(fileFullPath); @@ -1155,7 +1204,7 @@ public override bool Convert(Type to, string fileFullPath) BottomLayerExposureTime = (uint)(InitialExposureTime * 1000), MaterialId = 2, LayerThickness = $"{LayerHeight} mm", - AntiAliasing = 0, + AntiAliasing = (byte) (AntiAliasing > 1 ? 1 : 0), CrossSupportEnabled = 1, ExposureOffTime = (uint)HeaderSettings.LayerOffTime, HollowEnabled = 0, diff --git a/PrusaSL1Reader/PWSFile.cs b/PrusaSL1Reader/PWSFile.cs index 283d1a27..85eb25dd 100644 --- a/PrusaSL1Reader/PWSFile.cs +++ b/PrusaSL1Reader/PWSFile.cs @@ -12,6 +12,7 @@ using System.IO; using System.Threading.Tasks; using BinarySerialization; +using PrusaSL1Reader.Extensions; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -62,8 +63,8 @@ public class PWSFile : FileFormat #endregion - #region Enums - public enum LayerRleFormat + #region Enums + public enum LayerRleFormat { PWS, PW0 @@ -175,8 +176,7 @@ public void Validate(string mark, uint length, object obj = null) { if (!Mark.Equals(mark)) { - throw new FileLoadException( - $"'{Mark}' section expected, but got '{mark}'"); + throw new FileLoadException($"'{Mark}' section expected, but got '{mark}'"); } if (!ReferenceEquals(obj, null)) @@ -186,8 +186,7 @@ public void Validate(string mark, uint length, object obj = null) if (length > 0 && Length != length) { - throw new FileLoadException( - $"{Mark} section bytes: expected {Length}, got {length}, difference: {(int)Length - length}"); + throw new FileLoadException($"{Mark} section bytes: expected {Length}, got {length}, difference: {(int)Length - length}"); } } @@ -220,7 +219,7 @@ public class Header /// [FieldOrder(8)] public float RetractSpeed { get; set; } = 3; // mm/s [FieldOrder(9)] public float Volume { get; set; } - [FieldOrder(10)] public uint AntiAlias { get; set; } = 1; + [FieldOrder(10)] public uint AntiAliasing { get; set; } = 1; [FieldOrder(11)] public uint ResolutionX { get; set; } [FieldOrder(12)] public uint ResolutionY { get; set; } [FieldOrder(13)] public float Weight { get; set; } @@ -236,7 +235,7 @@ public Header() Section = new Section(SectionMark, this); } - public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(PixelSize)}: {PixelSize}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(LayerExposureTime)}: {LayerExposureTime}, {nameof(LayerOffTime)}: {LayerOffTime}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(Volume)}: {Volume}, {nameof(AntiAlias)}: {AntiAlias}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Weight)}: {Weight}, {nameof(Price)}: {Price}, {nameof(ResinType)}: {ResinType}, {nameof(PerLayerOverride)}: {PerLayerOverride}, {nameof(Offset1)}: {Offset1}, {nameof(Offset2)}: {Offset2}, {nameof(Offset3)}: {Offset3}"; + public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(PixelSize)}: {PixelSize}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(LayerExposureTime)}: {LayerExposureTime}, {nameof(LayerOffTime)}: {LayerOffTime}, {nameof(BottomExposureSeconds)}: {BottomExposureSeconds}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(Volume)}: {Volume}, {nameof(AntiAliasing)}: {AntiAliasing}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Weight)}: {Weight}, {nameof(Price)}: {Price}, {nameof(ResinType)}: {ResinType}, {nameof(PerLayerOverride)}: {PerLayerOverride}, {nameof(Offset1)}: {Offset1}, {nameof(Offset2)}: {Offset2}, {nameof(Offset3)}: {Offset3}"; public void Validate() { @@ -291,17 +290,16 @@ public Image Decode(bool consumeData = true) int pixel = 0; for (uint i = 0; i < Data.Length; i += 2) { - ushort color16 = (ushort)((Data[i]) + (Data[i+1] << 8)); - - int r = (color16 >> 11) & 0x1f; - int g = (color16 >> 5) & 0x3f; - int b = (color16 >> 0) & 0x1f; + ushort color16 = (ushort)(Data[i] + (Data[i+1] << 8)); + var r =(color16 >> 11) & 0x1f; + var g = (color16 >> 5) & 0x3f; + var b = (color16 >> 0) & 0x1f; span[pixel++] = new Rgba32( - (r << 3) | (r & 0x7), - (g << 2) | (g & 0x3), - (b << 3) | (b & 0x7), - byte.MaxValue); + (byte)((r << 3) | (r & 0x7)), + (byte)((g << 2) | (g & 0x3)), + (byte)((b << 3) | (b & 0x7)) + ); } if (consumeData) @@ -422,18 +420,16 @@ private Image DecodePWS() var image = new Image((int) Parent.ResolutionX, (int) Parent.ResolutionY); image.TryGetSinglePixelSpan(out var span); - - for (int bit = 0; bit < Parent.HeaderSettings.AntiAlias; bit++) + int index = 0; + for (byte bit = 0; bit < Parent.AntiAliasing; bit++) { - byte bitValue = (byte) (byte.MaxValue / ((1 << (byte) Parent.HeaderSettings.AntiAlias) - 1) * - (1 << bit)); + byte bitValue = (byte)(byte.MaxValue / ((1 << Parent.AntiAliasing) - 1) * (1 << bit)); int n = 0; - for (int index = 0; index < EncodedRle.Length; index++) + for (; index < EncodedRle.Length; index++) { // Lower 7 bits is the repeat count for the bit (0..127) - int reps = (EncodedRle[index] & 0x7f); - + int reps = EncodedRle[index] & 0x7f; // We only need to set the non-zero pixels // High bit is on for white, off for black @@ -447,15 +443,15 @@ private Image DecodePWS() n += reps; - if (n == span.Length) { + index++; break; } if (n > span.Length) { - Debug.WriteLine("Error image ran off the end"); + throw new FileLoadException("Error image ran off the end"); } } } @@ -467,33 +463,35 @@ public byte[] EncodePWS(Image image) { List rawData = new List(); - for (byte aalevel = 0; aalevel < Parent.HeaderSettings.AntiAlias; aalevel++) + bool obit; + int rep; + + void AddRep() { - bool obit = false; - int rep = 0; + if (rep <= 0) return; - void AddRep() - { - if (rep <= 0) return; + byte by = (byte)rep; - byte by = (byte)rep; + if (obit) + { + by |= 0x80; + //bitsOn += uint(rep) + } - if (obit) - { - by |= 0x80; - //bitsOn += uint(rep) - } + rawData.Add(by); + } - rawData.Add(by); - } + for (byte aalevel = 0; aalevel < Parent.AntiAliasing; aalevel++) + { + obit = false; + rep = 0; for (int y = 0; y < image.Height; y++) { Span pixelRowSpan = image.GetPixelRowSpan(y); for (int x = 0; x < image.Width; x++) { - var nbit = (pixelRowSpan[x].PackedValue & - (1 << (int)(8 - Parent.HeaderSettings.AntiAlias + aalevel))) != 0; + var nbit = (pixelRowSpan[x].PackedValue & (1 << (8 - Parent.AntiAliasing + aalevel))) != 0; if (nbit == obit) { @@ -518,6 +516,8 @@ void AddRep() AddRep(); } + DataLength = (uint) rawData.Count; + return rawData.ToArray(); } @@ -538,12 +538,12 @@ private Image DecodePW0() case 0x0: color = 0x00; index++; - reps = (reps * 256) + EncodedRle[index]; + reps = reps * 256 + EncodedRle[index]; break; case 0xf: color = 0xff; index++; - reps = (reps * 256) + EncodedRle[index]; + reps = reps * 256 + EncodedRle[index]; break; default: color = (byte) ((code << 4) | code); @@ -572,13 +572,13 @@ private Image DecodePW0() if (n > span.Length) { - Debug.WriteLine($"Error image ran off the end: {n-reps}({reps}) of {span.Length}"); + throw new FileLoadException($"Error image ran off the end: {n - reps}({reps}) of {span.Length}"); } } if (n != span.Length) { - Debug.WriteLine($"Error image ended short: {n} of {span.Length}"); + throw new FileLoadException($"Error image ended short: {n} of {span.Length}"); } return image; @@ -645,12 +645,14 @@ void PutReps() PutReps(); - var bytes = rawData.ToArray(); - ushort crc = CRCRle4(bytes); + EncodedRle = rawData.ToArray(); + DataLength = (uint)rawData.Count; + + ushort crc = CRCRle4(EncodedRle); rawData.Add((byte)(crc >> 8)); rawData.Add((byte)crc); - return bytes; + return EncodedRle; } public static ushort CRCRle4(byte[] data) @@ -697,12 +699,26 @@ public LayerDefinition(uint layersCount) : this() Layers = new LayerData[layersCount]; } - public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(LayersCount)}: {LayersCount}"; + [Ignore] + public LayerData this[uint index] + { + get => Layers[index]; + set => Layers[index] = value; + } + + [Ignore] + public LayerData this[int index] + { + get => Layers[index]; + set => Layers[index] = value; + } public void Validate() { - Section.Validate(SectionMark, (uint) (LayersCount * Helpers.Serializer.SizeOf(new LayerData())), this); + Section.Validate(SectionMark, (uint)(LayersCount * Helpers.Serializer.SizeOf(new LayerData())), this); } + + public override string ToString() => $"{nameof(Section)}: {Section}, {nameof(LayersCount)}: {LayersCount}"; } #endregion @@ -739,10 +755,10 @@ public void Validate() PrintParameterModifier.InitialExposureSeconds, PrintParameterModifier.ExposureSeconds, - PrintParameterModifier.BottomLayerOffTime, + //PrintParameterModifier.BottomLayerOffTime, PrintParameterModifier.LayerOffTime, - PrintParameterModifier.BottomLiftHeight, - PrintParameterModifier.BottomLiftSpeed, + //PrintParameterModifier.BottomLiftHeight, + //PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, @@ -755,6 +771,7 @@ public void Validate() public override uint ResolutionX => HeaderSettings.ResolutionX; public override uint ResolutionY => HeaderSettings.ResolutionY; + public override byte AntiAliasing => (byte) HeaderSettings.AntiAliasing; public override float LayerHeight => HeaderSettings.LayerHeight; @@ -816,7 +833,7 @@ public override void Encode(string fileFullPath) Preview preview = Preview.Encode(Thumbnails[0]); currentOffset += Helpers.SerializeWriteFileStream(outputFile, preview.Section); currentOffset += Helpers.SerializeWriteFileStream(outputFile, preview); - currentOffset += Helpers.WriteFileStream(outputFile, preview.Data); + currentOffset += outputFile.WriteBytes(preview.Data); } FileMarkSettings.LayerDefinitionAddress = currentOffset; @@ -828,7 +845,7 @@ public override void Encode(string fileFullPath) LayersDefinition.Layers[layerIndex] = layer; }); - LayersDefinition.Section.Length += (uint)Helpers.Serializer.SizeOf(LayersDefinition.Layers[0]) * LayerCount; + LayersDefinition.Section.Length += (uint)Helpers.Serializer.SizeOf(LayersDefinition[0]) * LayerCount; currentOffset += Helpers.SerializeWriteFileStream(outputFile, LayersDefinition.Section); uint offsetLayerRle = FileMarkSettings.LayerImageAddress = currentOffset + LayersDefinition.Section.Length; @@ -837,7 +854,6 @@ public override void Encode(string fileFullPath) foreach (var layer in LayersDefinition.Layers) { - outputFile.Seek(offsetLayerRle, SeekOrigin.Begin); string hash = Helpers.ComputeSHA1Hash(layer.EncodedRle); if (LayersHash.TryGetValue(hash, out var layerDataHash)) @@ -847,10 +863,12 @@ public override void Encode(string fileFullPath) } else { + LayersHash.Add(hash, layer); + layer.DataAddress = offsetLayerRle; + + outputFile.Seek(offsetLayerRle, SeekOrigin.Begin); offsetLayerRle += Helpers.SerializeWriteFileStream(outputFile, layer.EncodedRle); - layer.DataLength = (uint)layer.EncodedRle.Length; - LayersHash.Add(hash, layer); } outputFile.Seek(currentOffset, SeekOrigin.Begin); @@ -862,8 +880,6 @@ public override void Encode(string fileFullPath) Helpers.SerializeWriteFileStream(outputFile, FileMarkSettings); } - - } public override void Decode(string fileFullPath) @@ -917,11 +933,10 @@ public override void Decode(string fileFullPath) Debug.WriteLine(PreviewSettings); uint datasize = PreviewSettings.Width * PreviewSettings.Height * 2; - PreviewSettings.Validate(datasize); PreviewSettings.Data = new byte[datasize]; - inputFile.Read(PreviewSettings.Data, 0, PreviewSettings.Data.Length); + inputFile.ReadBytes(PreviewSettings.Data); Thumbnails[0] = PreviewSettings.Decode(true); } @@ -942,15 +957,16 @@ public override void Decode(string fileFullPath) for (int i = 0; i < LayerCount; i++) { - LayersDefinition.Layers[i] = Helpers.Deserialize(inputFile); - LayersDefinition.Layers[i].Parent = this; + LayersDefinition[i] = Helpers.Deserialize(inputFile); + LayersDefinition[i].Parent = this; } for (int i = 0; i < LayerCount; i++) { - inputFile.Seek(LayersDefinition.Layers[i].DataAddress, SeekOrigin.Begin); - LayersDefinition.Layers[i].EncodedRle = new byte[LayersDefinition.Layers[i].DataLength]; - inputFile.Read(LayersDefinition.Layers[i].EncodedRle, 0, LayersDefinition.Layers[i].EncodedRle.Length); + var layer = LayersDefinition[i]; + inputFile.Seek(layer.DataAddress, SeekOrigin.Begin); + layer.EncodedRle = new byte[layer.DataLength]; + inputFile.ReadBytes(layer.EncodedRle); /*if (LayerFormat == LayerRleFormat.PW0) { @@ -967,15 +983,13 @@ public override void Decode(string fileFullPath) } Parallel.For(0, LayerCount, layerIndex => { - this[layerIndex] = new Layer((uint)layerIndex, LayersDefinition.Layers[layerIndex].Decode()); + this[layerIndex] = new Layer((uint)layerIndex, LayersDefinition[(uint) layerIndex].Decode()); }); } public override object GetValueFromPrintParameterModifier(PrintParameterModifier modifier) { if (ReferenceEquals(modifier, PrintParameterModifier.LayerOffTime)) return HeaderSettings.LayerOffTime; - if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed)) return HeaderSettings.LiftSpeed * 60; - if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed)) return HeaderSettings.RetractSpeed * 60; var baseValue = base.GetValueFromPrintParameterModifier(modifier); return baseValue; @@ -983,24 +997,21 @@ public override object GetValueFromPrintParameterModifier(PrintParameterModifier public override bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, string value) { - /* void UpdateLayers() { - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - // Bottom : others - LayersDefinitions[layerIndex, aaIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds; - LayersDefinitions[layerIndex, aaIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? PrintParametersSettings.BottomLightOffDelay : PrintParametersSettings.LightOffDelay; - } + // Bottom : others + LayersDefinition[layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount + ? HeaderSettings.BottomExposureSeconds + : HeaderSettings.LayerExposureTime; } } if (ReferenceEquals(modifier, PrintParameterModifier.InitialLayerCount)) { HeaderSettings.BottomLayersCount = - PrintParametersSettings.BottomLayerCount = value.Convert(); + HeaderSettings.BottomLayersCount = value.Convert(); UpdateLayers(); return true; } @@ -1013,60 +1024,37 @@ void UpdateLayers() if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds)) { - HeaderSettings.LayerExposureSeconds = value.Convert(); + HeaderSettings.LayerExposureTime = value.Convert(); UpdateLayers(); return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerOffTime)) - { - PrintParametersSettings.BottomLightOffDelay = value.Convert(); - UpdateLayers(); - return true; - } if (ReferenceEquals(modifier, PrintParameterModifier.LayerOffTime)) { - HeaderSettings.LayerOffTime = - PrintParametersSettings.LightOffDelay = value.Convert(); + HeaderSettings.LayerOffTime = value.Convert(); UpdateLayers(); return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftHeight)) - { - PrintParametersSettings.BottomLiftHeight = value.Convert(); - return true; - } - if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftSpeed)) - { - PrintParametersSettings.BottomLiftSpeed = value.Convert(); - return true; - } + + if (ReferenceEquals(modifier, PrintParameterModifier.LiftHeight)) { - PrintParametersSettings.LiftHeight = value.Convert(); + HeaderSettings.LiftHeight = value.Convert(); + UpdateLayers(); return true; } if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed)) { - PrintParametersSettings.LiftingSpeed = value.Convert(); + HeaderSettings.LiftSpeed = value.Convert() / 60f; + UpdateLayers(); return true; } if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed)) { - PrintParametersSettings.RetractSpeed = value.Convert(); - return true; - } - - if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightPWM)) - { - HeaderSettings.BottomLightPWM = value.Convert(); + HeaderSettings.RetractSpeed = value.Convert() / 60f; + UpdateLayers(); return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.LightPWM)) - { - HeaderSettings.LightPWM = value.Convert(); - return true; - }*/ return false; } @@ -1093,26 +1081,15 @@ public override void SaveAs(string filePath = null) using (var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write)) { - outputFile.Seek(0, SeekOrigin.Begin); - /*Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); + outputFile.Seek(FileMarkSettings.HeaderAddress+Helpers.Serializer.SizeOf(HeaderSettings.Section), SeekOrigin.Begin); + Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); - if (HeaderSettings.Version == 2 && HeaderSettings.PrintParametersOffsetAddress > 0) - { - outputFile.Seek(HeaderSettings.PrintParametersOffsetAddress, SeekOrigin.Begin); - Helpers.SerializeWriteFileStream(outputFile, PrintParametersSettings); - Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings); - } - uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress; - for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++) + outputFile.Seek(FileMarkSettings.LayerDefinitionAddress + Helpers.Serializer.SizeOf(HeaderSettings.Section) + Helpers.Serializer.SizeOf(LayersDefinition), SeekOrigin.Begin); + for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { - for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++) - { - outputFile.Seek(layerOffset, SeekOrigin.Begin); - Helpers.SerializeWriteFileStream(outputFile, LayersDefinitions[layerIndex, aaIndex]); - layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex, aaIndex]); - } - }*/ + Helpers.SerializeWriteFileStream(outputFile, LayersDefinition[layerIndex]); + } outputFile.Close(); } diff --git a/PrusaSL1Reader/PrusaSL1Reader.csproj b/PrusaSL1Reader/PrusaSL1Reader.csproj index e53e199e..6529d68d 100644 --- a/PrusaSL1Reader/PrusaSL1Reader.csproj +++ b/PrusaSL1Reader/PrusaSL1Reader.csproj @@ -7,9 +7,9 @@ https://github.com/sn4k3/PrusaSL1Viewer https://github.com/sn4k3/PrusaSL1Viewer - 0.4.3.0 - 0.4.3.2 - 0.4.3 + 0.5.0.0 + 0.5.0.0 + 0.5 Open, view, edit, extract and convert DLP/SLA files generated from Slicers diff --git a/PrusaSL1Reader/SL1File.cs b/PrusaSL1Reader/SL1File.cs index 1473f338..9575de71 100644 --- a/PrusaSL1Reader/SL1File.cs +++ b/PrusaSL1Reader/SL1File.cs @@ -22,6 +22,7 @@ public class SL1File : FileFormat { #region Constants + public const string Keyword_AntiAliasing = "AntiAliasing"; public const string Keyword_BottomLightOffDelay = "BottomLightOffDelay"; public const string Keyword_LayerOffTime = "LayerOffTime"; public const string Keyword_LightOffDelay = "LightOffDelay"; @@ -285,7 +286,7 @@ public override string ToString() public override FileFormatType FileType => FileFormatType.Archive; public override FileExtension[] FileExtensions { get; } = { - new FileExtension("sl1", "Prusa SL1 Files") + new FileExtension("sl1", "PrusaSlicer SL1 Files") }; public override Type[] ConvertToFormats { get; } = @@ -311,6 +312,7 @@ public override string ToString() public override uint ResolutionX => PrinterSettings.DisplayPixelsX; public override uint ResolutionY => PrinterSettings.DisplayPixelsY; + public override byte AntiAliasing => (byte) (PrinterSettings.GammaCorrection > 0 ? LookupCustomValue(Keyword_AntiAliasing, 4) : 1); public override float LayerHeight => OutputConfigSettings.LayerHeight; @@ -601,7 +603,8 @@ public override bool Convert(Type to, string fileFullPath) PrintTime = (uint) OutputConfigSettings.PrintTime, ProjectorType = PrinterSettings.DisplayMirrorX ? 1u : 0u, ResolutionX = ResolutionX, - ResolutionY = ResolutionY + ResolutionY = ResolutionY, + AntiAliasLevel = ValidateAntiAliasingLevel() }, PrintParametersSettings = { @@ -661,7 +664,8 @@ public override bool Convert(Type to, string fileFullPath) BottomExposureSeconds = InitialExposureTime, Price = MaterialCost, Volume = UsedMaterial, - Weight = (float) Math.Round(OutputConfigSettings.UsedMaterial * MaterialSettings.MaterialDensity, 2) + Weight = (float) Math.Round(OutputConfigSettings.UsedMaterial * MaterialSettings.MaterialDensity, 2), + AntiAliasing = ValidateAntiAliasingLevel() } }; @@ -714,7 +718,8 @@ public override bool Convert(Type to, string fileFullPath) VolumeMl = OutputConfigSettings.UsedMaterial, WeightG = (float)Math.Round(OutputConfigSettings.UsedMaterial * MaterialSettings.MaterialDensity, 2), MachineName = MachineName, - MachineNameSize = (uint)MachineName.Length + MachineNameSize = (uint)MachineName.Length, + AntiAliasLevelInfo = ValidateAntiAliasingLevel() } }; @@ -760,7 +765,7 @@ public override bool Convert(Type to, string fileFullPath) BottomLayerExposureTime = (uint)(InitialExposureTime * 1000), MaterialId = 2, LayerThickness = $"{LayerHeight} mm", - AntiAliasing = 0, + AntiAliasing = (byte) (ValidateAntiAliasingLevel() > 1 ? 1 : 0), CrossSupportEnabled = 1, ExposureOffTime = LookupCustomValue(Keyword_LayerOffTime, defaultFormat.UserSettings.ExposureOffTime) *1000, HollowEnabled = PrintSettings.HollowingEnable ? (byte)1 : (byte)0, @@ -819,6 +824,7 @@ public override bool Convert(Type to, string fileFullPath) if (to == typeof(CWSFile)) { + CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile)); CWSFile file = new CWSFile { LayerManager = LayerManager @@ -850,6 +856,8 @@ public override bool Convert(Type to, string fileFullPath) //file.OutputSettings.AntiAliasingValue = 0; file.OutputSettings.FlipX = PrinterSettings.DisplayMirrorX; file.OutputSettings.FlipY = PrinterSettings.DisplayMirrorY; + file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel(); + file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1; diff --git a/PrusaSL1Reader/ZCodexFile.cs b/PrusaSL1Reader/ZCodexFile.cs index 1b3fe30b..c3eb73ff 100644 --- a/PrusaSL1Reader/ZCodexFile.cs +++ b/PrusaSL1Reader/ZCodexFile.cs @@ -87,7 +87,7 @@ public class UserSettingsdata public float ZLiftDistance { get; set; } = 5; public float ZLiftRetractRate { get; set; } = 100; public float ZLiftFeedRate { get; set; } = 100; - public byte AntiAliasing { get; set; } + public byte AntiAliasing { get; set; } = 0; public byte XCorrection { get; set; } public byte YCorrection { get; set; } public byte HollowEnabled { get; set; } @@ -144,7 +144,7 @@ public class LayerData public override FileFormatType FileType => FileFormatType.Archive; public override FileExtension[] FileExtensions { get; } = { - new FileExtension("zcodex", "ZCodex/Z-Suite Files") + new FileExtension("zcodex", "Z-Suite ZCodex Files") }; public override Type[] ConvertToFormats { get; } = null; @@ -167,6 +167,7 @@ public class LayerData public override uint ResolutionX => 1440; public override uint ResolutionY => 2560; + public override byte AntiAliasing => UserSettings.AntiAliasing; public override float LayerHeight => ResinMetadataSettings.LayerThickness; diff --git a/PrusaSL1Viewer/Forms/FrmMutation.Designer.cs b/PrusaSL1Viewer/Forms/FrmMutation.Designer.cs index 34e25e46..6f9d72dd 100644 --- a/PrusaSL1Viewer/Forms/FrmMutation.Designer.cs +++ b/PrusaSL1Viewer/Forms/FrmMutation.Designer.cs @@ -223,6 +223,7 @@ private void InitializeComponent() this.btnPreview.Text = "&Preview"; this.btnPreview.TextAlign = System.Drawing.ContentAlignment.MiddleRight; this.btnPreview.UseVisualStyleBackColor = true; + this.btnPreview.Visible = false; // // pbInfo // diff --git a/PrusaSL1Viewer/Forms/FrmMutation.cs b/PrusaSL1Viewer/Forms/FrmMutation.cs index 397f4079..78b39692 100644 --- a/PrusaSL1Viewer/Forms/FrmMutation.cs +++ b/PrusaSL1Viewer/Forms/FrmMutation.cs @@ -55,7 +55,8 @@ public FrmMutation(Mutation mutation, uint defaultIterations = 1) Mutation = mutation; DialogResult = DialogResult.Cancel; - if (defaultIterations == 0 || mutation.Mutate == Mutation.Mutates.PyrDownUp) + if (defaultIterations == 0 || + mutation.Mutate == Mutation.Mutates.PyrDownUp) { lbIterationsStart.Enabled = numIterationsStart.Enabled = @@ -70,6 +71,15 @@ public FrmMutation(Mutation mutation, uint defaultIterations = 1) numIterationsStart.Select(); } + if (Mutation.Mutate == Mutation.Mutates.SmoothGaussian || + Mutation.Mutate == Mutation.Mutates.SmoothMedian) + { + lbIterationsStop.Enabled = + nmIterationsEnd.Enabled = + cbIterationsFade.Enabled = + false; + } + Text = $"Mutate: {mutation.Mutate}"; lbDescription.Text = Mutation.Description; @@ -173,6 +183,22 @@ private void ItemClicked(object sender, EventArgs e) nmLayerRangeStart.Select(); return; } + + if (Mutation.Mutate == Mutation.Mutates.SmoothGaussian || + Mutation.Mutate == Mutation.Mutates.SmoothMedian) + { + if (IterationsFade) + { + MessageBox.Show("Smooth doesn't support fading.", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + if (Iterations % 2 != 1) + { + MessageBox.Show("Iterations must be a odd number.", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + } + if (MessageBox.Show($"Are you sure you want to {Mutation.Mutate}?", Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { diff --git a/PrusaSL1Viewer/Forms/FrmMutationResize.Designer.cs b/PrusaSL1Viewer/Forms/FrmMutationResize.Designer.cs index e2d8fa21..4da05662 100644 --- a/PrusaSL1Viewer/Forms/FrmMutationResize.Designer.cs +++ b/PrusaSL1Viewer/Forms/FrmMutationResize.Designer.cs @@ -83,6 +83,7 @@ private void InitializeComponent() // // nmX // + this.nmX.DecimalPlaces = 2; this.nmX.Location = new System.Drawing.Point(118, 187); this.nmX.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.nmX.Maximum = new decimal(new int[] { @@ -242,6 +243,7 @@ private void InitializeComponent() // // nmY // + this.nmY.DecimalPlaces = 2; this.nmY.Enabled = false; this.nmY.Location = new System.Drawing.Point(314, 187); this.nmY.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); diff --git a/PrusaSL1Viewer/Forms/FrmMutationResize.cs b/PrusaSL1Viewer/Forms/FrmMutationResize.cs index f48477e7..33e82668 100644 --- a/PrusaSL1Viewer/Forms/FrmMutationResize.cs +++ b/PrusaSL1Viewer/Forms/FrmMutationResize.cs @@ -29,16 +29,16 @@ public uint LayerRangeEnd set => nmLayerRangeEnd.Value = value; } - public uint X + public float X { get => (uint) nmX.Value; - set => nmX.Value = value; + set => nmX.Value = (decimal) value; } - public uint Y + public float Y { get => (uint)nmY.Value; - set => nmY.Value = value; + set => nmY.Value = (decimal) value; } public bool ConstrainXY @@ -150,11 +150,18 @@ private void ItemClicked(object sender, EventArgs e) nmLayerRangeStart.Select(); return; } - if (MessageBox.Show($"Are you sure you want to {Mutation.Mutate}?", Text, MessageBoxButtons.YesNo, + + if (X == 100 && Y == 100) + { + MessageBox.Show($"X and Y cant be 100% together.", Text, MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + if (MessageBox.Show($"Are you sure you want to {Mutation.Mutate}?\nX={X}% Y={Y}%", Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { DialogResult = DialogResult.OK; - if (X <= 0) // Should never happen! + if (X <= 0 || Y <= 0) // Should never happen! { DialogResult = DialogResult.Cancel; } diff --git a/PrusaSL1Viewer/FrmMain.Designer.cs b/PrusaSL1Viewer/FrmMain.Designer.cs index 73416c4d..6427dd83 100644 --- a/PrusaSL1Viewer/FrmMain.Designer.cs +++ b/PrusaSL1Viewer/FrmMain.Designer.cs @@ -67,7 +67,7 @@ private void InitializeComponent() this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.tsLayerPreviewTime = new System.Windows.Forms.ToolStripLabel(); this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); - this.tsLayerImageHighlightIslands = new System.Windows.Forms.ToolStripButton(); + this.tsLayerImageHighlightIssues = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.tsLayerImageLayerOutline = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); @@ -102,30 +102,37 @@ private void InitializeComponent() this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); this.tsGcodeLabelChars = new System.Windows.Forms.ToolStripLabel(); this.tsGCodeButtonSave = new System.Windows.Forms.ToolStripButton(); - this.tabPageIslands = new System.Windows.Forms.TabPage(); - this.lvIslands = new System.Windows.Forms.ListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.tsIslands = new System.Windows.Forms.ToolStrip(); - this.tsIslandsPrevious = new System.Windows.Forms.ToolStripButton(); - this.tsIslandsCount = new System.Windows.Forms.ToolStripLabel(); - this.tsIslandsNext = new System.Windows.Forms.ToolStripButton(); + this.tabPageIssues = new System.Windows.Forms.TabPage(); + this.lvIssues = new System.Windows.Forms.ListView(); + this.lvIssuesType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lvIssuesCount = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lvIssuesLayerHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lvIssuesXY = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.lvIssuesPixels = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tsIssues = new System.Windows.Forms.ToolStrip(); + this.tsIssuePrevious = new System.Windows.Forms.ToolStripButton(); + this.tsIssueCount = new System.Windows.Forms.ToolStripLabel(); + this.tsIssueNext = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator(); - this.tsIslandsRefresh = new System.Windows.Forms.ToolStripButton(); - this.tsIslandsRemove = new System.Windows.Forms.ToolStripButton(); + this.tsIsuesRefresh = new System.Windows.Forms.ToolStripButton(); + this.tsIssueRemove = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); - this.tsIslandsRepair = new System.Windows.Forms.ToolStripButton(); + this.tsIssuesRepair = new System.Windows.Forms.ToolStripButton(); this.imageList16x16 = new System.Windows.Forms.ImageList(this.components); this.tlRight = new System.Windows.Forms.TableLayoutPanel(); this.btnPreviousLayer = new System.Windows.Forms.Button(); this.btnNextLayer = new System.Windows.Forms.Button(); this.lbMaxLayer = new System.Windows.Forms.Label(); - this.lbInitialLayer = new System.Windows.Forms.Label(); this.panel1 = new System.Windows.Forms.Panel(); this.lbLayerActual = new System.Windows.Forms.Label(); this.tbLayer = new System.Windows.Forms.TrackBar(); + this.lbInitialLayer = new System.Windows.Forms.Label(); + this.panel2 = new System.Windows.Forms.Panel(); + this.btnFindLayer = new System.Windows.Forms.Button(); + this.btnLastLayer = new System.Windows.Forms.Button(); + this.btnFirstLayer = new System.Windows.Forms.Button(); + this.toolTipInformation = new System.Windows.Forms.ToolTip(this.components); + this.layerScrollTimer = new System.Windows.Forms.Timer(this.components); this.menu.SuspendLayout(); this.mainTable.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.scCenter)).BeginInit(); @@ -144,11 +151,12 @@ private void InitializeComponent() this.tsProperties.SuspendLayout(); this.tabPageGCode.SuspendLayout(); this.tsGCode.SuspendLayout(); - this.tabPageIslands.SuspendLayout(); - this.tsIslands.SuspendLayout(); + this.tabPageIssues.SuspendLayout(); + this.tsIssues.SuspendLayout(); this.tlRight.SuspendLayout(); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).BeginInit(); + this.panel2.SuspendLayout(); this.SuspendLayout(); // // menu @@ -337,9 +345,8 @@ private void InitializeComponent() // this.menuHelpWebsite.Image = global::PrusaSL1Viewer.Properties.Resources.Global_Network_icon_16x16; this.menuHelpWebsite.Name = "menuHelpWebsite"; - this.menuHelpWebsite.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) - | System.Windows.Forms.Keys.W))); - this.menuHelpWebsite.Size = new System.Drawing.Size(229, 22); + this.menuHelpWebsite.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F1))); + this.menuHelpWebsite.Size = new System.Drawing.Size(231, 22); this.menuHelpWebsite.Text = "&Website"; this.menuHelpWebsite.Click += new System.EventHandler(this.EventClick); // @@ -347,8 +354,9 @@ private void InitializeComponent() // this.menuHelpDonate.Image = global::PrusaSL1Viewer.Properties.Resources.Donate_16x16; this.menuHelpDonate.Name = "menuHelpDonate"; - this.menuHelpDonate.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.D))); - this.menuHelpDonate.Size = new System.Drawing.Size(229, 22); + this.menuHelpDonate.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) + | System.Windows.Forms.Keys.F1))); + this.menuHelpDonate.Size = new System.Drawing.Size(231, 22); this.menuHelpDonate.Text = "&Donate"; this.menuHelpDonate.Click += new System.EventHandler(this.EventClick); // @@ -357,21 +365,21 @@ private void InitializeComponent() this.menuHelpAbout.Image = global::PrusaSL1Viewer.Properties.Resources.Button_Info_16x16; this.menuHelpAbout.Name = "menuHelpAbout"; this.menuHelpAbout.ShortcutKeys = System.Windows.Forms.Keys.F1; - this.menuHelpAbout.Size = new System.Drawing.Size(229, 22); + this.menuHelpAbout.Size = new System.Drawing.Size(231, 22); this.menuHelpAbout.Text = "&About"; this.menuHelpAbout.Click += new System.EventHandler(this.EventClick); // // toolStripSeparator10 // this.toolStripSeparator10.Name = "toolStripSeparator10"; - this.toolStripSeparator10.Size = new System.Drawing.Size(226, 6); + this.toolStripSeparator10.Size = new System.Drawing.Size(228, 6); // // menuHelpInstallPrinters // this.menuHelpInstallPrinters.Image = global::PrusaSL1Viewer.Properties.Resources.CNCMachine_16x16; this.menuHelpInstallPrinters.Name = "menuHelpInstallPrinters"; - this.menuHelpInstallPrinters.Size = new System.Drawing.Size(229, 22); - this.menuHelpInstallPrinters.Text = "Instal printers into PrusaSlicer"; + this.menuHelpInstallPrinters.Size = new System.Drawing.Size(231, 22); + this.menuHelpInstallPrinters.Text = "Install profiles into PrusaSlicer"; this.menuHelpInstallPrinters.Click += new System.EventHandler(this.EventClick); // // statusBar @@ -447,7 +455,7 @@ private void InitializeComponent() this.toolStripSeparator6, this.tsLayerPreviewTime, this.toolStripSeparator14, - this.tsLayerImageHighlightIslands, + this.tsLayerImageHighlightIssues, this.toolStripSeparator7, this.tsLayerImageLayerOutline, this.toolStripSeparator9, @@ -533,18 +541,18 @@ private void InitializeComponent() this.toolStripSeparator14.Name = "toolStripSeparator14"; this.toolStripSeparator14.Size = new System.Drawing.Size(6, 25); // - // tsLayerImageHighlightIslands + // tsLayerImageHighlightIssues // - this.tsLayerImageHighlightIslands.Checked = true; - this.tsLayerImageHighlightIslands.CheckOnClick = true; - this.tsLayerImageHighlightIslands.CheckState = System.Windows.Forms.CheckState.Checked; - this.tsLayerImageHighlightIslands.Image = global::PrusaSL1Viewer.Properties.Resources.island_16x16; - this.tsLayerImageHighlightIslands.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsLayerImageHighlightIslands.Name = "tsLayerImageHighlightIslands"; - this.tsLayerImageHighlightIslands.Size = new System.Drawing.Size(63, 22); - this.tsLayerImageHighlightIslands.Text = "Islands"; - this.tsLayerImageHighlightIslands.ToolTipText = "Highlight islands on current layer.\r\nValid only if Islands are calculated."; - this.tsLayerImageHighlightIslands.Click += new System.EventHandler(this.EventClick); + this.tsLayerImageHighlightIssues.Checked = true; + this.tsLayerImageHighlightIssues.CheckOnClick = true; + this.tsLayerImageHighlightIssues.CheckState = System.Windows.Forms.CheckState.Checked; + this.tsLayerImageHighlightIssues.Image = global::PrusaSL1Viewer.Properties.Resources.warning_16x16; + this.tsLayerImageHighlightIssues.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsLayerImageHighlightIssues.Name = "tsLayerImageHighlightIssues"; + this.tsLayerImageHighlightIssues.Size = new System.Drawing.Size(58, 22); + this.tsLayerImageHighlightIssues.Text = "Issues"; + this.tsLayerImageHighlightIssues.ToolTipText = "Highlight Issues on current layer.\r\nValid only if Issues are calculated."; + this.tsLayerImageHighlightIssues.Click += new System.EventHandler(this.EventClick); // // toolStripSeparator7 // @@ -618,7 +626,7 @@ private void InitializeComponent() // this.tabControlLeft.Controls.Add(this.tbpThumbnailsAndInfo); this.tabControlLeft.Controls.Add(this.tabPageGCode); - this.tabControlLeft.Controls.Add(this.tabPageIslands); + this.tabControlLeft.Controls.Add(this.tabPageIssues); this.tabControlLeft.Dock = System.Windows.Forms.DockStyle.Fill; this.tabControlLeft.ImageList = this.imageList16x16; this.tabControlLeft.ItemSize = new System.Drawing.Size(130, 19); @@ -627,6 +635,7 @@ private void InitializeComponent() this.tabControlLeft.SelectedIndex = 0; this.tabControlLeft.Size = new System.Drawing.Size(394, 734); this.tabControlLeft.TabIndex = 5; + this.tabControlLeft.SelectedIndexChanged += new System.EventHandler(this.EventSelectedIndexChanged); // // tbpThumbnailsAndInfo // @@ -876,135 +885,143 @@ private void InitializeComponent() this.tsGCodeButtonSave.ToolTipText = "Save GCode to file"; this.tsGCodeButtonSave.Click += new System.EventHandler(this.EventClick); // - // tabPageIslands - // - this.tabPageIslands.Controls.Add(this.lvIslands); - this.tabPageIslands.Controls.Add(this.tsIslands); - this.tabPageIslands.ImageKey = "island-16x16.png"; - this.tabPageIslands.Location = new System.Drawing.Point(4, 23); - this.tabPageIslands.Name = "tabPageIslands"; - this.tabPageIslands.Padding = new System.Windows.Forms.Padding(3); - this.tabPageIslands.Size = new System.Drawing.Size(386, 707); - this.tabPageIslands.TabIndex = 3; - this.tabPageIslands.Text = "Islands"; - this.tabPageIslands.UseVisualStyleBackColor = true; - // - // lvIslands - // - this.lvIslands.Activation = System.Windows.Forms.ItemActivation.TwoClick; - this.lvIslands.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader4, - this.columnHeader2, - this.columnHeader3}); - this.lvIslands.Dock = System.Windows.Forms.DockStyle.Fill; - this.lvIslands.FullRowSelect = true; - this.lvIslands.GridLines = true; - this.lvIslands.HideSelection = false; - this.lvIslands.Location = new System.Drawing.Point(3, 28); - this.lvIslands.Name = "lvIslands"; - this.lvIslands.Size = new System.Drawing.Size(380, 676); - this.lvIslands.TabIndex = 8; - this.lvIslands.UseCompatibleStateImageBehavior = false; - this.lvIslands.View = System.Windows.Forms.View.Details; - this.lvIslands.ItemActivate += new System.EventHandler(this.lvIslands_ItemActivate); - this.lvIslands.SelectedIndexChanged += new System.EventHandler(this.lvIslands_SelectedIndexChanged); - this.lvIslands.KeyUp += new System.Windows.Forms.KeyEventHandler(this.EventKeyUp); - // - // columnHeader1 - // - this.columnHeader1.Text = "#"; - // - // columnHeader4 - // - this.columnHeader4.Text = "##"; - // - // columnHeader2 - // - this.columnHeader2.Text = "X, Y"; - this.columnHeader2.Width = 100; - // - // columnHeader3 - // - this.columnHeader3.Text = "Pixels"; - this.columnHeader3.Width = 80; - // - // tsIslands - // - this.tsIslands.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; - this.tsIslands.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.tsIslandsPrevious, - this.tsIslandsCount, - this.tsIslandsNext, + // tabPageIssues + // + this.tabPageIssues.Controls.Add(this.lvIssues); + this.tabPageIssues.Controls.Add(this.tsIssues); + this.tabPageIssues.ImageKey = "warning-16x16.png"; + this.tabPageIssues.Location = new System.Drawing.Point(4, 23); + this.tabPageIssues.Name = "tabPageIssues"; + this.tabPageIssues.Padding = new System.Windows.Forms.Padding(3); + this.tabPageIssues.Size = new System.Drawing.Size(386, 707); + this.tabPageIssues.TabIndex = 3; + this.tabPageIssues.Text = "Issues"; + this.tabPageIssues.UseVisualStyleBackColor = true; + // + // lvIssues + // + this.lvIssues.Activation = System.Windows.Forms.ItemActivation.TwoClick; + this.lvIssues.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.lvIssuesType, + this.lvIssuesCount, + this.lvIssuesLayerHeader, + this.lvIssuesXY, + this.lvIssuesPixels}); + this.lvIssues.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvIssues.FullRowSelect = true; + this.lvIssues.GridLines = true; + this.lvIssues.HideSelection = false; + this.lvIssues.Location = new System.Drawing.Point(3, 28); + this.lvIssues.Name = "lvIssues"; + this.lvIssues.Size = new System.Drawing.Size(380, 676); + this.lvIssues.TabIndex = 8; + this.lvIssues.UseCompatibleStateImageBehavior = false; + this.lvIssues.View = System.Windows.Forms.View.Details; + this.lvIssues.ItemActivate += new System.EventHandler(this.EventItemActivate); + this.lvIssues.SelectedIndexChanged += new System.EventHandler(this.EventSelectedIndexChanged); + this.lvIssues.KeyUp += new System.Windows.Forms.KeyEventHandler(this.EventKeyUp); + // + // lvIssuesType + // + this.lvIssuesType.Text = "Type"; + this.lvIssuesType.Width = 100; + // + // lvIssuesCount + // + this.lvIssuesCount.Text = "#"; + this.lvIssuesCount.Width = 50; + // + // lvIssuesLayerHeader + // + this.lvIssuesLayerHeader.Text = "Layer"; + this.lvIssuesLayerHeader.Width = 50; + // + // lvIssuesXY + // + this.lvIssuesXY.Text = "X, Y"; + this.lvIssuesXY.Width = 100; + // + // lvIssuesPixels + // + this.lvIssuesPixels.Text = "Pixels"; + this.lvIssuesPixels.Width = 55; + // + // tsIssues + // + this.tsIssues.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsIssues.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tsIssuePrevious, + this.tsIssueCount, + this.tsIssueNext, this.toolStripSeparator13, - this.tsIslandsRefresh, - this.tsIslandsRemove, + this.tsIsuesRefresh, + this.tsIssueRemove, this.toolStripSeparator12, - this.tsIslandsRepair}); - this.tsIslands.Location = new System.Drawing.Point(3, 3); - this.tsIslands.Name = "tsIslands"; - this.tsIslands.Size = new System.Drawing.Size(380, 25); - this.tsIslands.TabIndex = 7; - this.tsIslands.Text = "Thumbnail Menu"; - // - // tsIslandsPrevious - // - this.tsIslandsPrevious.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.tsIslandsPrevious.Enabled = false; - this.tsIslandsPrevious.Image = global::PrusaSL1Viewer.Properties.Resources.Back_16x16; - this.tsIslandsPrevious.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIslandsPrevious.Name = "tsIslandsPrevious"; - this.tsIslandsPrevious.Size = new System.Drawing.Size(23, 22); - this.tsIslandsPrevious.Text = "Previous"; - this.tsIslandsPrevious.ToolTipText = "Show previous island"; - this.tsIslandsPrevious.Click += new System.EventHandler(this.EventClick); - // - // tsIslandsCount - // - this.tsIslandsCount.Enabled = false; - this.tsIslandsCount.Name = "tsIslandsCount"; - this.tsIslandsCount.Size = new System.Drawing.Size(24, 22); - this.tsIslandsCount.Text = "0/0"; - // - // tsIslandsNext - // - this.tsIslandsNext.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.tsIslandsNext.Enabled = false; - this.tsIslandsNext.Image = global::PrusaSL1Viewer.Properties.Resources.Next_16x16; - this.tsIslandsNext.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIslandsNext.Name = "tsIslandsNext"; - this.tsIslandsNext.Size = new System.Drawing.Size(23, 22); - this.tsIslandsNext.Text = "tsIslandsNext"; - this.tsIslandsNext.ToolTipText = "Show next island"; - this.tsIslandsNext.Click += new System.EventHandler(this.EventClick); + this.tsIssuesRepair}); + this.tsIssues.Location = new System.Drawing.Point(3, 3); + this.tsIssues.Name = "tsIssues"; + this.tsIssues.Size = new System.Drawing.Size(380, 25); + this.tsIssues.TabIndex = 7; + this.tsIssues.Text = "Thumbnail Menu"; + // + // tsIssuePrevious + // + this.tsIssuePrevious.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tsIssuePrevious.Enabled = false; + this.tsIssuePrevious.Image = global::PrusaSL1Viewer.Properties.Resources.Back_16x16; + this.tsIssuePrevious.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsIssuePrevious.Name = "tsIssuePrevious"; + this.tsIssuePrevious.Size = new System.Drawing.Size(23, 22); + this.tsIssuePrevious.Text = "Previous"; + this.tsIssuePrevious.ToolTipText = "Show previous issue [CTRL+Left]"; + this.tsIssuePrevious.Click += new System.EventHandler(this.EventClick); + // + // tsIssueCount + // + this.tsIssueCount.Enabled = false; + this.tsIssueCount.Name = "tsIssueCount"; + this.tsIssueCount.Size = new System.Drawing.Size(24, 22); + this.tsIssueCount.Text = "0/0"; + // + // tsIssueNext + // + this.tsIssueNext.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.tsIssueNext.Enabled = false; + this.tsIssueNext.Image = global::PrusaSL1Viewer.Properties.Resources.Next_16x16; + this.tsIssueNext.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsIssueNext.Name = "tsIssueNext"; + this.tsIssueNext.Size = new System.Drawing.Size(23, 22); + this.tsIssueNext.Text = "tsIslandsNext"; + this.tsIssueNext.ToolTipText = "Show next issue [CTRL+Right]"; + this.tsIssueNext.Click += new System.EventHandler(this.EventClick); // // toolStripSeparator13 // this.toolStripSeparator13.Name = "toolStripSeparator13"; this.toolStripSeparator13.Size = new System.Drawing.Size(6, 25); // - // tsIslandsRefresh - // - this.tsIslandsRefresh.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; - this.tsIslandsRefresh.Enabled = false; - this.tsIslandsRefresh.Image = global::PrusaSL1Viewer.Properties.Resources.refresh_16x16; - this.tsIslandsRefresh.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIslandsRefresh.Name = "tsIslandsRefresh"; - this.tsIslandsRefresh.Size = new System.Drawing.Size(61, 22); - this.tsIslandsRefresh.Text = "Detect"; - this.tsIslandsRefresh.ToolTipText = "Compute Islands"; - this.tsIslandsRefresh.Click += new System.EventHandler(this.EventClick); - // - // tsIslandsRemove - // - this.tsIslandsRemove.Enabled = false; - this.tsIslandsRemove.Image = global::PrusaSL1Viewer.Properties.Resources.delete_16x16; - this.tsIslandsRemove.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIslandsRemove.Name = "tsIslandsRemove"; - this.tsIslandsRemove.Size = new System.Drawing.Size(70, 22); - this.tsIslandsRemove.Text = "Remove"; - this.tsIslandsRemove.ToolTipText = "Remove selected islands"; - this.tsIslandsRemove.Click += new System.EventHandler(this.EventClick); + // tsIsuesRefresh + // + this.tsIsuesRefresh.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.tsIsuesRefresh.Enabled = false; + this.tsIsuesRefresh.Image = global::PrusaSL1Viewer.Properties.Resources.refresh_16x16; + this.tsIsuesRefresh.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsIsuesRefresh.Name = "tsIsuesRefresh"; + this.tsIsuesRefresh.Size = new System.Drawing.Size(61, 22); + this.tsIsuesRefresh.Text = "Detect"; + this.tsIsuesRefresh.ToolTipText = "Compute Issues"; + this.tsIsuesRefresh.Click += new System.EventHandler(this.EventClick); + // + // tsIssueRemove + // + this.tsIssueRemove.Enabled = false; + this.tsIssueRemove.Image = global::PrusaSL1Viewer.Properties.Resources.delete_16x16; + this.tsIssueRemove.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsIssueRemove.Name = "tsIssueRemove"; + this.tsIssueRemove.Size = new System.Drawing.Size(70, 22); + this.tsIssueRemove.Text = "Remove"; + this.tsIssueRemove.ToolTipText = "Remove selected issue when possible"; + this.tsIssueRemove.Click += new System.EventHandler(this.EventClick); // // toolStripSeparator12 // @@ -1012,17 +1029,17 @@ private void InitializeComponent() this.toolStripSeparator12.Name = "toolStripSeparator12"; this.toolStripSeparator12.Size = new System.Drawing.Size(6, 25); // - // tsIslandsRepair + // tsIssuesRepair // - this.tsIslandsRepair.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; - this.tsIslandsRepair.Enabled = false; - this.tsIslandsRepair.Image = global::PrusaSL1Viewer.Properties.Resources.Wrench_16x16; - this.tsIslandsRepair.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIslandsRepair.Name = "tsIslandsRepair"; - this.tsIslandsRepair.Size = new System.Drawing.Size(60, 22); - this.tsIslandsRepair.Text = "Repair"; - this.tsIslandsRepair.ToolTipText = "Attempt to repair islands"; - this.tsIslandsRepair.Click += new System.EventHandler(this.EventClick); + this.tsIssuesRepair.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.tsIssuesRepair.Enabled = false; + this.tsIssuesRepair.Image = global::PrusaSL1Viewer.Properties.Resources.Wrench_16x16; + this.tsIssuesRepair.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsIssuesRepair.Name = "tsIssuesRepair"; + this.tsIssuesRepair.Size = new System.Drawing.Size(60, 22); + this.tsIssuesRepair.Text = "Repair"; + this.tsIssuesRepair.ToolTipText = "Attempt to repair issues"; + this.tsIssuesRepair.Click += new System.EventHandler(this.EventClick); // // imageList16x16 // @@ -1031,7 +1048,7 @@ private void InitializeComponent() this.imageList16x16.Images.SetKeyName(0, "DataList-16x16.png"); this.imageList16x16.Images.SetKeyName(1, "PhotoInfo-16x16.png"); this.imageList16x16.Images.SetKeyName(2, "GCode-16x16.png"); - this.imageList16x16.Images.SetKeyName(3, "island-16x16.png"); + this.imageList16x16.Images.SetKeyName(3, "warning-16x16.png"); // // tlRight // @@ -1040,32 +1057,36 @@ private void InitializeComponent() this.tlRight.Controls.Add(this.btnPreviousLayer, 0, 3); this.tlRight.Controls.Add(this.btnNextLayer, 0, 1); this.tlRight.Controls.Add(this.lbMaxLayer, 0, 0); - this.tlRight.Controls.Add(this.lbInitialLayer, 0, 4); this.tlRight.Controls.Add(this.panel1, 0, 2); + this.tlRight.Controls.Add(this.lbInitialLayer, 0, 5); + this.tlRight.Controls.Add(this.panel2, 0, 4); this.tlRight.Dock = System.Windows.Forms.DockStyle.Fill; this.tlRight.Location = new System.Drawing.Point(1557, 3); this.tlRight.Name = "tlRight"; - this.tlRight.RowCount = 5; + this.tlRight.RowCount = 6; this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); + this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 32F)); this.tlRight.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); this.tlRight.Size = new System.Drawing.Size(124, 734); this.tlRight.TabIndex = 6; // // btnPreviousLayer // - this.btnPreviousLayer.Dock = System.Windows.Forms.DockStyle.Fill; this.btnPreviousLayer.Enabled = false; this.btnPreviousLayer.Image = global::PrusaSL1Viewer.Properties.Resources.arrow_down_16x16; - this.btnPreviousLayer.Location = new System.Drawing.Point(3, 655); + this.btnPreviousLayer.Location = new System.Drawing.Point(3, 623); this.btnPreviousLayer.Name = "btnPreviousLayer"; this.btnPreviousLayer.Size = new System.Drawing.Size(118, 26); this.btnPreviousLayer.TabIndex = 14; + this.btnPreviousLayer.Tag = "0"; this.btnPreviousLayer.Text = "-"; this.btnPreviousLayer.UseVisualStyleBackColor = true; this.btnPreviousLayer.Click += new System.EventHandler(this.EventClick); + this.btnPreviousLayer.MouseDown += new System.Windows.Forms.MouseEventHandler(this.EventMouseDown); + this.btnPreviousLayer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.EventMouseUp); // // btnNextLayer // @@ -1076,9 +1097,12 @@ private void InitializeComponent() this.btnNextLayer.Name = "btnNextLayer"; this.btnNextLayer.Size = new System.Drawing.Size(118, 26); this.btnNextLayer.TabIndex = 8; + this.btnNextLayer.Tag = "1"; this.btnNextLayer.Text = "+"; this.btnNextLayer.UseVisualStyleBackColor = true; this.btnNextLayer.Click += new System.EventHandler(this.EventClick); + this.btnNextLayer.MouseDown += new System.Windows.Forms.MouseEventHandler(this.EventMouseDown); + this.btnNextLayer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.EventMouseUp); // // lbMaxLayer // @@ -1090,16 +1114,6 @@ private void InitializeComponent() this.lbMaxLayer.Text = "Layers"; this.lbMaxLayer.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // lbInitialLayer - // - this.lbInitialLayer.Dock = System.Windows.Forms.DockStyle.Fill; - this.lbInitialLayer.Location = new System.Drawing.Point(3, 684); - this.lbInitialLayer.Name = "lbInitialLayer"; - this.lbInitialLayer.Size = new System.Drawing.Size(118, 50); - this.lbInitialLayer.TabIndex = 11; - this.lbInitialLayer.Text = "Layers"; - this.lbInitialLayer.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // // panel1 // this.panel1.Controls.Add(this.lbLayerActual); @@ -1107,7 +1121,7 @@ private void InitializeComponent() this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; this.panel1.Location = new System.Drawing.Point(3, 85); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(118, 564); + this.panel1.Size = new System.Drawing.Size(118, 532); this.panel1.TabIndex = 13; // // lbLayerActual @@ -1125,11 +1139,86 @@ private void InitializeComponent() this.tbLayer.Location = new System.Drawing.Point(73, 0); this.tbLayer.Name = "tbLayer"; this.tbLayer.Orientation = System.Windows.Forms.Orientation.Vertical; - this.tbLayer.Size = new System.Drawing.Size(45, 564); + this.tbLayer.Size = new System.Drawing.Size(45, 532); this.tbLayer.TabIndex = 8; this.tbLayer.TickStyle = System.Windows.Forms.TickStyle.TopLeft; this.tbLayer.ValueChanged += new System.EventHandler(this.ValueChanged); // + // lbInitialLayer + // + this.lbInitialLayer.Dock = System.Windows.Forms.DockStyle.Fill; + this.lbInitialLayer.Location = new System.Drawing.Point(3, 684); + this.lbInitialLayer.Name = "lbInitialLayer"; + this.lbInitialLayer.Size = new System.Drawing.Size(118, 50); + this.lbInitialLayer.TabIndex = 11; + this.lbInitialLayer.Text = "Layers"; + this.lbInitialLayer.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // panel2 + // + this.panel2.Controls.Add(this.btnFindLayer); + this.panel2.Controls.Add(this.btnLastLayer); + this.panel2.Controls.Add(this.btnFirstLayer); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(3, 655); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(118, 26); + this.panel2.TabIndex = 15; + // + // btnFindLayer + // + this.btnFindLayer.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnFindLayer.Enabled = false; + this.btnFindLayer.Image = global::PrusaSL1Viewer.Properties.Resources.search_16x16; + this.btnFindLayer.Location = new System.Drawing.Point(37, 0); + this.btnFindLayer.Name = "btnFindLayer"; + this.btnFindLayer.Size = new System.Drawing.Size(44, 26); + this.btnFindLayer.TabIndex = 17; + this.btnFindLayer.Text = "-"; + this.toolTipInformation.SetToolTip(this.btnFindLayer, "Go to a layer index [CTRL+F]"); + this.btnFindLayer.UseVisualStyleBackColor = true; + this.btnFindLayer.Click += new System.EventHandler(this.EventClick); + // + // btnLastLayer + // + this.btnLastLayer.Dock = System.Windows.Forms.DockStyle.Right; + this.btnLastLayer.Enabled = false; + this.btnLastLayer.Image = global::PrusaSL1Viewer.Properties.Resources.arrow_top_16x16; + this.btnLastLayer.Location = new System.Drawing.Point(81, 0); + this.btnLastLayer.Name = "btnLastLayer"; + this.btnLastLayer.Size = new System.Drawing.Size(37, 26); + this.btnLastLayer.TabIndex = 16; + this.btnLastLayer.Text = "-"; + this.toolTipInformation.SetToolTip(this.btnLastLayer, "Go to the last layer [END]"); + this.btnLastLayer.UseVisualStyleBackColor = true; + this.btnLastLayer.Click += new System.EventHandler(this.EventClick); + // + // btnFirstLayer + // + this.btnFirstLayer.Dock = System.Windows.Forms.DockStyle.Left; + this.btnFirstLayer.Enabled = false; + this.btnFirstLayer.Image = global::PrusaSL1Viewer.Properties.Resources.arrow_end_16x16; + this.btnFirstLayer.Location = new System.Drawing.Point(0, 0); + this.btnFirstLayer.Name = "btnFirstLayer"; + this.btnFirstLayer.Size = new System.Drawing.Size(37, 26); + this.btnFirstLayer.TabIndex = 15; + this.btnFirstLayer.Text = "-"; + this.toolTipInformation.SetToolTip(this.btnFirstLayer, "Go to the first layer [HOME]"); + this.btnFirstLayer.UseVisualStyleBackColor = true; + this.btnFirstLayer.Click += new System.EventHandler(this.EventClick); + // + // toolTipInformation + // + this.toolTipInformation.AutoPopDelay = 10000; + this.toolTipInformation.InitialDelay = 500; + this.toolTipInformation.ReshowDelay = 100; + this.toolTipInformation.ToolTipTitle = "Information"; + // + // layerScrollTimer + // + this.layerScrollTimer.Interval = 150; + this.layerScrollTimer.Tick += new System.EventHandler(this.EventTimerTick); + // // FrmMain // this.AllowDrop = true; @@ -1173,14 +1262,15 @@ private void InitializeComponent() this.tabPageGCode.PerformLayout(); this.tsGCode.ResumeLayout(false); this.tsGCode.PerformLayout(); - this.tabPageIslands.ResumeLayout(false); - this.tabPageIslands.PerformLayout(); - this.tsIslands.ResumeLayout(false); - this.tsIslands.PerformLayout(); + this.tabPageIssues.ResumeLayout(false); + this.tabPageIssues.PerformLayout(); + this.tsIssues.ResumeLayout(false); + this.tsIssues.PerformLayout(); this.tlRight.ResumeLayout(false); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).EndInit(); + this.panel2.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -1255,27 +1345,27 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem menuMutate; private System.Windows.Forms.ToolStripSeparator toolStripSeparator10; private System.Windows.Forms.ToolStripMenuItem menuHelpInstallPrinters; - private System.Windows.Forms.TabPage tabPageIslands; - private System.Windows.Forms.ToolStrip tsIslands; - private System.Windows.Forms.ToolStripButton tsIslandsPrevious; - private System.Windows.Forms.ToolStripButton tsIslandsNext; - private System.Windows.Forms.ToolStripLabel tsIslandsCount; - private System.Windows.Forms.ListView lvIslands; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.ColumnHeader columnHeader3; - private System.Windows.Forms.ToolStripButton tsIslandsRefresh; + private System.Windows.Forms.TabPage tabPageIssues; + private System.Windows.Forms.ToolStrip tsIssues; + private System.Windows.Forms.ToolStripButton tsIssuePrevious; + private System.Windows.Forms.ToolStripButton tsIssueNext; + private System.Windows.Forms.ToolStripLabel tsIssueCount; + private System.Windows.Forms.ListView lvIssues; + private System.Windows.Forms.ColumnHeader lvIssuesCount; + private System.Windows.Forms.ColumnHeader lvIssuesXY; + private System.Windows.Forms.ColumnHeader lvIssuesPixels; + private System.Windows.Forms.ToolStripButton tsIsuesRefresh; private System.Windows.Forms.ToolStripSeparator toolStripSeparator11; private System.Windows.Forms.ToolStripLabel tsLayerImageMouseLocation; - private System.Windows.Forms.ColumnHeader columnHeader4; + private System.Windows.Forms.ColumnHeader lvIssuesLayerHeader; private System.Windows.Forms.ToolStripSeparator toolStripSeparator12; - private System.Windows.Forms.ToolStripButton tsIslandsRemove; + private System.Windows.Forms.ToolStripButton tsIssueRemove; private System.Windows.Forms.ToolStripMenuItem menuTools; private System.Windows.Forms.ToolStripMenuItem menuToolsRepairLayers; private System.Windows.Forms.ToolStripSeparator toolStripSeparator13; - private System.Windows.Forms.ToolStripButton tsIslandsRepair; + private System.Windows.Forms.ToolStripButton tsIssuesRepair; private System.Windows.Forms.ToolStripSeparator toolStripSeparator14; - private System.Windows.Forms.ToolStripButton tsLayerImageHighlightIslands; + private System.Windows.Forms.ToolStripButton tsLayerImageHighlightIssues; private System.Windows.Forms.TrackBar tbLayer; private System.Windows.Forms.TableLayoutPanel tlRight; private System.Windows.Forms.Label lbMaxLayer; @@ -1284,6 +1374,13 @@ private void InitializeComponent() private System.Windows.Forms.Button btnPreviousLayer; private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Label lbLayerActual; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.Button btnFirstLayer; + private System.Windows.Forms.Button btnLastLayer; + private System.Windows.Forms.Button btnFindLayer; + private System.Windows.Forms.ToolTip toolTipInformation; + private System.Windows.Forms.ColumnHeader lvIssuesType; + private System.Windows.Forms.Timer layerScrollTimer; } } diff --git a/PrusaSL1Viewer/FrmMain.cs b/PrusaSL1Viewer/FrmMain.cs index 41aa0935..52a594ff 100644 --- a/PrusaSL1Viewer/FrmMain.cs +++ b/PrusaSL1Viewer/FrmMain.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using System.Drawing; using System.IO; +using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; @@ -25,6 +26,8 @@ using Color = System.Drawing.Color; using Image = SixLabors.ImageSharp.Image; using Point = System.Drawing.Point; +using PointF = System.Drawing.PointF; +using Rectangle = System.Drawing.Rectangle; using Size = System.Drawing.Size; namespace PrusaSL1Viewer @@ -40,8 +43,9 @@ public partial class FrmMain : Form new Dictionary { {Mutation.Mutates.Resize, new Mutation(Mutation.Mutates.Resize, - "Resizes layer images in a X and/or Y factor, starting at 100% value\n" + - "NOTE: Build volume bounds are not validated after operation, please ensure scaling stays inside your limits." + "Resizes layer images in a X and/or Y factor, starting from 100% value\n" + + "NOTE 1: Build volume bounds are not validated after operation, please ensure scaling stays inside your limits.\n" + + "NOTE 2: X and Y are applied to original image, not to the rotated preview (If enabled)." )}, {Mutation.Mutates.Erode, new Mutation(Mutation.Mutates.Erode, "The basic idea of erosion is just like soil erosion only, it erodes away the boundaries of foreground object (Always try to keep foreground in white). " + @@ -82,10 +86,13 @@ public partial class FrmMain : Form "After performs up-sampling step of Gaussian pyramid decomposition\n" )}, {Mutation.Mutates.SmoothMedian, new Mutation(Mutation.Mutates.SmoothMedian, - "Finding median of size neighborhood" + "Each pixel becomes the median of its surrounding pixels. Also a good way to remove noise.\n" + + "Note: Iterations must be a odd number." )}, {Mutation.Mutates.SmoothGaussian, new Mutation(Mutation.Mutates.SmoothGaussian, - "Perform Gaussian Smoothing" + "Each pixel is a sum of fractions of each pixel in its neighborhood\n" + + "Very fast, but does not preserve sharp edges well.\n" + + "Note: Iterations must be a odd number." )}, }; @@ -102,9 +109,9 @@ public static FileFormat SlicerFile public Image ActualLayerImage { get; private set; } - public Dictionary> Islands { get; set; } + public SortedDictionary> Issues { get; set; } - public uint TotalIslands { get; set; } + public uint TotalIssues { get; set; } public bool IsChagingLayer { get; set; } @@ -133,6 +140,13 @@ public FrmMain() item.Click += EventClick; menuMutate.DropDownItems.Add(item); } + + foreach (LayerIssue.IssueType issueType in (LayerIssue.IssueType[]) Enum.GetValues( + typeof(LayerIssue.IssueType))) + { + var group = new ListViewGroup(issueType.ToString(), $"{issueType}s"){HeaderAlignment = HorizontalAlignment.Center}; + lvIssues.Groups.Add(group); + } } #endregion @@ -179,7 +193,7 @@ protected override void OnKeyUp(KeyEventArgs e) if (e.KeyCode == Keys.Home) { - ShowLayer(0); + btnFirstLayer.PerformClick(); e.Handled = true; return; } @@ -188,7 +202,7 @@ protected override void OnKeyUp(KeyEventArgs e) if (e.KeyCode == Keys.End) { - ShowLayer(SlicerFile.LayerCount-1); + btnLastLayer.PerformClick(); e.Handled = true; return; } @@ -197,13 +211,7 @@ protected override void OnKeyUp(KeyEventArgs e) { if (e.KeyCode == Keys.F) { - using (FrmInputBox inputBox = new FrmInputBox("Go to layer", "Select a layer index to go to", ActualLayer, null, 0, SlicerFile.LayerCount-1, 0, "Layer")) - { - if (inputBox.ShowDialog() == DialogResult.OK) - { - ShowLayer((uint)inputBox.NewValue); - } - } + btnFindLayer.PerformClick(); e.Handled = true; return; } @@ -221,6 +229,27 @@ protected override void OnKeyUp(KeyEventArgs e) e.Handled = true; return; } + + if (e.KeyCode == Keys.Left) + { + tsIssuePrevious.PerformClick(); + e.Handled = true; + return; + } + + if (e.KeyCode == Keys.Right) + { + tsIssueNext.PerformClick(); + e.Handled = true; + return; + } + } + else + { + if (e.KeyCode == Keys.F5) + { + ShowLayer(); + } } base.OnKeyUp(e); } @@ -291,7 +320,7 @@ private void EventClick(object sender, EventArgs e) if (ReferenceEquals(sender, menuFileReload)) { - ProcessFile(); + ProcessFile(ActualLayer); return; } @@ -571,7 +600,7 @@ private void EventClick(object sender, EventArgs e) ShowLayer(); - ComputeIslands(); + ComputeIssues(); menuFileSave.Enabled = menuFileSaveAs.Enabled = true; @@ -606,29 +635,30 @@ private void EventClick(object sender, EventArgs e) { string printerFolder = $"{Application.StartupPath}{Path.DirectorySeparatorChar}PrusaSlicer{Path.DirectorySeparatorChar}printer"; + string printFolder = + $"{Application.StartupPath}{Path.DirectorySeparatorChar}PrusaSlicer{Path.DirectorySeparatorChar}sla_print"; try { - string[] profiles = Directory.GetFiles(printerFolder); - string profilesNames = String.Empty; - - foreach (var profile in profiles) - { - profilesNames += $"{Path.GetFileNameWithoutExtension(profile)}\n"; - } + string[] printProfiles = Directory.GetFiles(printFolder); + string[] printerProfiles = Directory.GetFiles(printerFolder); + string printsNames = printProfiles.Aggregate(string.Empty, (current, profile) => current + $"{Path.GetFileNameWithoutExtension(profile)}\n"); + string printerNames = printerProfiles.Aggregate(string.Empty, (current, profile) => current + $"{Path.GetFileNameWithoutExtension(profile)}\n"); var result = MessageBox.Show( - "This action will install following printer profiles into PrusaSlicer:\n" + - "---------------\n" + - profilesNames + + "This action will install following profiles into PrusaSlicer:\n" + + "---------- PRINT PROFILES ----------\n" + + printsNames + + "--------- PRINTER PROFILES ---------\n" + + printerNames + "---------------\n" + "Click 'Yes' to override all profiles\n" + "Click 'No' to install only missing profiles without override\n" + - "Clock 'Abort' to cancel this operation", + "Click 'Cancel' to cancel this operation", "Install printers into PrusaSlicer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); - if (result == DialogResult.Abort) + if (result == DialogResult.Cancel) { return; } @@ -637,7 +667,7 @@ private void EventClick(object sender, EventArgs e) string targetFolder = $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}PrusaSlicer{Path.DirectorySeparatorChar}printer"; - foreach (var profile in profiles) + foreach (var profile in printerProfiles) { string targetFile = $"{targetFolder}{Path.DirectorySeparatorChar}{Path.GetFileName(profile)}"; @@ -824,49 +854,51 @@ private void EventClick(object sender, EventArgs e) } /************************ - * Islands Menu * + * Issues Menu * ***********************/ - if (ReferenceEquals(sender, tsIslandsPrevious)) + if (ReferenceEquals(sender, tsIssuePrevious)) { - if (!tsIslandsPrevious.Enabled) return; - int index = Convert.ToInt32(tsIslandsCount.Tag); - lvIslands.SelectedItems.Clear(); - lvIslands.Items[--index].Selected = true; - lvIslands_ItemActivate(lvIslands, null); + if (!tsIssuePrevious.Enabled) return; + int index = Convert.ToInt32(tsIssueCount.Tag); + lvIssues.SelectedItems.Clear(); + lvIssues.Items[--index].Selected = true; + EventItemActivate(lvIssues, null); return; } - if (ReferenceEquals(sender, tsIslandsNext)) + if (ReferenceEquals(sender, tsIssueNext)) { - if (!tsIslandsNext.Enabled) return; - int index = Convert.ToInt32(tsIslandsCount.Tag); - lvIslands.SelectedItems.Clear(); - lvIslands.Items[++index].Selected = true; - lvIslands_ItemActivate(lvIslands, null); + if (!tsIssueNext.Enabled) return; + int index = Convert.ToInt32(tsIssueCount.Tag); + lvIssues.SelectedItems.Clear(); + lvIssues.Items[++index].Selected = true; + EventItemActivate(lvIssues, null); return; } - if (ReferenceEquals(sender, tsIslandsRemove)) + if (ReferenceEquals(sender, tsIssueRemove)) { - if (!tsIslandsRemove.Enabled || ReferenceEquals(Islands, null)) return; + if (!tsIssueRemove.Enabled || ReferenceEquals(Issues, null)) return; - if (MessageBox.Show("Are you sure you want to remove all selected islands from image?\n" + - "Warning: Removing a island can cause another island to appears if the next layer have land in top of the removed island.\n" + + if (MessageBox.Show("Are you sure you want to remove all selected issues from image?\n" + + "Warning: Removing a island can cause another issues to appears if the next layer have land in top of the removed island.\n" + "Always check previous and next layer before perform a island removal to ensure safe operation.", "Remove islands?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return; - foreach (ListViewItem item in lvIslands.SelectedItems) + foreach (ListViewItem item in lvIssues.SelectedItems) { - if (!(item.Tag is LayerIsland island)) continue; + if (!(item.Tag is LayerIssue issue)) continue; - var image = ActualLayer == island.Owner.Index ? ActualLayerImage : island.Owner.Image; + var image = ActualLayer == issue.Layer.Index ? ActualLayerImage : issue.Layer.Image; - foreach (var pixel in island) + if(!issue.HaveValidPoint) continue; + + foreach (var pixel in issue) { image[pixel.X, pixel.Y] = Helpers.L8Black; - if (ActualLayer == island.Owner.Index) + if (ActualLayer == issue.Layer.Index) { int x = pixel.X; int y = pixel.Y; @@ -881,33 +913,33 @@ private void EventClick(object sender, EventArgs e) } } - if (ActualLayer == island.Owner.Index) pbLayer.Invalidate(); + if (ActualLayer == issue.Layer.Index) pbLayer.Invalidate(); - island.Owner.Image = image; - Islands[island.Owner.Index].Remove(island); - TotalIslands--; + issue.Layer.Image = image; + Issues[issue.Layer.Index].Remove(issue); + TotalIssues--; item.Remove(); } - UpdateIslandsInfo(); + UpdateIssuesInfo(); menuFileSave.Enabled = menuFileSaveAs.Enabled = true; return; } - if (ReferenceEquals(sender, tsIslandsRepair)) + if (ReferenceEquals(sender, tsIssuesRepair)) { EventClick(menuToolsRepairLayers, e); return; } - if (ReferenceEquals(sender, tsIslandsRefresh)) + if (ReferenceEquals(sender, tsIsuesRefresh)) { - if (MessageBox.Show("Are you sure you want to compute islands?", "Islands Compute", + if (MessageBox.Show("Are you sure you want to compute issues?", "Issues Compute", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return; - ComputeIslands(); + ComputeIssues(); return; } @@ -916,7 +948,7 @@ private void EventClick(object sender, EventArgs e) * Layer Menu * ***********************/ if (ReferenceEquals(sender, tsLayerImageRotate) || ReferenceEquals(sender, tsLayerImageLayerDifference) || - ReferenceEquals(sender, tsLayerImageHighlightIslands) || + ReferenceEquals(sender, tsLayerImageHighlightIssues) || ReferenceEquals(sender, tsLayerImageLayerOutline)) { ShowLayer(); @@ -952,6 +984,12 @@ private void EventClick(object sender, EventArgs e) } } + if (ReferenceEquals(sender, btnFirstLayer)) + { + ShowLayer(0); + return; + } + if (ReferenceEquals(sender, btnPreviousLayer)) { ShowLayer(false); @@ -963,6 +1001,24 @@ private void EventClick(object sender, EventArgs e) ShowLayer(true); return; } + + if (ReferenceEquals(sender, btnLastLayer)) + { + ShowLayer(SlicerFile.LayerCount-1); + return; + } + + if (ReferenceEquals(sender, btnFindLayer)) + { + using (FrmInputBox inputBox = new FrmInputBox("Go to layer", "Select a layer index to go to", ActualLayer, null, 0, SlicerFile.LayerCount - 1, 0, "Layer")) + { + if (inputBox.ShowDialog() == DialogResult.OK) + { + ShowLayer((uint)inputBox.NewValue); + } + } + return; + } } @@ -1092,39 +1148,44 @@ private void pbLayer_MouseMove(object sender, MouseEventArgs e) DrawPixel(true, location); } - private void lvIslands_ItemActivate(object sender, EventArgs e) + private void EventItemActivate(object sender, EventArgs e) { - if (lvIslands.SelectedItems.Count == 0) return; - var item = lvIslands.SelectedItems[0]; - - if (!(item.Tag is LayerIsland island)) return; - if (island.Owner.Index != ActualLayer) + if (ReferenceEquals(sender, lvIssues)) { - ShowLayer(island.Owner.Index); - //ShowLayer(island.Owner.Index); - } + if (lvIssues.SelectedItems.Count == 0) return; + var item = lvIssues.SelectedItems[0]; - uint x = island.X; - uint y = island.Y; + if (!(item.Tag is LayerIssue issue)) return; + if (issue.Layer.Index != ActualLayer) + { + ShowLayer(issue.Layer.Index); + } - if (tsLayerImageRotate.Checked) - { - //x = island.Y; - //y = SlicerFile.ResolutionX - 1 - island.X; - - //x = SlicerFile.ResolutionY - 1 - y; - //y = x; + if (issue.Type == LayerIssue.IssueType.TouchingBound) + { + pbLayer.ZoomToFit(); + } + else if (issue.X >= 0 && issue.Y >= 0) + { + int x = issue.X; + int y = issue.Y; - x = (uint) (ActualLayerImage.Height - 1 - island.Y); - y = island.X; - } + if (tsLayerImageRotate.Checked) + { + x = ActualLayerImage.Height - 1 - issue.Y; + y = issue.X; + } - //pbLayer.Zoom = 1200; - pbLayer.ZoomToRegion(x, y, 5, 5); - pbLayer.ZoomOut(true); + //pbLayer.Zoom = 1200; + pbLayer.ZoomToRegion(x, y, 5, 5); + pbLayer.ZoomOut(true); + } + + tsIssueCount.Tag = lvIssues.SelectedIndices[0]; + UpdateIssuesInfo(); + return; + } - tsIslandsCount.Tag = lvIslands.SelectedIndices[0]; - UpdateIslandsInfo(); } #endregion @@ -1145,14 +1206,14 @@ void Clear() pbLayer.Image = null; pbThumbnail.Image = null; tbGCode.Clear(); + tabPageIssues.Tag = null; - Islands = null; - TotalIslands = 0; - lvIslands.BeginUpdate(); - lvIslands.Items.Clear(); - lvIslands.Groups.Clear(); - lvIslands.EndUpdate(); - UpdateIslandsInfo(); + Issues = null; + TotalIssues = 0; + lvIssues.BeginUpdate(); + lvIssues.Items.Clear(); + lvIssues.EndUpdate(); + UpdateIssuesInfo(); lbMaxLayer.Text = lbLayerActual.Text = @@ -1190,7 +1251,7 @@ void Clear() { item.Enabled = false; } - foreach (ToolStripItem item in tsIslands.Items) + foreach (ToolStripItem item in tsIssues.Items) { item.Enabled = false; } @@ -1213,8 +1274,11 @@ void Clear() menuEdit.Enabled = menuMutate.Enabled = menuTools.Enabled = + btnFirstLayer.Enabled = btnNextLayer.Enabled = btnPreviousLayer.Enabled = + btnLastLayer.Enabled = + btnFindLayer.Enabled = false; @@ -1222,7 +1286,7 @@ void Clear() tsThumbnailsCount.Tag = null; tabControlLeft.TabPages.Remove(tabPageGCode); - tabControlLeft.TabPages.Remove(tabPageIslands); + tabControlLeft.TabPages.Remove(tabPageIssues); tabControlLeft.SelectedIndex = 0; } @@ -1240,10 +1304,10 @@ void EnableGUI(bool closeLoading = false) menu.Enabled = true; } - void ProcessFile() + void ProcessFile(uint actualLayer = 0) { if (ReferenceEquals(SlicerFile, null)) return; - ProcessFile(SlicerFile.FileFullPath); + ProcessFile(SlicerFile.FileFullPath, actualLayer); } void ProcessFile(string[] files) @@ -1265,7 +1329,7 @@ void ProcessFile(string[] files) } } - void ProcessFile(string fileName) + void ProcessFile(string fileName, uint actualLayer = 0) { Clear(); SlicerFile = FileFormat.FindByExtension(fileName, true, true); @@ -1299,7 +1363,7 @@ void ProcessFile(string fileName) ActualLayerImage = SlicerFile[0].Image; - lbMaxLayer.Text = $"{SlicerFile.TotalHeight}mm\n{SlicerFile.LayerCount}"; + lbMaxLayer.Text = $"{SlicerFile.TotalHeight}mm\n{SlicerFile.LayerCount-1}"; lbInitialLayer.Text = $"{SlicerFile.LayerHeight}mm\n0"; @@ -1374,15 +1438,17 @@ void ProcessFile(string fileName) menuMutate.Enabled = menuTools.Enabled = - tsIslandsRepair.Enabled = - tsIslandsRefresh.Enabled = + tsIssuesRepair.Enabled = + tsIsuesRefresh.Enabled = + + btnFindLayer.Enabled = true; if (!ReferenceEquals(SlicerFile.GCode, null)) { tabControlLeft.TabPages.Add(tabPageGCode); } - tabControlLeft.TabPages.Add(tabPageIslands); + tabControlLeft.TabPages.Add(tabPageIssues); //ShowLayer(0); @@ -1390,7 +1456,7 @@ void ProcessFile(string fileName) tsLayerResolution.Text = $"{{Width={SlicerFile.ResolutionX}, Height={SlicerFile.ResolutionY}}}"; tbLayer.Maximum = (int)SlicerFile.LayerCount - 1; - ShowLayer(); + ShowLayer(actualLayer); @@ -1439,8 +1505,8 @@ void RefreshInfo() foreach (PropertyInfo propertyInfo in config.GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance)) { + if(propertyInfo.Name.Equals("Item")) continue; ListViewItem item = new ListViewItem(propertyInfo.Name, group); - object obj = new object(); var value = propertyInfo.GetValue(config); if (!ReferenceEquals(value, null)) { @@ -1526,8 +1592,8 @@ void ShowLayer(uint layerNum) IsChagingLayer = true; ActualLayer = layerNum; - btnNextLayer.Enabled = layerNum < SlicerFile.LayerCount - 1; - btnPreviousLayer.Enabled = layerNum > 0; + btnLastLayer.Enabled = btnNextLayer.Enabled = layerNum < SlicerFile.LayerCount - 1; + btnFirstLayer.Enabled = btnPreviousLayer.Enabled = layerNum > 0; try { @@ -1549,6 +1615,12 @@ void ShowLayer(uint layerNum) { Image grayscale = ActualLayerImage.ToEmguImage(); grayscale = grayscale.Canny(80, 40, 3, true); + + + + var grayscaleinv = grayscale.ThresholdBinaryInv(new Gray(0), new Gray(255)); + + grayscale = ActualLayerImage.ToEmguImage() & grayscaleinv; /*grayscale = grayscale.Dilate(1).Erode(1); Gray gray = new Gray(255); @@ -1571,9 +1643,9 @@ void ShowLayer(uint layerNum) { var previousImage = SlicerFile[layerNum-1].Image; var nextImage = SlicerFile[layerNum+1].Image; - /*var newImage = new Image(previousImage.Width, previousImage.Height); + var newImage = new Image(previousImage.Width, previousImage.Height); - Parallel.For(0, ActualLayerImage.Height, y => { + /*Parallel.For(0, ActualLayerImage.Height, y => { var newImageSpan = newImage.GetPixelRowSpan(y); var previousImageSpan = previousImage.GetPixelRowSpan(y); for (int x = 0; x < ActualLayerImage.Width; x++) @@ -1586,11 +1658,12 @@ void ShowLayer(uint layerNum) imageRgba.Mutate(imgMaskIn => { - imgMaskIn.DrawImage(newImage, PixelColorBlendingMode.Normal, 0.7f); + imgMaskIn.DrawImage(newImage, PixelColorBlendingMode.Screen, 0.5f); });*/ //var nextImage = SlicerFile.GetLayerImage(layerNum+1); - Parallel.For(0, ActualLayerImage.Height, y => { + Parallel.For(0, ActualLayerImage.Height, y => + { var imageSpan = imageRgba.GetPixelRowSpan(y); var previousImageSpan = previousImage.GetPixelRowSpan(y); var nextImageSpan = nextImage.GetPixelRowSpan(y); @@ -1638,22 +1711,33 @@ void ShowLayer(uint layerNum) } } - if (tsLayerImageHighlightIslands.Checked && !ReferenceEquals(Islands, null) && Islands.Count > ActualLayer) + if (tsLayerImageHighlightIssues.Checked && + !ReferenceEquals(Issues, null) && + Issues.TryGetValue(ActualLayer, out var issues)) { - var islands = Islands[ActualLayer]; - - foreach (var island in islands) + foreach (var issue in issues) { - if (ReferenceEquals(island, null)) continue; // Removed islands - foreach (var pixel in island) + if (ReferenceEquals(issue, null)) continue; // Removed issue + if(!issue.HaveValidPoint) continue; + foreach (var pixel in issue) { var alpha = ActualLayerImage[pixel.X, pixel.Y].PackedValue; if (alpha == 0) continue; // alpha, Color.Yellow - alpha = Math.Max((byte)70, alpha); - imageRgba[pixel.X, pixel.Y] = new Rgba32(alpha, alpha, 0); + alpha = Math.Max((byte) 80, alpha); + switch (issue.Type) + { + case LayerIssue.IssueType.Island: + imageRgba[pixel.X, pixel.Y] = new Rgba32(alpha, alpha, 0); + break; + default: + imageRgba[pixel.X, pixel.Y] = new Rgba32(alpha, 0, 0); + break; + } + } } + } if (tsLayerImageRotate.Checked) @@ -1697,8 +1781,7 @@ void ShowLayer(uint layerNum) byte percent = (byte)((layerNum + 1) * 100 / SlicerFile.LayerCount); - //var islands = SlicerFile.LayerManager.GetAllIslands(); - //Debug.WriteLine(islands.Length); + watch.Stop(); tsLayerPreviewTime.Text = $"{watch.ElapsedMilliseconds}ms"; @@ -1744,18 +1827,33 @@ void AdjustThumbnailSplitter() scLeft.SplitterDistance = Math.Min(pbThumbnail.Image.Height + 5, 400); } - private void lvIslands_SelectedIndexChanged(object sender, EventArgs e) + private void EventSelectedIndexChanged(object sender, EventArgs e) { - tsIslandsRemove.Enabled = lvIslands.SelectedIndices.Count > 0; + if (ReferenceEquals(sender, lvIssues)) + { + tsIssueRemove.Enabled = lvIssues.SelectedIndices.Count > 0; + return; + } + + if (ReferenceEquals(sender, tabControlLeft)) + { + if(ReferenceEquals(tabControlLeft.SelectedTab, tabPageIssues)) + { + if (!ReferenceEquals(tabPageIssues.Tag, null)) return; + tabPageIssues.Tag = true; + ComputeIssues(); + } + return; + } } private void EventKeyUp(object sender, KeyEventArgs e) { - if (ReferenceEquals(sender, lvIslands)) + if (ReferenceEquals(sender, lvIssues)) { if (e.KeyCode == Keys.Escape) { - foreach (ListViewItem item in lvIslands.Items) + foreach (ListViewItem item in lvIssues.Items) { item.Selected = false; } @@ -1765,7 +1863,7 @@ private void EventKeyUp(object sender, KeyEventArgs e) if (e.Control && e.KeyCode == Keys.A) { - foreach (ListViewItem item in lvIslands.Items) + foreach (ListViewItem item in lvIssues.Items) { item.Selected = true; } @@ -1775,13 +1873,20 @@ private void EventKeyUp(object sender, KeyEventArgs e) if (e.KeyCode == Keys.Multiply) { - foreach (ListViewItem item in lvIslands.Items) + foreach (ListViewItem item in lvIssues.Items) { item.Selected = !item.Selected; } e.Handled = true; return; } + + if (e.KeyCode == Keys.Delete) + { + tsIssueRemove.PerformClick(); + e.Handled = true; + return; + } return; } } @@ -1841,12 +1946,15 @@ public void MutateLayers(Mutation.Mutates type) { uint layerStart; uint layerEnd; - uint iterationsStart; - uint iterationsEnd; + uint iterationsStart = 0; + uint iterationsEnd = 0; bool fade = false; float iterationSteps = 0; uint maxIteration = 0; + float x = 0; + float y = 0; + switch (type) { case Mutation.Mutates.Resize: @@ -1855,8 +1963,8 @@ public void MutateLayers(Mutation.Mutates type) if (inputBox.ShowDialog() != DialogResult.OK) return; layerStart = inputBox.LayerRangeStart; layerEnd = inputBox.LayerRangeEnd; - iterationsStart = inputBox.X; - iterationsEnd = inputBox.Y; + x = inputBox.X; + y = inputBox.Y; } break; @@ -1892,7 +2000,7 @@ public void MutateLayers(Mutation.Mutates type) { if (type == Mutation.Mutates.Resize) { - SlicerFile.Resize(layerStart, layerEnd, iterationsStart / 100f, iterationsEnd / 100f); + SlicerFile.Resize(layerStart, layerEnd, x / 100f, y / 100f); } else { @@ -1916,6 +2024,10 @@ public void MutateLayers(Mutation.Mutates type) var imageEgmu = image.ToEmguImage(); switch (type) { + case Mutation.Mutates.Resize: + var resizedImage = imageEgmu.Resize( (int) (iterationsStart / 100.0 * image.Width), (int) (iterationsEnd / 100.0 * image.Height), Inter.Lanczos4); + imageEgmu = resizedImage.Copy(new Rectangle(0, 0, image.Width, image.Height)); + break; case Mutation.Mutates.Erode: imageEgmu = imageEgmu.Erode((int) iterations); break; @@ -1991,52 +2103,51 @@ public void MutateLayers(Mutation.Mutates type) menuFileSaveAs.Enabled = true; } - private void UpdateIslandsInfo() + private void UpdateIssuesInfo() { - if (TotalIslands == 0) + if (TotalIssues == 0) { - tsIslandsPrevious.Enabled = - tsIslandsCount.Enabled = - tsIslandsNext.Enabled = false; + tsIssuePrevious.Enabled = + tsIssueCount.Enabled = + tsIssueNext.Enabled = false; - tsIslandsCount.Text = "0/0"; - tsIslandsCount.Tag = -1; + tsIssueCount.Text = "0/0"; + tsIssueCount.Tag = -1; } else { - int currentIslandSelected = Convert.ToInt32(tsIslandsCount.Tag); - tsIslandsCount.Enabled = true; - tsIslandsCount.Text = $"{currentIslandSelected+1}/{TotalIslands}"; + int currentIssueSelected = Convert.ToInt32(tsIssueCount.Tag); + tsIssueCount.Enabled = true; + tsIssueCount.Text = $"{currentIssueSelected+1}/{TotalIssues}"; - tsIslandsPrevious.Enabled = currentIslandSelected > 0; - tsIslandsNext.Enabled = currentIslandSelected+1 < TotalIslands; + tsIssuePrevious.Enabled = currentIssueSelected > 0; + tsIssueNext.Enabled = currentIssueSelected+1 < TotalIssues; } } - private void ComputeIslands() + private void ComputeIssues() { - TotalIslands = 0; - lvIslands.BeginUpdate(); - lvIslands.Items.Clear(); - lvIslands.Groups.Clear(); - lvIslands.EndUpdate(); - UpdateIslandsInfo(); + TotalIssues = 0; + lvIssues.BeginUpdate(); + lvIssues.Items.Clear(); + lvIssues.EndUpdate(); + UpdateIssuesInfo(); DisableGUI(); - FrmLoading.SetDescription("Computing Islands"); + FrmLoading.SetDescription("Computing Issues"); Task task = Task.Factory.StartNew(() => { bool result = false; try { - Islands = SlicerFile.LayerManager.GetAllIslands(); + Issues = SlicerFile.LayerManager.GetAllIssues(); result = true; } catch (Exception ex) { - MessageBox.Show(ex.Message, "Error while trying compute islands", MessageBoxButtons.OK, + MessageBox.Show(ex.Message, "Error while trying compute issues", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally @@ -2052,39 +2163,65 @@ private void ComputeIslands() FrmLoading.ShowDialog(); - lvIslands.BeginUpdate(); + lvIssues.BeginUpdate(); uint count = 0; try { - for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++) + foreach (var kv in Issues) { - ListViewGroup group = new ListViewGroup($"Layer {layerIndex} - {Islands[layerIndex].Count} Islands"); - for (var i = 0; i < Islands[layerIndex].Count; i++) + foreach (var issue in kv.Value) { + TotalIssues++; count++; - var island = Islands[layerIndex][i]; - TotalIslands++; - ListViewItem item = new ListViewItem(group) { Text = count.ToString() }; - item.SubItems.Add((i + 1).ToString()); - item.SubItems.Add($"{island.X}, {island.Y}"); - item.SubItems.Add(island.Size.ToString()); - item.Tag = island; - lvIslands.Groups.Add(group); - lvIslands.Items.Add(item); + ListViewItem item = new ListViewItem(lvIssues.Groups[(int)issue.Type]) {Text = issue.Type.ToString() }; + item.SubItems.Add(count.ToString()); + item.SubItems.Add(kv.Key.ToString()); + item.SubItems.Add($"{issue.X}, {issue.Y}"); + item.SubItems.Add(issue.Size.ToString()); + item.Tag = issue; + lvIssues.Items.Add(item); } } } catch (Exception ex) { - MessageBox.Show(ex.Message, "Error while trying compute islands", MessageBoxButtons.OK, + MessageBox.Show(ex.Message, "Error while trying compute issues", MessageBoxButtons.OK, MessageBoxIcon.Error); throw; } - lvIslands.EndUpdate(); + lvIssues.EndUpdate(); + + UpdateIssuesInfo(); + } + + private void EventMouseDown(object sender, MouseEventArgs e) + { + if (ReferenceEquals(sender, btnNextLayer) || ReferenceEquals(sender, btnPreviousLayer)) + { + layerScrollTimer.Tag = ReferenceEquals(sender, btnNextLayer); + layerScrollTimer.Start(); + return; + } + } + + private void EventMouseUp(object sender, MouseEventArgs e) + { + if (ReferenceEquals(sender, btnNextLayer) || ReferenceEquals(sender, btnPreviousLayer)) + { + layerScrollTimer.Stop(); + return; + } + } - UpdateIslandsInfo(); + private void EventTimerTick(object sender, EventArgs e) + { + if (ReferenceEquals(sender, layerScrollTimer)) + { + ShowLayer((bool)layerScrollTimer.Tag); + return; + } } } } diff --git a/PrusaSL1Viewer/FrmMain.resx b/PrusaSL1Viewer/FrmMain.resx index 30ef5f81..720daa62 100644 --- a/PrusaSL1Viewer/FrmMain.resx +++ b/PrusaSL1Viewer/FrmMain.resx @@ -126,16 +126,10 @@ 201, 17 - - 291, 17 - - - 649, 17 - 551, 17 - + 765, 17 @@ -145,69 +139,91 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAD2 - DQAAAk1TRnQBSQFMAgEBBAEAAUgBAwFIAQMBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABG + DgAAAk1TRnQBSQFMAgEBBAEAAdgBAwHYAQMBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8AZgADUAGjA1IBqQNS - AakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1ABo1wAAxYBHgMjATMDIwEz - AyMBMwMjATMDGAEhAwIBAwwAA1UBtANZAccDLwFJAwABAQMbASYDHAEnAxwBJwMcAScDHAEnAxwBJwMc - AScDHAEnAxwBJwMcAScDHAEnAwIBAwQAA1IBqTAAA1IBqRAAAycBOgMwAUwDMAFMAzABTAMwAUwDMAFM - AzABTAMwAUwDMAFMAycBOhwAAwQBBgMjATMDUgGpAbMBOAEAAf8BsgE3AQAB/wGyATYBAAH/AbMBNwEA - Af8CWAFWAbkDKQE/AwQBBgsAAf8DAAH/A0MBdwMpAT4DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMyAVEEAANSAakEAANQAZ0DUwGqA1MBqgNTAaoDUwGqA1MBqgNTAaoDUAGd - DAADUgGpEAADTgH7AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DTgH7GAADBQEHAzABTAGz - ATcBAAH/AdkBswGMAf8B9QHfAcUB/wH+Ae4B2AH/Af4B7gHYAf8B+gHnAc8B/wHZAbMBjAH/AbMBNwEA - Af8CMQEwAU0DAgEDBAADUQGiA1YBtgMqAUAEAAMQARUDEQEXAxEBFwMRARcDEQEXAxEBFwMRARcDEQEX - AxEBFwMRARcDEAEWCAADUgGpBAADUAGdA1MBqgNTAaoDHwEsHAADUgGpEwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/xgAAjEBMAFNAbcBgQEGAf8B6gHNAawB/wH6AeUBywH/AfgB4QHG - Af8B9gHgAcQB/wH2Ad8BxAH/AfcB4QHFAf8B+gHlAcsB/wHvAdUBtwH/AbMBNwEAAf8DIAEuBAADCgEO - AxEBFwMAAQE4AANSAakwAANSAakTAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - GAACagFEAfkB5QHHAaQB/wH3Ad8BwgH/AfMB2wG7Af8B8wHaAbsB/wHzAdsBvAH/AfMB2wG8Af8B8wHb - AbwB/wHzAdwBvQH/AfYB4QHDAf8B1QGvAYQB/wJYAVYBuQQAA1IB9AMAAf8DPgFsAw4BEwNCAXYDQwF3 - A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0MBdwNDAXcDQgF2AxQBGwQAA1IBqQMiATIDUgGpA1IBqQNS - AakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpAyIBMgNSAakTAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/GAABtAE5AQAC/wHwAdwC/wHvAdwB/wH+AesB1wH/AfkB5AHKAf8B8QHW - AbQB/wHxAdYBswH/AfEB1gG0Af8B8QHWAbQB/wHyAdgBtgH/AfMB2QG3Af8BswE5AQAB/wcAAf4DAAH/ - A0MBdwMeASsDVwHFA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1gBxgMmATkEAANS - AakDNAFVAzQBVSAAAzQBVQM0AVUDUgGpEwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/xgAA0gBhQG4AYIBBgH/AccBlwEiAf8BzwGlATQB/wHtAdIBtAH/Af0B6AHSAf8B7wHSAa0B/wHu - AdIBrAH/Ae4B0gGtAf8B7gHSAa0B/wH1AdwBvAH/AbMBNwEAAf8EAAMzAVMDPAFnAxQBHDgAA1IBqQM0 - AVUDNAFVA0YBgANSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNFAX8DNAFVAzQBVQNSAakTAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/EAADCgEOAyEBMQMjATMDIwEzAjEBMAFNAzMBUwGz - ATYBAAH/AeMBxQGiAf8B+QHjAckB/wHrAc4BpAH/AesBzgGmAf8B6wHOAaUB/wH3Ad8BwAH/AbMBNwEA - Af8EAAMzAVMDPAFnAxQBHDgAA1IBqQM0AVUDNAFVAz8BbgMyAVAQAAMnATsDRAF8AzQBVQM0AVUDUgGp - EwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wwAAwoBDgM/AW0DXAH4AYUBiQGN - Af8BOQE8AYQB/wNfAfMDOgFiAwkBDAGzATYBAAH/Ae0B0QG0Af8B6QHJAZ0B/wHpAckBnQH/AekByAGb - Af8B/AHoAdIB/wGzATgBAAH/BwAB/gMAAf8DQwF3Ax8BLANXAcUDWQHHA1kBxwNZAccDWQHHA1kBxwNZ - AccDWQHHA1kBxwNZAccDWAHGAyYBOQQAA1IBqQM0AVUDNAFVAwUBBwNVAbUDEQEXA1IBqQMpAT4EAANQ - AZ8DEQEXAzQBVQM0AVUDUgGpEwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wwA - Az4BawOAAf8C0gHRAf8B7wHuAe0B/wLvAe4B/wHSAdMB0gH/ATsBgAGBAf8DOgFgAzIBUAHQAacBOQH/ - AeoByQGcAf8B5AHDAZIB/wHyAdcBtQH/AdoBtgGQAf8CUwFSAagEAANSAfQDAAH/Az4BbAMOARMDQgF1 - A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0MBdwMUARsEAANSAakDNAFVAzQBVQQA - AzwBaANWAb4DIwE0A1UBtQMSARkDUQGgBAADNAFVAzQBVQNSAakTAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DXAHfDAADXAH4As0BzAH/AeMB4gHhAf8B3wHeAd0B/wHfAd4B3QH/AeMB4gHh - Af8DzAH/A2cB8gMZASMByAGYASUB/wHzAdoBtwH/AfEB1gGyAf8B/gHtAdkB/wG3AYEBBQH/AwoBDQQA - AwoBDgMRARcDAAEBOAADUgGpAzQBVQM0AVUDAAEBAy0BRgMKAQ4EAAM5AV8DXAHOAygBPAQAAzQBVQM0 - AVUDUgGpEwAB/wOCAf8DBQH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DXAHfAxcBIAwAAzYB/wHjAeIB4QH/ - AdcB1gHUAf8B1wHWAdQB/wHXAdYB1AH/AdcB1gHUAf8B4gHhAeAB/wGDAYgBjQH/BAABtwGAAQIC/wHw - AdwB/wH6AeYBzgH/AcEBkAEZAf8DQAFuCAADUQGiA1YBtgMqAUAEAAMQARUDEQEXAxEBFwMRARcDEQEX - AxEBFwMRARcDEQEXAxEBFwMRARcDEAEWCAADUgGpAzQBVQM0AVUDMwFTA1IBpgNKAYwHAAEBA0cBgwgA - AzQBVQM0AVUDUgGpEwAB/wOZAf8DhQH/AxIB/wMAAf8DAAH/AwAB/wNcAd8DFwEgEAADNgH/AfIB8QHw - Af8BzwHNAcsB/wHQAc4BywH/AdABzgHLAf8BzwHNAcsB/wHyAvAB/wE6AYEBhQH/BAADNwFbAbQBOQEA - Af8BtAE5AQAB/wNAAW8PAAH/AwAB/wNDAXcDKQE+AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DMgFRBAADUgGpAzQBVQM0AVUDEQEXA1ABngMkATYUAAM0AVUDNAFVA1IBqRAA - A1AB+wMAAf8DAAH/AwAB/wMAAf8DAAH/A1wB3wMXASAUAANiAfYB2wLaAf8B6AHnAeYB/wHRAc8BzgH/ - AdEBzwHOAf8B6AHnAeYB/wHbAtoB/wNiAfYgAANVAbQDWQHHAy8BSQMAAQEDGwEmAxwBJwMcAScDHAEn - AxwBJwMcAScDHAEnAxwBJwMcAScDHAEnAxwBJwMCAQMEAANSAakDIgEyA1IBqQNSAakDUgGpA1IBqQNS - AakDUgGpA1IBqQNSAakDUgGpA1IBqQMiATIDUgGpEAADIAEuAykBPwMpAT8DKQE/AykBPwMpAT8DEQEX - GAADLgFIA4AB/wHYAtcB/wH3AvYB/wH3AvYB/wHYAtcB/wOAAf8DLgFIZAADUAGjA1IBqQNSAakDUgGp - A1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1ABo0gAAy4BSANiAfYDNQH/AzUB/wNi - AfYDLgFIJAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/4EAAv8BgAEBAv8B/AEH - AgABvwH9AeABBwHwAQMCAAGgAR0B4AEHAeABAQEQAQEBoQH9AeABBwHgAQEBHwH/Ab8B/QHgAQcB4AEB - AgABgAEBAeABBwHgAQECAAGPAfEB4AEHAeABAQEfAf8BgAEBAeABBwGAAQEBHwH/AYMBwQHgAQcBAAEB - AgABgAFBAeABBwEAAQECAAGIAREB4AEHAQABAQEfAf8BgQERAeABBwEAAYMBEAEBAYEBMQHgAQ8BAAGH - AgABgQHxAeABHwEAAf8CAAGAAQEB4AE/AQAD/wGAAQEC/wGBAf8L + AakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1ABo1wAAxUBHQE3AYoBnwH1 + ATcBlwGrAfcDQwF3AlsBXQHIAkIBlwH1AlgBbQHjA0oBjAMKAQ0EAANVAbQDWQHHAy8BSQMAAQEDGwEm + AxwBJwMcAScDHAEnAxwBJwMcAScDHAEnAxwBJwMcAScDHAEnAxwBJwMCAQMEAANSAakwAANSAakQAAMn + AToDMAFMAzABTAMwAUwDMAFMAzABTAMwAUwDMAFMAzABTAMnAToUAAMFAQcDTAGSAVYCWAHBAxUBHQM9 + AWkBEgHIAfMB/wEgAZAB5gH/AjYB3AH/AjYB3QH/AmsB4wH/AkEB3gH/AjYB3QH/AlgBXQHLAwYBCAMA + Af8DAAH/A0MBdwMpAT4DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMy + AVEEAANSAakEAANQAZ0DUwGqA1MBqgNTAaoDUwGqA1MBqgNTAaoDUAGdDAADUgGpEAADTgH7AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DTgH7FAABMAIxAU0BEwHJAfMB/wETAckB9AH/AVEBeQGD + AesBWAFhAWQB2QEWAcAB8QH/ATcBPwHfAf8COQHgAf8COQHgAf8CcgHpAf8CRAHiAf8COQHgAf8COQHg + Af8DQAFxA1EBogNWAbYDKgFABAADEAEVAxEBFwMRARcDEQEXAxEBFwMRARcDEQEXAxEBFwMRARcDEQEX + AxABFggAA1IBqQQAA1ABnQNTAaoDUwGqAx8BLBwAA1IBqRMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8UAAMHAQoBRQGLAZwB8gEVAcoB9AH/ARUBygH0Af8BFQHKAfQB/wEhAaEB7gH/ + AjwB4wH/AjwB4wH/AjwB4wH/AqkB7wH/AkMB4wH/AjwB4wH/AjwB4wH/AlYBWAG5AwoBDgMRARcDAAEB + OAADUgGpMAADUgGpEwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wwAAxUBHQM9 + AWkDOgFiAVsBYAFjAdQBFgHLAfUB/wEWAcsB9QH/ARYBywH1Af8BJAGgAfAB/wI/AeYB/wI/AeYB/wI/ + AeYB/wLCAfYB/wJXAegB/wI/AeYB/wI/AeYB/wJXAVkBvwNSAfQDAAH/Az4BbAMOARMDQgF2A0MBdwND + AXcDQwF3A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0IBdgMUARsEAANSAakDIgEyA1IBqQNSAakDUgGp + A1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQMiATIDUgGpEwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wwAAUsCTAGQARcBywH2Af8BFwHLAfYB/wEXAcsB9gH/ARcBywH2Af8BKQGm + AcYB+gNDAXgDIgEyAksBxAH7AkIB6QH/AkIB6QH/As0B+AH/AmYB7QH/AkIB6QH/AkIB6QH/A1ABngMA + Af4DAAH/A0MBdwMeASsDVwHFA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1gBxgMm + ATkEAANSAakDNAFVAzQBVSAAAzQBVQM0AVUDUgGpEwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wwAA1EBoAEZAcwB9wH/ARkBzAH3Af8BGQHMAfcB/wEZAcwB9wH/A0MBdwgAA0oBjQJF + AewB/wJFAewB/wJhAe8B/wJJAewB/wJFAewB/wFBAVIB7QH/AVICUwGoAzMBUwM8AWcDFAEcOAADUgGp + AzQBVQM0AVUDRgGAA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA0UBfwM0AVUDNAFVA1IBqRMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8PAAEBAT8CQAFvAToBoQG6AfgBGgHNAfcB/wEa + Ac0B9wH/AxIBGAgAAwEBAgNGAX4CUgGPAfACSAHuAf8BSAFJAe4B/wFAAWEB1wH9AUUCRgF+AwMBBAMz + AVMDPAFnAxQBHDgAA1IBqQM0AVUDNAFVAz8BbgMyAVAQAAMnATsDRAF8AzQBVQM0AVUDUgGpEwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/w8AAQEBPwJAAW8BOwGgAboB+AEbAc4B+AH/ + ARsBzgH4Af8DEgEYEAADFwEgASIBvAH3Af8BHwHEAfcB/wEtAbsB3QH9AUUCRgF+AwMBBAMAAf4DAAH/ + A0MBdwMfASwDVwHFA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1kBxwNZAccDWQHHA1gBxgMmATkEAANS + AakDNAFVAzQBVQMFAQcDVQG1AxEBFwNSAakDKQE+BAADUAGfAxEBFwM0AVUDNAFVA1IBqRMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8MAANRAaABHQHOAfgB/wEdAc8B+QH/AR0BzwH5 + Af8BHQHPAfkB/wNDAXcQAANEAXoBHQHPAfkB/wEdAc8B+QH/AR0BzwH5Af8BHQHOAfgB/wFSAlMBqANS + AfQDAAH/Az4BbAMOARMDQgF1A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0MBdwNDAXcDQwF3A0MBdwMU + ARsEAANSAakDNAFVAzQBVQQAAzwBaANWAb4DIwE0A1UBtQMSARkDUQGgBAADNAFVAzQBVQNSAakTAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DXAHfDAABSwJMAZABHgHQAfoB/wEeAdAB+gH/ + AR4B0AH6Af8BHgHQAfoB/wEpAaYBxQH6A0MBeAMSARkDEwEaA0QBegEoAasBywH7AR4B0AH6Af8BHgHQ + AfoB/wEeAdAB+gH/AR4B0AH6Af8DSgGMAwoBDgMRARcDAAEBOAADUgGpAzQBVQM0AVUDAAEBAy0BRgMK + AQ4EAAM5AV8DXAHOAygBPAQAAzQBVQM0AVUDUgGpEwAB/wOCAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DXAHfAxcBIAwAAxUBHQM9AWkDOgFiAVwCYwHUAR8B0QH6Af8BHwHRAfoB/wEfAdAB+gH/AR8BywHz + Af8BHwHLAfMB/wEfAdAB+gH/AR8B0QH6Af8BHwHRAfoB/wFXAWoBcgHiAzoBYgM9AWkDFAEcA1EBogNW + AbYDKgFABAADEAEVAxEBFwMRARcDEQEXAxEBFwMRARcDEQEXAxEBFwMRARcDEQEXAxABFggAA1IBqQM0 + AVUDNAFVAzMBUwNSAaYDSgGMBwABAQNHAYMIAAM0AVUDNAFVA1IBqRMAAf8DmQH/A4UB/wMAAf8DAAH/ + AwAB/wMAAf8DXAHfAxcBIBgAAwcBCgFIAYwBnAHyASEB0gH7Af8BIQHSAfsB/wEhAdIB+wH/ASEB0gH7 + Af8BIQHSAfsB/wEhAdIB+wH/ASEB0gH7Af8BIQHSAfsB/wErAa8BzAH7AxEBFwsAAf8DAAH/A0MBdwMp + AT4DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMyAVEEAANSAakDNAFV + AzQBVQMRARcDUAGeAyQBNhQAAzQBVQM0AVUDUgGpEAADUAH7AwAB/wMAAf8DAAH/AwAB/wMAAf8DXAHf + AxcBIBwAATACMQFNASIB0gH8Af8BIgHSAfwB/wFVAX4BhwHrAVgBYwFlAdkBIgHSAfwB/wEiAdIB/AH/ + AVoBbQFxAeEBVwFrAXIB4gEiAdIB/AH/ASIB0gH8Af8DOAFeCAADVQG0A1kBxwMvAUkDAAEBAxsBJgMc + AScDHAEnAxwBJwMcAScDHAEnAxwBJwMcAScDHAEnAxwBJwMcAScDAgEDBAADUgGpAyIBMgNSAakDUgGp + A1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDIgEyA1IBqRAAAyABLgMpAT8DKQE/AykBPwMp + AT8DKQE/AxEBFyAAAwUBBwNMAZIBVgJYAcEDFQEdAz0BaQEjAdMB/AH/ASMB0wH8Af8BRQJGAX8DEAEV + A1YBswFLAkwBjwMEAQZMAANQAaMDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDUgGp + A1IBqQNSAakDUAGjXAADFQEdAUIBlwGrAfUBPAGkAbsB9wMgAS8YAAFCAU0BPgcAAT4DAAEoAwABQAMA + ASADAAEBAQABAQYAAQEWAAP/gQAC/wGAAQEC/wH8AQECAAG/Af0B4AEHAcADAAGgAR0B4AEHAcABAAEQ + AQEBoQH9AeABBwHAAQABHwH/Ab8B/QHgAQcEAAGAAQEB4AEHBAABjwHxAeABBwEDAQABHwH/AYABAQHg + AQcBAwEAAR8B/wGDAcEB4AEHAQMBwAIAAYABQQHgAQcBAwHAAgABiAERAeABBwIAAR8B/wGBAREB4AEH + AgABEAEBAYEBMQHgAQ8BwAEDAgABgQHxAeABHwHAAQMCAAGAAQEB4AE/AcABAwL/AYABAQL/AfwBPws= + + 291, 17 + + + 649, 17 + + + 551, 17 + + + 765, 17 + + + 863, 17 + + + 863, 17 + + + 1017, 17 + diff --git a/PrusaSL1Viewer/Images/arrow-down-double-16x16.png b/PrusaSL1Viewer/Images/arrow-down-double-16x16.png new file mode 100644 index 00000000..7393d689 Binary files /dev/null and b/PrusaSL1Viewer/Images/arrow-down-double-16x16.png differ diff --git a/PrusaSL1Viewer/Images/arrow-end-16x16.png b/PrusaSL1Viewer/Images/arrow-end-16x16.png new file mode 100644 index 00000000..ce9d9c7c Binary files /dev/null and b/PrusaSL1Viewer/Images/arrow-end-16x16.png differ diff --git a/PrusaSL1Viewer/Images/arrow-top-16x16.png b/PrusaSL1Viewer/Images/arrow-top-16x16.png new file mode 100644 index 00000000..8afa1a0e Binary files /dev/null and b/PrusaSL1Viewer/Images/arrow-top-16x16.png differ diff --git a/PrusaSL1Viewer/Images/warning-16x16.png b/PrusaSL1Viewer/Images/warning-16x16.png new file mode 100644 index 00000000..d29b5831 Binary files /dev/null and b/PrusaSL1Viewer/Images/warning-16x16.png differ diff --git a/PrusaSL1Viewer/Mutation.cs b/PrusaSL1Viewer/Mutation.cs index 3e26de1e..6828469b 100644 --- a/PrusaSL1Viewer/Mutation.cs +++ b/PrusaSL1Viewer/Mutation.cs @@ -16,7 +16,7 @@ public class Mutation public enum Mutates : byte { Resize, - LayerSmash, + //LayerSmash, Erode, Dilate, Opening, diff --git a/PrusaSL1Viewer/Properties/AssemblyInfo.cs b/PrusaSL1Viewer/Properties/AssemblyInfo.cs index 30624827..18c08238 100644 --- a/PrusaSL1Viewer/Properties/AssemblyInfo.cs +++ b/PrusaSL1Viewer/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // 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.4.3.0")] -[assembly: AssemblyFileVersion("0.4.3.0")] +[assembly: AssemblyVersion("0.5.0.0")] +[assembly: AssemblyFileVersion("0.5.0.0")] diff --git a/PrusaSL1Viewer/Properties/Resources.Designer.cs b/PrusaSL1Viewer/Properties/Resources.Designer.cs index 3adcdb17..6fd118f0 100644 --- a/PrusaSL1Viewer/Properties/Resources.Designer.cs +++ b/PrusaSL1Viewer/Properties/Resources.Designer.cs @@ -80,6 +80,36 @@ internal static System.Drawing.Bitmap arrow_down_16x16 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_down_double_16x16 { + get { + object obj = ResourceManager.GetObject("arrow-down-double-16x16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_end_16x16 { + get { + object obj = ResourceManager.GetObject("arrow-end-16x16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_top_16x16 { + get { + object obj = ResourceManager.GetObject("arrow-top-16x16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -490,6 +520,16 @@ internal static System.Drawing.Bitmap search_16x16 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap warning_16x16 { + get { + object obj = ResourceManager.GetObject("warning-16x16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/PrusaSL1Viewer/Properties/Resources.resx b/PrusaSL1Viewer/Properties/Resources.resx index de52dd1a..e198f5b0 100644 --- a/PrusaSL1Viewer/Properties/Resources.resx +++ b/PrusaSL1Viewer/Properties/Resources.resx @@ -157,12 +157,12 @@ ..\Images\arrow-up-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Images\Save-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Images\Wrench-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\arrow-down-double-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\PrusaSL1Viewer.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -175,14 +175,20 @@ ..\Images\Button-Info-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\arrow-down-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Images\Geometry-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\arrow-top-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Images\filter-filled-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Images\Cancel-32x32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\Save-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Images\Open-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -196,6 +202,9 @@ ..\Images\search-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\Cancel-32x32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Images\eye-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -220,6 +229,9 @@ ..\Images\pixel-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\arrow-end-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Images\SaveAs-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -247,7 +259,7 @@ ..\Images\island-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Images\arrow-down-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\warning-16x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/PrusaSL1Viewer/PrusaSL1Viewer.csproj b/PrusaSL1Viewer/PrusaSL1Viewer.csproj index 9f54ebe2..48c2a3f6 100644 --- a/PrusaSL1Viewer/PrusaSL1Viewer.csproj +++ b/PrusaSL1Viewer/PrusaSL1Viewer.csproj @@ -302,6 +302,10 @@ + + + + @@ -319,8 +323,8 @@ - xcopy /y $(ProjectDir)..\LICENSE $(ProjectDir)$(OutDir) -xcopy /i /e /y $(ProjectDir)..\PrusaSlicer $(ProjectDir)$(OutDir)\PrusaSlicer + xcopy /y /d $(ProjectDir)..\LICENSE $(ProjectDir)$(OutDir) +xcopy /i /y /d /s $(ProjectDir)..\PrusaSlicer $(ProjectDir)$(OutDir)\PrusaSlicer diff --git a/PrusaSlicer/printer/AnyCubic Photon S.ini b/PrusaSlicer/printer/AnyCubic Photon S.ini new file mode 100644 index 00000000..e6f21780 --- /dev/null +++ b/PrusaSlicer/printer/AnyCubic Photon S.ini @@ -0,0 +1,37 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:00 UTC +absolute_correction = 0 +area_fill = 50 +bed_custom_model = +bed_custom_texture = +bed_shape = 0x0,121x0,121x68,0x68 +default_sla_material_profile = Prusa Orange Tough 0.05 +default_sla_print_profile = 0.05 Normal +display_height = 68 +display_mirror_x = 1 +display_mirror_y = 0 +display_orientation = portrait +display_pixels_x = 2560 +display_pixels_y = 1440 +display_width = 121 +elefant_foot_compensation = 0.2 +elefant_foot_min_width = 0.2 +fast_tilt_time = 5 +gamma_correction = 1 +inherits = Original Prusa SL1 +max_exposure_time = 120 +max_initial_exposure_time = 300 +max_print_height = 165 +min_exposure_time = 1 +min_initial_exposure_time = 1 +print_host = +printer_model = SL1 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON_S\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_1\nLiftHeight_6\nLiftingSpeed_60\nRetractSpeed_150\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES +printer_settings_id = +printer_technology = SLA +printer_variant = default +printer_vendor = +printhost_apikey = +printhost_cafile = +relative_correction = 1,1 +slow_tilt_time = 8 +thumbnails = 400x400,800x480 diff --git a/PrusaSlicer/printer/AnyCubic Photon Zero.ini b/PrusaSlicer/printer/AnyCubic Photon Zero.ini new file mode 100644 index 00000000..4e7a9caf --- /dev/null +++ b/PrusaSlicer/printer/AnyCubic Photon Zero.ini @@ -0,0 +1,37 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:06 UTC +absolute_correction = 0 +area_fill = 50 +bed_custom_model = +bed_custom_texture = +bed_shape = 0x0,98.6x0,98.6x55.4,0x55.4 +default_sla_material_profile = Prusa Orange Tough 0.05 +default_sla_print_profile = 0.05 Normal +display_height = 55.4 +display_mirror_x = 1 +display_mirror_y = 0 +display_orientation = portrait +display_pixels_x = 854 +display_pixels_y = 480 +display_width = 98.6 +elefant_foot_compensation = 0.2 +elefant_foot_min_width = 0.2 +fast_tilt_time = 5 +gamma_correction = 1 +inherits = Original Prusa SL1 +max_exposure_time = 120 +max_initial_exposure_time = 300 +max_print_height = 150 +min_exposure_time = 1 +min_initial_exposure_time = 1 +print_host = +printer_model = SL1 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON_ZERO\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_1\nLiftHeight_6\nLiftingSpeed_60\nRetractSpeed_150\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES +printer_settings_id = +printer_technology = SLA +printer_variant = default +printer_vendor = +printhost_apikey = +printhost_cafile = +relative_correction = 1,1 +slow_tilt_time = 8 +thumbnails = 400x400,800x480 diff --git a/PrusaSlicer/printer/AnyCubic Photon.ini b/PrusaSlicer/printer/AnyCubic Photon.ini index 733c4647..4a0fd0c1 100644 --- a/PrusaSlicer/printer/AnyCubic Photon.ini +++ b/PrusaSlicer/printer/AnyCubic Photon.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 18:24:42 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:45:10 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLiftHeight_5\nBottomLiftSpeed_40\nLiftHeight_5\nLiftingSpeed_60\nRetractSpeed_150\nBottomLightOffDelay_2\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLiftHeight_5\nBottomLiftSpeed_40\nLiftHeight_5\nLiftSpeed_60\nRetractSpeed_150\nBottomLightOffDelay_2\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/EPAX X1.ini b/PrusaSlicer/printer/EPAX X1.ini index 31d5f8e4..04b6d451 100644 --- a/PrusaSlicer/printer/EPAX X1.ini +++ b/PrusaSlicer/printer/EPAX X1.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 18:28:00 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:14 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X1\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_2\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_40\nLiftingSpeed_60\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X1\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_2\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_40\nLiftSpeed_60\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/EPAX X10.ini b/PrusaSlicer/printer/EPAX X10.ini index 37fd0cc2..d12b2ca6 100644 --- a/PrusaSlicer/printer/EPAX X10.ini +++ b/PrusaSlicer/printer/EPAX X10.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 18:43:30 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:20 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X10\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_12\nBottomLiftHeight_7\nLiftHeight_7\nBottomLiftSpeed_40\nLiftingSpeed_60\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X10\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_12\nBottomLiftHeight_7\nLiftHeight_7\nBottomLiftSpeed_40\nLiftSpeed_60\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/EPAX X133 4K Mono.ini b/PrusaSlicer/printer/EPAX X133 4K Mono.ini index cdf8b6c2..03455297 100644 --- a/PrusaSlicer/printer/EPAX X133 4K Mono.ini +++ b/PrusaSlicer/printer/EPAX X133 4K Mono.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:32:19 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:25 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X133-4KMONO\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_10\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_40\nLiftingSpeed_40\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X133-4KMONO\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_10\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_40\nLiftSpeed_40\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/EPAX X156 4K Color.ini b/PrusaSlicer/printer/EPAX X156 4K Color.ini index 02c37349..93b5521e 100644 --- a/PrusaSlicer/printer/EPAX X156 4K Color.ini +++ b/PrusaSlicer/printer/EPAX X156 4K Color.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:33:06 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:39:31 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X156-4KCOLOR\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_40\nLiftingSpeed_40\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X156-4KCOLOR\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_40\nLiftSpeed_40\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Elegoo Mars Saturn.ini b/PrusaSlicer/printer/Elegoo Mars Saturn.ini index 0eb9b91c..65878590 100644 --- a/PrusaSlicer/printer/Elegoo Mars Saturn.ini +++ b/PrusaSlicer/printer/Elegoo Mars Saturn.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:24:54 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:40:39 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_SATURN\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_7\nBottomLiftSpeed_70\nLiftingSpeed_70\nRetractSpeed_70\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_SATURN\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_7\nBottomLiftSpeed_70\nLiftSpeed_70\nRetractSpeed_70\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Elegoo Mars.ini b/PrusaSlicer/printer/Elegoo Mars.ini index eeed32e7..574bccd4 100644 --- a/PrusaSlicer/printer/Elegoo Mars.ini +++ b/PrusaSlicer/printer/Elegoo Mars.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 18:44:02 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:40:32 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_MARS\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_90\nLiftingSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ELEGOO\nPRINTER_MODEL_MARS\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_90\nLiftSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Nova3D Elfin.ini b/PrusaSlicer/printer/Nova3D Elfin.ini index 54f154e9..78bc441c 100644 --- a/PrusaSlicer/printer/Nova3D Elfin.ini +++ b/PrusaSlicer/printer/Nova3D Elfin.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-03 at 21:50:40 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:01 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_NOVA3D\nPRINTER_MODEL_ELFIN\nSTART_CUSTOM_VALUES\nXppm_19.324\nYppm_19.324\nWaitBeforeExpoMs_2000\nLiftDistance_4\nLiftUpSpeed_120\nLiftDownSpeed_120\nLiftWhenFinished_80\nBlankingLayerTime_0\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_NOVA3D\nPRINTER_MODEL_ELFIN\n\nSTART_CUSTOM_VALUES\nXppm_19.324\nYppm_19.324\nWaitBeforeExpoMs_2000\nLiftHeight_4\nLiftSpeed_120\nRetractSpeed_120\nLiftWhenFinished_80\nBlankingLayerTime_0\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Peopoly Phenom L.ini b/PrusaSlicer/printer/Peopoly Phenom L.ini index 60a211d0..f8171a90 100644 --- a/PrusaSlicer/printer/Peopoly Phenom L.ini +++ b/PrusaSlicer/printer/Peopoly Phenom L.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:41:06 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:13 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM_L\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_9\nBottomLiftSpeed_32\nLiftingSpeed_45\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM_L\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_9\nBottomLiftSpeed_32\nLiftSpeed_45\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Peopoly Phenom Noir.ini b/PrusaSlicer/printer/Peopoly Phenom Noir.ini index 93f24f51..e2f5270b 100644 --- a/PrusaSlicer/printer/Peopoly Phenom Noir.ini +++ b/PrusaSlicer/printer/Peopoly Phenom Noir.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:41:22 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:18 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM_NOIR\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_8\nLiftHeight_8\nBottomLiftSpeed_36\nLiftingSpeed_45\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM_NOIR\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_8\nLiftHeight_8\nBottomLiftSpeed_36\nLiftSpeed_45\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Peopoly Phenom.ini b/PrusaSlicer/printer/Peopoly Phenom.ini index aa9a4b38..5a80dba8 100644 --- a/PrusaSlicer/printer/Peopoly Phenom.ini +++ b/PrusaSlicer/printer/Peopoly Phenom.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:23:09 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:08 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_36\nLiftingSpeed_48\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PEOPOLY\nPRINTER_MODEL_PHENOM\n\nSTART_CUSTOM_VALUES\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_12\nBottomLiftSpeed_36\nLiftSpeed_48\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Shuffle 4K.ini b/PrusaSlicer/printer/Phrozen Shuffle 4K.ini index b2ded0e0..3c24780f 100644 --- a/PrusaSlicer/printer/Phrozen Shuffle 4K.ini +++ b/PrusaSlicer/printer/Phrozen Shuffle 4K.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:24:40 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:28 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_4K\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_4K\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Shuffle Lite.ini b/PrusaSlicer/printer/Phrozen Shuffle Lite.ini index dae3165b..c9ee486c 100644 --- a/PrusaSlicer/printer/Phrozen Shuffle Lite.ini +++ b/PrusaSlicer/printer/Phrozen Shuffle Lite.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:27:07 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:32 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_LITE\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_LITE\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Shuffle XL.ini b/PrusaSlicer/printer/Phrozen Shuffle XL.ini index 93152d51..8f2ea49f 100644 --- a/PrusaSlicer/printer/Phrozen Shuffle XL.ini +++ b/PrusaSlicer/printer/Phrozen Shuffle XL.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:26:36 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:36 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_4K\n\nSTART_CUSTOM_VALUES\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE_4K\n\nSTART_CUSTOM_VALUES\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Shuffle.ini b/PrusaSlicer/printer/Phrozen Shuffle.ini index 5d2cfacb..41b8055c 100644 --- a/PrusaSlicer/printer/Phrozen Shuffle.ini +++ b/PrusaSlicer/printer/Phrozen Shuffle.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:14:00 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:24 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SHUFFLE\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Sonic Mini.ini b/PrusaSlicer/printer/Phrozen Sonic Mini.ini index cd284c3a..c3f71a06 100644 --- a/PrusaSlicer/printer/Phrozen Sonic Mini.ini +++ b/PrusaSlicer/printer/Phrozen Sonic Mini.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:29:16 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:36:09 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SONIC_MINI\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SONIC_MINI\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_7\nBottomLightOffDelay_7\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Sonic.ini b/PrusaSlicer/printer/Phrozen Sonic.ini index 7806b943..b4e44da8 100644 --- a/PrusaSlicer/printer/Phrozen Sonic.ini +++ b/PrusaSlicer/printer/Phrozen Sonic.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:29:10 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:40 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SONIC\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_6\nBottomLightOffDelay_6\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_SONIC\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_6\nBottomLightOffDelay_6\nBottomLiftHeight_6\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Phrozen Transform.ini b/PrusaSlicer/printer/Phrozen Transform.ini index 65406bd8..1360d3f4 100644 --- a/PrusaSlicer/printer/Phrozen Transform.ini +++ b/PrusaSlicer/printer/Phrozen Transform.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 22:32:45 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:41:58 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_TRANSFORM\n\nSTART_CUSTOM_VALUES\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_10\nLiftHeight_8\nBottomLiftSpeed_65\nLiftingSpeed_65\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_PHROZEN\nPRINTER_MODEL_TRANSFORM\n\nSTART_CUSTOM_VALUES\nLayerOffTime_10\nBottomLightOffDelay_10\nBottomLiftHeight_10\nLiftHeight_8\nBottomLiftSpeed_65\nLiftSpeed_65\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/QIDI Shadow5.5.ini b/PrusaSlicer/printer/QIDI Shadow5.5.ini index 20d573d8..9b1d73bb 100644 --- a/PrusaSlicer/printer/QIDI Shadow5.5.ini +++ b/PrusaSlicer/printer/QIDI Shadow5.5.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:10:30 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:42:10 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_SHADOW5.5\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_80\nLiftHeight_5\nBottomLiftSpeed_65\nLiftingSpeed_65\nRetractSpeed_65\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_SHADOW5.5\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_80\nLiftHeight_5\nBottomLiftSpeed_65\nLiftSpeed_65\nRetractSpeed_65\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/QIDI Shadow6.0 Pro.ini b/PrusaSlicer/printer/QIDI Shadow6.0 Pro.ini index a6332b66..8541b817 100644 --- a/PrusaSlicer/printer/QIDI Shadow6.0 Pro.ini +++ b/PrusaSlicer/printer/QIDI Shadow6.0 Pro.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-06-04 at 21:12:51 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:42:17 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_SHADOW6.0PRO\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_80\nLiftHeight_5\nBottomLiftSpeed_100\nLiftingSpeed_65\nRetractSpeed_65\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_SHADOW6.0PRO\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nLayerOffTime_0\nBottomLightOffDelay_0\nBottomLiftHeight_80\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_65\nRetractSpeed_65\nBottomLightPWM_255\nLightPWM_255\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/printer/Zortrax Inkspire.ini b/PrusaSlicer/printer/Zortrax Inkspire.ini index bd672c33..84e93ac5 100644 --- a/PrusaSlicer/printer/Zortrax Inkspire.ini +++ b/PrusaSlicer/printer/Zortrax Inkspire.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.2.0+win64 on 2020-04-25 at 21:34:59 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-12 at 00:42:42 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -25,7 +25,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X1\n\nSTART_CUSTOM_VALUES\nExposureOffTime_5\nZLiftDistance_5\nZLiftFeedRate_100\nZLiftRetractRate_100\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_EPAX\nPRINTER_MODEL_X1\n\nSTART_CUSTOM_VALUES\nLayerOffTime_5\nLiftHeight_5\nLiftSpeed_100\nRetractSpeed_100\nAntiAliasing_4 ; Use 0 or 1 for disable AntiAliasing with "printer gamma correction" set to 0, otherwise use multiples of 2 and "gamma correction" set to 1 for enable\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default diff --git a/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Heavy Supports.ini b/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Heavy Supports.ini new file mode 100644 index 00000000..b50c910e --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Heavy Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:37:18 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.025 UltraDetail +layer_height = 0.025 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 1 +support_head_penetration = 0.6 +support_head_width = 2 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.5 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Medium Supports.ini b/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Medium Supports.ini new file mode 100644 index 00000000..ed59379b --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.025 UltraDetail - Medium Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:36:13 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.025 UltraDetail +layer_height = 0.025 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 0.8 +support_head_penetration = 0.4 +support_head_width = 2 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.2 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.035 Detail - Heavy Supports.ini b/PrusaSlicer/sla_print/Universal 0.035 Detail - Heavy Supports.ini new file mode 100644 index 00000000..a46b970f --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.035 Detail - Heavy Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:34:54 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.035 Detail +layer_height = 0.035 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 1 +support_head_penetration = 0.6 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.5 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.035 Detail - Medium Supports.ini b/PrusaSlicer/sla_print/Universal 0.035 Detail - Medium Supports.ini new file mode 100644 index 00000000..fa0c7486 --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.035 Detail - Medium Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:34:31 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.035 Detail +layer_height = 0.035 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 0.8 +support_head_penetration = 0.4 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.2 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.05 Normal - Heavy Supports.ini b/PrusaSlicer/sla_print/Universal 0.05 Normal - Heavy Supports.ini new file mode 100644 index 00000000..10e334df --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.05 Normal - Heavy Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:24:57 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.05 Normal +layer_height = 0.05 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 1 +support_head_penetration = 0.6 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.5 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.05 Normal - Medium Supports.ini b/PrusaSlicer/sla_print/Universal 0.05 Normal - Medium Supports.ini new file mode 100644 index 00000000..79511c76 --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.05 Normal - Medium Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:23:55 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.05 Normal +layer_height = 0.05 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 0.8 +support_head_penetration = 0.4 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.2 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.1 Fast - Heavy Supports.ini b/PrusaSlicer/sla_print/Universal 0.1 Fast - Heavy Supports.ini new file mode 100644 index 00000000..825330a6 --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.1 Fast - Heavy Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:30:54 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.1 Fast +layer_height = 0.1 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 1 +support_head_penetration = 0.7 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.5 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/PrusaSlicer/sla_print/Universal 0.1 Fast - Medium Supports.ini b/PrusaSlicer/sla_print/Universal 0.1 Fast - Medium Supports.ini new file mode 100644 index 00000000..3edcb203 --- /dev/null +++ b/PrusaSlicer/sla_print/Universal 0.1 Fast - Medium Supports.ini @@ -0,0 +1,44 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-06-11 at 02:28:40 UTC +compatible_printers = +compatible_printers_condition = +default_sla_print_profile = +faded_layers = 10 +hollowing_closing_distance = 2 +hollowing_enable = 0 +hollowing_min_thickness = 3 +hollowing_quality = 0.5 +inherits = 0.1 Fast +layer_height = 0.1 +output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1 +pad_around_object = 0 +pad_around_object_everywhere = 0 +pad_brim_size = 1.6 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_object_connector_penetration = 0.3 +pad_object_connector_stride = 10 +pad_object_connector_width = 0.5 +pad_object_gap = 1 +pad_wall_height = 0 +pad_wall_slope = 90 +pad_wall_thickness = 1 +sla_print_settings_id = +slice_closing_radius = 0.005 +support_base_diameter = 3 +support_base_height = 1 +support_base_safety_distance = 1 +support_buildplate_only = 0 +support_critical_angle = 45 +support_head_front_diameter = 0.9 +support_head_penetration = 0.5 +support_head_width = 3 +support_max_bridge_length = 10 +support_max_bridges_on_pillar = 3 +support_max_pillar_link_distance = 10 +support_object_elevation = 5 +support_pillar_connection_mode = zigzag +support_pillar_diameter = 1.3 +support_pillar_widening_factor = 0 +support_points_density_relative = 100 +support_points_minimal_distance = 1 +supports_enable = 1 diff --git a/README.md b/README.md index a4934adc..27a2cf9e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Prusa SL1 File Viewer +# Prusa SL1 Viewer Open, view, edit, extract, convert, mutate and island checker for DLP files generated from Slicers. This simple tool can give you insight of supports and find some failures. Did you forget what resin or orther settings you used on a project? This can also save you, check every setting that were used with or simply change them! -Youtube video: https://www.youtube.com/watch?v=hJD2cgF5rxs +* Facebook group: https://www.facebook.com/groups/prusasl1viewer ![GUI Screenshot](https://raw.githubusercontent.com/sn4k3/PrusaSL1Viewer/master/PrusaSL1Viewer/Images/Screenshots/PrusaSL1Viewer_GUI.png) ![GUI Screenshot Islands](https://raw.githubusercontent.com/sn4k3/PrusaSL1Viewer/master/PrusaSL1Viewer/Images/Screenshots/PrusaSL1Viewer_GUI_Islands.png) @@ -46,13 +46,15 @@ But also, i need victims for test subject. Proceed at your own risk! ## Known Formats -* SL1 (Prusa SL1) -* Photon -* CBDDLP (Chitubox DLP) +* SL1 (PrusaSlicer) +* Photon (Chitubox) +* CBDDLP (Chitubox) * CBT (Chitubox) -* PHZ -* ZCodex -* CWS +* PWS (Photon Workshop) +* PW0 (Photon Workshop) +* PHZ (Chitubox) +* ZCodex (Z-Suite) +* CWS (NovaMaker) ## Available printers for PrusaSlicer @@ -63,6 +65,8 @@ But also, i need victims for test subject. Proceed at your own risk! * Zortrax Inkspire * Nova3D Elfin * AnyCubic Photon +* AnyCubic Photon S +* AnyCubic Photon Zero * Elegoo Mars * Elegoo Mars Saturn * Peopoly Phenom @@ -78,17 +82,28 @@ But also, i need victims for test subject. Proceed at your own risk! * Phrozen Sonic Mini * Phrozen Transform -## Install and configure printer under PrusaSlicer +## Available profiles for PrusaSlicer + +* Universal 0.1 Fast - Heavy Supports +* Universal 0.1 Fast - Medium Supports +* Universal 0.05 Normal - Heavy Supports +* Universal 0.05 Normal - Medium Supports +* Universal 0.035 Detail - Heavy Supports +* Universal 0.035 Detail - Medium Supports +* Universal 0.025 UltraDetail - Heavy Supports +* Universal 0.025 UltraDetail - Medium Supports + +## Install and configure profiles under PrusaSlicer 1. Download and install PrusaSlicer from: https://www.prusa3d.com/prusaslicer/ 1. Start and configure PrusaSlicer (Wizard) * Choose SL1 printer 1. Close PrusaSlicer -1. Open PrusaSL1Viewer - * Under Menu click -> About -> Install printers into PrusaSlicer +1. Open PrusaSL1Viewer if not already + * Under Menu click -> About -> Install profiles into PrusaSlicer 1. Open PrusaSlicer and check if profiles are there 1. To clean up interface remove printers that you will not use (OPTIONAL) -1. Duplicate or create your printer and tune the values if required +1. Duplicate and/or create your printer and tune the values if required 1. Look up under "Printer -> Notes" and configure parameters to the target slicer 1. Change only the value after the "_" (underscore)