Skip to content

Commit

Permalink
v4.0.6
Browse files Browse the repository at this point in the history
- (Add) Setting: Automations - Restrict the file name to valid ASCII characters (Default: Off)
- (Add) New check when opening a file that verify if the file name have invalid characters and prompt for rename based on the above introduced setting
- (Add) Rename file: Add a option to allow only ASCII characters on the file name
- (Improvement) LZ4 layer compression by reusing pools of memory buffers, this relief the LOH allocations and improves the overall performance
- (Fix) Phased Exposures: Disallow AnyCubic file formats from run the tool
  • Loading branch information
sn4k3 committed Dec 24, 2023
1 parent 1391412 commit b335f28
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 85 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 24/12/2023 - v4.0.6

- (Add) Setting: Automations - Restrict the file name to valid ASCII characters (Default: Off)
- (Add) New check when opening a file that verify if the file name have invalid characters and prompt for rename based on the above introduced setting
- (Add) Rename file: Add a option to allow only ASCII characters on the file name
- (Improvement) LZ4 layer compression by reusing pools of memory buffers, this relief the LOH allocations and improves the overall performance
- (Fix) Phased Exposures: Disallow AnyCubic file formats from run the tool

## 12/12/2023 - v4.0.5

- (Add) Tool - Phased Exposure: Replace "Double Exposure" with "Phased Exposure" tool, same effect but allow to define more steps (#778)
Expand Down
4 changes: 2 additions & 2 deletions UVtools.Core/Extensions/CompressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ public static int GetGzipUncompressedLength(ReadOnlyMemory<byte> compressedData)
public static int GetGzipUncompressedLength(Stream stream)
{
Span<byte> uncompressedLength = stackalloc byte[4];
stream.Position = stream.Length - 4;
stream.Seek(-4, SeekOrigin.End);
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); }
if (inputStream.Position == inputStream.Length) inputStream.Seek(0, SeekOrigin.Begin);

var compressedStream = new MemoryStream();
using (var gzipStream = new GZipStream(compressedStream, compressionLevel, true))
Expand Down
44 changes: 44 additions & 0 deletions UVtools.Core/FileFormats/FileFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,50 @@ void CheckAddProperties(object a, object b, uint? layerIndex = null)

return comparison;
}

/// <summary>
/// Checks if a filename is valid or not
/// </summary>
/// <param name="filename">The file name only, without path</param>
/// <param name="errorMessage">The error message to return</param>
/// <param name="onlyAsciiCharacters">If true, the <paramref name="filename"/> must contain only ASCII characters.</param>
/// <returns>True if filename is valid, otherwise false.</returns>
public static bool IsFileNameValid(string filename, out string errorMessage, bool onlyAsciiCharacters = false)
{
errorMessage = string.Empty;

var invalidFileNameChars = Path.GetInvalidFileNameChars();
var invalidChars = filename.Where(c => invalidFileNameChars.Contains(c)).Distinct();

if (invalidChars.Any())
{
errorMessage = $"The file \"{filename}\" have invalid characters.\nThe following in-name characters are forbidden: {string.Join(", ", invalidChars)}.";
return false;
}

if (onlyAsciiCharacters)
{
var nonAscii = filename.Where(c => !char.IsAscii(c)).Distinct();
if (nonAscii.Any())
{
errorMessage = $"The file \"{filename}\" have non-ASCII characters.\nThe following in-name characters are not allowed: {string.Join(", ", nonAscii)}.";
return false;
}
}

return true;
}

/// <summary>
/// Checks if a filename is valid or not
/// </summary>
/// <param name="filename">The file name only, without path</param>
/// <param name="onlyAsciiCharacters">If true, the <paramref name="filename"/> must contain only ASCII characters.</param>
/// <returns></returns>
public static bool IsFileNameValid(string filename, bool onlyAsciiCharacters = false)
{
return IsFileNameValid(filename, out _, onlyAsciiCharacters);
}
#endregion

#region Members
Expand Down
18 changes: 13 additions & 5 deletions UVtools.Core/Layers/Layer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Emgu.CV.CvEnum;
using K4os.Compression.LZ4;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
Expand Down Expand Up @@ -1990,20 +1991,27 @@ public static byte[] CompressMat(Mat mat, LayerCompressionCodec codec)
return mat.GetPngByes();
case LayerCompressionCodec.Lz4:
{
var span = mat.GetDataByteSpan();
/*var span = mat.GetDataByteSpan();
var target = new byte[LZ4Codec.MaximumOutputSize(span.Length)];
var encodedLength = LZ4Codec.Encode(span, target.AsSpan());
Array.Resize(ref target, encodedLength);
return target;*/

var span = mat.GetDataByteSpan();

var rent = ArrayPool<byte>.Shared.Rent(LZ4Codec.MaximumOutputSize(span.Length));
var rentSpan = rent.AsSpan();

var encodedLength = LZ4Codec.Encode(span, rentSpan);
var target = rentSpan[..encodedLength].ToArray();

ArrayPool<byte>.Shared.Return(rent);
return target;
}
case LayerCompressionCodec.GZip:
{
return CompressionExtensions.GZipCompressToBytes(mat.GetUnmanagedMemoryStream(FileAccess.Read), CompressionLevel.Fastest);
}
case LayerCompressionCodec.Deflate:
{
return CompressionExtensions.DeflateCompressToBytes(mat.GetUnmanagedMemoryStream(FileAccess.Read), CompressionLevel.Fastest);
}
/*case LayerCompressionMethod.None:
return mat.GetBytes();*/
default:
Expand Down
28 changes: 26 additions & 2 deletions UVtools.Core/Operations/Operation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public enum OperationImportFrom : byte
#endregion

#region Members

public const byte ClassNameLength = 9;
private FileFormat _slicerFile = null!;
private Rectangle _originalBoundingRectangle;
private OperationImportFrom _importedFrom = OperationImportFrom.None;
Expand All @@ -51,7 +53,8 @@ public enum OperationImportFrom : byte
private string? _profileName;
private bool _profileIsDefault;
private LayerRangeSelection _layerRangeSelection = LayerRangeSelection.All;
public const byte ClassNameLength = 9;
private string? _lastValidationMessage;

#endregion

#region Properties
Expand Down Expand Up @@ -336,6 +339,26 @@ public Point[][]? MaskPoints
[XmlIgnore]
public bool IsValidated { get; private set; }

/// <summary>
/// Gets the last validation message
/// </summary>
[XmlIgnore]
public string? LastValidationMessage
{
get => _lastValidationMessage;
private set
{
if(!RaiseAndSetIfChanged(ref _lastValidationMessage, value)) return;
RaisePropertyChanged(nameof(IsLastValidationSuccess));
}
}

/// <summary>
/// Gets if the last validation pass with success
/// </summary>
[XmlIgnore]
public bool IsLastValidationSuccess => string.IsNullOrWhiteSpace(_lastValidationMessage);

/// <summary>
/// Gets or sets an report to show to the user after complete the operation with success
/// </summary>
Expand Down Expand Up @@ -401,7 +424,8 @@ public bool ValidateSpawn(out string? message)
public string? Validate()
{
IsValidated = true;
return ValidateInternally();
LastValidationMessage = ValidateInternally();
return _lastValidationMessage;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/Operations/OperationDoubleExposure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class OperationDoubleExposure : Operation

public override string? ValidateSpawn()
{
if (!SlicerFile.CanUseLayerPositionZ || !SlicerFile.CanUseLayerLiftHeight || !SlicerFile.CanUseLayerExposureTime)
if (!SlicerFile.CanUseSameLayerPositionZ || !SlicerFile.CanUseLayerLiftHeight || !SlicerFile.CanUseLayerExposureTime)
{
return NotSupportedMessage;
}
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/Operations/OperationPhasedExposure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public PhasedExposure Clone()

public override string? ValidateSpawn()
{
if (!SlicerFile.CanUseLayerPositionZ || !SlicerFile.CanUseLayerLiftHeight || !SlicerFile.CanUseLayerExposureTime)
if (!SlicerFile.CanUseSameLayerPositionZ || !SlicerFile.CanUseLayerLiftHeight || !SlicerFile.CanUseLayerExposureTime)
{
return NotSupportedMessage;
}
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/UVtools.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Platforms>AnyCPU;x64</Platforms>
<Version>4.0.5</Version>
<Version>4.0.6</Version>

<GenerateDocumentationFile>True</GenerateDocumentationFile>
<DocumentationFile>..\documentation\$(AssemblyName).xml</DocumentationFile>
Expand Down
47 changes: 30 additions & 17 deletions UVtools.UI/Controls/RenameFileControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,38 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="UVtools.UI.Controls.RenameFileControl"
x:DataType="controls:RenameFileControl">
<Grid RowDefinitions="Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,10,*">
<TextBlock Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center"
Text="Old filename:"/>

<TextBox Grid.Row="0" Grid.Column="2"
Classes="TransparentReadOnly"
Text="{Binding OldFileNameNoExt}"/>
<StackPanel Orientation="Vertical" Spacing="10">
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,10,*">
<TextBlock Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center"
Text="Old filename:"/>

<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
Text="New filename:"/>
<TextBox Grid.Row="0" Grid.Column="2"
Classes="TransparentReadOnly"
Text="{Binding OldFileNameNoExt}"/>

<TextBox Grid.Row="2" Grid.Column="2"
Text="{Binding NewFileNameNoExt}"/>
<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
Text="New filename:"/>

<ToggleSwitch Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3"
IsChecked="{Binding Overwrite}"
OnContent="Overwrite the file if already exists"
OffContent="Prompt to overwrite the file if already exists"/>
</Grid>
<TextBox Grid.Row="2" Grid.Column="2"
Text="{Binding NewFileNameNoExt}"/>

<ToggleSwitch Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3"
IsChecked="{Binding OnlyAsciiCharacters}"
OffContent="Allow all valid characters on the file name"
OnContent="Restrict the file name to valid ASCII characters"
ToolTip.Tip="Some printers can only show and print files with valid ASCII characters. Enable this is recommended to ensure a proper file name."/>

<ToggleSwitch Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="3"
IsChecked="{Binding Overwrite}"
OffContent="Prompt to overwrite the file if already exists"
OnContent="Overwrite the file if already exists"/>
</Grid>

<SelectableTextBlock Foreground="Red"
IsVisible="{Binding !IsLastValidationSuccess}"
Text="{Binding LastValidationMessage, StringFormat='Error: {0}'}"/>
</StackPanel>
</UserControl>
Loading

0 comments on commit b335f28

Please sign in to comment.