Compare commits

...

3 Commits

8 changed files with 77 additions and 31 deletions

View File

@@ -14,6 +14,7 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutputPath>
<AssemblyName>PowerToys.ImageResizerCLI</AssemblyName>
<ApplicationIcon>..\ui\Resources\ImageResizer.ico</ApplicationIcon>
<NoWarn>$(NoWarn);SA1500;SA1402;CA1852</NoWarn>
</PropertyGroup>

View File

@@ -31,7 +31,7 @@ internal static class Program
Console.InputEncoding = Encoding.Unicode;
// Initialize logger to file (same as other modules)
CliLogger.Initialize("\\ImageResizer\\Logs");
CliLogger.Initialize("\\Image Resizer\\Logs");
CliLogger.Info($"ImageResizerCLI started with {args.Length} argument(s)");
try

View File

@@ -71,7 +71,7 @@ public:
UpdateRegistration(m_enabled);
app_name = GET_RESOURCE_STRING(IDS_IMAGERESIZER);
app_key = ImageResizerConstants::ModuleKey;
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::imageResizerLoggerName);
LoggerHelpers::init_logger(ImageResizerConstants::ModuleSaveFolderKey, L"", LogSettings::imageResizerLoggerName);
};
// Destroy the powertoy and free memory

View File

@@ -20,7 +20,7 @@ namespace ImageResizer
{
public partial class App : Application, IDisposable
{
private const string LogSubFolder = "\\ImageResizer\\Logs";
private const string LogSubFolder = "\\Image Resizer\\Logs";
/// <summary>
/// Gets cached AI availability state, checked at app startup.

View File

@@ -127,10 +127,41 @@ namespace ImageResizer.Models
public static CliOptions Parse(string[] args)
{
var options = new CliOptions();
// Pre-scan for legacy pipe name and /d arguments before System.CommandLine parsing
// This ensures backward compatibility with context menu invocations
const string pipeNamePrefix = "\\\\.\\pipe\\";
var filteredArgs = new List<string>();
if (args != null)
{
for (int i = 0; i < args.Length; i++)
{
var arg = args[i];
// Check for pipe name (legacy format from context menu)
if (arg.Contains(pipeNamePrefix))
{
int prefixIndex = arg.IndexOf(pipeNamePrefix, StringComparison.OrdinalIgnoreCase);
options.PipeName = arg.Substring(prefixIndex + pipeNamePrefix.Length);
continue;
}
// Check for legacy /d option (destination directory)
if (arg == "/d" && i + 1 < args.Length)
{
options.DestinationDirectory = args[++i];
continue;
}
filteredArgs.Add(arg);
}
}
var cmd = new ImageResizerRootCommand();
// Parse using System.CommandLine
var parseResult = new Parser(cmd).Parse(args);
// Parse using System.CommandLine with filtered arguments
var parseResult = new Parser(cmd).Parse(filteredArgs.ToArray());
if (parseResult.Errors.Count > 0)
{
@@ -146,7 +177,14 @@ namespace ImageResizer.Models
// Extract values from parse result using strongly typed options
options.ShowHelp = parseResult.GetValueForOption(cmd.HelpOption);
options.ShowConfig = parseResult.GetValueForOption(cmd.ShowConfigOption);
options.DestinationDirectory = parseResult.GetValueForOption(cmd.DestinationOption);
// Only override DestinationDirectory if not set by legacy /d option
var destOption = parseResult.GetValueForOption(cmd.DestinationOption);
if (!string.IsNullOrEmpty(destOption))
{
options.DestinationDirectory = destOption;
}
options.Width = parseResult.GetValueForOption(cmd.WidthOption);
options.Height = parseResult.GetValueForOption(cmd.HeightOption);
options.Unit = parseResult.GetValueForOption(cmd.UnitOption);
@@ -169,10 +207,9 @@ namespace ImageResizer.Models
var files = parseResult.GetValueForArgument(cmd.FilesArgument);
if (files != null)
{
const string pipeNamePrefix = "\\\\.\\pipe\\";
foreach (var file in files)
{
// Check for pipe name (must be at the start of the path)
// Check for pipe name in case it wasn't caught in pre-scan
if (file.StartsWith(pipeNamePrefix, StringComparison.OrdinalIgnoreCase))
{
options.PipeName = file.Substring(pipeNamePrefix.Length);

View File

@@ -123,9 +123,11 @@ namespace ImageResizer.Models
// Display the read text to the console
while ((file = sr.ReadLine()) != null)
{
if (IsValidImagePath(file))
// Named pipe paths are typically absolute, but ensure consistency
var absolutePath = Path.IsPathRooted(file) ? file : Path.GetFullPath(file);
if (IsValidImagePath(absolutePath))
{
batch.Files.Add(file);
batch.Files.Add(absolutePath);
}
}
}

View File

@@ -228,15 +228,8 @@ namespace ImageResizer.Properties
}
else if (e.PropertyName == nameof(Models.AiSize))
{
var oldAiSize = _aiSize;
_aiSize = settings.AiSize;
OnCollectionChanged(
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Replace,
_aiSize,
oldAiSize,
_sizes.Count + 1));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
else if (e.PropertyName == nameof(Sizes))
{

View File

@@ -9,7 +9,9 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using ImageResizer.Helpers;
using ImageResizer.Models;
@@ -24,6 +26,7 @@ namespace ImageResizer.ViewModels
private readonly IMainView _mainView;
private readonly Stopwatch _stopwatch = new Stopwatch();
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly Dispatcher _dispatcher;
private double _progress;
private TimeSpan _timeRemaining;
@@ -37,6 +40,7 @@ namespace ImageResizer.ViewModels
_batch = batch;
_mainViewModel = mainViewModel;
_mainView = mainView;
_dispatcher = Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher;
StartCommand = new RelayCommand(Start);
StopCommand = new RelayCommand(Stop);
@@ -60,7 +64,7 @@ namespace ImageResizer.ViewModels
public void Start()
{
_ = Task.Factory.StartNew(StartExecutingWork, _cancellationTokenSource.Token, TaskCreationOptions.None, TaskScheduler.Current);
_ = Task.Run(StartExecutingWork);
}
private void StartExecutingWork()
@@ -69,23 +73,32 @@ namespace ImageResizer.ViewModels
var errors = _batch.Process(
(completed, total) =>
{
var progress = completed / total;
Progress = progress;
_mainViewModel.Progress = progress;
_dispatcher.BeginInvoke(() =>
{
var progress = completed / total;
Progress = progress;
_mainViewModel.Progress = progress;
TimeRemaining = _stopwatch.Elapsed.Multiply((total - completed) / completed);
if (completed > 0)
{
TimeRemaining = _stopwatch.Elapsed.Multiply((total - completed) / completed);
}
});
},
_cancellationTokenSource.Token);
if (errors.Any())
_dispatcher.BeginInvoke(() =>
{
_mainViewModel.Progress = 0;
_mainViewModel.CurrentPage = new ResultsViewModel(_mainView, errors);
}
else
{
_mainView.Close();
}
if (errors.Any())
{
_mainViewModel.Progress = 0;
_mainViewModel.CurrentPage = new ResultsViewModel(_mainView, errors);
}
else
{
_mainView.Close();
}
});
}
public void Stop()