diff --git a/CHANGELOG.md b/CHANGELOG.md index afb465e..d9b9496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## ?/08/2020 - v0.7.1.0 + +* (Add) Settings & Issues: Enable or disable Empty Layers +* (Add) PrusaSlicer Printer: Nova Bene4 Mono +* (Add) CWS: Support the GRAY2RGB and RBG2GRAY encoding for Bene Mono +* (Add) Layer issue Z map paired with layer navigation tracker bar +* (Change) Shortcuts: + and - to go up and down on layers were change to W and S keys. Reason: + and - are bound to zoom and can lead to problems +* (Upgrade) OpenCV from 4.2 to 4.3 +* (Fix) CWS: Add missing Platform X,Y,Z size when converting from SL1 +* (Fix) CWS: Invert XY resolution when converting from SL1 + ## 04/08/2020 - v0.7.0.0 * (Add) "Rebuild GCode" button diff --git a/ImportPrusaSlicerData.bat b/ImportPrusaSlicerData.bat index d036b72..6e8a30b 100644 --- a/ImportPrusaSlicerData.bat +++ b/ImportPrusaSlicerData.bat @@ -13,22 +13,23 @@ SET files[3]=EPAX X133 4K Mono.ini SET files[4]=EPAX X156 4K Color.ini SET files[5]=Zortrax Inkspire.ini SET files[6]=Nova3D Elfin.ini -SET files[7]=AnyCubic Photon.ini -SET files[8]=AnyCubic Photon S.ini -SET files[9]=AnyCubic Photon Zero.ini -SET files[10]=Elegoo Mars.ini -SET files[11]=Elegoo Mars 2 Pro.ini -SET files[12]=Elegoo Mars Saturn.ini -SET files[13]=Peopoly Phenom.ini -SET files[14]=Peopoly Phenom L.ini -SET files[15]=Peopoly Phenom Noir.ini -SET files[16]=QIDI Shadow5.5.ini -SET files[17]=QIDI Shadow6.0 Pro.ini -SET files[18]=Phrozen Shuffle.ini -SET files[19]=Phrozen Shuffle Lite.ini -SET files[20]=Phrozen Shuffle XL.ini -SET files[21]=Phrozen Shuffle 4K.ini -SET files[22]=Phrozen Sonic.ini +SET files[7]=Nova3D Bene4 Mono.ini +SET files[8]=AnyCubic Photon.ini +SET files[9]=AnyCubic Photon S.ini +SET files[10]=AnyCubic Photon Zero.ini +SET files[11]=Elegoo Mars.ini +SET files[12]=Elegoo Mars 2 Pro.ini +SET files[13]=Elegoo Mars Saturn.ini +SET files[14]=Peopoly Phenom.ini +SET files[15]=Peopoly Phenom L.ini +SET files[16]=Peopoly Phenom Noir.ini +SET files[17]=QIDI Shadow5.5.ini +SET files[18]=QIDI Shadow6.0 Pro.ini +SET files[19]=Phrozen Shuffle.ini +SET files[20]=Phrozen Shuffle Lite.ini +SET files[21]=Phrozen Shuffle XL.ini +SET files[22]=Phrozen Shuffle 4K.ini +SET files[23]=Phrozen Sonic.ini SET files[24]=Phrozen Sonic Mini.ini SET files[25]=Phrozen Transform.ini SET files[26]=Kelant S400.ini diff --git a/PrusaSlicer/printer/Nova3D Bene4 Mono.ini b/PrusaSlicer/printer/Nova3D Bene4 Mono.ini new file mode 100644 index 0000000..583d56d --- /dev/null +++ b/PrusaSlicer/printer/Nova3D Bene4 Mono.ini @@ -0,0 +1,37 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-09-04 at 20:31:20 UTC +absolute_correction = 0 +area_fill = 50 +bed_custom_model = +bed_custom_texture = +bed_shape = 0x0,116x0,116x65.02,0x65.02 +default_sla_material_profile = Prusa Orange Tough 0.05 +default_sla_print_profile = 0.05 Normal +display_height = 65.02 +display_mirror_x = 0 +display_mirror_y = 0 +display_orientation = portrait +display_pixels_x = 2549 +display_pixels_y = 1566 +display_width = 116 +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 = 130 +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_BENE4_MONO\n\nSTART_CUSTOM_VALUES\nFLIP_XY\nXppm_19.608\nYppm_19.608\nWaitBeforeExpoMs_3000\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\nNOVAMAKER_GRAY2RGB_ENCODE ; Required for Bene4 Mono as output images are in RGB\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/Nova3D Elfin.ini b/PrusaSlicer/printer/Nova3D Elfin.ini index 89c22f7..b9375de 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-26 at 17:18:51 UTC +# generated by PrusaSlicer 2.2.0+win64 on 2020-09-04 at 22:08:49 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\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_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\nFLIP_XY\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/README.md b/README.md index ee27996..6e6757a 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ But also, i need victims for test subject. Proceed at your own risk! * EPAX X156 4K Color * Zortrax Inkspire * Nova3D Elfin +* Nova3D Bene4 Mono * AnyCubic Photon * AnyCubic Photon S * AnyCubic Photon Zero diff --git a/UVtools.Cmd/Program.cs b/UVtools.Cmd/Program.cs index 909b31c..cc0a3de 100644 --- a/UVtools.Cmd/Program.cs +++ b/UVtools.Cmd/Program.cs @@ -187,7 +187,7 @@ namespace UVtools.Cmd { Console.WriteLine("Computing Issues, please wait."); sw.Restart(); - var issueList = fileFormat.LayerManager.GetAllIssues(null, null, null, progress); + var issueList = fileFormat.LayerManager.GetAllIssues(null, null, null, true, progress); sw.Stop(); Console.WriteLine("Issues:"); diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index 16db414..7e3c16e 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -37,6 +37,11 @@ namespace UVtools.Core.Extensions return mat.GetPixelSpan(mat.NumberOfChannels, mat.GetPixelPos(x, y)); } + public static Span GetSinglePixelSpan(this Mat mat, int pos) + { + return mat.GetPixelSpan(mat.NumberOfChannels, pos); + } + public static unsafe Span GetPixelRowSpan(this Mat mat, int y, int length = 0, int offset = 0) { diff --git a/UVtools.Core/Extensions/MathExtensions.cs b/UVtools.Core/Extensions/MathExtensions.cs index a56aa1d..0316b50 100644 --- a/UVtools.Core/Extensions/MathExtensions.cs +++ b/UVtools.Core/Extensions/MathExtensions.cs @@ -1,4 +1,12 @@ -using System; +/* + * 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; namespace UVtools.Core.Extensions { diff --git a/UVtools.Core/Extensions/ParallelExtensions.cs b/UVtools.Core/Extensions/ParallelExtensions.cs new file mode 100644 index 0000000..45d54af --- /dev/null +++ b/UVtools.Core/Extensions/ParallelExtensions.cs @@ -0,0 +1,48 @@ +/* + * 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; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace UVtools.Core.Extensions +{ + public static class ParallelExtensions + { + public static void ForAllInApproximateOrder(this ParallelQuery source, Action action) + { + Partitioner.Create(source) + .AsParallel() + .AsOrdered() + .ForAll(action); + } + + public static void ForEachInApproximateOrder(this ParallelQuery source, Action action) + { + + source = Partitioner.Create(source) + .AsParallel() + .AsOrdered(); + + Parallel.ForEach(source, action); + + } + + public static IEnumerable OrderedParallel(this IEnumerable list, Func action) + { + var unorderedResult = new ConcurrentBag<(long, T1)>(); + Parallel.ForEach(list, (o, state, i) => + { + unorderedResult.Add((i, action.Invoke(o))); + }); + var ordered = unorderedResult.OrderBy(o => o.Item1); + return ordered.Select(o => o.Item2); + } + } +} diff --git a/UVtools.Core/Extensions/SpanExtensions.cs b/UVtools.Core/Extensions/SpanExtensions.cs index 0a9ffeb..204fde1 100644 --- a/UVtools.Core/Extensions/SpanExtensions.cs +++ b/UVtools.Core/Extensions/SpanExtensions.cs @@ -1,4 +1,11 @@ -using System; +/* + * 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; using System.Runtime.CompilerServices; using System.Threading.Tasks; diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs index 075a166..11ce9c3 100644 --- a/UVtools.Core/FileFormats/CWSFile.cs +++ b/UVtools.Core/FileFormats/CWSFile.cs @@ -14,6 +14,10 @@ using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Emgu.CV; +using Emgu.CV.CvEnum; +using Emgu.CV.Util; using UVtools.Core.Extensions; using UVtools.Core.Operations; @@ -111,8 +115,18 @@ namespace UVtools.Core.FileFormats public override FileFormatType FileType => FileFormatType.Archive; + public enum PrinterType : byte + { + Unknown, + Elfin, + BeneMono + } + + public PrinterType Printer { get; set; } = PrinterType.Unknown; + public override FileExtension[] FileExtensions { get; } = { - new FileExtension("cws", "NovaMaker CWS Files") + new FileExtension("cws", "NovaMaker CWS Files"), + //new FileExtension("cws", "NovaMaker Bene Mono CWS Files", "Bene") }; public override Type[] ConvertToFormats { get; } = @@ -204,6 +218,7 @@ namespace UVtools.Core.FileFormats public override void Encode(string fileFullPath, OperationProgress progress = null) { base.Encode(fileFullPath, progress); + if (Printer == PrinterType.Unknown) Printer = PrinterType.Elfin; using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create)) { string arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; @@ -224,16 +239,52 @@ namespace UVtools.Core.FileFormats tw.WriteLine($"{displayNameAttribute.DisplayName.PadRight(24)}= {propertyInfo.GetValue(SliceSettings)}"); } } - - for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + + //for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) + Parallel.For(0, LayerCount, + new ParallelOptions{MaxDegreeOfParallelism = Printer == PrinterType.Elfin ? 1 : Environment.ProcessorCount}, + layerIndex => { - progress.Token.ThrowIfCancellationRequested(); + if (progress.Token.IsCancellationRequested) return; + Layer layer = this[layerIndex]; - var layerImagePath = $"{Path.GetFileNameWithoutExtension(fileFullPath)}{layerIndex.ToString().PadLeft(LayerCount.ToString().Length, '0')}.png"; - outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create); - progress++; - } + var layerImagePath = + $"{Path.GetFileNameWithoutExtension(fileFullPath)}{layerIndex.ToString().PadLeft(LayerCount.ToString().Length, '0')}.png"; + + if (Printer == PrinterType.Elfin) + { + outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create); + } + else + { + using (var mat = layer.LayerMat) + using (var matEncode = new Mat(mat.Height, mat.Step / 3, DepthType.Cv8U, 3)) + { + var span = mat.GetPixelSpan(); + var spanEncode = matEncode.GetPixelSpan(); + for (int i = 0; i < span.Length; i++) + { + spanEncode[i] = span[i]; + } + + using (VectorOfByte vec = new VectorOfByte()) + { + CvInvoke.Imencode(".png", matEncode, vec); + lock (progress.Mutex) + { + outputFile.PutFileContent(layerImagePath, vec.ToArray(), ZipArchiveMode.Create); + } + } + } + + lock (progress.Mutex) + { + progress++; + } + + } + }); RebuildGCode(); outputFile.PutFileContent($"{Path.GetFileNameWithoutExtension(fileFullPath)}.gcode", GCode.ToString(), ZipArchiveMode.Create); @@ -319,36 +370,35 @@ namespace UVtools.Core.FileFormats LayerManager = new LayerManager(OutputSettings.LayersNum, this); + progress.ItemCount = OutputSettings.LayersNum; + var gcode = GCode.ToString(); float currentHeight = 0; - foreach (var zipArchiveEntry in inputFile.Entries) + + int layerSize = OutputSettings.LayersNum.ToString().Length; + + inputFile.Entries.AsParallel().ForAllInApproximateOrder(zipArchiveEntry => + //foreach (var zipArchiveEntry in inputFile.Entries) { - if (!zipArchiveEntry.Name.EndsWith(".png")) continue; + if (!zipArchiveEntry.Name.EndsWith(".png") || progress.Token.IsCancellationRequested) return; // - .png - 4 numbers - int layerSize = OutputSettings.LayersNum.ToString().Length; - string layerStr = zipArchiveEntry.Name.Substring(zipArchiveEntry.Name.Length - 4 - layerSize, layerSize); + string layerStr = + zipArchiveEntry.Name.Substring(zipArchiveEntry.Name.Length - 4 - layerSize, layerSize); uint layerIndex = uint.Parse(layerStr); var startStr = $"{GCodeKeywordSlice} {layerIndex}"; - var stripGcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length); - stripGcode = stripGcode.Substring(0, stripGcode.IndexOf(GCodeKeywordDelay, stripGcode.IndexOf(GCodeKeywordSlice))).Trim(' ', '\n', '\r', '\t'); + var stripGcode = + gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + + startStr.Length); + stripGcode = stripGcode + .Substring(0, stripGcode.IndexOf(GCodeKeywordDelay, stripGcode.IndexOf(GCodeKeywordSlice))) + .Trim(' ', '\n', '\r', '\t'); //var startCurrPos = stripGcode.Remove(0, ";currPos:".Length); - /* - * -; 0 -M106 S255 -; 45000 -M106 S0 -; Blank -G1 Z4 F120 -G1 Z-3.9 F120 -; 45000 - */ - var currPos = Regex.Match(stripGcode, "G1 Z([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase); + //var currPos = Regex.Match(stripGcode, "G1 Z([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase); var exposureTime = Regex.Match(stripGcode, "; (\\d+)", RegexOptions.IgnoreCase); /*var pwm = Regex.Match(stripGcode, "M106 S(\\d+)", RegexOptions.IgnoreCase); if (layerIndex < InitialLayerCount) @@ -360,25 +410,79 @@ G1 Z-3.9 F120 OutputSettings.LayerLightPWM = byte.Parse(pwm.Groups[1].Value); }*/ - if (currPos.Success) + /*if (currPos.Success) { var nextMatch = currPos.NextMatch(); if (nextMatch.Success) { - currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value) + float.Parse(currPos.NextMatch().Groups[1].Value), 2); + currentHeight = + (float) Math.Round( + currentHeight + float.Parse(currPos.Groups[1].Value) + + float.Parse(currPos.NextMatch().Groups[1].Value), 2); } else { - currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value), 2); + currentHeight = (float) Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value), 2); + } + }*/ + + byte[] buffer; + + lock (progress) + { + using (var stream = zipArchiveEntry.Open()) + { + buffer = stream.ToArray(); + if (Printer == PrinterType.Unknown) + { + using (Mat mat = new Mat()) + { + CvInvoke.Imdecode(buffer, ImreadModes.AnyColor, mat); + Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono; + } + } + + stream.Close(); } } - LayerManager[layerIndex] = new Layer(layerIndex, zipArchiveEntry.Open(), zipArchiveEntry.Name) + + if (Printer == PrinterType.Elfin) { - PositionZ = currentHeight, - ExposureTime = float.Parse(exposureTime.Groups[1].Value) / 1000f - }; - } + LayerManager[layerIndex] = + new Layer(layerIndex, buffer, zipArchiveEntry.Name) + { + PositionZ = GetHeightFromLayer(layerIndex), + ExposureTime = float.Parse(exposureTime.Groups[1].Value) / 1000f + }; + } + else + { + using (Mat mat = new Mat()) + { + CvInvoke.Imdecode(buffer, ImreadModes.Color, mat); + using (Mat matDecode = new Mat(mat.Height, mat.Step, DepthType.Cv8U, 1)) + { + var span = mat.GetPixelSpan(); + var spanDecode = matDecode.GetPixelSpan(); + for (int i = 0; i < span.Length; i++) + { + spanDecode[i] = span[i]; + } + + LayerManager[layerIndex] = + new Layer(layerIndex, matDecode, zipArchiveEntry.Name) + { + PositionZ = GetHeightFromLayer(layerIndex), + ExposureTime = float.Parse(exposureTime.Groups[1].Value) / 1000f + }; + } + } + + } + + progress++; + }); } LayerManager.GetBoundingRectangle(progress); diff --git a/UVtools.Core/FileFormats/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs index 904da8c..8f72fb5 100644 --- a/UVtools.Core/FileFormats/FileExtension.cs +++ b/UVtools.Core/FileFormats/FileExtension.cs @@ -26,6 +26,11 @@ namespace UVtools.Core.FileFormats /// public string Description { get; } + /// + /// Gets a tag object + /// + public object Tag { get; } + /// /// Gets the file filter for open and save dialogs /// @@ -33,15 +38,18 @@ namespace UVtools.Core.FileFormats #endregion #region Constructor + /// /// Constructor /// /// The extension name without the dot (.) /// The extension description - public FileExtension(string extension, string description) + /// Tag object + public FileExtension(string extension, string description, object tag = null) { Extension = extension; Description = description; + Tag = tag; } #endregion diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs index f727562..009cc0d 100644 --- a/UVtools.Core/FileFormats/SL1File.cs +++ b/UVtools.Core/FileFormats/SL1File.cs @@ -1000,18 +1000,21 @@ namespace UVtools.Core.FileFormats file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float) Math.Round(LookupCustomValue("Yppm", defaultFormat.SliceSettings.Xppm), 3); file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX; file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY; + file.OutputSettings.PlatformXSize = PrinterSettings.DisplayWidth; + file.OutputSettings.PlatformYSize = PrinterSettings.DisplayHeight; + file.OutputSettings.PlatformZSize = PrinterSettings.MaxPrintHeight; file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight; file.SliceSettings.LayersNum = file.OutputSettings.LayersNum = LayerCount; file.SliceSettings.HeadLayersNum = file.OutputSettings.NumberBottomLayers = InitialLayerCount; file.SliceSettings.LayersExpoMs = file.OutputSettings.LayerTime = (uint) LayerExposureTime * 1000; file.SliceSettings.HeadLayersExpoMs = file.OutputSettings.BottomLayersTime = (uint) InitialExposureTime * 1000; - file.SliceSettings.WaitBeforeExpoMs = LookupCustomValue("WaitBeforeExpoMs", file.SliceSettings.WaitBeforeExpoMs); + file.SliceSettings.WaitBeforeExpoMs = LookupCustomValue("WaitBeforeExpoMs", defaultFormat.SliceSettings.WaitBeforeExpoMs); file.SliceSettings.LiftDistance = file.OutputSettings.LiftDistance = (float) Math.Round(LookupCustomValue(Keyword_LiftHeight, file.SliceSettings.LiftDistance), 2); file.SliceSettings.LiftUpSpeed = file.OutputSettings.ZLiftFeedRate = file.OutputSettings.ZBottomLiftFeedRate = (float) Math.Round(LookupCustomValue(Keyword_LiftSpeed, file.SliceSettings.LiftUpSpeed), 2); file.SliceSettings.LiftDownSpeed = file.OutputSettings.ZLiftRetractRate = (float) Math.Round(LookupCustomValue(Keyword_RetractSpeed, file.SliceSettings.LiftDownSpeed), 2); - file.SliceSettings.LiftWhenFinished = LookupCustomValue("LiftWhenFinished", file.SliceSettings.LiftWhenFinished); + file.SliceSettings.LiftWhenFinished = LookupCustomValue("LiftWhenFinished", defaultFormat.SliceSettings.LiftWhenFinished); - file.OutputSettings.BlankingLayerTime = LookupCustomValue("BlankingLayerTime", file.OutputSettings.BlankingLayerTime); + file.OutputSettings.BlankingLayerTime = LookupCustomValue("BlankingLayerTime", defaultFormat.OutputSettings.BlankingLayerTime); //file.OutputSettings.RenderOutlines = false; //file.OutputSettings.OutlineWidthInset = 0; //file.OutputSettings.OutlineWidthOutset = 0; @@ -1025,14 +1028,18 @@ namespace UVtools.Core.FileFormats file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel(); file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1; - - if (LookupCustomValue("FLIP_XY", false, true)) { file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort) ResolutionY; file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort) ResolutionX; + + file.OutputSettings.PlatformXSize = PrinterSettings.DisplayHeight; + file.OutputSettings.PlatformYSize = PrinterSettings.DisplayWidth; } + file.Printer = LookupCustomValue("NOVAMAKER_GRAY2RGB_ENCODE", false, true) || + MachineName.Contains("Bene4 Mono") ? CWSFile.PrinterType.BeneMono : CWSFile.PrinterType.Elfin; + file.Encode(fileFullPath, progress); return true; diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 25ffd00..414cab8 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -756,6 +756,7 @@ namespace UVtools.Core public List GetAllIssues( IslandDetectionConfiguration islandConfig = null, ResinTrapDetectionConfiguration resinTrapConfig = null, TouchingBoundDetectionConfiguration touchBoundConfig = null, + bool emptyLayersConfig = true, OperationProgress progress = null) { if(ReferenceEquals(islandConfig, null)) islandConfig = new IslandDetectionConfiguration(); @@ -786,7 +787,11 @@ namespace UVtools.Core if (progress.Token.IsCancellationRequested) return; if (layer.NonZeroPixelCount == 0) { - result.Add(new LayerIssue(layer, LayerIssue.IssueType.EmptyLayer)); + if (emptyLayersConfig) + { + result.Add(new LayerIssue(layer, LayerIssue.IssueType.EmptyLayer)); + } + lock (progress.Mutex) { progress++; @@ -939,7 +944,7 @@ namespace UVtools.Core } } - if (points.Count == 0) continue; + if (points.Count == 0) continue; // Should never happen if (pixelsSupportingIsland >= islandConfig.RequiredPixelsToSupport) continue; // Not a island, bounding is strong, i think... if (pixelsSupportingIsland > 0 && diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 60c546a..d3b86c9 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,12 +10,12 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, repair, conversion and manipulation - 0.7.0.0 + 0.7.1.0 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 - 0.7.0.0 - 0.7.0.0 + 0.7.1.0 + 0.7.1.0 @@ -47,7 +47,7 @@ - + diff --git a/UVtools.GUI/App.config b/UVtools.GUI/App.config index 5134bee..da1367e 100644 --- a/UVtools.GUI/App.config +++ b/UVtools.GUI/App.config @@ -213,8 +213,7 @@ True - + 10 @@ -241,6 +240,9 @@ True + + True + diff --git a/UVtools.GUI/Controls/TrackBarHighlight.cs b/UVtools.GUI/Controls/TrackBarHighlight.cs new file mode 100644 index 0000000..88e32da --- /dev/null +++ b/UVtools.GUI/Controls/TrackBarHighlight.cs @@ -0,0 +1,93 @@ +/* + * 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; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using UVtools.Core.Extensions; + +namespace UVtools.GUI.Controls +{ + public class TrackBarHighlight : TrackBar + { + private uint[] _highlightValues = null; + + [DllImport("user32.dll")] + public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam); + + private const int TBM_GETNUMTICS = 0x0410; + private const int TBM_GETTICPOS = 0x40F; + + private const byte TrackerMargin = 12; + + //public event PaintEventHandler PaintOver; + + public Pen HighlightPen { get; set; } = new Pen(Color.FromArgb(50, Color.Red), 2); + public byte LineLength { get; set; } = 10; + + public uint[] HighlightValues + { + get => _highlightValues; + set { _highlightValues = value; Invalidate(); } + } + + public TrackBarHighlight() + { + SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true); + } + + /*protected override void OnInvalidated(InvalidateEventArgs e) + { + base.OnInvalidated(e); + Debug.WriteLine("Invalidated"); + DrawHighlights(); + }*/ + + /*protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + + // WM_PAINT + if (m.Msg == 0x0F) + { + using (Graphics lgGraphics = Graphics.FromHwndInternal(m.HWnd)) + OnPaintOver(new PaintEventArgs(lgGraphics, ClientRectangle)); + } + }*/ + + protected virtual void OnPaintOver(PaintEventArgs e) + { + //PaintOver?.Invoke(this, e); + //Debug.WriteLine("Paint"); + DrawHighlights(e.Graphics); + } + + public int GetTickPos(int index) => SendMessage(Handle, TBM_GETTICPOS, index, 0); + public int NumTicks => SendMessage(Handle, TBM_GETNUMTICS, 0, 0); + + public void DrawHighlights(Graphics gfx = null) + { + if (HighlightValues is null) return; + if (gfx is null) gfx = CreateGraphics(); + + gfx.SmoothingMode = SmoothingMode.HighSpeed; + + int startX = Width / 2 - LineLength / 2; + int endX = startX + LineLength; + foreach (var value in HighlightValues) + { + var tickPos = GetTickPos((int)value); + if (tickPos == -1) continue; + //int y = (int)(Height - TrackerStartMargin - (Height / Maximum * value)); + int y = (Height - tickPos).Clamp(1, Height); + gfx.DrawLine(HighlightPen, startX, y, endX, y); + } + } + } +} diff --git a/UVtools.GUI/Extensions/BitmapExtension.cs b/UVtools.GUI/Extensions/BitmapExtension.cs new file mode 100644 index 0000000..9d44915 --- /dev/null +++ b/UVtools.GUI/Extensions/BitmapExtension.cs @@ -0,0 +1,698 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; +using Emgu.CV; +using Emgu.CV.Cuda; +using Emgu.CV.CvEnum; +using Emgu.CV.Structure; +using Emgu.CV.Util; +using Emgu.Util; + +namespace UVtools.GUI.Extensions +{ + /// + /// Provide extension method to convert IInputArray to and from Bitmap + /// + public static class BitmapExtension + { + #region Color Palette + + /// + /// The ColorPalette of Grayscale for Bitmap Format8bppIndexed + /// + public static readonly ColorPalette GrayscalePalette = GenerateGrayscalePalette(); + + private static ColorPalette GenerateGrayscalePalette() + { + using (Bitmap image = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) + { + ColorPalette palette = image.Palette; + for (int i = 0; i < 256; i++) + { + palette.Entries[i] = Color.FromArgb(i, i, i); + } + + return palette; + } + } + + /// + /// Convert the color palette to four lookup tables + /// + /// The color palette to transform + /// Lookup table for the B channel + /// Lookup table for the G channel + /// Lookup table for the R channel + /// Lookup table for the A channel + public static void ColorPaletteToLookupTable(ColorPalette palette, out Matrix bTable, + out Matrix gTable, out Matrix rTable, out Matrix aTable) + { + bTable = new Matrix(256, 1); + gTable = new Matrix(256, 1); + rTable = new Matrix(256, 1); + aTable = new Matrix(256, 1); + byte[,] bData = bTable.Data; + byte[,] gData = gTable.Data; + byte[,] rData = rTable.Data; + byte[,] aData = aTable.Data; + + Color[] colors = palette.Entries; + for (int i = 0; i < colors.Length; i++) + { + Color c = colors[i]; + bData[i, 0] = c.B; + gData[i, 0] = c.G; + rData[i, 0] = c.R; + aData[i, 0] = c.A; + } + } + + #endregion + + /// + /// Convert raw data to bitmap + /// + /// The pointer to the raw data + /// The step + /// The size of the image + /// The source image color type + /// The number of channels + /// The source image depth type + /// Try to create Bitmap that shares the data with the image + /// The Bitmap + public static Bitmap RawDataToBitmap(IntPtr scan0, int step, Size size, Type srcColorType, int numberOfChannels, + Type srcDepthType, bool tryDataSharing = false) + { + if (tryDataSharing) + { + if (srcColorType == typeof(Gray) && srcDepthType == typeof(Byte)) + { + //Grayscale of Bytes + Bitmap bmpGray = new Bitmap( + size.Width, + size.Height, + step, + PixelFormat.Format8bppIndexed, + scan0 + ) {Palette = GrayscalePalette}; + + + return bmpGray; + } + // Mono in Linux doesn't support scan0 constructor with Format24bppRgb, use ToBitmap instead + // See https://bugzilla.novell.com/show_bug.cgi?id=363431 + // TODO: check mono buzilla Bug 363431 to see when it will be fixed + + if ( + Platform.OperationSystem == Platform.OS.Windows && + Platform.ClrType == Platform.Clr.DotNet && + srcColorType == typeof(Bgr) && srcDepthType == typeof(Byte) + && (step & 3) == 0) + { + //Bgr byte + return new Bitmap( + size.Width, + size.Height, + step, + PixelFormat.Format24bppRgb, + scan0); + } + + if (srcColorType == typeof(Bgra) && srcDepthType == typeof(Byte)) + { + //Bgra byte + return new Bitmap( + size.Width, + size.Height, + step, + PixelFormat.Format32bppArgb, + scan0); + } + + //PixelFormat.Format16bppGrayScale is not supported in .NET + //else if (typeof(TColor) == typeof(Gray) && typeof(TDepth) == typeof(UInt16)) + //{ + // return new Bitmap( + // size.width, + // size.height, + // step, + // PixelFormat.Format16bppGrayScale; + // scan0); + //} + } + + PixelFormat format; //= System.Drawing.Imaging.PixelFormat.Undefined; + + if (srcColorType == typeof(Gray)) // if this is a gray scale image + { + format = PixelFormat.Format8bppIndexed; + } + else if (srcColorType == typeof(Bgra)) //if this is Bgra image + { + format = PixelFormat.Format32bppArgb; + } + else if (srcColorType == typeof(Bgr)) //if this is a Bgr Byte image + { + format = PixelFormat.Format24bppRgb; + } + else + { + using (Mat m = new Mat(size.Height, size.Width, CvInvoke.GetDepthType(srcDepthType), numberOfChannels, + scan0, step)) + using (Mat m2 = new Mat()) + { + CvInvoke.CvtColor(m, m2, srcColorType, typeof(Bgr)); + return RawDataToBitmap(m2.DataPointer, m2.Step, m2.Size, typeof(Bgr), 3, srcDepthType); + } + } + + Bitmap bmp = new Bitmap(size.Width, size.Height, format); + BitmapData data = bmp.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.WriteOnly, + format); + using (Mat bmpMat = new Mat(size.Height, size.Width, DepthType.Cv8U, numberOfChannels, data.Scan0, + data.Stride)) + using (Mat dataMat = new Mat(size.Height, size.Width, CvInvoke.GetDepthType(srcDepthType), numberOfChannels, + scan0, step)) + { + if (srcDepthType == typeof(Byte)) + dataMat.CopyTo(bmpMat); + else + { + + double scale = 1.0, shift = 0.0; + RangeF range = dataMat.GetValueRange(); + if (range.Max > 255.0 || range.Min < 0) + { + scale = range.Max.Equals(range.Min) ? 0.0 : 255.0 / (range.Max - range.Min); + shift = scale.Equals(0) ? range.Min : -range.Min * scale; + } + + CvInvoke.ConvertScaleAbs(dataMat, bmpMat, scale, shift); + } + } + + bmp.UnlockBits(data); + + if (format == PixelFormat.Format8bppIndexed) + bmp.Palette = GrayscalePalette; + return bmp; + } + + /// + /// Convert the mat into Bitmap, the pixel values are copied over to the Bitmap + /// + public static Bitmap ToBitmap(this Mat mat) + { + if (mat.Dims > 3) + return null; + int channels = mat.NumberOfChannels; + Size s = mat.Size; + Type colorType; + switch (channels) + { + case 1: + colorType = typeof(Gray); + + if (s.Equals(Size.Empty)) + return null; + if ((s.Width | 3) != 0) //handle the special case where width is not a multiple of 4 + { + Bitmap bmp = new Bitmap(s.Width, s.Height, PixelFormat.Format8bppIndexed) + { + Palette = GrayscalePalette + }; + BitmapData bitmapData = bmp.LockBits(new Rectangle(Point.Empty, s), ImageLockMode.WriteOnly, + PixelFormat.Format8bppIndexed); + using (Mat m = new Mat(s.Height, s.Width, DepthType.Cv8U, 1, bitmapData.Scan0, + bitmapData.Stride)) + { + mat.CopyTo(m); + } + + bmp.UnlockBits(bitmapData); + return bmp; + } + + break; + case 3: + colorType = typeof(Bgr); + break; + case 4: + colorType = typeof(Bgra); + break; + default: + throw new Exception("Unknown color type"); + } + + return RawDataToBitmap(mat.DataPointer, mat.Step, s, colorType, mat.NumberOfChannels, + CvInvoke.GetDepthType(mat.Depth), true); + } + + + /// + /// Convert the umat into Bitmap, the pixel values are copied over to the Bitmap + /// + public static Bitmap ToBitmap(this UMat umat) + { + using (Mat tmp = umat.GetMat(AccessType.Read)) + { + return tmp.ToBitmap(); + } + } + + /// + /// Convert the gpuMat into Bitmap, the pixel values are copied over to the Bitmap + /// + public static Bitmap ToBitmap(this GpuMat gpuMat) + { + using (Mat tmp = new Mat()) + { + gpuMat.Download(tmp); + return tmp.ToBitmap(); + } + } + + /// + /// Create an Image < TColor, TDepth > from Bitmap + /// + public static Image ToImage(this Bitmap bitmap) where + TColor : struct, IColor + where TDepth : new() + { + Size size = bitmap.Size; + Image image = new Image(size); + + switch (bitmap.PixelFormat) + { + case PixelFormat.Format32bppRgb: + if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte)) + { + BitmapData data = bitmap.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.ReadOnly, + bitmap.PixelFormat); + + using (Image mat = + new Image(size.Width, size.Height, data.Stride, data.Scan0)) + { + CvInvoke.MixChannels(mat, image, new[] {0, 0, 1, 1, 2, 2}); + } + + bitmap.UnlockBits(data); + } + else + { + using (Image tmp = bitmap.ToImage()) + image.ConvertFrom(tmp); + } + + break; + case PixelFormat.Format32bppArgb: + if (typeof(TColor) == typeof(Bgra) && typeof(TDepth) == typeof(Byte)) + image.CopyFromBitmap(bitmap); + else + { + BitmapData data = bitmap.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.ReadOnly, + bitmap.PixelFormat); + using (Image tmp = + new Image(size.Width, size.Height, data.Stride, data.Scan0)) + image.ConvertFrom(tmp); + bitmap.UnlockBits(data); + } + + break; + case PixelFormat.Format8bppIndexed: + if (typeof(TColor) == typeof(Bgra) && typeof(TDepth) == typeof(Byte)) + { + Matrix bTable, gTable, rTable, aTable; + ColorPaletteToLookupTable(bitmap.Palette, out bTable, out gTable, out rTable, out aTable); + BitmapData data = bitmap.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.ReadOnly, + bitmap.PixelFormat); + using (Image indexValue = + new Image(size.Width, size.Height, data.Stride, data.Scan0)) + { + using (Mat b = new Mat()) + using (Mat g = new Mat()) + using (Mat r = new Mat()) + using (Mat a = new Mat()) + { + CvInvoke.LUT(indexValue, bTable, b); + CvInvoke.LUT(indexValue, gTable, g); + CvInvoke.LUT(indexValue, rTable, r); + CvInvoke.LUT(indexValue, aTable, a); + using (VectorOfMat mv = new VectorOfMat(b, g, r, a)) + { + CvInvoke.Merge(mv, image); + } + } + } + + bitmap.UnlockBits(data); + bTable.Dispose(); + gTable.Dispose(); + rTable.Dispose(); + aTable.Dispose(); + } + else + { + using (Image tmp = bitmap.ToImage()) + image.ConvertFrom(tmp); + } + + break; + case PixelFormat.Format24bppRgb: + if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte)) + image.CopyFromBitmap(bitmap); + else + { + BitmapData data = bitmap.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.ReadOnly, + bitmap.PixelFormat); + using (Image tmp = + new Image(size.Width, size.Height, data.Stride, data.Scan0)) + image.ConvertFrom(tmp); + bitmap.UnlockBits(data); + } + + break; + case PixelFormat.Format1bppIndexed: + if (typeof(TColor) == typeof(Gray) && typeof(TDepth) == typeof(Byte)) + { + int rows = size.Height; + int cols = size.Width; + BitmapData data = bitmap.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.ReadOnly, + bitmap.PixelFormat); + + int fullByteCount = cols >> 3; + int partialBitCount = cols & 7; + + int mask = 1 << 7; + + Int64 srcAddress = data.Scan0.ToInt64(); + Byte[,,] imagedata = image.Data as Byte[,,]; + + Byte[] row = new byte[fullByteCount + (partialBitCount == 0 ? 0 : 1)]; + + int v = 0; + for (int i = 0; i < rows; i++, srcAddress += data.Stride) + { + Marshal.Copy((IntPtr) srcAddress, row, 0, row.Length); + + for (int j = 0; j < cols; j++, v <<= 1) + { + if ((j & 7) == 0) + { + //fetch the next byte + v = row[j >> 3]; + } + + imagedata[i, j, 0] = (v & mask) == 0 ? (Byte) 0 : (Byte) 255; + } + } + } + else + { + using (Image tmp = bitmap.ToImage()) + image.ConvertFrom(tmp); + } + + break; + default: + + #region Handle other image type + + // Bitmap bgraImage = new Bitmap(value.Width, value.Height, PixelFormat.Format32bppArgb); + // using (Graphics g = Graphics.FromImage(bgraImage)) + // { + // g.DrawImageUnscaled(value, 0, 0, value.Width, value.Height); + // } + // Bitmap = bgraImage; + using (Image tmp1 = new Image(size)) + { + Byte[,,] data = tmp1.Data; + for (int i = 0; i < size.Width; i++) + for (int j = 0; j < size.Height; j++) + { + Color color = bitmap.GetPixel(i, j); + data[j, i, 0] = color.B; + data[j, i, 1] = color.G; + data[j, i, 2] = color.R; + data[j, i, 3] = color.A; + } + + image.ConvertFrom(tmp1); + } + + #endregion + + break; + } + + return image; + } + + + /// + /// Utility function for converting Bitmap to Image + /// + /// the bitmap to copy data from + /// The image to copy data to + private static void CopyFromBitmap(this Image image, Bitmap bmp) where + TColor : struct, IColor + where TDepth : new() + { + BitmapData data = bmp.LockBits( + new Rectangle(Point.Empty, bmp.Size), + ImageLockMode.ReadOnly, + bmp.PixelFormat); + + using (Matrix mat = + new Matrix(bmp.Height, bmp.Width, image.NumberOfChannels, data.Scan0, data.Stride)) + CvInvoke.cvCopy(mat.Ptr, image.Ptr, IntPtr.Zero); + + bmp.UnlockBits(data); + } + + /// + /// Provide a more efficient way to convert Image<Gray, Byte>, Image<Bgr, Byte> and Image<Bgra, Byte> into Bitmap + /// such that the image data is shared with Bitmap. + /// If you change the pixel value on the Bitmap, you change the pixel values on the Image object as well! + /// For other types of image this property has the same effect as ToBitmap() + /// Take extra caution not to use the Bitmap after the Image object is disposed + /// + /// The color of the image + /// The depth of the image + /// The image to create Bitmap from + /// A bitmap representation of the image. In the cases of Image<Gray, Byte>, Image<Bgr, Byte> and Image<Bgra, Byte>, the image data is shared between the Bitmap and the Image object. + public static Bitmap AsBitmap(this Image image) where + TColor : struct, IColor + where TDepth : new() + { + IntPtr scan0; + int step; + Size size; + CvInvoke.cvGetRawData(image.Ptr, out scan0, out step, out size); + + return RawDataToBitmap(scan0, step, size, typeof(TColor), image.NumberOfChannels, typeof(TDepth), true); + } + + /// + /// Convert this image into Bitmap, the pixel values are copied over to the Bitmap + /// + /// For better performance on Image<Gray, Byte> and Image<Bgr, Byte>, consider using the Bitmap property + /// This image in Bitmap format, the pixel data are copied over to the Bitmap + public static Bitmap ToBitmap(this Image image) where + TColor : struct, IColor + where TDepth : new() + { + Type typeOfColor = typeof(TColor); + Type typeofDepth = typeof(TDepth); + + PixelFormat format = PixelFormat.Undefined; + + if (typeOfColor == typeof(Gray)) // if this is a gray scale image + { + format = PixelFormat.Format8bppIndexed; + } + else if (typeOfColor == typeof(Bgra)) //if this is Bgra image + { + format = PixelFormat.Format32bppArgb; + } + else if (typeOfColor == typeof(Bgr)) //if this is a Bgr Byte image + { + format = PixelFormat.Format24bppRgb; + } + else + { + using (Image temp = image.Convert()) + return ToBitmap(temp); + } + + if (typeof(TDepth) == typeof(Byte)) + { + Size size = image.Size; + Bitmap bmp = new Bitmap(size.Width, size.Height, format); + BitmapData data = bmp.LockBits( + new Rectangle(Point.Empty, size), + ImageLockMode.WriteOnly, + format); + //using (Matrix m = new Matrix(size.Height, size.Width, data.Scan0, data.Stride)) + using (Mat mat = new Mat(size.Height, size.Width, DepthType.Cv8U, image.NumberOfChannels, + data.Scan0, data.Stride)) + { + image.Mat.CopyTo(mat); + } + + bmp.UnlockBits(data); + + if (format == PixelFormat.Format8bppIndexed) + bmp.Palette = GrayscalePalette; + return bmp; + } + + using (Image temp = image.Convert()) + return temp.ToBitmap(); + } + + /// Create a Bitmap image of certain size + /// The image to be converted to Bitmap + /// The width of the bitmap + /// The height of the bitmap + /// This image in Bitmap format of the specific size + public static Bitmap ToBitmap(this Image image, int width, int height) where + TColor : struct, IColor + where TDepth : new() + { + using (Image scaledImage = image.Resize(width, height, Inter.Linear)) + return scaledImage.ToBitmap(); + } + + + + /// + /// Convert the CudaImage to its equivalent Bitmap representation + /// + public static Bitmap ToBitmap(this CudaImage cudaImage) where + TColor : struct, IColor + where TDepth : new() + { + if (typeof(TColor) == typeof(Bgr) && typeof(TDepth) == typeof(Byte)) + { + Size s = cudaImage.Size; + Bitmap result = new Bitmap(s.Width, s.Height, PixelFormat.Format24bppRgb); + BitmapData data = result.LockBits(new Rectangle(Point.Empty, result.Size), + ImageLockMode.WriteOnly, result.PixelFormat); + using (Image tmp = new Image(s.Width, s.Height, data.Stride, data.Scan0) + ) + { + cudaImage.Download(tmp); + } + + result.UnlockBits(data); + return result; + } + + using (Image tmp = cudaImage.ToImage()) + { + return tmp.ToBitmap(); + } + } + } + + /// + /// Class that can be used to read file into Mat + /// + public class BitmapFileReaderMat : IFileReaderMat + { + /// + /// Read the file into a Mat + /// + /// The name of the image file + /// The Mat to read into + /// Image load type. + /// True if the file can be read into the Mat + public bool ReadFile(String fileName, Mat mat, ImreadModes loadType) + { + try + { + using (Bitmap bmp = new Bitmap(fileName)) + using (Image image = bmp.ToImage()) + image.Mat.CopyTo(mat); + return true; + } + catch (Exception e) + { + Debug.WriteLine(e); + //throw; + return false; + } + + } + } + + /// + /// Class that can be used to write the Mat to a file + /// + public class BitmapFileWriterMat : IFileWriterMat + { + /// + /// Write the Mat into the file + /// + /// The Mat to write + /// The name of the file to be written into + /// True if the file has been written into Mat + public bool WriteFile(Mat mat, String fileName) + { + try + { + //Try to save the image using .NET's Bitmap class + String extension = Path.GetExtension(fileName); + if (!String.IsNullOrEmpty(extension)) + using (Bitmap bmp = mat.ToBitmap()) + { + switch (extension.ToLower()) + { + case ".jpg": + case ".jpeg": + bmp.Save(fileName, ImageFormat.Jpeg); + break; + case ".bmp": + bmp.Save(fileName, ImageFormat.Bmp); + break; + case ".png": + bmp.Save(fileName, ImageFormat.Png); + break; + case ".tiff": + case ".tif": + bmp.Save(fileName, ImageFormat.Tiff); + break; + case ".gif": + bmp.Save(fileName, ImageFormat.Gif); + break; + default: + throw new NotImplementedException(String.Format("Saving to {0} format is not supported", extension)); + } + } + return true; + } + catch (Exception e) + { + Debug.WriteLine(e); + //throw; + return false; + } + } + } +} \ No newline at end of file diff --git a/UVtools.GUI/Forms/FrmMutationMask.cs b/UVtools.GUI/Forms/FrmMutationMask.cs index 5ff9a02..eded54c 100644 --- a/UVtools.GUI/Forms/FrmMutationMask.cs +++ b/UVtools.GUI/Forms/FrmMutationMask.cs @@ -13,6 +13,7 @@ using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using UVtools.Core.Extensions; +using UVtools.GUI.Extensions; namespace UVtools.GUI.Forms { diff --git a/UVtools.GUI/Forms/FrmSettings.Designer.cs b/UVtools.GUI/Forms/FrmSettings.Designer.cs index f5eb74b..e075727 100644 --- a/UVtools.GUI/Forms/FrmSettings.Designer.cs +++ b/UVtools.GUI/Forms/FrmSettings.Designer.cs @@ -94,6 +94,8 @@ this.label8 = new System.Windows.Forms.Label(); this.nmIslandRequiredPixelBrightnessToProcessCheck = new System.Windows.Forms.NumericUpDown(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label42 = new System.Windows.Forms.Label(); + this.cbComputeTouchingBounds = new System.Windows.Forms.CheckBox(); this.cbAutoComputeIssuesClickOnTab = new System.Windows.Forms.CheckBox(); this.tabSettings = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); @@ -163,8 +165,7 @@ this.cbLayerRepairLayersIslands = new System.Windows.Forms.CheckBox(); this.panel1 = new System.Windows.Forms.Panel(); this.toolTip = new System.Windows.Forms.ToolTip(this.components); - this.cbComputeTouchingBounds = new System.Windows.Forms.CheckBox(); - this.label42 = new System.Windows.Forms.Label(); + this.cbComputeEmptyLayers = new System.Windows.Forms.CheckBox(); ((System.ComponentModel.ISupportInitialize)(this.nmOutlineHollowAreasLineThickness)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nmOutlineLayerBoundsLineThickness)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nmOutlinePrintVolumeBoundsLineThickness)).BeginInit(); @@ -1027,6 +1028,7 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.cbComputeEmptyLayers); this.groupBox1.Controls.Add(this.label42); this.groupBox1.Controls.Add(this.cbComputeTouchingBounds); this.groupBox1.Controls.Add(this.cbAutoComputeIssuesClickOnTab); @@ -1041,6 +1043,25 @@ this.groupBox1.TabStop = false; this.groupBox1.Text = "Commun"; // + // label42 + // + this.label42.AutoSize = true; + this.label42.Location = new System.Drawing.Point(6, 81); + this.label42.Name = "label42"; + this.label42.Size = new System.Drawing.Size(73, 18); + this.label42.TabIndex = 20; + this.label42.Text = "Compute:"; + // + // cbComputeTouchingBounds + // + this.cbComputeTouchingBounds.AutoSize = true; + this.cbComputeTouchingBounds.Location = new System.Drawing.Point(272, 79); + this.cbComputeTouchingBounds.Name = "cbComputeTouchingBounds"; + this.cbComputeTouchingBounds.Size = new System.Drawing.Size(141, 22); + this.cbComputeTouchingBounds.TabIndex = 19; + this.cbComputeTouchingBounds.Text = "Touching bounds"; + this.cbComputeTouchingBounds.UseVisualStyleBackColor = true; + // // cbAutoComputeIssuesClickOnTab // this.cbAutoComputeIssuesClickOnTab.AutoSize = true; @@ -1072,7 +1093,7 @@ this.tabPage1.Location = new System.Drawing.Point(4, 27); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(616, 546); + this.tabPage1.Size = new System.Drawing.Size(616, 594); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "General"; this.tabPage1.UseVisualStyleBackColor = true; @@ -1382,7 +1403,7 @@ this.tabPage2.Location = new System.Drawing.Point(4, 27); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(616, 546); + this.tabPage2.Size = new System.Drawing.Size(616, 594); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "Layer Preview"; this.tabPage2.UseVisualStyleBackColor = true; @@ -1563,7 +1584,7 @@ this.tabPage4.Location = new System.Drawing.Point(4, 27); this.tabPage4.Name = "tabPage4"; this.tabPage4.Padding = new System.Windows.Forms.Padding(3); - this.tabPage4.Size = new System.Drawing.Size(616, 546); + this.tabPage4.Size = new System.Drawing.Size(616, 594); this.tabPage4.TabIndex = 3; this.tabPage4.Text = "Pixel Editor"; this.tabPage4.UseVisualStyleBackColor = true; @@ -1745,7 +1766,7 @@ this.tabPage5.Location = new System.Drawing.Point(4, 27); this.tabPage5.Name = "tabPage5"; this.tabPage5.Padding = new System.Windows.Forms.Padding(3); - this.tabPage5.Size = new System.Drawing.Size(616, 546); + this.tabPage5.Size = new System.Drawing.Size(616, 594); this.tabPage5.TabIndex = 4; this.tabPage5.Text = "Layer Repair"; this.tabPage5.UseVisualStyleBackColor = true; @@ -1877,24 +1898,15 @@ this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info; this.toolTip.ToolTipTitle = "Information"; // - // cbComputeTouchingBounds + // cbComputeEmptyLayers // - this.cbComputeTouchingBounds.AutoSize = true; - this.cbComputeTouchingBounds.Location = new System.Drawing.Point(272, 79); - this.cbComputeTouchingBounds.Name = "cbComputeTouchingBounds"; - this.cbComputeTouchingBounds.Size = new System.Drawing.Size(141, 22); - this.cbComputeTouchingBounds.TabIndex = 19; - this.cbComputeTouchingBounds.Text = "Touching bounds"; - this.cbComputeTouchingBounds.UseVisualStyleBackColor = true; - // - // label42 - // - this.label42.AutoSize = true; - this.label42.Location = new System.Drawing.Point(6, 81); - this.label42.Name = "label42"; - this.label42.Size = new System.Drawing.Size(73, 18); - this.label42.TabIndex = 20; - this.label42.Text = "Compute:"; + this.cbComputeEmptyLayers.AutoSize = true; + this.cbComputeEmptyLayers.Location = new System.Drawing.Point(419, 79); + this.cbComputeEmptyLayers.Name = "cbComputeEmptyLayers"; + this.cbComputeEmptyLayers.Size = new System.Drawing.Size(117, 22); + this.cbComputeEmptyLayers.TabIndex = 21; + this.cbComputeEmptyLayers.Text = "Empty Layers"; + this.cbComputeEmptyLayers.UseVisualStyleBackColor = true; // // FrmSettings // @@ -2091,5 +2103,6 @@ private System.Windows.Forms.CheckBox cbZoomIssuesAuto; private System.Windows.Forms.Label label42; private System.Windows.Forms.CheckBox cbComputeTouchingBounds; + private System.Windows.Forms.CheckBox cbComputeEmptyLayers; } } diff --git a/UVtools.GUI/Forms/FrmSettings.cs b/UVtools.GUI/Forms/FrmSettings.cs index b972a8f..1e715bd 100644 --- a/UVtools.GUI/Forms/FrmSettings.cs +++ b/UVtools.GUI/Forms/FrmSettings.cs @@ -85,10 +85,11 @@ namespace UVtools.GUI.Forms // Issues cbComputeIssuesOnLoad.Checked = Settings.Default.ComputeIssuesOnLoad; + cbAutoComputeIssuesClickOnTab.Checked = Settings.Default.AutoComputeIssuesClickOnTab; cbComputeIslands.Checked = Settings.Default.ComputeIslands; cbComputeResinTraps.Checked = Settings.Default.ComputeResinTraps; cbComputeTouchingBounds.Checked = Settings.Default.ComputeTouchingBounds; - cbAutoComputeIssuesClickOnTab.Checked = Settings.Default.AutoComputeIssuesClickOnTab; + cbComputeEmptyLayers.Checked = Settings.Default.ComputeEmptyLayers; cbIslandAllowDiagonalBonds.Checked = Settings.Default.IslandAllowDiagonalBonds; nmIslandBinaryThreshold.Value = Settings.Default.IslandBinaryThreshold; @@ -263,10 +264,11 @@ namespace UVtools.GUI.Forms // Issues Settings.Default.ComputeIssuesOnLoad = cbComputeIssuesOnLoad.Checked; + Settings.Default.AutoComputeIssuesClickOnTab = cbAutoComputeIssuesClickOnTab.Checked; Settings.Default.ComputeIslands = cbComputeIslands.Checked; Settings.Default.ComputeResinTraps = cbComputeResinTraps.Checked; Settings.Default.ComputeTouchingBounds = cbComputeTouchingBounds.Checked; - Settings.Default.AutoComputeIssuesClickOnTab = cbAutoComputeIssuesClickOnTab.Checked; + Settings.Default.ComputeEmptyLayers = cbComputeEmptyLayers.Checked; Settings.Default.IslandAllowDiagonalBonds = cbIslandAllowDiagonalBonds.Checked; Settings.Default.IslandBinaryThreshold = (byte)nmIslandBinaryThreshold.Value; diff --git a/UVtools.GUI/FrmMain.Designer.cs b/UVtools.GUI/FrmMain.Designer.cs index 049330f..0d93cc0 100644 --- a/UVtools.GUI/FrmMain.Designer.cs +++ b/UVtools.GUI/FrmMain.Designer.cs @@ -1,4 +1,6 @@ -namespace UVtools.GUI +using UVtools.GUI.Controls; + +namespace UVtools.GUI { partial class FrmMain { @@ -153,7 +155,7 @@ this.tsIssueNext = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator(); this.tsIssueRemove = new System.Windows.Forms.ToolStripButton(); - this.tsIssuesRefresh = new System.Windows.Forms.ToolStripSplitButton(); + this.tsIssuesDetect = new System.Windows.Forms.ToolStripSplitButton(); this.tsIssuesDetectIslands = new System.Windows.Forms.ToolStripMenuItem(); this.tsIssuesDetectResinTraps = new System.Windows.Forms.ToolStripMenuItem(); this.tsIssuesDetectTouchingBounds = new System.Windows.Forms.ToolStripMenuItem(); @@ -247,9 +249,9 @@ this.btnPreviousLayer = new System.Windows.Forms.Button(); this.btnNextLayer = new System.Windows.Forms.Button(); this.lbMaxLayer = new System.Windows.Forms.Label(); - this.panel1 = new System.Windows.Forms.Panel(); + this.panelLayerNavigation = new System.Windows.Forms.Panel(); + this.pbTrackerIssues = new System.Windows.Forms.PictureBox(); this.lbActualLayer = 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(); @@ -260,6 +262,7 @@ this.toolTipInformation = new System.Windows.Forms.ToolTip(this.components); this.layerScrollTimer = new System.Windows.Forms.Timer(this.components); this.mouseHoldTimer = new System.Windows.Forms.Timer(this.components); + this.tbLayer = new UVtools.GUI.Controls.TrackBarHighlight(); this.menu.SuspendLayout(); this.mainTable.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.scCenter)).BeginInit(); @@ -316,9 +319,10 @@ ((System.ComponentModel.ISupportInitialize)(this.lvLog)).BeginInit(); this.tsLog.SuspendLayout(); this.tlRight.SuspendLayout(); - this.panel1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).BeginInit(); + this.panelLayerNavigation.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbTrackerIssues)).BeginInit(); this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).BeginInit(); this.SuspendLayout(); // // menu @@ -1456,6 +1460,7 @@ this.flvIssues.UseHotItem = true; this.flvIssues.View = System.Windows.Forms.View.Details; this.flvIssues.VirtualMode = true; + this.flvIssues.ItemsChanged += new System.EventHandler(this.flvIssues_ItemsChanged); this.flvIssues.SelectionChanged += new System.EventHandler(this.EventSelectedIndexChanged); this.flvIssues.KeyUp += new System.Windows.Forms.KeyEventHandler(this.EventKeyUp); this.flvIssues.MouseClick += new System.Windows.Forms.MouseEventHandler(this.EventMouseClick); @@ -1533,7 +1538,7 @@ this.tsIssueNext, this.toolStripSeparator13, this.tsIssueRemove, - this.tsIssuesRefresh, + this.tsIssuesDetect, this.toolStripSeparator12, this.tsIssuesRepair}); this.tsIssues.Location = new System.Drawing.Point(3, 3); @@ -1597,21 +1602,20 @@ "tion, need reslice."; this.tsIssueRemove.Click += new System.EventHandler(this.EventClick); // - // tsIssuesRefresh + // tsIssuesDetect // - this.tsIssuesRefresh.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; - this.tsIssuesRefresh.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tsIssuesDetect.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.tsIssuesDetect.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.tsIssuesDetectIslands, this.tsIssuesDetectResinTraps, this.tsIssuesDetectTouchingBounds, this.tsIssuesDetectEmptyLayers}); - this.tsIssuesRefresh.Image = global::UVtools.GUI.Properties.Resources.refresh_16x16; - this.tsIssuesRefresh.ImageTransparentColor = System.Drawing.Color.Magenta; - this.tsIssuesRefresh.Name = "tsIssuesRefresh"; - this.tsIssuesRefresh.Size = new System.Drawing.Size(73, 22); - this.tsIssuesRefresh.Text = "&Detect"; - this.tsIssuesRefresh.ToolTipText = "Compute Issues"; - this.tsIssuesRefresh.ButtonClick += new System.EventHandler(this.EventClick); + this.tsIssuesDetect.Image = global::UVtools.GUI.Properties.Resources.refresh_16x16; + this.tsIssuesDetect.Name = "tsIssuesDetect"; + this.tsIssuesDetect.Size = new System.Drawing.Size(73, 22); + this.tsIssuesDetect.Text = "&Detect"; + this.tsIssuesDetect.ToolTipText = "Compute Issues"; + this.tsIssuesDetect.ButtonClick += new System.EventHandler(this.EventClick); // // tsIssuesDetectIslands // @@ -1619,7 +1623,7 @@ this.tsIssuesDetectIslands.CheckOnClick = true; this.tsIssuesDetectIslands.CheckState = System.Windows.Forms.CheckState.Checked; this.tsIssuesDetectIslands.Name = "tsIssuesDetectIslands"; - this.tsIssuesDetectIslands.Size = new System.Drawing.Size(180, 22); + this.tsIssuesDetectIslands.Size = new System.Drawing.Size(166, 22); this.tsIssuesDetectIslands.Text = "&Islands"; // // tsIssuesDetectResinTraps @@ -1628,7 +1632,7 @@ this.tsIssuesDetectResinTraps.CheckOnClick = true; this.tsIssuesDetectResinTraps.CheckState = System.Windows.Forms.CheckState.Checked; this.tsIssuesDetectResinTraps.Name = "tsIssuesDetectResinTraps"; - this.tsIssuesDetectResinTraps.Size = new System.Drawing.Size(180, 22); + this.tsIssuesDetectResinTraps.Size = new System.Drawing.Size(166, 22); this.tsIssuesDetectResinTraps.Text = "&Resin traps"; // // tsIssuesDetectTouchingBounds @@ -1637,7 +1641,7 @@ this.tsIssuesDetectTouchingBounds.CheckOnClick = true; this.tsIssuesDetectTouchingBounds.CheckState = System.Windows.Forms.CheckState.Checked; this.tsIssuesDetectTouchingBounds.Name = "tsIssuesDetectTouchingBounds"; - this.tsIssuesDetectTouchingBounds.Size = new System.Drawing.Size(180, 22); + this.tsIssuesDetectTouchingBounds.Size = new System.Drawing.Size(166, 22); this.tsIssuesDetectTouchingBounds.Text = "&Touching Bounds"; // // tsIssuesDetectEmptyLayers @@ -1645,9 +1649,8 @@ this.tsIssuesDetectEmptyLayers.Checked = true; this.tsIssuesDetectEmptyLayers.CheckOnClick = true; this.tsIssuesDetectEmptyLayers.CheckState = System.Windows.Forms.CheckState.Checked; - this.tsIssuesDetectEmptyLayers.Enabled = false; this.tsIssuesDetectEmptyLayers.Name = "tsIssuesDetectEmptyLayers"; - this.tsIssuesDetectEmptyLayers.Size = new System.Drawing.Size(180, 22); + this.tsIssuesDetectEmptyLayers.Size = new System.Drawing.Size(166, 22); this.tsIssuesDetectEmptyLayers.Text = "&Empty Layers"; // // toolStripSeparator12 @@ -2702,7 +2705,7 @@ 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.panel1, 0, 2); + this.tlRight.Controls.Add(this.panelLayerNavigation, 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; @@ -2760,15 +2763,27 @@ this.lbMaxLayer.Text = "Layers"; this.lbMaxLayer.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // panel1 + // panelLayerNavigation // - this.panel1.Controls.Add(this.lbActualLayer); - this.panel1.Controls.Add(this.tbLayer); - 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(138, 557); - this.panel1.TabIndex = 13; + this.panelLayerNavigation.Controls.Add(this.pbTrackerIssues); + this.panelLayerNavigation.Controls.Add(this.lbActualLayer); + this.panelLayerNavigation.Controls.Add(this.tbLayer); + this.panelLayerNavigation.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelLayerNavigation.Location = new System.Drawing.Point(3, 85); + this.panelLayerNavigation.Name = "panelLayerNavigation"; + this.panelLayerNavigation.Size = new System.Drawing.Size(138, 557); + this.panelLayerNavigation.TabIndex = 13; + // + // pbTrackerIssues + // + this.pbTrackerIssues.Dock = System.Windows.Forms.DockStyle.Right; + this.pbTrackerIssues.Location = new System.Drawing.Point(83, 0); + this.pbTrackerIssues.Margin = new System.Windows.Forms.Padding(0); + this.pbTrackerIssues.Name = "pbTrackerIssues"; + this.pbTrackerIssues.Size = new System.Drawing.Size(10, 557); + this.pbTrackerIssues.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pbTrackerIssues.TabIndex = 10; + this.pbTrackerIssues.TabStop = false; // // lbActualLayer // @@ -2780,17 +2795,6 @@ this.lbActualLayer.TabIndex = 9; this.lbActualLayer.Text = "?"; // - // tbLayer - // - this.tbLayer.Dock = System.Windows.Forms.DockStyle.Right; - this.tbLayer.Location = new System.Drawing.Point(93, 0); - this.tbLayer.Name = "tbLayer"; - this.tbLayer.Orientation = System.Windows.Forms.Orientation.Vertical; - this.tbLayer.Size = new System.Drawing.Size(45, 557); - 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; @@ -2881,6 +2885,20 @@ this.mouseHoldTimer.Interval = 1000; this.mouseHoldTimer.Tick += new System.EventHandler(this.EventTimerTick); // + // tbLayer + // + this.tbLayer.Dock = System.Windows.Forms.DockStyle.Right; + this.tbLayer.HighlightValues = null; + this.tbLayer.LineLength = ((byte)(20)); + this.tbLayer.Location = new System.Drawing.Point(93, 0); + this.tbLayer.Margin = new System.Windows.Forms.Padding(0); + this.tbLayer.Name = "tbLayer"; + this.tbLayer.Orientation = System.Windows.Forms.Orientation.Vertical; + this.tbLayer.Size = new System.Drawing.Size(45, 557); + this.tbLayer.TabIndex = 8; + this.tbLayer.TickStyle = System.Windows.Forms.TickStyle.TopLeft; + this.tbLayer.ValueChanged += new System.EventHandler(this.ValueChanged); + // // FrmMain // this.AllowDrop = true; @@ -2890,6 +2908,7 @@ this.Controls.Add(this.mainTable); this.Controls.Add(this.statusBar); this.Controls.Add(this.menu); + this.DoubleBuffered = true; this.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.KeyPreview = true; @@ -2983,10 +3002,11 @@ this.tsLog.ResumeLayout(false); this.tsLog.PerformLayout(); this.tlRight.ResumeLayout(false); - this.panel1.ResumeLayout(false); - this.panel1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).EndInit(); + this.panelLayerNavigation.ResumeLayout(false); + this.panelLayerNavigation.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbTrackerIssues)).EndInit(); this.panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -3062,13 +3082,13 @@ private System.Windows.Forms.ToolStripButton tsLayerImageHighlightIssues; private System.Windows.Forms.ToolStripButton tsLayerImageShowCrosshairs; private System.Windows.Forms.ToolStripSeparator toolStripSeparator25; - private System.Windows.Forms.TrackBar tbLayer; + private TrackBarHighlight tbLayer; private System.Windows.Forms.TableLayoutPanel tlRight; private System.Windows.Forms.Label lbMaxLayer; private System.Windows.Forms.Label lbInitialLayer; private System.Windows.Forms.Button btnNextLayer; private System.Windows.Forms.Button btnPreviousLayer; - private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panelLayerNavigation; private System.Windows.Forms.Label lbActualLayer; private System.Windows.Forms.Panel panel2; private System.Windows.Forms.Button btnFirstLayer; @@ -3084,7 +3104,7 @@ private System.Windows.Forms.ToolStripMenuItem menuNewVersion; private System.Windows.Forms.ToolStripMenuItem menuFileSettings; private System.Windows.Forms.ToolStripSeparator toolStripSeparator15; - private System.Windows.Forms.ToolStripSplitButton tsIssuesRefresh; + private System.Windows.Forms.ToolStripSplitButton tsIssuesDetect; private System.Windows.Forms.ToolStripMenuItem tsIssuesDetectIslands; private System.Windows.Forms.ToolStripMenuItem tsIssuesDetectResinTraps; private System.Windows.Forms.ToolStripSplitButton tsLayerImageLayerOutline; @@ -3224,6 +3244,7 @@ private System.Windows.Forms.Timer mouseHoldTimer; private System.Windows.Forms.ToolStripMenuItem tsIssuesDetectEmptyLayers; private System.Windows.Forms.ToolStripMenuItem tsIssuesDetectTouchingBounds; + private System.Windows.Forms.PictureBox pbTrackerIssues; } } diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs index ea74593..bda7d50 100644 --- a/UVtools.GUI/FrmMain.cs +++ b/UVtools.GUI/FrmMain.cs @@ -29,6 +29,7 @@ using UVtools.Core.FileFormats; using UVtools.Core.Operations; using UVtools.Core.PixelEditor; using UVtools.GUI.Controls; +using UVtools.GUI.Extensions; using UVtools.GUI.Forms; using UVtools.GUI.Properties; @@ -203,6 +204,7 @@ namespace UVtools.GUI #region Constructors public FrmMain() { + //SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); InitializeComponent(); FrmLoading = new FrmLoading(); Program.SetAllControlsFontSize(Controls, 11); @@ -223,6 +225,7 @@ namespace UVtools.GUI tsIssuesDetectIslands.Checked = Settings.Default.ComputeIslands; tsIssuesDetectResinTraps.Checked = Settings.Default.ComputeResinTraps; tsIssuesDetectTouchingBounds.Checked = Settings.Default.ComputeTouchingBounds; + tsIssuesDetectEmptyLayers.Checked = Settings.Default.ComputeEmptyLayers; tsLayerImageLayerOutlinePrintVolumeBounds.Checked = Settings.Default.OutlinePrintVolumeBounds; tsLayerImageLayerOutlineLayerBounds.Checked = Settings.Default.OutlineLayerBounds; tsLayerImageLayerOutlineHollowAreas.Checked = Settings.Default.OutlineHollowAreas; @@ -300,6 +303,8 @@ namespace UVtools.GUI flvProperties.ShowGroups = true; flvProperties.AlwaysGroupByColumn = flvProperties.AllColumns[2]; + panelLayerNavigation.Paint += (sender, args) => Debug.WriteLine("Panel Paint"); + if (Settings.Default.CheckForUpdatesOnStartup) { Task.Factory.StartNew(AppLoadTask); @@ -349,19 +354,19 @@ namespace UVtools.GUI protected override void OnKeyPress(KeyPressEventArgs e) { - if (ReferenceEquals(SlicerFile, null) || IsChangingLayer) + if (SlicerFile is null || IsChangingLayer) { return; } - if (e.KeyChar == '-') + if (e.KeyChar == 's') { ShowLayer(false); e.Handled = true; return; } - if (e.KeyChar == '+') + if (e.KeyChar == 'w') { ShowLayer(true); e.Handled = true; @@ -374,7 +379,7 @@ namespace UVtools.GUI protected override void OnKeyUp(KeyEventArgs e) { - if (ReferenceEquals(SlicerFile, null)) + if (SlicerFile is null) { return; } @@ -450,11 +455,14 @@ namespace UVtools.GUI ZoomToFit(); } + tbLayer.Invalidate(); + tbLayer.Update(); + tbLayer.Refresh(); lbActualLayer.Location = new Point(lbActualLayer.Location.X, - Math.Max(1, - Math.Min(tbLayer.Height - 40, - (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbActualLayer.Height / 2) - )); + ((int)(tbLayer.Height - (float)tbLayer.Height / tbLayer.Maximum * tbLayer.Value) - lbActualLayer.Height / 2) + .Clamp(1, tbLayer.Height - lbActualLayer.Height)); + + UpdateLayerTrackerHighlightIssues(); } @@ -816,7 +824,9 @@ namespace UVtools.GUI var touchingBoundConfig = new TouchingBoundDetectionConfiguration{Enabled = false}; if (islandConfig.Enabled || resinTrapConfig.Enabled) - ComputeIssues(islandConfig, resinTrapConfig, touchingBoundConfig); + { + ComputeIssues(islandConfig, resinTrapConfig, touchingBoundConfig, tsIssuesDetectEmptyLayers.Checked); + } } DisableGUI(); @@ -862,7 +872,7 @@ namespace UVtools.GUI ShowLayer(); - ComputeIssues(GetIslandDetectionConfiguration(), GetResinTrapDetectionConfiguration(), GetTouchingBoundsDetectionConfiguration()); + tsIssuesDetect.PerformButtonClick(); menuFileSave.Enabled = menuFileSaveAs.Enabled = true; @@ -1228,7 +1238,7 @@ namespace UVtools.GUI } pbThumbnail.Image = SlicerFile.Thumbnails[i]?.ToBitmap(); - + tsThumbnailsCount.Text = $"{i + 1}/{SlicerFile.CreatedThumbnailsCount}"; tsThumbnailsNext.Enabled = true; @@ -1622,12 +1632,12 @@ namespace UVtools.GUI return; } - if (ReferenceEquals(sender, tsIssuesRefresh)) + if (ReferenceEquals(sender, tsIssuesDetect)) { /*if (MessageBox.Show("Are you sure you want to compute issues?", "Issues Compute", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return;*/ - ComputeIssues(GetIslandDetectionConfiguration(), GetResinTrapDetectionConfiguration(), GetTouchingBoundsDetectionConfiguration()); + ComputeIssues(GetIslandDetectionConfiguration(), GetResinTrapDetectionConfiguration(), GetTouchingBoundsDetectionConfiguration(), tsIssuesDetectEmptyLayers.Checked); return; } @@ -2074,6 +2084,54 @@ namespace UVtools.GUI ShowLayer(false); } } + + private void flvIssues_ItemsChanged(object sender, ItemsChangedEventArgs e) + { + if (e.NewObjectCount == 0 || Issues is null) + { + tbLayer.HighlightValues = null; + UpdateLayerTrackerHighlightIssues(); + return; + } + + List layerIndexes = new List(); + foreach (var issue in Issues) + { + if (layerIndexes.Contains(issue.LayerIndex)) continue; + layerIndexes.Add(issue.LayerIndex); + } + tbLayer.HighlightValues = layerIndexes.ToArray(); + UpdateLayerTrackerHighlightIssues(); + } + + void UpdateLayerTrackerHighlightIssues() + { + var highlightValues = tbLayer.HighlightValues; + + + if (highlightValues is null) + { + pbTrackerIssues.Image = null; + return; + } + + using (Mat mat = new Mat(pbTrackerIssues.Height, pbTrackerIssues.Width, DepthType.Cv8U, 3)) + { + mat.SetTo(new MCvScalar(255, 255, 255)); + var color = new MCvScalar(0, 0, 255); + + foreach (var value in highlightValues) + { + var tickPos = tbLayer.GetTickPos((int) value); + if (tickPos == -1) continue; + //int y = (int)(Height - TrackerStartMargin - (Height / Maximum * value)); + int y = (pbTrackerIssues.Height - tickPos).Clamp(0, pbTrackerIssues.Height); + CvInvoke.Line(mat, new Point(0, y), new Point(mat.Width, y), color); + } + + pbTrackerIssues.Image = mat.ToBitmap(); + } + } #endregion #region Methods @@ -2368,7 +2426,7 @@ namespace UVtools.GUI menuTools.Enabled = tsIssuesRepair.Enabled = - tsIssuesRefresh.Enabled = + tsIssuesDetect.Enabled = btnFindLayer.Enabled = true; @@ -2399,7 +2457,7 @@ namespace UVtools.GUI if (Settings.Default.ComputeIssuesOnLoad) { - ComputeIssues(GetIslandDetectionConfiguration(), GetResinTrapDetectionConfiguration(), GetTouchingBoundsDetectionConfiguration()); + tsIssuesDetect.PerformButtonClick(); } } @@ -2658,35 +2716,90 @@ namespace UVtools.GUI if (layerNum > 0 && layerNum < SlicerFile.LayerCount-1) { using (var previousImage = SlicerFile[layerNum - 1].LayerMat) + using (var nextImage = SlicerFile[layerNum + 1].LayerMat) { - using (var nextImage = SlicerFile[layerNum + 1].LayerMat) - { - var previousSpan = previousImage.GetPixelSpan(); - var nextSpan = nextImage.GetPixelSpan(); + var previousSpan = previousImage.GetPixelSpan(); + var nextSpan = nextImage.GetPixelSpan(); - for (int pixel = 0; pixel < imageSpan.Length; pixel++) + /*Parallel.For(0, imageSpan.Length, i => + { + var currentByte = ActualLayerImage.GetSinglePixelSpan(i); + var previousByte = previousImage.GetSinglePixelSpan(i); + var nextByte = nextImage.GetSinglePixelSpan(i); + + if (currentByte[0] != 0) return; + Color color = Color.Empty; + if (previousByte[0] > 0 && nextByte[0] > 0) { - if (imageSpan[pixel] != 0) continue; + color = Settings.Default.PreviousNextLayerColor; + } + else if (previousByte[0] > 0) + { + color = Settings.Default.PreviousLayerColor; + } + else if (nextByte[0] > 0) + { + color = Settings.Default.NextLayerColor; + } + + if (color.IsEmpty) return; + ActualLayerImageBgr.SetByte(i * 3, new[]{ color.B , color.G, color.R }); + });*/ + + /*Parallel.For(0, ActualLayerImage.Height, y => + { + var currentSpan = ActualLayerImage.GetPixelRowSpan(y); + var currentRGBSpan = ActualLayerImageBgr.GetPixelRowSpan(y); + var previousSpan = previousImage.GetPixelRowSpan(y); + var nextSpan = nextImage.GetPixelRowSpan(y); + + for (int x = 0; x < currentSpan.Length; x++) + { + if (currentSpan[x] != 0) continue; Color color = Color.Empty; - if (previousSpan[pixel] > 0 && nextSpan[pixel] > 0) + if (previousSpan[x] > 0 && nextSpan[x] > 0) { color = Settings.Default.PreviousNextLayerColor; } - else if (previousSpan[pixel] > 0) + else if (previousSpan[x] > 0) { color = Settings.Default.PreviousLayerColor; } - else if (nextSpan[pixel] > 0) + else if (nextSpan[x] > 0) { color = Settings.Default.NextLayerColor; } if (color.IsEmpty) continue; - var bgrPixel = pixel * 3; - imageBgrSpan[bgrPixel] = color.B; // B - imageBgrSpan[++bgrPixel] = color.G; // G - imageBgrSpan[++bgrPixel] = color.R; // R + var bgrPixel = x * 3; + currentRGBSpan[bgrPixel] = color.B; // B + currentRGBSpan[++bgrPixel] = color.G; // G + currentRGBSpan[++bgrPixel] = color.R; // R } + });*/ + + for (int pixel = 0; pixel < imageSpan.Length; pixel++) + { + if (imageSpan[pixel] != 0) continue; + Color color = Color.Empty; + if (previousSpan[pixel] > 0 && nextSpan[pixel] > 0) + { + color = Settings.Default.PreviousNextLayerColor; + } + else if (previousSpan[pixel] > 0) + { + color = Settings.Default.PreviousLayerColor; + } + else if (nextSpan[pixel] > 0) + { + color = Settings.Default.NextLayerColor; + } + + if (color.IsEmpty) continue; + var bgrPixel = pixel * 3; + imageBgrSpan[bgrPixel] = color.B; // B + imageBgrSpan[++bgrPixel] = color.G; // G + imageBgrSpan[++bgrPixel] = color.R; // R } } } @@ -2742,7 +2855,7 @@ namespace UVtools.GUI color = Settings.Default.TouchingBoundsColor; break; } - + foreach (var pixel in issue) { int pixelPos = ActualLayerImage.GetPixelPos(pixel); @@ -2944,10 +3057,8 @@ namespace UVtools.GUI //lbLayers.Text = $"{SlicerFile.GetHeightFromLayer(layerNum)} / {SlicerFile.TotalHeight}mm\n{layerNum} / {SlicerFile.LayerCount-1}\n{percent}%"; lbActualLayer.Text = $"{layer.PositionZ}mm\n{ActualLayer}\n{percent}%"; lbActualLayer.Location = new Point(lbActualLayer.Location.X, - Math.Max(1, - Math.Min(tbLayer.Height- lbActualLayer.Height, - (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbActualLayer.Height/2) - )); + ((int)(tbLayer.Height - (float)tbLayer.Height / tbLayer.Maximum * tbLayer.Value) - lbActualLayer.Height / 2) + .Clamp(1, tbLayer.Height - lbActualLayer.Height)); //pbLayers.Value = percent; lbActualLayer.Invalidate(); @@ -3034,7 +3145,7 @@ namespace UVtools.GUI if (ReferenceEquals(tabControlLeft.SelectedTab, tabPageIssues)) { if (!ReferenceEquals(tabPageIssues.Tag, null) || !Settings.Default.AutoComputeIssuesClickOnTab) return; - ComputeIssues(GetIslandDetectionConfiguration(), GetResinTrapDetectionConfiguration(), GetTouchingBoundsDetectionConfiguration()); + tsIssuesDetect.PerformButtonClick(); } return; } @@ -3946,7 +4057,7 @@ namespace UVtools.GUI } - private void ComputeIssues(IslandDetectionConfiguration islandConfig = null, ResinTrapDetectionConfiguration resinTrapConfig = null, TouchingBoundDetectionConfiguration touchingBoundConfig = null) + private void ComputeIssues(IslandDetectionConfiguration islandConfig = null, ResinTrapDetectionConfiguration resinTrapConfig = null, TouchingBoundDetectionConfiguration touchingBoundConfig = null, bool emptyLayersConfig = true) { tabPageIssues.Tag = true; flvIssues.ClearObjects(); @@ -3959,7 +4070,7 @@ namespace UVtools.GUI { try { - Issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, resinTrapConfig, touchingBoundConfig, FrmLoading.RestartProgress()); + Issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, resinTrapConfig, touchingBoundConfig, emptyLayersConfig, FrmLoading.RestartProgress()); } catch (OperationCanceledException) { @@ -4303,7 +4414,7 @@ namespace UVtools.GUI if (ReferenceEquals(Issues, null)) { - ComputeIssues(islandConfig, resinTrapConfig, touchingBoundConfig); + ComputeIssues(islandConfig, resinTrapConfig, touchingBoundConfig, false); } else { @@ -4319,7 +4430,7 @@ namespace UVtools.GUI { try { - var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, resinTrapConfig, touchingBoundConfig, + var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, resinTrapConfig, touchingBoundConfig, false, FrmLoading.RestartProgress()); issues.RemoveAll(issue => issue.Type != LayerIssue.IssueType.Island); // Remove all non islands diff --git a/UVtools.GUI/FrmMain.resx b/UVtools.GUI/FrmMain.resx index 247236a..3ea8bb3 100644 --- a/UVtools.GUI/FrmMain.resx +++ b/UVtools.GUI/FrmMain.resx @@ -158,7 +158,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABk - FAAAAk1TRnQBSQFMAgEBBgEAAZABCQGQAQkBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + FAAAAk1TRnQBSQFMAgEBBgEAAegBCQHoAQkBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIC4AAxgBIgMwAUsDMAFMAzIBUDMAAQEDJAE2AysBQqwAAyIBMQNWAbkDXQHi AwAB/wMAAf8BKgEtASgB/gNTAawDTQGVAwABARgAAwkBDAMzAVIDUAGdA1cB6AMAAf4DKwH8Ay8BSqQA AyEBMANZAewBKwEuASkB+gNRAfcDUgH0A1MB8QNIAfYDQQH5AwAB/wNPAZsDAAEBCAADFQEdAz8BbgNV @@ -206,7 +206,7 @@ BAADUgGpAzQBVQM0AVUgAAM0AVUDNAFVA1IBqQgAA0oBiwMAAf8DAAH/A08BnAQAA00BlQMAAf8DVAGr CAADTwGcAwAB/wMAAf8DSgGLBAADUQGgAQABzAH3Af8BAAHMAfcB/wEAAcwB9wH/AQABzAH3Af8DQwF3 CAADSgGNAgAB7AH/AgAB7AH/AgAB7wH/AgAB7AH/AgAB7AH/AgAB7QH/AVICUwGoA1IBqAMAAf8DAAH/ - AwAB/wNRAfcDOQH9A1ABnwsAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNSAagEAANSAakDNAFVAzQBVQNG + AwAB/wNRAfcDQAH9A1ABnwsAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNSAagEAANSAakDNAFVAzQBVQNG AYADUgGpA1IBqQNSAakDUgGpA1IBqQNSAakDRQF/AzQBVQM0AVUDUgGpBAADUQGiAwAB/wMAAf8DSQGJ CAADLwFKAwAB/wNUAe4MAANJAYkDAAH/AwAB/wNRAaIDAAEBAT8CQAFvAT4CXAH4AQABzQH3Af8BAAHN AfcB/wMSARgIAAMBAQIDRgF+AlIBXQHwAgAB7gH/AgAB7gH/AkABqAH9AUUCRgF+AwMBBANSAagDAAH/ diff --git a/UVtools.GUI/Properties/AssemblyInfo.cs b/UVtools.GUI/Properties/AssemblyInfo.cs index 8b41501..6478ac8 100644 --- a/UVtools.GUI/Properties/AssemblyInfo.cs +++ b/UVtools.GUI/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.7.1.0")] +[assembly: AssemblyFileVersion("0.7.1.0")] diff --git a/UVtools.GUI/Properties/Settings.Designer.cs b/UVtools.GUI/Properties/Settings.Designer.cs index 2577425..151754b 100644 --- a/UVtools.GUI/Properties/Settings.Designer.cs +++ b/UVtools.GUI/Properties/Settings.Designer.cs @@ -862,5 +862,17 @@ namespace UVtools.GUI.Properties { this["ComputeTouchingBounds"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool ComputeEmptyLayers { + get { + return ((bool)(this["ComputeEmptyLayers"])); + } + set { + this["ComputeEmptyLayers"] = value; + } + } } } diff --git a/UVtools.GUI/Properties/Settings.settings b/UVtools.GUI/Properties/Settings.settings index 2fcbdee..1672b37 100644 --- a/UVtools.GUI/Properties/Settings.settings +++ b/UVtools.GUI/Properties/Settings.settings @@ -212,5 +212,8 @@ True + + True + \ No newline at end of file diff --git a/UVtools.GUI/UVtools.GUI.csproj b/UVtools.GUI/UVtools.GUI.csproj index c193df3..d81347b 100644 --- a/UVtools.GUI/UVtools.GUI.csproj +++ b/UVtools.GUI/UVtools.GUI.csproj @@ -91,11 +91,8 @@ ..\packages\CyotekImageBox.1.3.0-Alpha1\lib\net20\Cyotek.Windows.Forms.ImageBox.dll - - ..\packages\Emgu.CV.4.3.0.3890\lib\net461\Emgu.CV.Platform.NetFramework.dll - - - ..\packages\Emgu.CV.4.3.0.3890\lib\net461\Emgu.CV.Platform.NetStandard.dll + + ..\packages\Emgu.CV.4.4.0.4061\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll ..\packages\ObjectListView.Official.2.9.2-alpha2\lib\net20\ObjectListView.dll @@ -107,6 +104,11 @@ + + ..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll + True + True + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll True @@ -139,7 +141,11 @@ True - + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + @@ -157,6 +163,10 @@ Component + + Component + + Form @@ -504,19 +514,17 @@ UVtools.Core - - - + xcopy /i /y /d /s $(ProjectDir)..\PrusaSlicer $(ProjectDir)$(OutDir)\PrusaSlicer xcopy /d /y $(ProjectDir)..\UVtools.Cmd\$(OutDir)netcoreapp3.1\* $(ProjectDir)$(OutDir) + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + - \ No newline at end of file diff --git a/UVtools.GUI/packages.config b/UVtools.GUI/packages.config index 5a4c820..da264e0 100644 --- a/UVtools.GUI/packages.config +++ b/UVtools.GUI/packages.config @@ -1,10 +1,11 @@  - - + + + @@ -13,6 +14,7 @@ + \ No newline at end of file diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs index 2054c3a..5df4324 100644 --- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs +++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs @@ -163,6 +163,9 @@ + + +