- **File formats:**
   - (Add) OSF (Vlare Open File Format)
   - (Fix) CTB Encrypted: Bottom Retract Height for TSMC was constraining incorrectly with the normal total retract height
   - (Fix) CWS: Only issue `;<Slice>` command when the exposure is about to happen (#514)
- **GCode:**
   - (Add) Command `CommandWaitSyncDelay` for movement wait sync delay instead of depending on G4 wait command
   - (Fix) Wrong parsing and set of wait times when using a wait after lift / wait before retract
- (Improvement) Auto update: Make sure the download url exists before attempt the download, if not, instead it will prompt for manual download and update
- (Improvement) MacOS: Remove `com.apple.quarantine` flag from the auto downloaded files
- (Upgrade) .NET from 6.0.7 to 6.0.8
- (Upgrade) AvaloniaUI from 0.10.17 to 0.10.18
This commit is contained in:
Tiago Conceição
2022-08-17 21:23:51 +01:00
parent 247ed74aa7
commit 57f077f444
29 changed files with 965 additions and 527 deletions
+15 -1
View File
@@ -1,5 +1,19 @@
# Changelog
## 17/08/2022 - v3.6.0
- **File formats:**
- (Add) OSF (Vlare Open File Format)
- (Fix) CTB Encrypted: Bottom Retract Height for TSMC was constraining incorrectly with the normal total retract height
- (Fix) CWS: Only issue `;<Slice>` command when the exposure is about to happen (#514)
- **GCode:**
- (Add) Command `CommandWaitSyncDelay` for movement wait sync delay instead of depending on G4 wait command
- (Fix) Wrong parsing and set of wait times when using a wait after lift / wait before retract
- (Improvement) Auto update: Make sure the download url exists before attempt the download, if not, instead it will prompt for manual download and update
- (Improvement) MacOS: Remove `com.apple.quarantine` flag from the auto downloaded files
- (Upgrade) .NET from 6.0.7 to 6.0.8
- (Upgrade) AvaloniaUI from 0.10.17 to 0.10.18
## 29/07/2022 - v3.5.6
- **Tools**
@@ -7,7 +21,7 @@
- (Add) Able to choose the size midpoint rounding method (#520)
- (Fix) Allow to flash alone D03 commands (#520)
- (Fix) Correct line thickness to have at least 1px error (#523)
- (Improvement) Layer arithmetic: Use ; to split and start a new arithmetic operation
- (Improvement) Layer arithmetic: Use ; to split and start a new arithmetic operation (#519)
- (Add) Cmd: Convert command now allow to pass 'auto' as target type to auto convert specific files, valid for SL1 files configured with FILEFORMAT_xxx (#522)
- (Add) GCode: Command to sync and wait for movement completion [Only enabled for cws format] (#514)
- (Add) VDT: Transition layer count
+16 -15
View File
@@ -1,13 +1,14 @@
# UVtools
[![License](https://img.shields.io/github/license/sn4k3/UVtools?style=flat-square)](https://github.com/sn4k3/UVtools/blob/master/LICENSE)
[![GitHub repo size](https://img.shields.io/github/repo-size/sn4k3/UVtools?style=flat-square)](#)
[![Code size](https://img.shields.io/github/languages/code-size/sn4k3/UVtools?style=flat-square)](#)
[![Total code](https://img.shields.io/tokei/lines/github/sn4k3/UVtools?style=flat-square)](#)
[![Nuget](https://img.shields.io/nuget/v/UVtools.Core?style=flat-square)](https://www.nuget.org/packages/UVtools.Core)
[![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/sn4k3/UVtools?include_prereleases&style=flat-square)](https://github.com/sn4k3/UVtools/releases)
[![Downloads](https://img.shields.io/github/downloads/sn4k3/UVtools/total?style=flat-square)](https://github.com/sn4k3/UVtools/releases)
[![Chocolatey](https://img.shields.io/chocolatey/dt/uvtools?color=brown&label=Chocolatey&style=flat-square)](https://community.chocolatey.org/packages/uvtools)
[![License](https://img.shields.io/github/license/sn4k3/UVtools?style=for-the-badge)](https://github.com/sn4k3/UVtools/blob/master/LICENSE)
[![GitHub repo size](https://img.shields.io/github/repo-size/sn4k3/UVtools?style=for-the-badge)](#)
[![Code size](https://img.shields.io/github/languages/code-size/sn4k3/UVtools?style=for-the-badge)](#)
[![Total code](https://img.shields.io/tokei/lines/github/sn4k3/UVtools?style=for-the-badge)](#)
[![Nuget](https://img.shields.io/nuget/v/UVtools.Core?style=for-the-badge)](https://www.nuget.org/packages/UVtools.Core)
[![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/sn4k3/UVtools?include_prereleases&style=for-the-badge)](https://github.com/sn4k3/UVtools/releases)
[![Downloads](https://img.shields.io/github/downloads/sn4k3/UVtools/total?style=for-the-badge)](https://github.com/sn4k3/UVtools/releases)
[![Chocolatey](https://img.shields.io/chocolatey/dt/uvtools?color=brown&label=Chocolatey&style=for-the-badge)](https://community.chocolatey.org/packages/uvtools)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/sn4k3?color=red&style=for-the-badge)](https://github.com/sponsors/sn4k3)
## Download the latest version at:
https://github.com/sn4k3/UVtools/releases/latest
@@ -106,6 +107,7 @@ But also, i need victims for test subject. Proceed at your own risk!
- ZIP (Generic / Phrozen Zip)
- VDA.ZIP (Voxeldance Additive)
- VDT (Voxeldance Tango)
- OSF (Vlare Open File Format)
- UVJ (Zip file format for manual manipulation)
- Image files (png, jpg, jpeg, jp2, tif, bmp, pbm, pgm, ras, sr)
@@ -339,7 +341,7 @@ Easy to use calls that allow you work with the formats. For more information nav
Nuget package: https://www.nuget.org/packages/UVtools.Core
[![Nuget](https://img.shields.io/nuget/v/UVtools.Core?style=flat-square)](https://www.nuget.org/packages/UVtools.Core)
[![Nuget](https://img.shields.io/nuget/v/UVtools.Core?style=for-the-badge)](https://www.nuget.org/packages/UVtools.Core)
```powershell
dotnet add package UVtools.Core
@@ -376,13 +378,12 @@ The fastest way to compile the project is by run the `build/compile.bat`, howeve
# Support my work / Donate
All my work here is given for free (OpenSource), it took some hours to build, test and polish the program.
If you're happy to contribute for a better program and for my work i will appreciate the tip.
- Sponsor: https://github.com/sponsors/sn4k3
- PayPal: https://paypal.me/SkillTournament
If you're happy to contribute for a better program and for my work i will appreciate the tip.
Use one of the following methods:
[![GitHub Sponsors](https://img.shields.io/badge/Donate-Sponsor-red?style=for-the-badge)](https://github.com/sponsors/sn4k3)
[![Donate PayPal](https://img.shields.io/badge/Donate-PayPal-blue?style=for-the-badge)](https://paypal.me/SkillTournament)
# Contributors
[![GitHub contributors](https://img.shields.io/github/contributors/sn4k3/UVtools?style=for-the-badge)](https://github.com/sn4k3/UVtools/graphs/contributors)
[![Contributors](https://contrib.rocks/image?repo=sn4k3/UVtools)](https://github.com/sn4k3/UVtools/graphs/contributors)
+11 -10
View File
@@ -1,11 +1,12 @@
- **Tools**
- **PCB Exposure:**
- (Add) Able to choose the size midpoint rounding method (#520)
- (Fix) Allow to flash alone D03 commands (#520)
- (Fix) Correct line thickness to have at least 1px error (#523)
- (Improvement) Layer arithmetic: Use ; to split and start a new arithmetic operation
- (Add) Cmd: Convert command now allow to pass 'auto' as target type to auto convert specific files, valid for SL1 files configured with FILEFORMAT_xxx (#522)
- (Add) GCode: Command to sync and wait for movement completion [Only enabled for cws format] (#514)
- (Add) VDT: Transition layer count
- (Upgrade) AvaloniaUI from 0.10.16 to 0.10.17
- **File formats:**
- (Add) OSF (Vlare Open File Format)
- (Fix) CTB Encrypted: Bottom Retract Height for TSMC was constraining incorrectly with the normal total retract height
- (Fix) CWS: Only issue `;<Slice>` command when the exposure is about to happen (#514)
- **GCode:**
- (Add) Command `CommandWaitSyncDelay` for movement wait sync delay instead of depending on G4 wait command
- (Fix) Wrong parsing and set of wait times when using a wait after lift / wait before retract
- (Improvement) Auto update: Make sure the download url exists before attempt the download, if not, instead it will prompt for manual download and update
- (Improvement) MacOS: Remove `com.apple.quarantine` flag from the auto downloaded files
- (Upgrade) .NET from 6.0.7 to 6.0.8
- (Upgrade) AvaloniaUI from 0.10.17 to 0.10.18
+5 -1
View File
@@ -98,7 +98,11 @@ struct HEADER {
ushort RetractSpeedEnd <fgcolor=cBlack, bgcolor=cRed>; // 7
ubyte RetractDecelerationChange <fgcolor=cBlack, bgcolor=cRed>; // 5
ubyte Unknown[8] <fgcolor=cWhite, bgcolor=cBlack>;
ushort BottomWaitTimeAfterCureMagnified100Times <fgcolor=cBlack, bgcolor=cRed>; // s * 100
ushort BottomWaitTimeAfterLiftMagnified100Times <fgcolor=cBlack, bgcolor=cRed>; // s * 100
ushort BottomWaitTimeBeforeCureMagnified100Times <fgcolor=cBlack, bgcolor=cRed>; // s * 100
ushort Reserved <fgcolor=cWhite, bgcolor=cBlack>;
ubyte ProtocolType <fgcolor=cBlack, bgcolor=cRed>; // 0
} header;
@@ -38,7 +38,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.17" />
<PackageReference Include="Avalonia" Version="0.10.18" />
</ItemGroup>
<ItemGroup>
+106 -107
View File
@@ -10,123 +10,122 @@ using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.CompilerServices;
using Microsoft.Toolkit.HighPerformance;
using CommunityToolkit.HighPerformance;
namespace UVtools.Core.Extensions
namespace UVtools.Core.Extensions;
public static class CompressionExtensions
{
public static class CompressionExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetGzipUncompressedLength(ReadOnlyMemory<byte> compressedData)
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetGzipUncompressedLength(ReadOnlyMemory<byte> compressedData)
return BitConverter.ToInt32(compressedData.Slice(compressedData.Length - 4, 4).Span);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetGzipUncompressedLength(Stream stream)
{
Span<byte> uncompressedLength = stackalloc byte[4];
stream.Position = stream.Length - 4;
stream.Read(uncompressedLength);
stream.Seek(0, SeekOrigin.Begin);
return BitConverter.ToInt32(uncompressedLength);
}
public static MemoryStream GZipCompress(Stream inputStream, CompressionLevel compressionLevel, bool leaveStreamOpen = false)
{
if (inputStream.Position == inputStream.Length) { inputStream.Seek(0, SeekOrigin.Begin); }
var compressedStream = new MemoryStream();
using (var gzipStream = new GZipStream(compressedStream, compressionLevel, true))
{
return BitConverter.ToInt32(compressedData.Slice(compressedData.Length - 4, 4).Span);
inputStream.CopyTo(gzipStream);
}
if (!leaveStreamOpen) { inputStream.Close(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetGzipUncompressedLength(Stream stream)
{
Span<byte> uncompressedLength = stackalloc byte[4];
stream.Position = stream.Length - 4;
stream.Read(uncompressedLength);
stream.Seek(0, SeekOrigin.Begin);
return BitConverter.ToInt32(uncompressedLength);
}
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
}
public static MemoryStream GZipCompress(Stream inputStream, CompressionLevel compressionLevel, bool leaveStreamOpen = false)
{
if (inputStream.Position == inputStream.Length) { inputStream.Seek(0, SeekOrigin.Begin); }
public static MemoryStream GZipCompress(byte[] inputStream, CompressionLevel compressionLevel) =>
GZipCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
var compressedStream = new MemoryStream();
using (var gzipStream = new GZipStream(compressedStream, compressionLevel, true))
{
inputStream.CopyTo(gzipStream);
}
if (!leaveStreamOpen) { inputStream.Close(); }
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
}
public static MemoryStream GZipCompress(byte[] inputStream, CompressionLevel compressionLevel) =>
GZipCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
public static byte[] GZipCompressToBytes(byte[] inputStream, CompressionLevel compressionLevel)
{
using var ms = GZipCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
return ms.ToArray();
}
public static byte[] GZipCompressToBytes(byte[] inputStream, CompressionLevel compressionLevel)
{
using var ms = GZipCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
return ms.ToArray();
}
public static MemoryStream GZipDecompress(Stream compressedStream, bool leaveStreamOpen = false)
{
if (compressedStream.Position == compressedStream.Length) { compressedStream.Seek(0, SeekOrigin.Begin); }
public static MemoryStream GZipDecompress(Stream compressedStream, bool leaveStreamOpen = false)
{
if (compressedStream.Position == compressedStream.Length) { compressedStream.Seek(0, SeekOrigin.Begin); }
var uncompressedStream = new MemoryStream(GetGzipUncompressedLength(compressedStream));
using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress, leaveStreamOpen);
gzipStream.CopyTo(uncompressedStream);
var uncompressedStream = new MemoryStream(GetGzipUncompressedLength(compressedStream));
using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress, leaveStreamOpen);
gzipStream.CopyTo(uncompressedStream);
return uncompressedStream;
}
public static ArraySegment<byte> GZipDecompress(ReadOnlyMemory<byte> compressedData)
{
using var uncompressedStream = new MemoryStream(GetGzipUncompressedLength(compressedData));
using (var gzipStream = new GZipStream(compressedData.AsStream(), CompressionMode.Decompress, false))
{
gzipStream.CopyTo(uncompressedStream);
}
return uncompressedStream.TryGetBuffer(out var buffer)
? buffer
: uncompressedStream.ToArray();
}
public static MemoryStream DeflateCompress(Stream inputStream, CompressionLevel compressionLevel, bool leaveStreamOpen = false)
{
if (inputStream.Position == inputStream.Length) { inputStream.Seek(0, SeekOrigin.Begin); }
var compressedStream = new MemoryStream();
using (var gzipStream = new DeflateStream(compressedStream, compressionLevel, true))
{
inputStream.CopyTo(gzipStream);
}
if (!leaveStreamOpen) { inputStream.Close(); }
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
}
public static MemoryStream DeflateCompress(byte[] inputStream, CompressionLevel compressionLevel) =>
DeflateCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
public static byte[] DeflateCompressToBytes(byte[] inputStream, CompressionLevel compressionLevel)
{
using var ms = DeflateCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
return ms.ToArray();
}
public static MemoryStream DeflateDecompress(Stream compressedStream, bool leaveStreamOpen = false)
{
if (compressedStream.Position == compressedStream.Length) { compressedStream.Seek(0, SeekOrigin.Begin); }
var uncompressedStream = new MemoryStream();
using var gzipStream = new DeflateStream(compressedStream, CompressionMode.Decompress, leaveStreamOpen);
gzipStream.CopyTo(uncompressedStream);
return uncompressedStream;
}
public static ArraySegment<byte> DeflateDecompress(ReadOnlyMemory<byte> compressedData)
{
using var uncompressedStream = new MemoryStream();
using (var gzipStream = new DeflateStream(compressedData.AsStream(), CompressionMode.Decompress, false))
{
gzipStream.CopyTo(uncompressedStream);
}
return uncompressedStream.TryGetBuffer(out var buffer)
? buffer
: uncompressedStream.ToArray();
}
return uncompressedStream;
}
}
public static ArraySegment<byte> GZipDecompress(ReadOnlyMemory<byte> compressedData)
{
using var uncompressedStream = new MemoryStream(GetGzipUncompressedLength(compressedData));
using (var gzipStream = new GZipStream(compressedData.AsStream(), CompressionMode.Decompress, false))
{
gzipStream.CopyTo(uncompressedStream);
}
return uncompressedStream.TryGetBuffer(out var buffer)
? buffer
: uncompressedStream.ToArray();
}
public static MemoryStream DeflateCompress(Stream inputStream, CompressionLevel compressionLevel, bool leaveStreamOpen = false)
{
if (inputStream.Position == inputStream.Length) { inputStream.Seek(0, SeekOrigin.Begin); }
var compressedStream = new MemoryStream();
using (var gzipStream = new DeflateStream(compressedStream, compressionLevel, true))
{
inputStream.CopyTo(gzipStream);
}
if (!leaveStreamOpen) { inputStream.Close(); }
compressedStream.Seek(0, SeekOrigin.Begin);
return compressedStream;
}
public static MemoryStream DeflateCompress(byte[] inputStream, CompressionLevel compressionLevel) =>
DeflateCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
public static byte[] DeflateCompressToBytes(byte[] inputStream, CompressionLevel compressionLevel)
{
using var ms = DeflateCompress(new ReadOnlyMemory<byte>(inputStream).AsStream(), compressionLevel);
return ms.ToArray();
}
public static MemoryStream DeflateDecompress(Stream compressedStream, bool leaveStreamOpen = false)
{
if (compressedStream.Position == compressedStream.Length) { compressedStream.Seek(0, SeekOrigin.Begin); }
var uncompressedStream = new MemoryStream();
using var gzipStream = new DeflateStream(compressedStream, CompressionMode.Decompress, leaveStreamOpen);
gzipStream.CopyTo(uncompressedStream);
return uncompressedStream;
}
public static ArraySegment<byte> DeflateDecompress(ReadOnlyMemory<byte> compressedData)
{
using var uncompressedStream = new MemoryStream();
using (var gzipStream = new DeflateStream(compressedData.AsStream(), CompressionMode.Decompress, false))
{
gzipStream.CopyTo(uncompressedStream);
}
return uncompressedStream.TryGetBuffer(out var buffer)
? buffer
: uncompressedStream.ToArray();
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Toolkit.HighPerformance;
using CommunityToolkit.HighPerformance;
using UVtools.Core.EmguCV;
using UVtools.Core.Objects;
+1 -1
View File
@@ -955,7 +955,7 @@ public class CTBEncryptedFile : FileFormat
get => Settings.BottomRetractHeight2;
set
{
value = Math.Clamp((float)Math.Round(value, 2), 0, RetractHeightTotal);
value = Math.Clamp((float)Math.Round(value, 2), 0, BottomRetractHeightTotal);
base.BottomRetractHeight2 = Settings.BottomRetractHeight2 = value;
}
}
+28 -5
View File
@@ -570,23 +570,33 @@ public class CWSFile : FileFormat
{
GCode = new GCodeBuilder
{
SyncMovementsWithDelay = true,
UseComments = true,
GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Relative,
GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute,
GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds,
GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndex0Started,
GCodeShowImagePosition = GCodeBuilder.GCodeShowImagePositions.WhenRequired,
LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G1,
EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1
EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1,
CommandSyncMovements =
{
Enabled = true
},
CommandWaitSyncDelay =
{
Enabled = true,
}
};
GCode.CommandShowImageM6054.Set(";<Slice>", "{0}");
GCode.CommandWaitSyncDelay.Set(";<Delay>", "0{0}");
GCode.CommandWaitG4.Set(";<Delay>", "{0}");
GCode.CommandSyncMovements.Enabled = true;
}
#endregion
#region Methods
protected override void EncodeInternally(OperationProgress progress)
{
//var filename = fileFullPath.EndsWith(TemporaryFileAppend) ? Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(fileFullPath)) : Path.GetFileNameWithoutExtension(fileFullPath);
@@ -799,7 +809,7 @@ public class CWSFile : FileFormat
// Must discover png depth grayscale or color
if (DecodeType == FileDecodeType.Full && Printer == PrinterType.Unknown)
{
var inputFilename = Path.GetFileNameWithoutExtension(FileFullPath)!;
//var inputFilename = Path.GetFileNameWithoutExtension(FileFullPath)!;
foreach (var pngEntry in inputFile.Entries)
{
if (!pngEntry.Name.EndsWith(".png")) continue;
@@ -836,6 +846,17 @@ public class CWSFile : FileFormat
public override void RebuildGCode()
{
if (!SupportsGCode || SuppressRebuildGCode) return;
switch (Printer)
{
case PrinterType.Wanhao:
GCode!.CommandWaitSyncDelay.Command = ";<Takes>";
break;
default:
GCode!.CommandWaitSyncDelay.Command = ";<Delay>";
break;
}
//string arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits";
//GCode.Clear();
//GCode.AppendLine($"; {About.Website} {About.Software} {Assembly.GetExecutingAssembly().GetName().Version} {arch} {DateTime.UtcNow}");
@@ -981,5 +1002,7 @@ public class CWSFile : FileFormat
//Decode(FileFullPath, progress);
}
#endregion
}
+1 -1
View File
@@ -29,7 +29,7 @@ public class ChituboxFile : FileFormat
{
#region Constants
public const byte USED_VERSION = 3; // 318570521
public const byte USED_VERSION = 3;
public const uint MAGIC_CBDDLP = 0x12FD0019; // 318570521
public const uint MAGIC_CTB = 0x12FD0086; // 318570630
+32 -4
View File
@@ -384,11 +384,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
//new CXDLPv1File(), // Creality Box v1
new CXDLPFile(), // Creality Box
new LGSFile(), // LGS, LGS30
//new OSFFile(), // OSF
new FlashForgeSVGXFile(), // SVGX
new GenericZIPFile(), // Generic zip files
new VDAFile(), // VDA
new VDTFile(), // VDT
new OSFFile(), // OSF
new UVJFile(), // UVJ
new ImageFile(), // images
};
@@ -1505,9 +1505,21 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
ResolutionX = (uint) value.Width;
ResolutionY = (uint) value.Height;
RaisePropertyChanged();
RaisePropertyChanged(nameof(DisplayAspectRatio));
RaisePropertyChanged(nameof(DisplayAspectRatioStr));
RaisePropertyChanged(nameof(Xppmm));
RaisePropertyChanged(nameof(Yppmm));
RaisePropertyChanged(nameof(Ppmm));
RaisePropertyChanged(nameof(PpmmMax));
RaisePropertyChanged(nameof(PixelSizeMicrons));
RaisePropertyChanged(nameof(PixelArea));
RaisePropertyChanged(nameof(PixelAreaMicrons));
RaisePropertyChanged(nameof(PixelHeight));
RaisePropertyChanged(nameof(PixelHeightMicrons));
RaisePropertyChanged(nameof(PixelSize));
RaisePropertyChanged(nameof(PixelSizeMax));
RaisePropertyChanged(nameof(PixelWidth));
RaisePropertyChanged(nameof(PixelWidthMicrons));
}
}
@@ -1534,9 +1546,25 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
get => new(DisplayWidth, DisplayHeight);
set
{
DisplayWidth = value.Width;
DisplayHeight = value.Height;
DisplayWidth = (float)Math.Round(value.Width, 4);
DisplayHeight = (float)Math.Round(value.Height, 4);
RaisePropertyChanged();
RaisePropertyChanged(nameof(DisplayAspectRatio));
RaisePropertyChanged(nameof(DisplayAspectRatioStr));
RaisePropertyChanged(nameof(DisplayDiagonal));
RaisePropertyChanged(nameof(DisplayDiagonalInches));
RaisePropertyChanged(nameof(Xppmm));
RaisePropertyChanged(nameof(Yppmm));
RaisePropertyChanged(nameof(Ppmm));
RaisePropertyChanged(nameof(PpmmMax));
RaisePropertyChanged(nameof(PixelSizeMicrons));
RaisePropertyChanged(nameof(PixelArea));
RaisePropertyChanged(nameof(PixelAreaMicrons));
RaisePropertyChanged(nameof(PixelHeight));
RaisePropertyChanged(nameof(PixelHeightMicrons));
RaisePropertyChanged(nameof(PixelSize));
RaisePropertyChanged(nameof(PixelSizeMax));
RaisePropertyChanged(nameof(PixelWidth));
}
}
@@ -5266,7 +5294,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (differenceLayerCount > 0 && initBlack)
{
using var blackMat = EmguExtensions.InitMat(Resolution);
using var blackMat = CreateMat(false);
var pngBytes = blackMat.GetPngByes();
for (var layerIndex = oldLayerCount; layerIndex < newLayerCount; layerIndex++)
{
+6 -3
View File
@@ -327,7 +327,10 @@ public class JXSFile : FileFormat
GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.FilenamePng0Started,
LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G0,
EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G0,
SyncMovementsWithDelay = true
CommandWaitSyncDelay =
{
Enabled = true
}
};
}
#endregion
@@ -528,7 +531,7 @@ public class JXSFile : FileFormat
{
case "gcode":
lastCommand = value;
if (value.StartsWith("M106 S") && value.StartsWith("M106 S0")) GCode.AppendWaitG4(0);
if (value.StartsWith("M106 S0")) GCode.AppendWaitG4(0);
GCode.AppendLine(value);
break;
case "slice":
@@ -545,7 +548,7 @@ public class JXSFile : FileFormat
if (lastCommand.StartsWith("G0") || lastCommand.StartsWith("G1"))
{
lastCommand = $"G4 0{value}";
GCode.AppendWaitG4($"0{value}");
GCode.AppendWaitSyncDelay(value);
break;
}
GCode.AppendWaitG4(value);
+4 -4
View File
@@ -263,10 +263,10 @@ public class LGSFile : FileFormat
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
new (typeof(LGSFile), "lgs", "Longer Orange 10"),
new (typeof(LGSFile), "lgs30", "Longer Orange 30"),
new (typeof(LGSFile), "lgs120", "Longer Orange 120"),
new (typeof(LGSFile), "lgs4k", "Longer Orange 4k"),
new (typeof(LGSFile), "lgs", "Longer Orange 10 (LGS)"),
new (typeof(LGSFile), "lgs30", "Longer Orange 30 (LGS30)"),
new (typeof(LGSFile), "lgs120", "Longer Orange 120 (LGS120)"),
new (typeof(LGSFile), "lgs4k", "Longer Orange 4k (LGS4K)"),
};
public override PrintParameterModifier[]? PrintParameterModifiers { get; } =
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -248,7 +248,7 @@ public class OSLAFile : FileFormat
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
new (typeof(OSLAFile), "osla", "Open SLA universal binary file"),
new (typeof(OSLAFile), "osla", "Open SLA universal binary file (OSLA)"),
//new ("omsla", "Open mSLA universal binary file"),
//new ("odlp", "Open DLP universal binary file"),
};
+1 -1
View File
@@ -177,7 +177,7 @@ public class UVJFile : FileFormat
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
new(typeof(UVJFile), "uvj", "UVJ")
new(typeof(UVJFile), "uvj", "Vendor-neutral format (UVJ)")
};
public override PrintParameterModifier[]? PrintParameterModifiers { get; } = {
+1 -1
View File
@@ -198,7 +198,7 @@ public class VDTFile : FileFormat
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
new(typeof(VDTFile), "vdt", "Voxeldance Tango VDT")
new(typeof(VDTFile), "vdt", "Voxeldance Tango (VDT)")
};
public override PrintParameterModifier[]? PrintParameterModifiers { get; } = {
+99 -29
View File
@@ -26,6 +26,20 @@ namespace UVtools.Core.GCode;
public class GCodeBuilder : BindableBase
{
#region Events
public event EventHandler? BeforeRebuildGCode;
protected virtual void OnBeforeRebuildGCode()
{
BeforeRebuildGCode?.Invoke(this, EventArgs.Empty);
}
public event EventHandler? AfterRebuildGCode;
protected virtual void OnAfterRebuildGCode()
{
AfterRebuildGCode?.Invoke(this, EventArgs.Empty);
}
#endregion
#region Commands
public GCodeCommand CommandUnitsMillimetersG21 { get; } = new("G21", null, "Set units to be mm");
@@ -42,6 +56,7 @@ public class GCodeBuilder : BindableBase
public GCodeCommand CommandSyncMovements { get; } = new("G4", "P0", "Sync movements", false);
public GCodeCommand CommandWaitSyncDelay { get; } = new("G4", "P0{0}", "Sync movement", false);
public GCodeCommand CommandWaitG4 { get; } = new("G4", "P{0}", "Delay");
public GCodeCommand CommandShowImageM6054 = new("M6054", "\"{0}\"", "Show image");
@@ -98,6 +113,20 @@ public class GCodeBuilder : BindableBase
LayerIndex0Started,
LayerIndex1Started,
}
public enum GCodeShowImagePositions : byte
{
/// <summary>
/// Show image at start of each layer block commands
/// </summary>
FirstLine,
/// <summary>
/// Show image just before exposing / turning LED ON
/// </summary>
WhenRequired
}
#endregion
#region Members
@@ -108,13 +137,13 @@ public class GCodeBuilder : BindableBase
private GCodeTimeUnits _gCodeTimeUnit = GCodeTimeUnits.Milliseconds;
private GCodeSpeedUnits _gCodeSpeedUnit = GCodeSpeedUnits.MillimetersPerMinute;
private GCodeShowImageTypes _gCodeShowImageType = GCodeShowImageTypes.FilenamePng1Started;
private bool _syncMovementsWithDelay;
private bool _useTailComma = true;
private bool _useComments = true;
private ushort _maxLedPower = byte.MaxValue;
private uint _lineCount;
private GCodeMoveCommands _layerMoveCommand;
private GCodeMoveCommands _endGCodeMoveCommand;
private GCodeShowImagePositions _gCodeShowImagePosition = GCodeShowImagePositions.FirstLine;
#endregion
@@ -144,6 +173,12 @@ public class GCodeBuilder : BindableBase
set => RaiseAndSetIfChanged(ref _gCodeShowImageType, value);
}
public GCodeShowImagePositions GCodeShowImagePosition
{
get => _gCodeShowImagePosition;
set => RaiseAndSetIfChanged(ref _gCodeShowImagePosition, value);
}
public GCodeMoveCommands LayerMoveCommand
{
get => _layerMoveCommand;
@@ -156,12 +191,6 @@ public class GCodeBuilder : BindableBase
set => RaiseAndSetIfChanged(ref _endGCodeMoveCommand, value);
}
public bool SyncMovementsWithDelay
{
get => _syncMovementsWithDelay;
set => RaiseAndSetIfChanged(ref _syncMovementsWithDelay, value);
}
public bool UseTailComma
{
get => _useTailComma;
@@ -183,14 +212,12 @@ public class GCodeBuilder : BindableBase
public string BeginStartGCodeComments { get; set; } = ";START_GCODE_BEGIN";
public string EndStartGCodeComments { get; set; } = ";END_GCODE_BEGIN";
public string BeginLayerComments { get; set; } = ";LAYER_START:{0}" + Environment.NewLine +
";PositionZ:{1}mm";
public string BeginLayerComments { get; set; } = $";LAYER_START:{{0}}{Environment.NewLine};PositionZ:{{1}}mm";
public string EndLayerComments { get; set; } = ";LAYER_END";
public string BeginEndGCodeComments { get; set; } = ";START_GCODE_END";
public string EndEndGCodeComments { get; set; } = ";END_GCODE_END" + Environment.NewLine +
";<Completed>";
public string EndEndGCodeComments { get; set; } = $";END_GCODE_END{Environment.NewLine};<Completed>";
public uint LineCount
{
@@ -373,12 +400,12 @@ public class GCodeBuilder : BindableBase
else
AppendMoveG1(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.MaximumSpeed));
if (_syncMovementsWithDelay)
if (CommandWaitSyncDelay.Enabled)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(
finalRaiseZPositionRelative + lastLiftHeight, slicerFile.MaximumSpeed, 0.75f);
var time = ConvertFromSeconds(seconds);
if (seconds > 0) AppendWaitG4($"0{time}", "Sync movement");
if (seconds > 0) AppendWaitSyncDelay(time);
}
AppendSyncMovements();
@@ -401,11 +428,11 @@ public class GCodeBuilder : BindableBase
else
AppendMoveG1(raiseZ, feedRate);
if (_syncMovementsWithDelay)
if (CommandWaitSyncDelay.Enabled)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(absRaiseZ, rawSpeed, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
AppendWaitSyncDelay(time);
}
}
@@ -495,11 +522,11 @@ public class GCodeBuilder : BindableBase
AppendLineOverrideComment(CommandMoveG0, $"Z Lift ({i+1})", lifts[i].z, lifts[i].feedrate); // Z Lift
}
if (_syncMovementsWithDelay && layer is not null)
if (CommandWaitSyncDelay.Enabled && layer is not null)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
AppendWaitSyncDelay(time);
}
AppendSyncMovements();
@@ -517,11 +544,11 @@ public class GCodeBuilder : BindableBase
AppendLineOverrideComment(CommandMoveG0, $"Retract ({i+1})", retracts[i].z, retracts[i].feedrate);
}
if (_syncMovementsWithDelay && layer is not null)
if (CommandWaitSyncDelay.Enabled && layer is not null)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
AppendWaitSyncDelay(time);
}
AppendSyncMovements();
@@ -556,11 +583,11 @@ public class GCodeBuilder : BindableBase
AppendLineOverrideComment(CommandMoveG1, $"Z Lift ({i+1})", lifts[i].z, lifts[i].feedrate); // Z Lift
}
if (_syncMovementsWithDelay && layer is not null)
if (CommandWaitSyncDelay.Enabled && layer is not null)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
AppendWaitSyncDelay(time);
}
AppendSyncMovements();
@@ -578,11 +605,11 @@ public class GCodeBuilder : BindableBase
AppendLineOverrideComment(CommandMoveG1, $"Retract ({i+1})", retracts[i].z, retracts[i].feedrate);
}
if (_syncMovementsWithDelay && layer is not null)
if (CommandWaitSyncDelay.Enabled && layer is not null)
{
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
AppendWaitSyncDelay(time);
}
AppendSyncMovements();
@@ -601,6 +628,19 @@ public class GCodeBuilder : BindableBase
new List<(float, float)> { new(downZ, downFeedrate) },
waitAfterLift, waitAfterRetract, layer);
public void AppendWaitSyncDelay(float time, string? comment = null)
{
if (time < 0) return;
AppendLineOverrideComment(CommandWaitSyncDelay, comment, time);
}
public void AppendWaitSyncDelay(string timeStr, string? comment = null)
{
if (!float.TryParse(timeStr, out var time)) return;
if (time < 0) return;
AppendLineOverrideComment(CommandWaitSyncDelay, comment, timeStr);
}
public void AppendWaitG4(float time, string? comment = null)
{
if (time < 0) return;
@@ -668,6 +708,8 @@ public class GCodeBuilder : BindableBase
public void RebuildGCode(FileFormat slicerFile, StringBuilder? header) => RebuildGCode(slicerFile, header?.ToString());
public void RebuildGCode(FileFormat slicerFile, string? header = null)
{
OnBeforeRebuildGCode();
Clear();
AppendUVtools();
@@ -752,7 +794,10 @@ public class GCodeBuilder : BindableBase
//if (layer.CanExpose)
//{ Dont check this for compability
AppendShowImageM6054(GetShowImageString(layerIndex));
if (_gCodeShowImagePosition == GCodeShowImagePositions.FirstLine)
{
AppendShowImageM6054(GetShowImageString(layerIndex));
}
//}
if (liftHeightTotal > 0 && Layer.RoundHeight(liftHeightTotal + layer.PositionZ) > layer.PositionZ)
@@ -774,6 +819,10 @@ public class GCodeBuilder : BindableBase
}
AppendWaitG4(waitBeforeCure, "Wait before cure"); // Safer to parse if present
if (_gCodeShowImagePosition == GCodeShowImagePositions.WhenRequired && layer.CanExpose)
{
AppendShowImageM6054(GetShowImageString(layerIndex));
}
AppendExposure(exposureTime, pwmValue);
if(waitAfterCure > 0) AppendWaitG4(waitAfterCure, "Wait after cure");
@@ -784,6 +833,7 @@ public class GCodeBuilder : BindableBase
}
AppendEndGCode(slicerFile);
OnAfterRebuildGCode();
}
public void RebuildGCode(FileFormat slicerFile, object[]? configs, string separator = ":")
@@ -879,6 +929,23 @@ public class GCodeBuilder : BindableBase
Match match;
if (line[0] == ';')
{
match = Regex.Match(line, @"^;.*(layer\s+|layer:\s*|LAYER_START:\s*)(\d+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
if (match.Success && match.Groups.Count > 2 && uint.TryParse(match.Groups[2].Value, out var layerIndex))
{
if (layerIndex > slicerFile.LayerCount)
{
throw new FileLoadException(
$"GCode parser detected the layer {layerIndex}, but the file was sliced to {slicerFile.LayerCount} layers.",
slicerFile.FileFullPath);
}
layerBlock.SetLayer(true);
layerBlock.LayerIndex = layerIndex;
continue;
}
}
// Display image
if (line.StartsWith(CommandShowImageM6054.Command))
{
@@ -888,8 +955,7 @@ public class GCodeBuilder : BindableBase
if (match.Success && match.Groups.Count >= 2) // Begin new layer
{
var layerIndex = uint.Parse(match.Groups[1].Value);
if (_gCodeShowImageType is GCodeShowImageTypes.FilenamePng1Started or GCodeShowImageTypes
.LayerIndex1Started) layerIndex--;
if (_gCodeShowImageType is GCodeShowImageTypes.FilenamePng1Started or GCodeShowImageTypes.LayerIndex1Started) layerIndex--;
if (layerIndex > slicerFile.LayerCount)
{
throw new FileLoadException(
@@ -898,7 +964,11 @@ public class GCodeBuilder : BindableBase
}
// Propagate values before switch to the new layer
layerBlock.SetLayer(true);
if (_gCodeShowImagePosition == GCodeShowImagePositions.FirstLine && layerBlock.LayerIndex != layerIndex)
{
layerBlock.SetLayer(true);
}
layerBlock.LayerIndex = layerIndex;
continue;
@@ -970,12 +1040,12 @@ public class GCodeBuilder : BindableBase
RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2)
{
if (_syncMovementsWithDelay && match.Groups[1].Value.StartsWith('0')) continue; // Sync movement delay, skip
if (/*CommandWaitSyncDelay.Enabled && */match.Groups[1].Value.StartsWith('0')) continue; // Sync movement delay, skip
var waitTime = float.Parse(match.Groups[1].Value);
if (layerBlock.PositionZ.HasValue &&
layerBlock.LiftHeight.HasValue &&
//layerBlock.LiftHeight.HasValue &&
!layerBlock.RetractSpeed.HasValue) // Must be wait time after lift, if not, don't blame me!
{
layerBlock.WaitTimeAfterLift ??= 0;
+1 -1
View File
@@ -304,7 +304,7 @@ public class GCodeLayer
layer.RetractSpeed2 = RetractSpeed2 ?? SlicerFile.GetBottomOrNormalValue(layer, SlicerFile.BottomRetractSpeed2, SlicerFile.RetractSpeed2);
layer.LightPWM = LightPWM ?? 0;//SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
if (SlicerFile.GCode!.SyncMovementsWithDelay) // Dirty fix of the value
if (SlicerFile.GCode!.CommandWaitSyncDelay.Enabled) // Dirty fix of the value
{
var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer, 1.5f);
if (syncTime < layer.WaitTimeBeforeCure)
+5 -4
View File
@@ -756,12 +756,12 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat);
break;
case LayerCompressionCodec.Lz4:
mat = new Mat(SlicerFile.Resolution, DepthType.Cv8U, 1);
mat = SlicerFile.CreateMat(false);
LZ4Codec.Decode(_compressedBytes.AsSpan(), mat.GetDataByteSpan());
break;
case LayerCompressionCodec.GZip:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
mat = SlicerFile.CreateMat(false);
unsafe
{
fixed (byte* pBuffer = _compressedBytes)
@@ -777,7 +777,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
}
case LayerCompressionCodec.Deflate:
{
mat = new(SlicerFile.Resolution, DepthType.Cv8U, 1);
mat = SlicerFile.CreateMat(false);
unsafe
{
fixed (byte* pBuffer = _compressedBytes)
@@ -1619,7 +1619,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
var span = mat.GetDataByteSpan();
var target = new byte[LZ4Codec.MaximumOutputSize(span.Length)];
var encodedLength = LZ4Codec.Encode(span, target.AsSpan());
return target[..encodedLength];
Array.Resize(ref target, encodedLength);
return target;
}
case LayerCompressionCodec.GZip:
{
+9
View File
@@ -56,4 +56,13 @@ public sealed class UInt24BigEndian
{
return (int)Value;
}
public static uint operator +(UInt24BigEndian a, UInt24BigEndian b) => a.Value + b.Value;
public static uint operator -(UInt24BigEndian a, UInt24BigEndian b) => a.Value - b.Value;
public static uint operator *(UInt24BigEndian a, UInt24BigEndian b) => a.Value * b.Value;
public static uint operator /(UInt24BigEndian a, UInt24BigEndian b) => a.Value / b.Value;
}
+1 -1
View File
@@ -202,7 +202,7 @@ public class Slicer
public static uint MillimetersToLayers(float millimeters, float layerHeight) => (uint)(millimeters / layerHeight);
public static uint MillimetersToLayers(double millimeters, double layerHeight) => (uint)(millimeters / layerHeight);
public static uint MillimetersToLayers(decimal millimeters, decimal layerHeight) => (uint)(millimeters / layerHeight);
public static uint MillimetersToLayers(decimal millimeters, decimal layerHeight) => layerHeight > 0 ? (uint)(millimeters / layerHeight) : 0;
public static uint LayersToMillimeters(uint layers, float layerHeight) => (uint)(layers * layerHeight);
public static uint LayersToMillimeters(uint layers, double layerHeight) => (uint)(layers * layerHeight);
+2 -2
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.5.6</Version>
<Version>3.6.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -61,13 +61,13 @@
<ItemGroup>
<PackageReference Include="AnimatedGif" Version="1.0.5" />
<PackageReference Include="BinarySerializer" Version="8.6.2.2" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.0.0" />
<PackageReference Include="Emgu.CV" Version="4.5.5.4823" />
<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="K4os.Compression.LZ4" Version="1.2.16" />
<PackageReference Include="KdTree" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.2.0" />
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
+1 -1
View File
@@ -42,7 +42,7 @@
<RegistryValue Root="HKCR" Key="*\shell\UVtools" Value="Open with UVtools" Type="string" />
<RegistryValue Root="HKCR" Key="*\shell\UVtools" Name="Icon" Value="[INSTALLLOCATION]UVtools.exe" Type="string" />
<RegistryValue Root="HKCR" Key="*\shell\UVtools" Name="Position" Value="Top" Type="string" />
<RegistryValue Root="HKCR" Key="*\shell\UVtools" Name="AppliesTo" Value="System.FileName:&quot;*.sl1&quot; OR System.FileName:&quot;*.sl1s&quot; OR System.FileName:&quot;*.zip&quot; OR System.FileName:&quot;*.photon&quot; OR System.FileName:&quot;*.cbddlp&quot; OR System.FileName:&quot;*.ctb&quot; OR System.FileName:&quot;*.photons&quot; OR System.FileName:&quot;*.phz&quot; OR System.FileName:&quot;*.fdg&quot; OR System.FileName:&quot;*.pws&quot; OR System.FileName:&quot;*.pw0&quot; OR System.FileName:&quot;*.pwx&quot; OR System.FileName:&quot;*.dlp&quot; OR System.FileName:&quot;*.pwmx&quot; OR System.FileName:&quot;*.pwmb&quot; OR System.FileName:&quot;*.pwmo&quot; OR System.FileName:&quot;*.pwms&quot; OR System.FileName:&quot;*.pwma&quot; OR System.FileName:&quot;*.pmsq&quot; OR System.FileName:&quot;*.pm3&quot; OR System.FileName:&quot;*.pm3m&quot; OR System.FileName:&quot;*.cws&quot; OR System.FileName:&quot;*.osla&quot; OR System.FileName:&quot;*.jxs&quot; OR System.FileName:&quot;*.zcode&quot; OR System.FileName:&quot;*.zcodex&quot; OR System.FileName:&quot;*.mdlp&quot; OR System.FileName:&quot;*.gr1&quot; OR System.FileName:&quot;*.cxdlp&quot; OR System.FileName:&quot;*.lgs&quot; OR System.FileName:&quot;*.lgs30&quot; OR System.FileName:&quot;*.lgs120&quot; OR System.FileName:&quot;*.lgs4k&quot; OR System.FileName:&quot;*.svgx&quot; OR System.FileName:&quot;*.vdt&quot; OR System.FileName:&quot;*.uvj&quot; OR System.FileName:&quot;*.png&quot; OR System.FileName:&quot;*.jpg&quot; OR System.FileName:&quot;*.jpeg&quot; OR System.FileName:&quot;*.jp2&quot; OR System.FileName:&quot;*.tif&quot; OR System.FileName:&quot;*.tiff&quot; OR System.FileName:&quot;*.bmp&quot; OR System.FileName:&quot;*.pbm&quot; OR System.FileName:&quot;*.pgm&quot; OR System.FileName:&quot;*.sr&quot; OR System.FileName:&quot;*.ras&quot;" Type="string" />
<RegistryValue Root="HKCR" Key="*\shell\UVtools" Name="AppliesTo" Value="System.FileName:&quot;*.sl1&quot; OR System.FileName:&quot;*.sl1s&quot; OR System.FileName:&quot;*.zip&quot; OR System.FileName:&quot;*.photon&quot; OR System.FileName:&quot;*.cbddlp&quot; OR System.FileName:&quot;*.ctb&quot; OR System.FileName:&quot;*.photons&quot; OR System.FileName:&quot;*.phz&quot; OR System.FileName:&quot;*.fdg&quot; OR System.FileName:&quot;*.pws&quot; OR System.FileName:&quot;*.pw0&quot; OR System.FileName:&quot;*.pwx&quot; OR System.FileName:&quot;*.dlp&quot; OR System.FileName:&quot;*.pwmx&quot; OR System.FileName:&quot;*.pwmb&quot; OR System.FileName:&quot;*.pwmo&quot; OR System.FileName:&quot;*.pwms&quot; OR System.FileName:&quot;*.pwma&quot; OR System.FileName:&quot;*.pmsq&quot; OR System.FileName:&quot;*.pm3&quot; OR System.FileName:&quot;*.pm3m&quot; OR System.FileName:&quot;*.cws&quot; OR System.FileName:&quot;*.osla&quot; OR System.FileName:&quot;*.jxs&quot; OR System.FileName:&quot;*.zcode&quot; OR System.FileName:&quot;*.zcodex&quot; OR System.FileName:&quot;*.mdlp&quot; OR System.FileName:&quot;*.gr1&quot; OR System.FileName:&quot;*.cxdlp&quot; OR System.FileName:&quot;*.lgs&quot; OR System.FileName:&quot;*.lgs30&quot; OR System.FileName:&quot;*.lgs120&quot; OR System.FileName:&quot;*.lgs4k&quot; OR System.FileName:&quot;*.svgx&quot; OR System.FileName:&quot;*.vdt&quot; OR System.FileName:&quot;*.osf&quot; OR System.FileName:&quot;*.uvj&quot; OR System.FileName:&quot;*.png&quot; OR System.FileName:&quot;*.jpg&quot; OR System.FileName:&quot;*.jpeg&quot; OR System.FileName:&quot;*.jp2&quot; OR System.FileName:&quot;*.tif&quot; OR System.FileName:&quot;*.tiff&quot; OR System.FileName:&quot;*.bmp&quot; OR System.FileName:&quot;*.pbm&quot; OR System.FileName:&quot;*.pgm&quot; OR System.FileName:&quot;*.sr&quot; OR System.FileName:&quot;*.ras&quot;" Type="string" />
<RegistryKey Root="HKCR" Key="*\shell\UVtools\command" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes" />
<RegistryValue Root="HKCR" Key="*\shell\UVtools\command" Value="&quot;[INSTALLLOCATION]UVtools.exe&quot; &quot;%1&quot;" Type="string" />
</Component>
+5 -5
View File
@@ -2,7 +2,7 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ComponentRules="OneToOne"?>
<!-- SourceDir instructs IsWiX the location of the directory that contains files for this merge module -->
<?define SourceDir="..\publish\UVtools_win-x64_v3.5.6"?>
<?define SourceDir="..\publish\UVtools_win-x64_v3.6.0"?>
<Module Id="UVtools" Language="1033" Version="1.0.0.0">
<Package Id="12aaa1cf-ff06-4a02-abd5-2ac01ac4f83b" Manufacturer="PTRTECH" InstallerVersion="200" Keywords="MSLA, DLP" Description="MSLA/DLP, file analysis, repair, conversion and manipulation" InstallScope="perMachine" Platform="x64" />
<Directory Id="TARGETDIR" Name="SourceDir">
@@ -1554,11 +1554,11 @@
<Component Id="owcD2245B900E5C448485AD96FE57629D9D" Guid="D2245B90-0E5C-4484-85AD-96FE57629D9D">
<File Id="owfD2245B900E5C448485AD96FE57629D9D" Source="$(var.SourceDir)\UVtoolsCmd.runtimeconfig.json" KeyPath="yes" />
</Component>
<Component Id="owc3110926C9437495884D1A256F611E7C5" Guid="3110926C-9437-4958-84D1-A256F611E7C5">
<File Id="owf3110926C9437495884D1A256F611E7C5" Source="$(var.SourceDir)\Microsoft.Toolkit.HighPerformance.dll" KeyPath="yes" />
<Component Id="owc1AE8795C4CF24718B9BFE67B19A54931" Guid="1AE8795C-4CF2-4718-B9BF-E67B19A54931">
<File Id="owf1AE8795C4CF24718B9BFE67B19A54931" Source="$(var.SourceDir)\CommunityToolkit.HighPerformance.dll" KeyPath="yes" />
</Component>
<Component Id="owc6FEB071413A045D9BB5F9C092F36EA8A" Guid="6FEB0714-13A0-45D9-BB5F-9C092F36EA8A">
<File Id="owf6FEB071413A045D9BB5F9C092F36EA8A" Source="$(var.SourceDir)\mscordaccore_amd64_amd64_6.0.722.32202.dll" KeyPath="yes" />
<Component Id="owcFD966BCC9E7C4739A03A214ED65F3A9F" Guid="FD966BCC-9E7C-4739-A03A-214ED65F3A9F">
<File Id="owfFD966BCC9E7C4739A03A214ED65F3A9F" Source="$(var.SourceDir)\mscordaccore_amd64_amd64_6.0.822.36306.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="ProgramMenuFolder">
+33 -40
View File
@@ -1178,55 +1178,48 @@ public partial class MainWindow : WindowEx
public async void MenuNewVersionClicked()
{
var result =
await this.MessageBoxWithHeaderQuestion(
if (string.IsNullOrWhiteSpace(VersionChecker.DownloadLink))
{
var result = await this.MessageBoxWithHeaderQuestion(
$"Do you like to manually download and update {About.Software} v{About.VersionStr} to v{VersionChecker.Version}?",
"## Changelog: \n\n" +
$"{VersionChecker.Changelog}",
$"Update UVtools to v{VersionChecker.Version}?",
ButtonEnum.YesNoCancel, true);
if (result == ButtonResult.Yes)
{
SystemAware.OpenBrowser(VersionChecker.UrlLatestRelease);
}
}
else
{
var result = await this.MessageBoxWithHeaderQuestion(
$"Do you like to auto-update {About.Software} v{About.VersionStr} to v{VersionChecker.Version}?",
"Yes: Auto update \n" +
"No: Manual update \n" +
"No: Manual download and update \n" +
"Cancel: No action \n\n" +
"Changelog: \n\n" +
$"{VersionChecker.Changelog}",
"## Changelog: \n\n" +
$"{VersionChecker.Changelog}",
$"Update UVtools to v{VersionChecker.Version}?",
ButtonEnum.YesNoCancel, true);
if (result == ButtonResult.No)
{
SystemAware.OpenBrowser(VersionChecker.UrlLatestRelease);
return;
}
if (result == ButtonResult.Yes)
{
IsGUIEnabled = false;
ShowProgressWindow($"Downloading: {VersionChecker.Filename}");
await VersionChecker.AutoUpgrade(Progress);
/*var task = await Task.Factory.StartNew( () =>
switch (result)
{
try
{
VersionChecker.AutoUpgrade(Progress);
return true;
}
catch (OperationCanceledException)
{
}
catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(exception.ToString(), "Error opening the file"));
}
return false;
});
*/
IsGUIEnabled = true;
return;
case ButtonResult.No:
SystemAware.OpenBrowser(VersionChecker.UrlLatestRelease);
break;
case ButtonResult.Yes:
IsGUIEnabled = false;
ShowProgressWindow($"Downloading: {VersionChecker.Filename}");
await VersionChecker.AutoUpgrade(Progress);
IsGUIEnabled = true;
break;
}
}
}
#endregion
+28 -35
View File
@@ -16,6 +16,7 @@ using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Avalonia.Threading;
using UVtools.Core;
using UVtools.Core.Extensions;
@@ -42,15 +43,12 @@ public class AppVersionChecker : BindableBase
{
try
{
var package = File.ReadAllText(file);
var package = File.ReadAllText(file).Trim();
if (!string.IsNullOrWhiteSpace(package) && (package.EndsWith("-x64") || package.EndsWith("-arm64")))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return $"{About.Software}_{package}_v{_version}.msi";
return SystemAware.IsRunningLinuxAppImage()
? $"{About.Software}_{package}_v{_version}.AppImage"
: $"{About.Software}_{package}_v{_version}.zip";
if (OperatingSystem.IsWindows()) return $"{About.Software}_{package}_v{_version}.msi";
if (SystemAware.IsRunningLinuxAppImage()) return $"{About.Software}_{package}_v{_version}.AppImage";
return $"{About.Software}_{package}_v{_version}.zip";
}
}
catch (Exception e)
@@ -59,17 +57,17 @@ public class AppVersionChecker : BindableBase
}
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
if (OperatingSystem.IsWindows())
{
return $"{About.Software}_win-x64_v{_version}.msi";
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
if (OperatingSystem.IsLinux())
{
return SystemAware.IsRunningLinuxAppImage()
? $"{About.Software}_linux-x64_v{_version}.AppImage"
: $"{About.Software}_linux-x64_v{_version}.zip";
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
if (OperatingSystem.IsMacOS())
{
return RuntimeInformation.ProcessArchitecture is Architecture.Arm or Architecture.Arm64
? $"{About.Software}_osx-arm64_v{_version}.zip"
@@ -122,7 +120,7 @@ public class AppVersionChecker : BindableBase
public string UrlLatestRelease = $"{About.Website}/releases/latest";
public string DownloadLink => string.IsNullOrEmpty(Filename) ? null : $"{About.Website}/releases/download/v{_version}/{Filename}";
public string DownloadLink { get; private set; }
public bool HaveNewVersion => !string.IsNullOrEmpty(Version);
@@ -132,6 +130,8 @@ public class AppVersionChecker : BindableBase
{
try
{
_version = null;
DownloadLink = null;
var request = new HttpRequestMessage
{
RequestUri = new Uri(GitHubReleaseApi),
@@ -149,31 +149,23 @@ public class AppVersionChecker : BindableBase
Debug.WriteLine($"Version checker: v{About.VersionStr} <=> v{tag_name}");
Version checkVersion = new(tag_name);
Changelog = json["body"]?.ToString();
//if (string.Compare(tag_name, App.VersionStr, StringComparison.OrdinalIgnoreCase) > 0)
if (About.Version.CompareTo(checkVersion) < 0)
{
Debug.WriteLine($"New version detected: {DownloadLink}\n" +
$"{_changelog}");
Dispatcher.UIThread.InvokeAsync(() =>
var assets = json["assets"].AsArray();
Version = tag_name;
var fileName = Filename;
foreach (var asset in assets)
{
Version = tag_name;
});
if (asset["name"]!.ToString() != fileName) continue;
DownloadLink = asset["browser_download_url"]!.ToString();
break;
}
Debug.WriteLine($"New version detected: {DownloadLink}\n{_changelog}");
return true;
}
/*string htmlCode = client.DownloadString($"{About.Website}/releases");
const string searchFor = "/releases/tag/";
var startIndex = htmlCode.IndexOf(searchFor, StringComparison.InvariantCultureIgnoreCase) +
searchFor.Length;
var endIndex = htmlCode.IndexOf("\"", startIndex, StringComparison.InvariantCultureIgnoreCase);
var version = htmlCode.Substring(startIndex, endIndex - startIndex);
if (string.Compare(version, $"v{AppSettings.VersionStr}", StringComparison.OrdinalIgnoreCase) > 0)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
Version = version;;
});
return true;
}*/
}
catch (Exception e)
{
@@ -185,7 +177,7 @@ public class AppVersionChecker : BindableBase
public async Task<bool> AutoUpgrade(OperationProgress progress)
{
if (!HaveNewVersion) return false;
if (!HaveNewVersion || string.IsNullOrWhiteSpace(DownloadLink)) return false;
progress.ItemName = "Megabytes";
try
{
@@ -228,7 +220,7 @@ public class AppVersionChecker : BindableBase
Thread.Sleep(500);
SystemAware.StartProcess(newFullPath);
}
else // others
else // MacOS and generic linux (no AppImage)
{
var upgradeFolder = "UPDATED_VERSION";
var targetDir = Path.Combine(App.ApplicationPath, upgradeFolder);
@@ -249,16 +241,17 @@ public class AppVersionChecker : BindableBase
await stream.WriteLineAsync($"echo {About.Software} v{About.Version} updater script");
await stream.WriteLineAsync($"cd '{App.ApplicationPath}'");
await stream.WriteLineAsync($"killall {About.Software}");
await stream.WriteLineAsync("sleep 0.5");
await stream.WriteLineAsync("sleep 1");
//stream.WriteLine($"[ -f {About.Software} ] && {App.AppExecutableQuoted} & || dotnet {About.Software}.dll &");
if (SystemAware.IsRunningMacOSApp)
{
await stream.WriteLineAsync($"find {upgradeFolder} -print0 | xargs -0 xattr -d com.apple.quarantine");
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* ../../../");
await stream.WriteLineAsync($"open ../../../{About.Software}.app");
}
else
else // Linux generic
{
await stream.WriteLineAsync($"cp -fR {upgradeFolder}/* .");
await stream.WriteLineAsync($"if [ -f '{About.Software}' ]; then");
+9 -9
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>3.5.6</Version>
<Version>3.6.0</Version>
<Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
@@ -39,15 +39,15 @@
<NoWarn>1701;1702;</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.17" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.17" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.17" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.17" />
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="MessageBox.Avalonia" Version="2.0.2" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="5.2.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="5.2.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="5.2.0" />
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.14" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="5.3.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="5.3.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="5.3.0" />
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.17" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UVtools.AvaloniaControls\UVtools.AvaloniaControls.csproj" />
@@ -36,6 +36,7 @@
Minimum="0"
Maximum="0.200"
Increment="0.01"
FormatString="F3"
Value="{Binding LayerHeight}"/>
<TextBlock Grid.Row="0" Grid.Column="4"