* (Add) Pixel editor - Text: Preview of text operation (#120)
* (Add) Calibration - Elephant Foot: 'Part scale' factor to scale up test parts
* (Change) Allow tools text descriptions to be selectable and copied
* (Fix) Pixel editor - Text: Round font scale to avoid precision error
This commit is contained in:
Tiago Conceição
2021-01-03 23:57:43 +00:00
parent a7d15a24d0
commit b36dce28a6
13 changed files with 91 additions and 62 deletions
+8 -1
View File
@@ -1,6 +1,13 @@
# Changelog
## 03/12/2020 - v2.1.1
## 03/01/2021 - v2.1.2
* (Add) Pixel editor - Text: Preview of text operation (#120)
* (Add) Calibration - Elephant Foot: 'Part scale' factor to scale up test parts
* (Change) Allow tools text descriptions to be selectable and copied
* (Fix) Pixel editor - Text: Round font scale to avoid precision error
## 03/01/2021 - v2.1.1
* (Add) About box: Primary screen identifier and open on screen identifier
* (Add) Calibrator - External tests
+2
View File
@@ -153,6 +153,7 @@ Building: $runtime"
$macPublishFolder = "$publishFolder/${macAppFolder}"
$macInfoplist = "$platformsFolder/$runtime/Info.plist"
$macOutputInfoplist = "$macPublishFolder/Contents"
$macTargetZipLegacy = "$publishFolder/${software}_${runtime}-legacy_v$version.zip"
New-Item -ItemType directory -Path "$macPublishFolder"
New-Item -ItemType directory -Path "$macPublishFolder/Contents"
@@ -165,6 +166,7 @@ Building: $runtime"
wsl cp -a "$publishFolder/$runtime/." "$macPublishFolder/Contents/MacOS"
wsl cd "$publishFolder/" `&`& pwd `&`& zip -r "../$targetZip" "$macAppFolder/*"
wsl cd "$publishFolder/$runtime" `&`& pwd `&`& zip -r "../../$macTargetZipLegacy" .
}
else {
+3 -5
View File
@@ -81,11 +81,9 @@ namespace UVtools.Core.Extensions
{
var halfWidth = src.Width / 2.0f;
var halfHeight = src.Height / 2.0f;
using (var translateTransform = new Matrix<double>(2, 3))
{
CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), -angle, 1.0, translateTransform);
CvInvoke.WarpAffine(src, src, translateTransform, src.Size);
}
using var translateTransform = new Matrix<double>(2, 3);
CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), -angle, 1.0, translateTransform);
CvInvoke.WarpAffine(src, src, translateTransform, src.Size);
}
/// <summary>
@@ -32,6 +32,7 @@ namespace UVtools.Core.Operations
private ushort _normalLayers = 70;
private decimal _bottomExposure = 60;
private decimal _normalExposure = 12;
private decimal _partScale = 1;
private byte _margin = 30;
private bool _isErodeEnabled = true;
private byte _erodeStartIteration = 2;
@@ -195,6 +196,12 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _normalExposure, Math.Round(value, 2));
}
public decimal PartScale
{
get => _partScale;
set => RaiseAndSetIfChanged(ref _partScale, Math.Round(value, 2));
}
public byte Margin
{
get => _margin;
@@ -384,8 +391,8 @@ namespace UVtools.Core.Operations
layers[0] = EmguExtensions.InitMat(Resolution);
LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected;
const int length = 250;
const int triangleLength = 50;
int length = (int) (250 * _partScale);
int triangleLength = (int) (50 * _partScale);
const byte startX = 2;
const byte startY = 2;
int x = startX;
@@ -410,7 +417,7 @@ namespace UVtools.Core.Operations
y += triangleLength;
addPoint();
y += 50;
y += triangleLength;
addPoint();
x += triangleLength;
@@ -439,16 +446,15 @@ namespace UVtools.Core.Operations
addPoint();
const byte ellipseHeight = 50;
int ellipseHeight = (int) (50 * _partScale);
maxY += ellipseHeight;
using Mat shape = EmguExtensions.InitMat(new Size(maxX + startX, maxY + startY));
CvInvoke.FillPoly(shape, new VectorOfPoint(pointList.ToArray()), EmguExtensions.WhiteByte, lineType);
CvInvoke.Circle(shape, new Point(0, 0), length / 4, EmguExtensions.BlackByte,
-1, lineType);
CvInvoke.Circle(shape, new Point(0, 0), length / 4, EmguExtensions.BlackByte, -1, lineType);
CvInvoke.Ellipse(shape, new Point(maxX / 2, maxY - ellipseHeight), new Size(maxX / 3, ellipseHeight), 0, 0, 360,
EmguExtensions.WhiteByte, -1, lineType);
CvInvoke.Circle(shape, new Point(length / 2, maxY - 100), length / 5, EmguExtensions.BlackByte, -1, lineType);
CvInvoke.Circle(shape, new Point(length / 2, (int) (maxY - 100 * _partScale)), length / 5, EmguExtensions.BlackByte, -1, lineType);
int currentX = 0;
int currentY = 0;
@@ -456,16 +462,17 @@ namespace UVtools.Core.Operations
maxX = 0;
const FontFace font = FontFace.HersheyDuplex;
const byte fontStartX = 30;
const byte fontStartY = length / 4 + 42;
const double fontScale = 1.3;
const byte fontThickness = 3;
const byte fontMargin = 42;
int fontMargin = (int)(42 * _partScale);
int fontStartX = (int) (30 * _partScale);
int fontStartY = length / 4 + fontMargin;
double fontScale = 1.3 * (double) _partScale;
int fontThickness = (int) (3 * _partScale);
void addText(Mat mat, ushort number, params string[] text)
{
CvInvoke.PutText(mat, number.ToString(), new Point(100, 55), font, 1.5, EmguExtensions.BlackByte, 4, lineType);
CvInvoke.PutText(mat, "UVtools EP", new Point(fontStartX, fontStartY), font, 0.8, EmguExtensions.BlackByte, 2, lineType);
CvInvoke.PutText(mat, number.ToString(), new Point((int) (100 * _partScale), (int) (55 * _partScale)), font, 1.5 * (double) _partScale, EmguExtensions.BlackByte, (int) (4 * _partScale), lineType);
CvInvoke.PutText(mat, "UVtools EP", new Point(fontStartX, fontStartY), font, 0.8 * (double) _partScale, EmguExtensions.BlackByte, (int) (2 * _partScale), lineType);
CvInvoke.PutText(mat, $"{Microns}um", new Point(fontStartX, fontStartY + fontMargin), font, fontScale, EmguExtensions.BlackByte, fontThickness, lineType);
CvInvoke.PutText(mat, $"{BottomExposure}|{NormalExposure}s", new Point(fontStartX, fontStartY + fontMargin * 2), font, fontScale, EmguExtensions.BlackByte, fontThickness, lineType);
if (text is null) return;
+1 -1
View File
@@ -33,7 +33,7 @@ namespace UVtools.Core.PixelEditor
public double FontScale
{
get => _fontScale;
set => RaiseAndSetIfChanged(ref _fontScale, value);
set => RaiseAndSetIfChanged(ref _fontScale, Math.Round(value, 2));
}
public ushort Thickness
+2 -2
View File
@@ -9,8 +9,8 @@
<RepositoryType>Git</RepositoryType>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
<Version>2.1.1</Version>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>2.1.2</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -9,7 +9,7 @@
<Grid ColumnDefinitions="Auto,10,350">
<StackPanel Spacing="10">
<Grid
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
ColumnDefinitions="Auto,10,100,5,Auto,20,Auto,10,100,5,Auto"
>
@@ -89,28 +89,35 @@
Increment="0.5"
Minimum="0.1"
Maximum="200"
Value="{Binding Operation.NormalExposure}"
/>
Value="{Binding Operation.NormalExposure}"/>
<TextBlock Grid.Row="4" Grid.Column="10"
VerticalAlignment="Center"
Text="s"/>
<TextBlock Grid.Row="6" Grid.Column="0"
VerticalAlignment="Center"
Text="Margin:"/>
Text="Part scale:"/>
<NumericUpDown Grid.Row="6" Grid.Column="2"
ClipValueToMinMax="True"
Increment="0.1"
Minimum="1"
Maximum="10"
Value="{Binding Operation.PartScale}"/>
<TextBlock Grid.Row="6" Grid.Column="6"
VerticalAlignment="Center"
Text="Margin:"/>
<NumericUpDown Grid.Row="6" Grid.Column="8"
ClipValueToMinMax="True"
Increment="1"
Minimum="0"
Maximum="255"
Value="{Binding Operation.Margin}"
/>
<TextBlock Grid.Row="6" Grid.Column="4"
Value="{Binding Operation.Margin}"/>
<TextBlock Grid.Row="6" Grid.Column="10"
VerticalAlignment="Center"
Text="px"/>
<StackPanel Grid.Row="6" Grid.Column="6"
<StackPanel Grid.Row="8" Grid.Column="0"
VerticalAlignment="Center"
Spacing="0">
<TextBlock
@@ -123,7 +130,7 @@
</StackPanel>
<StackPanel Grid.Row="6" Grid.Column="8"
<StackPanel Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="9"
VerticalAlignment="Center"
Spacing="0">
<TextBlock FontWeight="Bold">
@@ -140,12 +147,12 @@
Text="{Binding Operation.ObjectCount}"/>
</StackPanel>
<CheckBox Grid.Row="8" Grid.Column="0"
<CheckBox Grid.Row="10" Grid.Column="0"
Grid.ColumnSpan="6"
IsChecked="{Binding Operation.OutputOriginalPart}"
Content="Output an unmodified part (The original)" />
<CheckBox Grid.Row="8" Grid.Column="6"
<CheckBox Grid.Row="10" Grid.Column="6"
Grid.ColumnSpan="5"
IsChecked="{Binding Operation.EnableAntiAliasing}"
Content="Enable Anti-Aliasing" />
+17 -11
View File
@@ -32,6 +32,7 @@ using UVtools.WPF.Structures;
using Color = UVtools.WPF.Structures.Color;
using Helpers = UVtools.WPF.Controls.Helpers;
using Point = System.Drawing.Point;
using Size = System.Drawing.Size;
namespace UVtools.WPF
{
@@ -460,11 +461,9 @@ namespace UVtools.WPF
if (_showLayerOutlineEdgeDetection)
{
using (var canny = new Mat())
{
CvInvoke.Canny(LayerCache.Image, canny, 80, 40, 3, true);
CvInvoke.CvtColor(canny, LayerCache.ImageBgr, ColorConversion.Gray2Bgra);
}
using var canny = new Mat();
CvInvoke.Canny(LayerCache.Image, canny, 80, 40, 3, true);
CvInvoke.CvtColor(canny, LayerCache.ImageBgr, ColorConversion.Gray2Bgra);
}
else if (_showLayerImageDifference)
{
@@ -1310,16 +1309,16 @@ namespace UVtools.WPF
if (DrawingPixelDrawing.BrushSize > 1)
{
cursor = EmguExtensions.InitMat(new System.Drawing.Size(DrawingPixelDrawing.BrushSize, DrawingPixelDrawing.BrushSize), 4);
cursor = EmguExtensions.InitMat(new Size(DrawingPixelDrawing.BrushSize, DrawingPixelDrawing.BrushSize), 4);
switch (DrawingPixelDrawing.BrushShape)
{
case PixelDrawing.BrushShapeType.Rectangle:
CvInvoke.Rectangle(cursor,
new Rectangle(Point.Empty, new System.Drawing.Size(DrawingPixelDrawing.BrushSize, DrawingPixelDrawing.BrushSize)),
new Rectangle(Point.Empty, new Size(DrawingPixelDrawing.BrushSize, DrawingPixelDrawing.BrushSize)),
_pixelEditorCursorColor, DrawingPixelDrawing.Thickness, DrawingPixelDrawing.LineType);
_pixelEditorCursorColor.V3 = 255;
CvInvoke.Rectangle(cursor,
new Rectangle(Point.Empty, new System.Drawing.Size(DrawingPixelDrawing.BrushSize-1, DrawingPixelDrawing.BrushSize-1)),
new Rectangle(Point.Empty, new Size(DrawingPixelDrawing.BrushSize-1, DrawingPixelDrawing.BrushSize-1)),
_pixelEditorCursorColor, 1, DrawingPixelDrawing.LineType);
break;
case PixelDrawing.BrushShapeType.Circle:
@@ -1342,14 +1341,21 @@ namespace UVtools.WPF
}
break;
case PixelOperation.PixelOperationType.Text:
break;
var text = DrawingPixelText.Text;
if (string.IsNullOrEmpty(text) || DrawingPixelText.FontScale < 0.2) return;
int baseLine = 0;
var size = CvInvoke.GetTextSize(text, DrawingPixelText.Font, DrawingPixelText.FontScale, DrawingPixelText.Thickness, ref baseLine);
cursor = EmguExtensions.InitMat(size, 4);
CvInvoke.PutText(cursor, text, new Point(0, 0), DrawingPixelText.Font, DrawingPixelText.FontScale, _pixelEditorCursorColor, DrawingPixelText.Thickness, DrawingPixelText.LineType, DrawingPixelText.Mirror);
cursor = EmguExtensions.InitMat(new Size(size.Width * 2, size.Height * 2), 4);
//CvInvoke.Rectangle(cursor, new Rectangle(Point.Empty, size), _pixelEditorCursorColor, -1, DrawingPixelText.LineType);
//_pixelEditorCursorColor.V3 = 255;
//CvInvoke.Rectangle(cursor, new Rectangle(new Point(size.Width, 0), size), _pixelEditorCursorColor, 1, DrawingPixelText.LineType);
CvInvoke.PutText(cursor, text, new Point(size.Width, size.Height), DrawingPixelText.Font, DrawingPixelText.FontScale, _pixelEditorCursorColor, DrawingPixelText.Thickness, DrawingPixelText.LineType, DrawingPixelText.Mirror);
if (_showLayerImageRotated)
{
CvInvoke.Rotate(cursor, cursor, RotateFlags.Rotate90Clockwise);
}
break;
case PixelOperation.PixelOperationType.Supports:
case PixelOperation.PixelOperationType.DrainHole:
+4 -10
View File
@@ -9,16 +9,12 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Skia;
using Avalonia.Threading;
using DynamicData;
using Emgu.CV;
@@ -192,12 +188,10 @@ namespace UVtools.WPF
{
unsafe
{
using (var framebuffer = bitmap.Lock())
{
var data = (uint*)framebuffer.Address.ToPointer();
data[bitmap.GetPixelPos(location)] =
color.ToUint32();
}
using var framebuffer = bitmap.Lock();
var data = (uint*)framebuffer.Address.ToPointer();
data[bitmap.GetPixelPos(location)] =
color.ToUint32();
}
LayerImageBox.InvalidateArrange();
+1 -1
View File
@@ -672,7 +672,7 @@ namespace UVtools.WPF
DefaultExtension = extension.Extension,
Filters = new List<FileDialogFilter>
{
new FileDialogFilter
new()
{
Name = extension.Description,
Extensions = new List<string>
+1 -1
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>2.1.1</Version>
<Version>2.1.2</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+11 -3
View File
@@ -13,17 +13,25 @@
<!-- Description -->
<Border
Grid.Row="0"
Background="WhiteSmoke"
Padding="20"
Padding="10"
IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
>
<Panel>
<TextBlock
<TextBox
HorizontalAlignment="Left"
TextWrapping="Wrap"
MaxWidth="{Binding DescriptionMaxWidth}"
FontSize="16"
IsReadOnly="True"
AcceptsReturn="True"
Background="Transparent"
CaretBrush="Transparent"
BorderBrush="Transparent"
Watermark="Description:"
UseFloatingWatermark="True"
Padding="5"
Width="Infinity"
Text="{Binding Description}"/>
</Panel>
</Border>
+1 -1
View File
@@ -525,7 +525,7 @@ namespace UVtools.WPF.Windows
{
if (Bounds.Width == 0) return true;
ScrollViewerMaxHeight = this.GetScreenWorkingArea().Height - Bounds.Height + ToolControl.Bounds.Height - UserSettings.Instance.General.WindowsVerticalMargin;
DescriptionMaxWidth = Math.Max(Bounds.Width, ToolControl.Bounds.Width) - 40;
DescriptionMaxWidth = Math.Max(Bounds.Width, ToolControl.Bounds.Width) - 10;
Description = toolControl.BaseOperation.Description;
return false;
}, TimeSpan.FromMilliseconds(1));