mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-12 19:42:32 +02:00
43c1a6a944
- **PCB Exposure:** - (Add) Parse of deprecated commands (G70, G71, G90, G91) - (Fix) Able to have parameterless macro apertures (#503) - **UI:** - (Add) Menu -> File -> Free unused RAM: Force the garbage collection of all unused objects within the program to free unused memory (RAM). It's never required for the end user run this. The program will automatically take care of it when required. This function is for debug purposes. - (Improvement) Window title bar: Show elapsed minutes and seconds instead of total seconds minutes and second - (Fix) Tool - Mask: Loaded image resolution shows as (unloaded) - (Fix) Applying a large set of modifications in layer depth with pixel editor cause huge memory spike due layer aggregation without disposing, leading to program crash on most cases where RAM is insufficient (#506) - (Upgrade) AvaloniaUI from 0.10.15 to 0.10.16
149 lines
4.5 KiB
C#
149 lines
4.5 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Markup.Xaml;
|
|
using Emgu.CV;
|
|
using Emgu.CV.CvEnum;
|
|
using Emgu.CV.Structure;
|
|
using UVtools.Core.Extensions;
|
|
using UVtools.Core.Operations;
|
|
using UVtools.WPF.Extensions;
|
|
using UVtools.WPF.Windows;
|
|
using Bitmap = Avalonia.Media.Imaging.Bitmap;
|
|
|
|
namespace UVtools.WPF.Controls.Tools;
|
|
|
|
public class ToolMaskControl : ToolControl
|
|
{
|
|
private bool _isMaskInverted;
|
|
private byte _genMinimumBrightness = 200;
|
|
private byte _genMaximumBrightness = byte.MaxValue;
|
|
private uint _genDiameter;
|
|
private Bitmap _maskImage;
|
|
public OperationMask Operation => BaseOperation as OperationMask;
|
|
|
|
public bool IsMaskInverted
|
|
{
|
|
get => _isMaskInverted;
|
|
set
|
|
{
|
|
if(!RaiseAndSetIfChanged(ref _isMaskInverted, value)) return;
|
|
if (!Operation.HaveInputMask) return;
|
|
Operation.InvertMask();
|
|
MaskImage = Operation.Mask.ToBitmap();
|
|
}
|
|
}
|
|
|
|
public byte GenMinimumBrightness
|
|
{
|
|
get => _genMinimumBrightness;
|
|
set => RaiseAndSetIfChanged(ref _genMinimumBrightness, value);
|
|
}
|
|
|
|
public byte GenMaximumBrightness
|
|
{
|
|
get => _genMaximumBrightness;
|
|
set => RaiseAndSetIfChanged(ref _genMaximumBrightness, value);
|
|
}
|
|
|
|
public uint GenDiameter
|
|
{
|
|
get => _genDiameter;
|
|
set => RaiseAndSetIfChanged(ref _genDiameter, value);
|
|
}
|
|
|
|
public string InfoPrinterResolutionStr => $"Printer resolution: {App.SlicerFile.Resolution}";
|
|
public string InfoMaskResolutionStr => $"Mask resolution: "+ (Operation.HaveInputMask ? Operation.Mask.Size.ToString() : "(Unloaded)");
|
|
|
|
public Bitmap MaskImage
|
|
{
|
|
get => _maskImage;
|
|
set
|
|
{
|
|
if(!RaiseAndSetIfChanged(ref _maskImage, value)) return;
|
|
RaisePropertyChanged(nameof(InfoMaskResolutionStr));
|
|
ParentWindow.ButtonOkEnabled = Operation.HaveInputMask;
|
|
}
|
|
}
|
|
|
|
public ToolMaskControl()
|
|
{
|
|
BaseOperation = new OperationMask(SlicerFile);
|
|
if (!ValidateSpawn()) return;
|
|
InitializeComponent();
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
AvaloniaXamlLoader.Load(this);
|
|
}
|
|
|
|
public override void Callback(ToolWindow.Callbacks callback)
|
|
{
|
|
switch (callback)
|
|
{
|
|
case ToolWindow.Callbacks.Init:
|
|
ParentWindow.ButtonOkEnabled = false;
|
|
break;
|
|
case ToolWindow.Callbacks.Loaded:
|
|
case ToolWindow.Callbacks.ClearROI:
|
|
Operation.Mask = null;
|
|
MaskImage = null;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public async void ImportImageMask()
|
|
{
|
|
var dialog = new OpenFileDialog
|
|
{
|
|
Filters = Helpers.ImagesFileFilter,
|
|
AllowMultiple = false
|
|
};
|
|
|
|
var result = await dialog.ShowAsync(ParentWindow);
|
|
if (result is null || result.Length == 0) return;
|
|
|
|
try
|
|
{
|
|
Operation.LoadFromFile(result[0], _isMaskInverted, App.MainWindow.ROI.Size.IsEmpty ? SlicerFile.Resolution : App.MainWindow.ROI.Size);
|
|
MaskImage = Operation.Mask.ToBitmap();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
await ParentWindow.MessageBoxError(e.ToString(), "Error while trying to read the image");
|
|
}
|
|
}
|
|
|
|
public void GenerateMask()
|
|
{
|
|
var roi = App.MainWindow.ROI;
|
|
Operation.Mask = roi.IsEmpty ? App.MainWindow.LayerCache.Image.NewBlank() : new Mat(roi.Size, DepthType.Cv8U, 1);
|
|
|
|
int radius = (int)_genDiameter;
|
|
if (radius == 0)
|
|
{
|
|
radius = Math.Min(Operation.Mask.Width, Operation.Mask.Height) / 2;
|
|
}
|
|
else
|
|
{
|
|
radius = radius.Clamp(2, Math.Min(Operation.Mask.Width, Operation.Mask.Height)) / 2;
|
|
}
|
|
|
|
var maxScalar = new MCvScalar(_genMaximumBrightness);
|
|
Operation.Mask.SetTo(maxScalar);
|
|
|
|
var center = new Point(Operation.Mask.Width / 2, Operation.Mask.Height / 2);
|
|
var colorDifference = _genMinimumBrightness - _genMaximumBrightness;
|
|
//CvInvoke.Circle(Mask, center, radius, minScalar, -1);
|
|
|
|
for (decimal i = 1; i < radius; i++)
|
|
{
|
|
int color = (int)(_genMinimumBrightness - i / radius * colorDifference); //or some another color calculation
|
|
CvInvoke.Circle(Operation.Mask, center, (int)i, new MCvScalar(color), 2);
|
|
}
|
|
|
|
if (_isMaskInverted) Operation.InvertMask();
|
|
MaskImage = Operation.Mask.ToBitmap();
|
|
}
|
|
} |