mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-16 01:06:50 +01:00
Compare commits
3 Commits
stable
...
yuleng/ima
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
890ca89909 | ||
|
|
4d22126065 | ||
|
|
5ef3fab105 |
@@ -79,7 +79,6 @@
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Foundation" Version="1.8.251104000" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.39" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.251106002" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace ImageResizer
|
||||
return;
|
||||
}
|
||||
|
||||
// AI Super Resolution is not supported on Windows 10 - skip cache check entirely
|
||||
// AI Super Resolution is not supported on Windows 10 - skip check entirely
|
||||
if (OSVersionHelper.IsWindows10())
|
||||
{
|
||||
AiAvailabilityState = AiAvailabilityState.NotSupported;
|
||||
@@ -93,31 +93,9 @@ namespace ImageResizer
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load AI availability from cache (written by Runner's background detection)
|
||||
var cachedState = Services.AiAvailabilityCacheService.LoadCache();
|
||||
|
||||
if (cachedState.HasValue)
|
||||
{
|
||||
AiAvailabilityState = cachedState.Value;
|
||||
Logger.LogInfo($"AI state loaded from cache: {AiAvailabilityState}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// No valid cache - default to NotSupported (Runner will detect and cache for next startup)
|
||||
AiAvailabilityState = AiAvailabilityState.NotSupported;
|
||||
Logger.LogInfo("No AI cache found, defaulting to NotSupported");
|
||||
}
|
||||
|
||||
// If AI is potentially available, start background initialization (non-blocking)
|
||||
if (AiAvailabilityState == AiAvailabilityState.Ready)
|
||||
{
|
||||
_ = InitializeAiServiceAsync(); // Fire and forget - don't block UI
|
||||
}
|
||||
else
|
||||
{
|
||||
// AI not available - set NoOp service immediately
|
||||
ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
|
||||
}
|
||||
// Default to ModelNotReady initially, will be updated after window loads
|
||||
AiAvailabilityState = AiAvailabilityState.ModelNotReady;
|
||||
ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
|
||||
}
|
||||
|
||||
var batch = ResizeBatch.FromCommandLine(Console.In, e?.Args);
|
||||
@@ -128,6 +106,61 @@ namespace ImageResizer
|
||||
|
||||
// Temporary workaround for issue #1273
|
||||
WindowHelpers.BringToForeground(new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle);
|
||||
|
||||
// Check AI availability after window is loaded
|
||||
// WinAiSuperResolutionService handles UI thread dispatching internally
|
||||
if (!OSVersionHelper.IsWindows10())
|
||||
{
|
||||
mainWindow.Loaded += async (s, args) =>
|
||||
{
|
||||
await InitializeAiAsync();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize AI availability check.
|
||||
/// WinAiSuperResolutionService handles UI thread dispatching internally.
|
||||
/// </summary>
|
||||
private static async System.Threading.Tasks.Task InitializeAiAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyState = Services.WinAiSuperResolutionService.GetModelReadyState();
|
||||
|
||||
switch (readyState)
|
||||
{
|
||||
case Microsoft.Windows.AI.AIFeatureReadyState.Ready:
|
||||
AiAvailabilityState = AiAvailabilityState.Ready;
|
||||
// Initialize the AI service
|
||||
var aiService = await Services.WinAiSuperResolutionService.CreateAsync();
|
||||
if (aiService != null)
|
||||
{
|
||||
ResizeBatch.SetAiSuperResolutionService(aiService);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Microsoft.Windows.AI.AIFeatureReadyState.NotReady:
|
||||
AiAvailabilityState = AiAvailabilityState.ModelNotReady;
|
||||
break;
|
||||
|
||||
case Microsoft.Windows.AI.AIFeatureReadyState.DisabledByUser:
|
||||
case Microsoft.Windows.AI.AIFeatureReadyState.NotSupportedOnCurrentSystem:
|
||||
default:
|
||||
AiAvailabilityState = AiAvailabilityState.NotSupported;
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify UI that AI state has been determined
|
||||
AiInitializationCompleted?.Invoke(null, AiAvailabilityState);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to check AI availability: {ex.Message}");
|
||||
AiAvailabilityState = AiAvailabilityState.NotSupported;
|
||||
AiInitializationCompleted?.Invoke(null, AiAvailabilityState);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -200,46 +233,6 @@ namespace ImageResizer
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize AI Super Resolution service asynchronously in background.
|
||||
/// Runs without blocking UI startup - state change event notifies completion.
|
||||
/// </summary>
|
||||
private static async System.Threading.Tasks.Task InitializeAiServiceAsync()
|
||||
{
|
||||
AiAvailabilityState finalState;
|
||||
|
||||
try
|
||||
{
|
||||
// Create and initialize AI service using async factory
|
||||
var aiService = await Services.WinAiSuperResolutionService.CreateAsync();
|
||||
|
||||
if (aiService != null)
|
||||
{
|
||||
ResizeBatch.SetAiSuperResolutionService(aiService);
|
||||
Logger.LogInfo("AI Super Resolution service initialized successfully.");
|
||||
finalState = AiAvailabilityState.Ready;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialization failed - use default NoOp service
|
||||
ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
|
||||
Logger.LogWarning("AI Super Resolution service initialization failed. Using default service.");
|
||||
finalState = AiAvailabilityState.NotSupported;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log error and use default NoOp service
|
||||
ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
|
||||
Logger.LogError($"Exception during AI service initialization: {ex.Message}");
|
||||
finalState = AiAvailabilityState.NotSupported;
|
||||
}
|
||||
|
||||
// Update cached state and notify listeners
|
||||
AiAvailabilityState = finalState;
|
||||
AiInitializationCompleted?.Invoke(null, finalState);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Dispose AI Super Resolution service
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK.AI" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
|
||||
<PackageReference Include="System.CommandLine" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ManagedCommon;
|
||||
using Microsoft.Windows.AI;
|
||||
using Microsoft.Windows.AI.Imaging;
|
||||
using Windows.Graphics.Imaging;
|
||||
@@ -33,44 +34,78 @@ namespace ImageResizer.Services
|
||||
|
||||
/// <summary>
|
||||
/// Async factory method to create and initialize WinAiSuperResolutionService.
|
||||
/// Returns null if initialization fails.
|
||||
/// Must be called on UI thread. Returns null if initialization fails.
|
||||
/// </summary>
|
||||
public static async Task<WinAiSuperResolutionService> CreateAsync()
|
||||
{
|
||||
// Ensure we're on UI thread for Windows AI API calls
|
||||
if (Application.Current?.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
return await Application.Current.Dispatcher.InvokeAsync(() => CreateAsync()).Task.Unwrap();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogInfo($"ImageScaler.CreateAsync() called on thread {Thread.CurrentThread.ManagedThreadId}");
|
||||
var imageScaler = await ImageScaler.CreateAsync();
|
||||
if (imageScaler == null)
|
||||
{
|
||||
Logger.LogWarning("ImageScaler.CreateAsync() returned null");
|
||||
return null;
|
||||
}
|
||||
|
||||
Logger.LogInfo("ImageScaler created successfully");
|
||||
return new WinAiSuperResolutionService(imageScaler);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"ImageScaler.CreateAsync() failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the ready state of the ImageScaler model.
|
||||
/// Must be called on UI thread for accurate results.
|
||||
/// </summary>
|
||||
public static AIFeatureReadyState GetModelReadyState()
|
||||
{
|
||||
// Ensure we're on UI thread for Windows AI API calls
|
||||
if (Application.Current?.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => GetModelReadyState());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return ImageScaler.GetReadyState();
|
||||
Logger.LogInfo($"ImageScaler.GetReadyState() called on thread {Thread.CurrentThread.ManagedThreadId}");
|
||||
var state = ImageScaler.GetReadyState();
|
||||
Logger.LogInfo($"ImageScaler.GetReadyState() returned: {state}");
|
||||
return state;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"ImageScaler.GetReadyState() failed: {ex.Message}");
|
||||
// If we can't get the state, treat it as disabled by user
|
||||
// The caller should check if it's Ready or NotReady
|
||||
return AIFeatureReadyState.DisabledByUser;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the AI model is ready (download if needed).
|
||||
/// Must be called on UI thread.
|
||||
/// </summary>
|
||||
public static async Task<AIFeatureReadyResult> EnsureModelReadyAsync(IProgress<double> progress = null)
|
||||
{
|
||||
// Ensure we're on UI thread for Windows AI API calls
|
||||
if (Application.Current?.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
return await Application.Current.Dispatcher.InvokeAsync(() => EnsureModelReadyAsync(progress)).Task.Unwrap();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Logger.LogInfo($"ImageScaler.EnsureReadyAsync() called on thread {Thread.CurrentThread.ManagedThreadId}");
|
||||
var operation = ImageScaler.EnsureReadyAsync();
|
||||
|
||||
// Register progress handler if provided
|
||||
@@ -83,10 +118,13 @@ namespace ImageResizer.Services
|
||||
};
|
||||
}
|
||||
|
||||
return await operation;
|
||||
var result = await operation;
|
||||
Logger.LogInfo($"ImageScaler.EnsureReadyAsync() completed: Status={result?.Status}, ExtendedError={result?.ExtendedError}");
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"ImageScaler.EnsureReadyAsync() failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +402,7 @@ namespace ImageResizer.ViewModels
|
||||
});
|
||||
|
||||
// Call EnsureReadyAsync to download and prepare the AI model
|
||||
// Note: WinAiSuperResolutionService handles dispatching to UI thread internally
|
||||
var result = await WinAiSuperResolutionService.EnsureModelReadyAsync(progress);
|
||||
|
||||
if (result?.Status == Microsoft.Windows.AI.AIFeatureReadyResultState.Success)
|
||||
|
||||
Reference in New Issue
Block a user