diff --git a/src/modules/imageresizer/ui/App.xaml.cs b/src/modules/imageresizer/ui/App.xaml.cs
index 95e45b7f7b..3a70313608 100644
--- a/src/modules/imageresizer/ui/App.xaml.cs
+++ b/src/modules/imageresizer/ui/App.xaml.cs
@@ -107,33 +107,26 @@ namespace ImageResizer
// Temporary workaround for issue #1273
WindowHelpers.BringToForeground(new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle);
- // Check AI availability on UI thread after window is loaded
- // Windows AI APIs require proper COM apartment and SynchronizationContext
+ // Check AI availability after window is loaded
+ // WinAiSuperResolutionService handles UI thread dispatching internally
if (!OSVersionHelper.IsWindows10())
{
- mainWindow.Loaded += (s, args) =>
+ mainWindow.Loaded += async (s, args) =>
{
- // Use Dispatcher to ensure we're on the UI thread
- mainWindow.Dispatcher.InvokeAsync(async () =>
- {
- await InitializeAiOnUIThreadAsync();
- });
+ await InitializeAiAsync();
};
}
}
///
- /// Initialize AI availability check on UI thread.
- /// Windows AI APIs require proper COM apartment context.
+ /// Initialize AI availability check.
+ /// WinAiSuperResolutionService handles UI thread dispatching internally.
///
- private static async System.Threading.Tasks.Task InitializeAiOnUIThreadAsync()
+ private static async System.Threading.Tasks.Task InitializeAiAsync()
{
try
{
- Logger.LogInfo($"Checking AI availability on UI thread (Thread: {System.Threading.Thread.CurrentThread.ManagedThreadId})");
-
var readyState = Services.WinAiSuperResolutionService.GetModelReadyState();
- Logger.LogInfo($"ImageScaler.GetReadyState() returned: {readyState}");
switch (readyState)
{
@@ -144,21 +137,18 @@ namespace ImageResizer
if (aiService != null)
{
ResizeBatch.SetAiSuperResolutionService(aiService);
- Logger.LogInfo("AI Super Resolution service initialized successfully on UI thread.");
}
break;
case Microsoft.Windows.AI.AIFeatureReadyState.NotReady:
AiAvailabilityState = AiAvailabilityState.ModelNotReady;
- Logger.LogInfo("AI model not ready, user can download via UI.");
break;
case Microsoft.Windows.AI.AIFeatureReadyState.DisabledByUser:
case Microsoft.Windows.AI.AIFeatureReadyState.NotSupportedOnCurrentSystem:
default:
AiAvailabilityState = AiAvailabilityState.NotSupported;
- Logger.LogInfo($"AI not supported: {readyState}");
break;
}
@@ -167,7 +157,7 @@ namespace ImageResizer
}
catch (Exception ex)
{
- Logger.LogError($"Failed to check AI availability on UI thread: {ex.Message}");
+ Logger.LogError($"Failed to check AI availability: {ex.Message}");
AiAvailabilityState = AiAvailabilityState.NotSupported;
AiInitializationCompleted?.Invoke(null, AiAvailabilityState);
}
diff --git a/src/modules/imageresizer/ui/Services/WinAiSuperResolutionService.cs b/src/modules/imageresizer/ui/Services/WinAiSuperResolutionService.cs
index 4cd752184a..ce5f68086e 100644
--- a/src/modules/imageresizer/ui/Services/WinAiSuperResolutionService.cs
+++ b/src/modules/imageresizer/ui/Services/WinAiSuperResolutionService.cs
@@ -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
///
/// Async factory method to create and initialize WinAiSuperResolutionService.
- /// Returns null if initialization fails.
+ /// Must be called on UI thread. Returns null if initialization fails.
///
public static async Task 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;
}
}
+ ///
+ /// Get the ready state of the ImageScaler model.
+ /// Must be called on UI thread for accurate results.
+ ///
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;
}
}
+ ///
+ /// Ensure the AI model is ready (download if needed).
+ /// Must be called on UI thread.
+ ///
public static async Task EnsureModelReadyAsync(IProgress 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;
}
}
diff --git a/src/modules/imageresizer/ui/ViewModels/InputViewModel.cs b/src/modules/imageresizer/ui/ViewModels/InputViewModel.cs
index c241728276..4ef4a20344 100644
--- a/src/modules/imageresizer/ui/ViewModels/InputViewModel.cs
+++ b/src/modules/imageresizer/ui/ViewModels/InputViewModel.cs
@@ -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)