- (Add) Raft relief: Tabs type - Creates tabs around the raft to easily insert a tool under it and detach the raft from build plate
- (Add) Linux AppImage binaries (You won't get them with auto-update, please download AppImage once before can use auto-update feature in the future)
- (Change) Rename "layer compression method" to "layer compression codec", please redefine the codec setting if you changed before
- (Improvement) Linux and macOS releases are now compiled, published and packed under Linux (WSL). Windows release still and must be published under windows.
This commit is contained in:
Tiago Conceição
2022-03-21 03:43:24 +00:00
parent a3f907fda8
commit a5bef99372
19 changed files with 460 additions and 167 deletions
-21
View File
@@ -1,21 +0,0 @@
name: Submit UVtools package to Windows Package Manager Community Repository
on:
release:
types: [published]
jobs:
winget:
name: Publish winget package
runs-on: windows-latest
steps:
- name: Submit package to Windows Package Manager Community Repository
run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
$installerUrl = $github.release.assets | Where-Object -Property name -match '.+win-x64.+\.msi' | Select -ExpandProperty browser_download_url -First 1
if($null -eq $installerUrl){ exit 1 }
$version = $github.release.tag_name.Replace('v', '')
if($version.Length -lt 5){ exit 2 }
.\wingetcreate.exe update PTRTECH.UVtools --version $version --urls $installerUrl --token ${{ secrets.WINGET_TOKEN }} --submit
+47
View File
@@ -0,0 +1,47 @@
name: Winget and Nuget package publish
on:
release:
types: [published]
jobs:
winget:
name: Winget - Pull request
runs-on: windows-latest
timeout-minutes: 10
steps:
- name: Submit package to Windows Package Manager Community Repository
run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
$installerUrl = $github.event.release.assets | Where-Object -Property name -match '.+win-x64.+\.msi' | Select -ExpandProperty browser_download_url -First 1
if($null -eq $installerUrl){ exit 1 }
$version = $github.event.release.tag_name.Replace('v', '')
if($version.Length -lt 5){ exit 2 }
.\wingetcreate.exe update PTRTECH.UVtools --version $version --urls $installerUrl --token ${WINGET_TOKEN} --submit
env:
WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
nuget:
name: Nuget - Publish package
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Verify commit exists in origin/main
run: |
git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
git branch --remote --contains | grep origin/main
- name: Set VERSION variable from tag
run: |
echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
echo "VERSION=${VERSION:1}" >> $GITHUB_ENV
- name: Build
run: dotnet build --configuration Release
- name: Pack
run: dotnet pack UVtools.Core --configuration Release --no-build --output .
- name: Push nuget.org
run: dotnet nuget push UVtools.Core.${VERSION}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${NUGET_TOKEN}
env:
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## 21/03/2022 - v3.1.1
- (Add) Raft relief: Tabs type - Creates tabs around the raft to easily insert a tool under it and detach the raft from build plate
- (Add) Linux AppImage binaries (You won't get them with auto-update, please download AppImage once before can use auto-update feature in the future)
- (Change) Rename "layer compression method" to "layer compression codec", please redefine the codec setting if you changed before
- (Improvement) Linux and macOS releases are now compiled, published and packed under Linux (WSL). Windows release still and must be published under windows.
## 17/03/2022 - v3.1.0
- **Benchmark:**
+1 -1
View File
@@ -71,7 +71,7 @@ public static class CoreSettings
/// <summary>
/// Gets or sets the default compression type for layers
/// </summary>
public static Layer.LayerCompressionMethod DefaultLayerCompressionMethod { get; set; } = Layer.LayerCompressionMethod.Png;
public static Layer.LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = Layer.LayerCompressionCodec.Png;
/// <summary>
/// Gets the default folder to save the settings
@@ -103,7 +103,7 @@ public static class ZipArchiveExtensions
{
//Gets the complete path for the destination file, including any
//relative paths that were in the zip file
var destFileName = Path.Combine(destinationPath, file.FullName);
var destFileName = Path.GetFullPath(Path.Combine(destinationPath, file.FullName));
var fullDestDirPath = Path.GetFullPath(destinationPath + Path.DirectorySeparatorChar);
if (!destFileName.StartsWith(fullDestDirPath)) return; // Entry is outside the target dir
+4 -4
View File
@@ -4490,16 +4490,16 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// <summary>
/// Changes the compression method of all layers to a new method
/// </summary>
/// <param name="to">The new method to change to</param>
/// <param name="newCodec">The new method to change to</param>
/// <param name="progress"></param>
public void ChangeLayersCompressionMethod(Layer.LayerCompressionMethod to, OperationProgress? progress = null)
public void ChangeLayersCompressionMethod(Layer.LayerCompressionCodec newCodec, OperationProgress? progress = null)
{
progress ??= new OperationProgress($"Changing layers compress method to {to}");
progress ??= new OperationProgress($"Changing layers compression codec to {newCodec}");
progress.Reset("Layers", LayerCount);
Parallel.ForEach(this, CoreSettings.GetParallelOptions(progress), layer =>
{
layer.CompressionMethod = to;
layer.CompressionCodec = newCodec;
progress.LockAndIncrement();
});
}
+32 -32
View File
@@ -30,7 +30,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
{
#region Enums
public enum LayerCompressionMethod : byte
public enum LayerCompressionCodec : byte
{
[Description("PNG: Compression=High Speed=Slow (Use with low RAM)")]
Png,
@@ -56,7 +56,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
#region Members
public object Mutex = new();
private LayerCompressionMethod _compressionMethod;
private LayerCompressionCodec _compressionCodec;
private byte[]? _compressedBytes;
private uint _nonZeroPixelCount;
private Rectangle _boundingRectangle = Rectangle.Empty;
@@ -593,21 +593,21 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/// <summary>
/// Gets or sets the compression method used to cache the image
/// </summary>
public LayerCompressionMethod CompressionMethod
public LayerCompressionCodec CompressionCodec
{
get => _compressionMethod;
get => _compressionCodec;
set
{
if (!HaveImage)
{
RaiseAndSetIfChanged(ref _compressionMethod, value);
RaiseAndSetIfChanged(ref _compressionCodec, value);
return;
}
// Handle conversion
if (_compressionMethod == value) return;
if (_compressionCodec == value) return;
using var mat = LayerMat;
_compressionMethod = value;
_compressionCodec = value;
_compressedBytes = CompressMat(mat, value);
RaisePropertyChanged();
}
@@ -634,7 +634,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
get
{
if (_compressedBytes is null) return null;
if (_compressionMethod == LayerCompressionMethod.Png) return _compressedBytes;
if (_compressionCodec == LayerCompressionCodec.Png) return _compressedBytes;
using var mat = LayerMat;
return mat.GetPngByes();
@@ -656,17 +656,17 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
if (!HaveImage) return null!;
Mat mat;
switch (_compressionMethod)
switch (_compressionCodec)
{
case LayerCompressionMethod.Png:
case LayerCompressionCodec.Png:
mat = new Mat();
CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat);
break;
case LayerCompressionMethod.Lz4:
case LayerCompressionCodec.Lz4:
mat = new Mat(SlicerFile.Resolution, DepthType.Cv8U, 1);
LZ4Codec.Decode(_compressedBytes.AsSpan(), mat.GetDataByteSpan());
break;
case LayerCompressionMethod.GZip:
case LayerCompressionCodec.GZip:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
var matSpan = mat.GetDataByteSpan();
@@ -683,7 +683,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
break;
}
case LayerCompressionMethod.Deflate:
case LayerCompressionCodec.Deflate:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
var matSpan = mat.GetDataByteSpan();
@@ -715,7 +715,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
{
if (value is not null)
{
CompressedBytes = CompressMat(value, _compressionMethod);
CompressedBytes = CompressMat(value, _compressionCodec);
}
GetBoundingRectangle(value, true);
@@ -815,10 +815,10 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
#region Constructor
public Layer(uint index, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null)
public Layer(uint index, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null)
{
compressionMethod ??= CoreSettings.DefaultLayerCompressionMethod;
_compressionMethod = compressionMethod.Value;
compressionMethod ??= CoreSettings.DefaultLayerCompressionCodec;
_compressionCodec = compressionMethod.Value;
SlicerFile = slicerFile;
_index = index;
@@ -828,9 +828,9 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
ResetParameters();
}
public Layer(uint index, byte[] pngBytes, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, slicerFile, compressionMethod)
public Layer(uint index, byte[] pngBytes, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(index, slicerFile, compressionMethod)
{
if (_compressionMethod == LayerCompressionMethod.Png)
if (_compressionCodec == LayerCompressionCodec.Png)
{
CompressedBytes = pngBytes;
}
@@ -844,25 +844,25 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
_isModified = false;
}
public Layer(uint index, Mat layerMat, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, slicerFile, compressionMethod)
public Layer(uint index, Mat layerMat, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(index, slicerFile, compressionMethod)
{
LayerMat = layerMat;
_isModified = false;
}
public Layer(uint index, Stream stream, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(index, stream.ToArray(), slicerFile, compressionMethod)
public Layer(uint index, Stream stream, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(index, stream.ToArray(), slicerFile, compressionMethod)
{ }
public Layer(FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, slicerFile, compressionMethod)
public Layer(FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(0, slicerFile, compressionMethod)
{ }
public Layer(byte[] pngBytes, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, pngBytes, slicerFile, compressionMethod)
public Layer(byte[] pngBytes, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(0, pngBytes, slicerFile, compressionMethod)
{ }
public Layer(Mat layerMat, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, layerMat, slicerFile, compressionMethod)
public Layer(Mat layerMat, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(0, layerMat, slicerFile, compressionMethod)
{ }
public Layer(Stream stream, FileFormat slicerFile, LayerCompressionMethod? compressionMethod = null) : this(0, stream, slicerFile, compressionMethod) { }
public Layer(Stream stream, FileFormat slicerFile, LayerCompressionCodec? compressionMethod = null) : this(0, stream, slicerFile, compressionMethod) { }
#endregion
@@ -1504,20 +1504,20 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
return clonedLayers;
}
public static byte[] CompressMat(Mat mat, LayerCompressionMethod method)
public static byte[] CompressMat(Mat mat, LayerCompressionCodec codec)
{
switch (method)
switch (codec)
{
case LayerCompressionMethod.Png:
case LayerCompressionCodec.Png:
return mat.GetPngByes();
case LayerCompressionMethod.Lz4:
case LayerCompressionCodec.Lz4:
{
var span = mat.GetDataByteSpan();
var target = new byte[LZ4Codec.MaximumOutputSize(span.Length)];
var encodedLength = LZ4Codec.Encode(span, target.AsSpan());
return target[..encodedLength];
}
case LayerCompressionMethod.GZip:
case LayerCompressionCodec.GZip:
{
/*var matSpan = mat.GetDataByteSpan();
var compressedBytes = new byte[matSpan.Length];
@@ -1537,7 +1537,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
gZipStream.Write(mat.GetDataByteSpan());
return compressedStream.ToArray();
}
case LayerCompressionMethod.Deflate:
case LayerCompressionCodec.Deflate:
{
using var compressedStream = new MemoryStream();
using var deflateStream = new DeflateStream(compressedStream, CompressionLevel.Fastest);
@@ -1547,7 +1547,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
/*case LayerCompressionMethod.None:
return mat.GetBytes();*/
default:
throw new ArgumentOutOfRangeException(nameof(method));
throw new ArgumentOutOfRangeException(nameof(codec));
}
}
+174 -9
View File
@@ -10,8 +10,12 @@ using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV.Util;
using UVtools.Core.EmguCV;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
@@ -23,9 +27,17 @@ public class OperationRaftRelief : Operation
#region Enums
public enum RaftReliefTypes : byte
{
[Description("Relief: Drill raft to relief pressure and remove some mass")]
Relief,
[Description("Dimming: Darkens the raft to cure it less")]
Dimming,
Decimate
[Description("Decimate: Remove the raft and keep supports only on the plate")]
Decimate,
[Description("Tabs: Creates tabs around the raft to easily insert a tool under it and detach the raft from build plate")]
Tabs
}
#endregion
@@ -38,6 +50,9 @@ public class OperationRaftRelief : Operation
private byte _wallMargin = 40; // +/- 2mm
private byte _holeDiameter = 80; // +/- 4mm
private byte _holeSpacing = 40; // +/- 2mm
private byte _tabBrightness = byte.MaxValue;
private ushort _tabTriangleBase = 200;
private ushort _tabTriangleHeight = 250;
#endregion
@@ -57,7 +72,20 @@ public class OperationRaftRelief : Operation
public override Enumerations.LayerRangeSelection StartLayerRangeSelection =>
Enumerations.LayerRangeSelection.None;
public override string? ValidateInternally()
{
var sb = new StringBuilder();
if (_reliefType == RaftReliefTypes.Tabs)
{
if(_tabTriangleHeight == 0) sb.AppendLine("The tab height can't be 0");
if(_tabTriangleBase == 0) sb.AppendLine("The tab base can't be 0");
if(_tabBrightness == 0) sb.AppendLine("The tab brightness can't be 0");
}
return sb.ToString();
}
public override string ToString()
{
var result = $"[{_reliefType}] [Mask layer: {_maskLayerIndex}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
@@ -75,8 +103,6 @@ public class OperationRaftRelief : Operation
#endregion
#region Properties
public static Array RaftReliefItems => Enum.GetValues(typeof(RaftReliefTypes));
public RaftReliefTypes ReliefType
{
get => _reliefType;
@@ -86,12 +112,15 @@ public class OperationRaftRelief : Operation
RaisePropertyChanged(nameof(IsRelief));
RaisePropertyChanged(nameof(IsDimming));
RaisePropertyChanged(nameof(IsDecimate));
RaisePropertyChanged(nameof(IsTabs));
RaisePropertyChanged(nameof(BrightnessPercent));
}
}
public bool IsRelief => _reliefType == RaftReliefTypes.Relief;
public bool IsDimming => _reliefType == RaftReliefTypes.Dimming;
public bool IsDecimate => _reliefType == RaftReliefTypes.Decimate;
public bool IsTabs => _reliefType == RaftReliefTypes.Tabs;
public uint MaskLayerIndex
{
@@ -115,7 +144,7 @@ public class OperationRaftRelief : Operation
}
}
public decimal BrightnessPercent => Math.Round(_brightness * 100 / 255M, 2);
public decimal BrightnessPercent => Math.Round((_reliefType == RaftReliefTypes.Tabs ? _tabBrightness : _brightness) * 100 / 255M, 2);
public byte DilateIterations
{
@@ -140,13 +169,36 @@ public class OperationRaftRelief : Operation
get => _holeSpacing;
set => RaiseAndSetIfChanged(ref _holeSpacing, value);
}
public byte TabBrightness
{
get => _tabBrightness;
set => RaiseAndSetIfChanged(ref _tabBrightness, Math.Max((byte)1, value));
}
public ushort TabTriangleBase
{
get => _tabTriangleBase;
set => RaiseAndSetIfChanged(ref _tabTriangleBase, Math.Max((ushort)5, value));
}
public ushort TabTriangleHeight
{
get => _tabTriangleHeight;
set
{
if (!RaiseAndSetIfChanged(ref _tabTriangleHeight, Math.Max((ushort)5, value))) return;
RaisePropertyChanged(nameof(BrightnessPercent));
}
}
#endregion
#region Equality
protected bool Equals(OperationRaftRelief other)
{
return _reliefType == other._reliefType && _maskLayerIndex == other._maskLayerIndex && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing;
return _reliefType == other._reliefType && _maskLayerIndex == other._maskLayerIndex && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing && _tabTriangleBase == other._tabTriangleBase && _tabTriangleHeight == other._tabTriangleHeight;
}
public override bool Equals(object? obj)
@@ -159,7 +211,18 @@ public class OperationRaftRelief : Operation
public override int GetHashCode()
{
return HashCode.Combine((int) _reliefType, _maskLayerIndex, _ignoreFirstLayers, _brightness, _dilateIterations, _wallMargin, _holeDiameter, _holeSpacing);
var hashCode = new HashCode();
hashCode.Add((int) _reliefType);
hashCode.Add(_maskLayerIndex);
hashCode.Add(_ignoreFirstLayers);
hashCode.Add(_brightness);
hashCode.Add(_dilateIterations);
hashCode.Add(_wallMargin);
hashCode.Add(_holeDiameter);
hashCode.Add(_holeSpacing);
hashCode.Add(_tabTriangleBase);
hashCode.Add(_tabTriangleHeight);
return hashCode.ToHashCode();
}
#endregion
@@ -176,7 +239,6 @@ public class OperationRaftRelief : Operation
var anchor = new Point(-1, -1);
var kernel = EmguExtensions.Kernel3x3Rectangle;
uint firstSupportLayerIndex = _maskLayerIndex;
if (firstSupportLayerIndex <= 0)
{
@@ -185,13 +247,13 @@ public class OperationRaftRelief : Operation
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
{
progress.ThrowIfCancellationRequested();
progress++;
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200);
if (circles.Length >= minSupportsRequired) break;
supportsMat.Dispose();
supportsMat = null;
progress++;
}
}
else
@@ -265,6 +327,109 @@ public class OperationRaftRelief : Operation
case RaftReliefTypes.Decimate:
supportsMat.CopyTo(target);
break;
case RaftReliefTypes.Tabs:
{
using var contours = mat.FindContours(RetrType.External);
var span = mat.GetDataByteSpan();
var minX = 10;
var maxX = mat.Size.Width - 10;
var minY = 10;
var maxY = mat.Size.Height - 10;
var triangleBaseRadius = _tabTriangleBase / 2;
var triangleHeightRadius = _tabTriangleHeight / 2;
var directions = new[]
{
new Point(0, -1), // Up
new Point(1, 0), // Right
new Point(0, 1), // Down
new Point(-1, 0), // Left
};
var color = new MCvScalar(_tabBrightness);
for (var i = 0; i < contours.Size; i++)
{
using var contour = new EmguContour(contours[i]);
if(contour.Centroid.IsAnyNegative() || contour.Area < 10000) continue;
for (var dir = 0; dir < directions.Length; dir++)
{
var direction = directions[dir];
var foundFirstWhite = false;
var foundPoint = false;
var x = contour.Centroid.X;
var y = contour.Centroid.Y;
while (!foundPoint
&& x >= minX && x <= maxX && y >= minY && y <= maxY
&& contour.Bounds.Contains(x, y))
{
var pixel = span[mat.GetPixelPos(x, y)];
if (pixel > 0)
{
if (!foundFirstWhite)
{
foundFirstWhite = true;
continue;
}
if (CvInvoke.PointPolygonTest(contours[i], new PointF(x, y), false) == 0) // Must be on edge
{
foundPoint = true;
break;
}
}
x += direction.X;
y += direction.Y;
}
if(!foundPoint) continue;
var polygon = new Point[3];
switch (dir)
{
case 0: // Up
polygon[0] = new Point(Math.Max(10, x - triangleBaseRadius), y);
polygon[1] = new Point(Math.Min(mat.Width - 10, x + triangleBaseRadius), y);
polygon[2] = new Point(x, Math.Max(10, y - triangleHeightRadius));
break;
case 1: // Right
polygon[0] = new Point(x, Math.Max(10, y - triangleBaseRadius));
polygon[1] = new Point(x, Math.Min(mat.Width - 10, y + triangleBaseRadius));
polygon[2] = new Point(Math.Min(mat.Width - 10, x + triangleHeightRadius), y);
break;
case 2: // Down
polygon[0] = new Point(Math.Max(10, x - triangleBaseRadius), y);
polygon[1] = new Point(Math.Min(mat.Width - 10, x + triangleBaseRadius), y);
polygon[2] = new Point(x, Math.Min(mat.Height - 10, y + triangleHeightRadius));
break;
case 3: // Left
polygon[0] = new Point(x, Math.Max(10, y - triangleBaseRadius));
polygon[1] = new Point(x, Math.Min(mat.Width - 10, y + triangleBaseRadius));
polygon[2] = new Point(Math.Max(10, x - triangleHeightRadius), y);
break;
}
CvInvoke.Ellipse(mat, new Point(x, y), new Size(triangleBaseRadius, (int)(triangleBaseRadius / 1.5)), 90 * dir, 0, 180, EmguExtensions.WhiteColor, -1, LineType.AntiAlias);
using var vec = new VectorOfPoint(polygon);
CvInvoke.FillPoly(mat, vec, color, LineType.AntiAlias);
}
}
break;
}
default:
throw new ArgumentOutOfRangeException(nameof(ReliefType));
}
ApplyMask(original, target);
+21
View File
@@ -271,4 +271,25 @@ public static class SystemAware
return stringBuilder.ToString();
}
/// <summary>
/// Gets if is running under Linux and under AppImage format
/// </summary>
public static bool IsRunningLinuxAppImage(out string? path)
{
path = null;
if (!OperatingSystem.IsLinux()) return false;
path = Environment.GetEnvironmentVariable("APPIMAGE");
return !string.IsNullOrWhiteSpace(path);
}
/// <summary>
/// Gets if is running under Linux and under AppImage format
/// </summary>
/// <returns></returns>
public static bool IsRunningLinuxAppImage() => IsRunningLinuxAppImage(out _);
/// <summary>
/// Gets if is running under MacOS and under app format
/// </summary>
public static bool IsRunningMacOSApp => OperatingSystem.IsMacOS() && AppContext.BaseDirectory.EndsWith(".app/Contents/MacOS");
}
+1 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>3.1.0</Version>
<Version>3.1.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -15,8 +15,8 @@
<ComboBox Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Stretch"
SelectedItem="{Binding Operation.ReliefType}"
Items="{Binding Operation.RaftReliefItems}"/>
Items="{Binding Operation.ReliefType, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Operation.ReliefType, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
<TextBlock
Grid.Row="2"
@@ -65,49 +65,99 @@ you must manually input the layer index of the last raft where it ends and suppo
Classes="ValueLabel ValueLabel_sun"
Minimum="0"
Maximum="255"
IsVisible="{Binding !Operation.IsDecimate}"
Value="{Binding Operation.Brightness}"/>
<TextBlock
Grid.Row="6" Grid.Column="4"
IsVisible="{Binding !Operation.IsDecimate}"
Text="{Binding Operation.BrightnessPercent, StringFormat=\{0:F2\}%}" VerticalAlignment="Center"/>
Value="{Binding Operation.Brightness}">
<NumericUpDown.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="Operation.IsRelief"/>
<Binding Path="Operation.IsDimming"/>
</MultiBinding>
</NumericUpDown.IsVisible>
</NumericUpDown>
<NumericUpDown Grid.Row="6" Grid.Column="2"
Classes="ValueLabel ValueLabel_sun"
Minimum="0"
Maximum="255"
IsVisible="{Binding Operation.IsTabs}"
Value="{Binding Operation.TabBrightness}"/>
<TextBlock Grid.Row="6" Grid.Column="4"
IsVisible="{Binding !Operation.IsDecimate}"
Text="{Binding Operation.BrightnessPercent, StringFormat=\{0:F2\}%}" VerticalAlignment="Center"/>
<TextBlock
Grid.Row="8" Grid.Column="0"
IsVisible="{Binding !Operation.IsDecimate}"
Text="Supports margin:" VerticalAlignment="Center"/>
<TextBlock Grid.Row="8" Grid.Column="0"
Text="Supports margin:" VerticalAlignment="Center">
<TextBlock.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="Operation.IsRelief"/>
<Binding Path="Operation.IsDimming"/>
</MultiBinding>
</TextBlock.IsVisible>
</TextBlock>
<TextBlock
Grid.Row="8" Grid.Column="0"
IsVisible="{Binding Operation.IsDecimate}"
ToolTip.Tip="Raft will be replaced by the present supports and then dilated by this value to thicken the supports and increase the adhesion.
<TextBlock Grid.Row="8" Grid.Column="0"
IsVisible="{Binding Operation.IsDecimate}"
ToolTip.Tip="Raft will be replaced by the present supports and then dilated by this value to thicken the supports and increase the adhesion.
&#x0a;Use large numbers with tiny supports for best adhesion."
Text="Dilate supports by:" VerticalAlignment="Center"/>
Text="Dilate supports by:" VerticalAlignment="Center"/>
<TextBlock Grid.Row="8" Grid.Column="0"
IsVisible="{Binding Operation.IsTabs}"
Text="Tab triangle base:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="8" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
Minimum="0"
Maximum="255"
Value="{Binding Operation.DilateIterations}"/>
Minimum="0"
Maximum="255"
IsVisible="{Binding !Operation.IsTabs}"
Value="{Binding Operation.DilateIterations}"/>
<TextBlock
Grid.Row="10" Grid.Column="0"
Text="Wall margin:" VerticalAlignment="Center"
IsVisible="{Binding !Operation.IsDecimate}"
/>
<NumericUpDown Grid.Row="8" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
Minimum="5"
Maximum="65535"
IsVisible="{Binding Operation.IsTabs}"
Value="{Binding Operation.TabTriangleBase}"/>
<TextBlock Grid.Row="10" Grid.Column="0"
Text="Wall margin:" VerticalAlignment="Center">
<TextBlock.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="Operation.IsRelief"/>
<Binding Path="Operation.IsDimming"/>
</MultiBinding>
</TextBlock.IsVisible>
</TextBlock>
<TextBlock Grid.Row="10" Grid.Column="0"
IsVisible="{Binding Operation.IsTabs}"
Text="Tab triangle height:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="10" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
Minimum="1"
Maximum="255"
Value="{Binding Operation.WallMargin}"
IsVisible="{Binding !Operation.IsDecimate}"/>
Value="{Binding Operation.WallMargin}">
<NumericUpDown.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="Operation.IsRelief"/>
<Binding Path="Operation.IsDimming"/>
</MultiBinding>
</NumericUpDown.IsVisible>
</NumericUpDown>
<TextBlock
Grid.Row="12"
<NumericUpDown Grid.Row="10" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
Minimum="5"
Maximum="65535"
IsVisible="{Binding Operation.IsTabs}"
Value="{Binding Operation.TabTriangleHeight}"/>
<TextBlock Grid.Row="12" Grid.Column="0"
Text="Hole diameter:" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"/>
@@ -121,8 +171,7 @@ you must manually input the layer index of the last raft where it ends and suppo
<TextBlock
Grid.Row="14" Grid.Column="0"
Text="Hole spacing:" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"
/>
IsVisible="{Binding Operation.IsRelief}"/>
<NumericUpDown Grid.Row="14" Grid.Column="2"
Classes="ValueLabel ValueLabel_px"
+4 -4
View File
@@ -1163,7 +1163,7 @@ public partial class MainWindow : WindowEx
public async void MenuFileSettingsClicked()
{
var oldTheme = Settings.General.Theme;
var oldLayerCompressionMethod = Settings.General.LayerCompressionMethod;
var oldLayerCompressionCodec = Settings.General.LayerCompressionCodec;
var settingsWindow = new SettingsWindow();
await settingsWindow.ShowDialog(this);
if (settingsWindow.DialogResult == DialogResults.OK)
@@ -1173,16 +1173,16 @@ public partial class MainWindow : WindowEx
App.ApplyTheme();
}
if (oldLayerCompressionMethod != Settings.General.LayerCompressionMethod)
if (oldLayerCompressionCodec != Settings.General.LayerCompressionCodec)
{
IsGUIEnabled = false;
ShowProgressWindow($"Changing layer compression method from {oldLayerCompressionMethod.ToString().ToUpper()} to {Settings.General.LayerCompressionMethod.ToString().ToUpper()}");
ShowProgressWindow($"Changing layers compression codec from {oldLayerCompressionCodec.ToString().ToUpper()} to {Settings.General.LayerCompressionCodec.ToString().ToUpper()}");
await Task.Factory.StartNew(() =>
{
try
{
SlicerFile.ChangeLayersCompressionMethod(Settings.General.LayerCompressionMethod, Progress);
SlicerFile.ChangeLayersCompressionMethod(Settings.General.LayerCompressionCodec, Progress);
return true;
}
catch (OperationCanceledException)
+1
View File
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.ExceptionServices;
using Avalonia;
using Projektanker.Icons.Avalonia;
+70 -47
View File
@@ -13,6 +13,7 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Avalonia.Threading;
using UVtools.Core;
@@ -43,7 +44,9 @@ public class AppVersionChecker : BindableBase
var package = File.ReadAllText(file);
if (!string.IsNullOrWhiteSpace(package) && (package.EndsWith("-x64") || package.EndsWith("-arm64")))
{
return $"{About.Software}_{package}_v{_version}.zip";
return SystemAware.IsRunningLinuxAppImage()
? $"{About.Software}_{package}_v{_version}.AppImage"
: $"{About.Software}_{package}_v{_version}.zip";
}
}
catch (Exception e)
@@ -58,20 +61,22 @@ public class AppVersionChecker : BindableBase
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return $"{About.Software}_linux-x64_v{_version}.zip";
return SystemAware.IsRunningLinuxAppImage()
? $"{About.Software}_linux-x64_v{_version}.AppImage"
: $"{About.Software}_linux-x64_v{_version}.zip";
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
if (RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64) return $"{About.Software}_osx-arm64_v{_version}.zip";
return $"{About.Software}_osx-x64_v{_version}.zip";
return RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64
? $"{About.Software}_osx-arm64_v{_version}.zip"
: $"{About.Software}_osx-x64_v{_version}.zip";
}
return $"{About.Software}_universal-x86-x64_v{_version}.zip";
}
}
public string Runtime
/*public string Runtime
{
get
{
@@ -90,7 +95,7 @@ public class AppVersionChecker : BindableBase
return "universal-x86-x64";
}
}
}*/
public string Version
{
@@ -180,8 +185,9 @@ public class AppVersionChecker : BindableBase
progress.ItemName = "Megabytes";
try
{
var downloadFilename = Filename;
var path = Path.GetTempPath();
DownloadedFile = Path.Combine(path, Filename);
DownloadedFile = Path.Combine(path, downloadFilename);
Debug.WriteLine($"Downloading to: {DownloadedFile}");
progress.ItemName = "Megabytes";
@@ -203,53 +209,70 @@ public class AppVersionChecker : BindableBase
}
else
{
string upgradeFolder = "UPDATED_VERSION";
var targetDir = Path.Combine(App.ApplicationPath, upgradeFolder);
await using (var stream = File.Open(DownloadedFile, FileMode.Open))
// Linux AppImage
if (downloadFilename.EndsWith(".AppImage") && SystemAware.IsRunningLinuxAppImage(out var appImagePath))
{
using ZipArchive zip = new(stream, ZipArchiveMode.Read);
zip.ExtractToDirectory(targetDir, true);
var directory = Path.GetDirectoryName(appImagePath);
var oldFileName = Path.GetFileName(appImagePath);
// Try to keep same filename logic if user renamed the file, like UVtools.AppImage would keep same same
var newFilename = Regex.Replace(oldFileName, @"v\d.\d.\d", $"v{_version}");
var newFullPath = Path.Combine(directory, newFilename);
if (File.Exists(appImagePath)) File.Delete(appImagePath);
File.Move(DownloadedFile, newFullPath, true);
SystemAware.StartProcess("chmod", $"a+x \"{newFullPath}\"");
SystemAware.StartProcess(newFullPath);
}
File.Delete(DownloadedFile);
string upgradeFileName = $"{About.Software}_upgrade.sh";
var upgradeFile = Path.Combine(App.ApplicationPath, upgradeFileName);
await using (var stream = File.CreateText(upgradeFile))
else // others
{
await stream.WriteLineAsync("#!/bin/bash");
await stream.WriteLineAsync($"echo {About.Software} v{App.Version} updater script");
await stream.WriteLineAsync($"cd '{App.ApplicationPath}'");
await stream.WriteLineAsync($"killall {About.Software}");
await stream.WriteLineAsync("sleep 0.5");
//stream.WriteLine($"[ -f {About.Software} ] && {App.AppExecutableQuoted} & || dotnet {About.Software}.dll &");
if (OperatingSystem.IsMacOS() && App.ApplicationPath.EndsWith(".app/Contents/MacOS"))
var upgradeFolder = "UPDATED_VERSION";
var targetDir = Path.Combine(App.ApplicationPath, upgradeFolder);
await using (var stream = File.Open(DownloadedFile, FileMode.Open))
{
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* ../../../");
await stream.WriteLineAsync($"open ../../../{About.Software}.app");
}
else
{
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* .");
await stream.WriteLineAsync($"if [ -f '{About.Software}' ]; then");
await stream.WriteLineAsync($" ./{About.Software} &");
await stream.WriteLineAsync("else");
await stream.WriteLineAsync($" dotnet {About.Software}.dll &");
await stream.WriteLineAsync("fi");
using ZipArchive zip = new(stream, ZipArchiveMode.Read);
zip.ExtractToDirectory(targetDir, true);
}
await stream.WriteLineAsync($"rm -fr {upgradeFolder}");
await stream.WriteLineAsync("sleep 0.5");
await stream.WriteLineAsync($"rm -f {upgradeFileName}");
//stream.WriteLine("exit");
stream.Close();
File.Delete(DownloadedFile);
var upgradeFileName = $"{About.Software}_upgrade.sh";
var upgradeFile = Path.Combine(App.ApplicationPath, upgradeFileName);
await using (var stream = File.CreateText(upgradeFile))
{
stream.NewLine = "\n";
await stream.WriteLineAsync("#!/bin/bash");
await stream.WriteLineAsync($"echo {About.Software} v{App.Version} updater script");
await stream.WriteLineAsync($"cd '{App.ApplicationPath}'");
await stream.WriteLineAsync($"killall {About.Software}");
await stream.WriteLineAsync("sleep 0.5");
//stream.WriteLine($"[ -f {About.Software} ] && {App.AppExecutableQuoted} & || dotnet {About.Software}.dll &");
if (SystemAware.IsRunningMacOSApp)
{
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* ../../../");
await stream.WriteLineAsync($"open ../../../{About.Software}.app");
}
else
{
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* .");
await stream.WriteLineAsync($"if [ -f '{About.Software}' ]; then");
await stream.WriteLineAsync($" ./{About.Software} &");
await stream.WriteLineAsync("else");
await stream.WriteLineAsync($" dotnet {About.Software}.dll &");
await stream.WriteLineAsync("fi");
}
await stream.WriteLineAsync($"rm -fr {upgradeFolder}");
await stream.WriteLineAsync("sleep 0.5");
await stream.WriteLineAsync($"rm -f {upgradeFileName}");
//stream.WriteLine("exit");
}
SystemAware.StartProcess("bash", $"\"{upgradeFile}\"");
//App.NewInstance(App.MainWindow.SlicerFile?.FileFullPath);
}
SystemAware.StartProcess("bash", $"\"{upgradeFile}\"");
//App.NewInstance(App.MainWindow.SlicerFile?.FileFullPath);
Environment.Exit(0);
}
}
+2 -1
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>3.1.0</Version>
<Version>3.1.1</Version>
<Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
@@ -43,6 +43,7 @@
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.13" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.13" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.13" />
<PackageReference Include="Emgu.CV.runtime.ubuntu.20.04-x64" Version="4.5.4.4788" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
<PackageReference Include="MessageBox.Avalonia" Version="2.0.0" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="4.2.1" />
+6 -6
View File
@@ -43,7 +43,7 @@ public sealed class UserSettings : BindableBase
private bool _loadDemoFileOnStartup = true;
private bool _loadLastRecentFileOnStartup;
private int _maxDegreeOfParallelism = -1;
private Layer.LayerCompressionMethod _layerCompressionMethod = CoreSettings.DefaultLayerCompressionMethod;
private Layer.LayerCompressionCodec _layerCompressionCodec = CoreSettings.DefaultLayerCompressionCodec;
private bool _windowsCanResize;
private bool _windowsTakeIntoAccountScreenScaling = true;
@@ -102,10 +102,10 @@ public sealed class UserSettings : BindableBase
set => RaiseAndSetIfChanged(ref _maxDegreeOfParallelism, Math.Min(value, Environment.ProcessorCount));
}
public Layer.LayerCompressionMethod LayerCompressionMethod
public Layer.LayerCompressionCodec LayerCompressionCodec
{
get => _layerCompressionMethod;
set => RaiseAndSetIfChanged(ref _layerCompressionMethod, value);
get => _layerCompressionCodec;
set => RaiseAndSetIfChanged(ref _layerCompressionCodec, value);
}
public bool WindowsCanResize
@@ -1641,7 +1641,7 @@ public sealed class UserSettings : BindableBase
}
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
CoreSettings.DefaultLayerCompressionCodec = _instance.General.LayerCompressionCodec;
if (_instance.Network.RemotePrinters.Count == 0)
{
@@ -1864,7 +1864,7 @@ public sealed class UserSettings : BindableBase
Instance.SavesCount++;
_instance.ModifiedDateTime = DateTime.Now;
CoreSettings.MaxDegreeOfParallelism = _instance.General.MaxDegreeOfParallelism;
CoreSettings.DefaultLayerCompressionMethod = _instance.General.LayerCompressionMethod;
CoreSettings.DefaultLayerCompressionCodec = _instance.General.LayerCompressionCodec;
try
{
XmlExtensions.SerializeToFile(_instance, FilePath, XmlExtensions.SettingsIndent);
+4 -4
View File
@@ -526,7 +526,7 @@ public class BenchmarkWindow : WindowEx
public void TestPNGCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Png);
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Png);
}
public void TestPNGDecompress(BenchmarkResolution resolution)
@@ -534,7 +534,7 @@ public class BenchmarkWindow : WindowEx
public void TestGZipCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.GZip);
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.GZip);
}
public void TestGZipDecompress(BenchmarkResolution resolution)
@@ -542,7 +542,7 @@ public class BenchmarkWindow : WindowEx
public void TestDeflateCompress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Deflate);
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Deflate);
}
public void TestDeflateDecompress(BenchmarkResolution resolution)
@@ -550,7 +550,7 @@ public class BenchmarkWindow : WindowEx
public void TestLZ4Compress(BenchmarkResolution resolution)
{
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionMethod.Lz4);
Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Lz4);
}
public void TestLZ4Decompress(BenchmarkResolution resolution)
+4 -4
View File
@@ -126,15 +126,15 @@
<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
ToolTip.Tip="Sets the compression method used to store layer image cache.
ToolTip.Tip="Sets the compression codec used to store the layer image cache.
&#x0a;The selected method will impact RAM usage and operations speed."
Text="Layer compression:"/>
Text="Layer compression codec:"/>
<ComboBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="17"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Items="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Settings.General.LayerCompressionMethod, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
Items="{Binding Settings.General.LayerCompressionCodec, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Settings.General.LayerCompressionCodec, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
</Grid>
</StackPanel>
+1 -1
View File
@@ -178,7 +178,7 @@ Set-Location $PSScriptRoot\..
### Configuration ###
####################################
$enableMSI = $true
$buildOnly = 'win-x64'
#$buildOnly = 'win-x64'
#$buildOnly = 'linux-x64'
#$buildOnly = 'osx-x64'
#$buildOnly = 'osx-arm64'