Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'PrusaSL1Viewer/FrmMain.cs')
-rw-r--r--PrusaSL1Viewer/FrmMain.cs376
1 files changed, 356 insertions, 20 deletions
diff --git a/PrusaSL1Viewer/FrmMain.cs b/PrusaSL1Viewer/FrmMain.cs
index 3c01050..d5a965f 100644
--- a/PrusaSL1Viewer/FrmMain.cs
+++ b/PrusaSL1Viewer/FrmMain.cs
@@ -7,22 +7,53 @@
*/
using System;
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
+using Emgu.CV.Structure;
using PrusaSL1Reader;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
+using Color = System.Drawing.Color;
+using Point = System.Drawing.Point;
namespace PrusaSL1Viewer
{
public partial class FrmMain : Form
{
+ #region Enums
+ public enum eMutate
+ {
+ Erode,
+ Dilate,
+ PyrDownUp,
+ SmoothMedian,
+ SmoothGaussian
+ }
+ #endregion
+
#region Properties
+
+ public static readonly Dictionary<eMutate, string> MutateDescriptions = new Dictionary<eMutate, string>
+ {
+ {eMutate.Erode, "Erodes image using a 3x3 rectangular structuring element.\n" +
+ "Erosion are applied several (iterations) times"},
+ {eMutate.Dilate, "Dilates image using a 3x3 rectangular structuring element.\n" +
+ "Dilation are applied several (iterations) times"},
+ {eMutate.PyrDownUp, "Performs downsampling step of Gaussian pyramid decomposition.\n" +
+ "First it convolves image with the specified filter and then downsamples the image by rejecting even rows and columns.\n" +
+ "After performs up-sampling step of Gaussian pyramid decomposition\n" +
+ "First it upsamples image by injecting even zero rows and columns and then convolves result with the specified filter multiplied by 4 for interpolation"},
+ {eMutate.SmoothMedian, "Finding median of size neighborhood"},
+ {eMutate.SmoothGaussian, "Perform Gaussian Smoothing"}
+ };
+
public FrmLoading FrmLoading { get; }
public static FileFormat SlicerFile
{
@@ -31,6 +62,7 @@ namespace PrusaSL1Viewer
}
public uint ActualLayer => (uint)(sbLayers.Maximum - sbLayers.Value);
+ public Image<L8> ActualLayerImage { get; private set; }
#endregion
@@ -46,6 +78,16 @@ namespace PrusaSL1Viewer
DragEnter += (s, e) => { if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; };
DragDrop += (s, e) => { ProcessFile((string[])e.Data.GetData(DataFormats.FileDrop)); };
+
+ foreach (eMutate mutate in (eMutate[])Enum.GetValues(typeof(eMutate)))
+ {
+ var item = new ToolStripMenuItem(mutate.ToString())
+ {
+ ToolTipText = MutateDescriptions[mutate], Tag = mutate, AutoToolTip = true
+ };
+ item.Click += ItemClicked;
+ menuMutate.DropDownItems.Add(item);
+ }
}
#endregion
@@ -68,6 +110,19 @@ namespace PrusaSL1Viewer
e.Handled = true;
return;
}
+
+ if ((e.KeyCode == Keys.NumPad0 || e.KeyCode == Keys.D0) && e.Control)
+ {
+ pbLayer.ZoomToFit();
+ e.Handled = true;
+ return;
+ }
+ }
+
+ protected override void OnResize(EventArgs e)
+ {
+ base.OnResize(e);
+ pbLayer.ZoomToFit();
}
#endregion
@@ -131,7 +186,33 @@ namespace PrusaSL1Viewer
if (ReferenceEquals(sender, menuFileSave))
{
- SlicerFile.Save();
+ DisableGUI();
+ FrmLoading.SetDescription($"Saving {Path.GetFileName(SlicerFile.FileFullPath)}");
+
+ Task<bool> task = Task<bool>.Factory.StartNew(() =>
+ {
+ bool result = false;
+ try
+ {
+ SlicerFile.Save();
+ result = true;
+ }
+ catch (Exception)
+ {
+ }
+ finally
+ {
+ Invoke((MethodInvoker)delegate {
+ // Running on the UI thread
+ EnableGUI(true);
+ });
+ }
+
+ return result;
+ });
+
+ FrmLoading.ShowDialog();
+
menuFileSave.Enabled =
menuFileSaveAs.Enabled = false;
return;
@@ -141,16 +222,44 @@ namespace PrusaSL1Viewer
{
using (SaveFileDialog dialog = new SaveFileDialog())
{
- dialog.Filter = SlicerFile.FileFilter;
+ var ext = Path.GetExtension(SlicerFile.FileFullPath);
+ dialog.Filter = $"{ext.Remove(0, 1)} files (*{ext})|*{ext}";
dialog.AddExtension = true;
dialog.FileName =
$"{Path.GetFileNameWithoutExtension(SlicerFile.FileFullPath)}_copy";
if (dialog.ShowDialog() == DialogResult.OK)
{
- SlicerFile.SaveAs(dialog.FileName);
+ DisableGUI();
+ FrmLoading.SetDescription($"Saving {Path.GetFileName(dialog.FileName)}");
+
+ Task<bool> task = Task<bool>.Factory.StartNew(() =>
+ {
+ bool result = false;
+ try
+ {
+ SlicerFile.SaveAs(dialog.FileName);
+ result = true;
+ }
+ catch (Exception)
+ {
+ }
+ finally
+ {
+ Invoke((MethodInvoker)delegate {
+ // Running on the UI thread
+ EnableGUI(true);
+ });
+ }
+
+ return result;
+ });
+
+ FrmLoading.ShowDialog();
+
menuFileSave.Enabled =
menuFileSaveAs.Enabled = false;
- ProcessFile(dialog.FileName);
+ UpdateTitle();
+ //ProcessFile(dialog.FileName);
}
}
@@ -236,7 +345,7 @@ namespace PrusaSL1Viewer
return;
}
- // Edit
+ // Edit & mutate
if (!ReferenceEquals(item.Tag, null))
{
if (item.Tag.GetType() == typeof(FileFormat.PrintParameterModifier))
@@ -264,25 +373,32 @@ namespace PrusaSL1Viewer
return;
}
+
+ if (item.Tag.GetType() == typeof(eMutate))
+ {
+ eMutate mutate = (eMutate)item.Tag;
+ MutateLayers(mutate);
+ return;
+ }
}
// View
// About
- if (ReferenceEquals(sender, menuAboutAbout))
+ if (ReferenceEquals(sender, menuHelpAbout))
{
Program.FrmAbout.ShowDialog();
return;
}
- if (ReferenceEquals(sender, menuAboutWebsite))
+ if (ReferenceEquals(sender, menuHelpWebsite))
{
Process.Start(About.Website);
return;
}
- if (ReferenceEquals(sender, menuAboutDonate))
+ if (ReferenceEquals(sender, menuHelpDonate))
{
MessageBox.Show(
"All my work here is given for free (OpenSource), it took some hours to build, test and polish the program.\n" +
@@ -292,6 +408,60 @@ namespace PrusaSL1Viewer
Process.Start(About.Donate);
return;
}
+
+ if (ReferenceEquals(sender, menuHelpInstallPrinters))
+ {
+ string printerFolder = $"{Application.StartupPath}{Path.DirectorySeparatorChar}PrusaSlicer{Path.DirectorySeparatorChar}printer";
+ try
+ {
+ string[] profiles = Directory.GetFiles(printerFolder);
+ string profilesNames = String.Empty;
+
+ foreach (var profile in profiles)
+ {
+ profilesNames += $"{Path.GetFileNameWithoutExtension(profile)}\n";
+ }
+
+ var result = MessageBox.Show(
+ "This action will install following printer profiles into PrusaSlicer:\n" +
+ "---------------\n" +
+ profilesNames +
+ "---------------\n" +
+ "Click 'Yes' to override all profiles\n" +
+ "Click 'No' to install only missing profiles without override\n" +
+ "Clock 'Abort' to cancel this operation",
+ "Install printers into PrusaSlicer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
+
+
+ if (result == DialogResult.Abort)
+ {
+ return;
+ }
+
+ bool overwrite = result == DialogResult.Yes;
+ string targetFolder = $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}PrusaSlicer{Path.DirectorySeparatorChar}printer";
+
+ foreach (var profile in profiles)
+ {
+ string targetFile = $"{targetFolder}{Path.DirectorySeparatorChar}{Path.GetFileName(profile)}";
+ if (!overwrite && File.Exists(targetFile)) continue;
+ File.Copy(profile, targetFile, overwrite);
+ }
+
+ MessageBox.Show(
+ "Printers were installed.\nRestart PrusaSlicer and check if printers are present.",
+ "Operation Completed", MessageBoxButtons.OK, MessageBoxIcon.Information);
+
+ }
+ catch (Exception exception)
+ {
+ MessageBox.Show(exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+
+
+
+ return;
+ }
}
/************************
@@ -453,7 +623,7 @@ namespace PrusaSL1Viewer
/************************
* Layer Menu *
***********************/
- if (ReferenceEquals(sender, tsLayerImageRotate) || ReferenceEquals(sender, tsLayerImageLayerDifference))
+ if (ReferenceEquals(sender, tsLayerImageRotate) || ReferenceEquals(sender, tsLayerImageLayerDifference) || ReferenceEquals(sender, tsLayerImageLayerOutline))
{
sbLayers_ValueChanged(sbLayers, null);
return;
@@ -585,10 +755,10 @@ namespace PrusaSL1Viewer
menuFileConvert.DropDownItems.Clear();
menuEdit.DropDownItems.Clear();
- /*foreach (ToolStripItem item in menuEdit.DropDownItems)
+ foreach (ToolStripItem item in menuMutate.DropDownItems)
{
item.Enabled = false;
- }*/
+ }
foreach (ToolStripItem item in tsThumbnails.Items)
{
@@ -618,7 +788,8 @@ namespace PrusaSL1Viewer
menuFileConvert.Enabled =
sbLayers.Enabled =
pbLayers.Enabled =
- menuEdit.Enabled =
+ menuEdit.Enabled =
+ menuMutate.Enabled =
false;
@@ -739,6 +910,11 @@ namespace PrusaSL1Viewer
tsThumbnailsNext.Enabled = SlicerFile.CreatedThumbnailsCount > 1;
AdjustThumbnailSplitter();
}
+
+ foreach (ToolStripItem item in menuMutate.DropDownItems)
+ {
+ item.Enabled = true;
+ }
foreach (ToolStripItem item in tsLayer.Items)
{
item.Enabled = true;
@@ -756,10 +932,11 @@ namespace PrusaSL1Viewer
sbLayers.Enabled =
pbLayers.Enabled =
- menuEdit.Enabled =
+ menuEdit.Enabled =
+ menuMutate.Enabled =
true;
- if (!string.IsNullOrEmpty(SlicerFile.GCode))
+ if (!ReferenceEquals(SlicerFile.GCode, null))
{
tabControlLeft.TabPages.Add(tbpGCode);
}
@@ -772,12 +949,18 @@ namespace PrusaSL1Viewer
sbLayers.Value = sbLayers.Maximum;
tabControlLeft.SelectedIndex = 0;
+ tsLayerResolution.Text = $"{{Width={SlicerFile.ResolutionX}, Height={SlicerFile.ResolutionY}}}";
RefreshInfo();
- tsLayerResolution.Text = pbLayer.Image?.PhysicalDimension.ToString() ?? string.Empty;
+ pbLayer.ZoomToFit();
+ UpdateTitle();
+ }
+
+ void UpdateTitle()
+ {
Text = $"{FrmAbout.AssemblyTitle} Version: {FrmAbout.AssemblyVersion} File: {Path.GetFileName(SlicerFile.FileFullPath)}";
}
@@ -830,9 +1013,9 @@ namespace PrusaSL1Viewer
tsPropertiesLabelCount.Text = $"Properties: {lvProperties.Items.Count}";
tsPropertiesLabelGroups.Text = $"Groups: {lvProperties.Groups.Count}";
- if (!string.IsNullOrEmpty(SlicerFile.GCode))
+ if (!ReferenceEquals(SlicerFile.GCode, null))
{
- tbGCode.Text = SlicerFile.GCode;
+ tbGCode.Text = SlicerFile.GCode.ToString();
tsGCodeLabelLines.Text = $"Lines: {tbGCode.Lines.Length}";
tsGcodeLabelChars.Text = $"Chars: {tbGCode.Text.Length}";
}
@@ -861,12 +1044,21 @@ namespace PrusaSL1Viewer
Stopwatch watch = Stopwatch.StartNew();
- var image = SlicerFile.GetLayerImage(layerNum);
- if (tsLayerImageLayerDifference.Checked)
+ var image = SlicerFile[layerNum].Image;
+ ActualLayerImage = image.Clone();
+
+ if (tsLayerImageLayerOutline.Checked)
+ {
+ Emgu.CV.Image<Gray, byte> grayscale = image.ToEmguImage();
+ grayscale = grayscale.Canny(100, 200, 3, true);
+ image = grayscale.ToImageSharpL8();
+ grayscale.Dispose();
+ }
+ else if (tsLayerImageLayerDifference.Checked)
{
if (layerNum > 0)
{
- var previousImage = SlicerFile.GetLayerImage(layerNum - 1);
+ var previousImage = SlicerFile[layerNum-1].Image;
//var nextImage = SlicerFile.GetLayerImage(layerNum+1);
@@ -960,5 +1152,149 @@ namespace PrusaSL1Viewer
scLeft.SplitterDistance = Math.Min(pbThumbnail.Image.Height + 5, 400);
}
#endregion
+
+ private void pbLayer_Zoomed(object sender, Cyotek.Windows.Forms.ImageBoxZoomEventArgs e)
+ {
+ tsLayerImageZoomValueLabel.Text = $"{e.NewZoom} %";
+ }
+
+ void DrawPixel(bool isAdd, Point location, Color color, L8 pixelL8)
+ {
+ var point = pbLayer.PointToImage(location);
+ int x = point.X;
+ int y = point.Y;
+
+ if (tsLayerImageRotate.Checked)
+ {
+ x = point.Y;
+ y = ActualLayerImage.Height - 1 - point.X;
+ }
+
+
+ if (isAdd && ActualLayerImage[x, y].PackedValue > byte.MaxValue / 2)
+ {
+ return;
+ }
+ if (!isAdd && ActualLayerImage[x, y].PackedValue < byte.MaxValue / 2)
+ {
+ return;
+ }
+
+ ActualLayerImage[x, y] = pixelL8;
+ Bitmap bmp = pbLayer.Image as Bitmap;
+ bmp.SetPixel(point.X, point.Y, color);
+
+ /*if (bmp.GetPixel(point.X, point.Y).GetBrightness() == returnif) return;
+ bmp.SetPixel(point.X, point.Y, color);
+ ActualLayerImage[point.X, point.Y] = pixelL8;
+ var newImage = ActualLayerImage.Clone();
+ if (tsLayerImageRotate.Checked)
+ {
+ newImage.Mutate(mut => mut.Rotate(RotateMode.Rotate270));
+ }
+ SlicerFile[ActualLayer].Image = newImage;*/
+ pbLayer.Invalidate();
+ menuFileSave.Enabled = menuFileSaveAs.Enabled = true;
+ }
+
+ private void pbLayer_MouseUp(object sender, MouseEventArgs e)
+ {
+ if (!tsLayerImagePixelEdit.Checked || (e.Button & MouseButtons.Right) == 0) return;
+ if (!pbLayer.IsPointInImage(e.Location)) return;
+
+
+ if (Control.ModifierKeys == Keys.Shift)
+ {
+ DrawPixel(false, e.Location, Color.DarkRed, Helpers.L8Black);
+ }
+ else
+ {
+ DrawPixel(true, e.Location, Color.Green, Helpers.L8White);
+ }
+
+ SlicerFile[ActualLayer].Image = ActualLayerImage;
+ }
+
+ private void pbLayer_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (!tsLayerImagePixelEdit.Checked || (e.Button & MouseButtons.Right) == 0) return;
+ if (!pbLayer.IsPointInImage(e.Location)) return;
+
+ if (Control.ModifierKeys == Keys.Shift)
+ {
+ DrawPixel(false, e.Location, Color.DarkRed, Helpers.L8Black);
+ return;
+ }
+
+ DrawPixel(true, e.Location, Color.Green, Helpers.L8White);
+ }
+
+ public void MutateLayers(eMutate type)
+ {
+ decimal value = 0;
+ using (FrmInputBox inputBox = new FrmInputBox($"Mutate - {type}", MutateDescriptions[type], 0))
+ {
+ if (inputBox.ShowDialog() != DialogResult.OK) return;
+ value = inputBox.NewValue;
+ if (value == 0) return;
+ }
+
+ DisableGUI();
+ FrmLoading.SetDescription($"Mutating - {type}");
+
+ Task<bool> task = Task<bool>.Factory.StartNew(() =>
+ {
+ bool result = false;
+ try
+ {
+ Parallel.ForEach(SlicerFile, (layer) =>
+ {
+ var image = layer.Image;
+ var imageEgmu = image.ToEmguImage();
+ switch (type)
+ {
+ case eMutate.Erode:
+ imageEgmu = imageEgmu.Erode((int) value);
+ break;
+ case eMutate.Dilate:
+ imageEgmu = imageEgmu.Dilate((int) value);
+ break;
+ case eMutate.PyrDownUp:
+ imageEgmu = imageEgmu.PyrDown().PyrUp();
+ break;
+ case eMutate.SmoothMedian:
+ imageEgmu = imageEgmu.SmoothMedian((int) value);
+ break;
+ case eMutate.SmoothGaussian:
+ imageEgmu = imageEgmu.SmoothGaussian((int)value);
+ break;
+ }
+ layer.Image = imageEgmu.ToImageSharpL8();
+ imageEgmu.Dispose();
+ });
+ result = true;
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"{ex.Message}\nPlease try diferent values for the mutation", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ finally
+ {
+ Invoke((MethodInvoker)delegate {
+ // Running on the UI thread
+ EnableGUI(true);
+ });
+ }
+
+ return result;
+ });
+
+ FrmLoading.ShowDialog();
+
+ ShowLayer(ActualLayer);
+
+ menuFileSave.Enabled =
+ menuFileSaveAs.Enabled = true;
+ }
}
}