/ src / modules / imageresizer / ui / App.xaml.cs
App.xaml.cs
  1  #pragma warning disable IDE0073
  2  // Copyright (c) Brice Lambson
  3  // The Brice Lambson licenses this file to you under the MIT license.
  4  // See the LICENSE file in the project root for more information.  Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
  5  #pragma warning restore IDE0073
  6  
  7  using System;
  8  using System.Globalization;
  9  using System.Runtime.InteropServices;
 10  using System.Text;
 11  using System.Windows;
 12  using ImageResizer.Models;
 13  using ImageResizer.Properties;
 14  using ImageResizer.Utilities;
 15  using ImageResizer.ViewModels;
 16  using ImageResizer.Views;
 17  using ManagedCommon;
 18  
 19  namespace ImageResizer
 20  {
 21      public partial class App : Application, IDisposable
 22      {
 23          private const string LogSubFolder = "\\Image Resizer\\Logs";
 24  
 25          /// <summary>
 26          /// Gets cached AI availability state, checked at app startup.
 27          /// Can be updated after model download completes or background initialization.
 28          /// </summary>
 29          public static AiAvailabilityState AiAvailabilityState { get; internal set; }
 30  
 31          /// <summary>
 32          /// Event fired when AI initialization completes in background.
 33          /// Allows UI to refresh state when initialization finishes.
 34          /// </summary>
 35          public static event EventHandler<AiAvailabilityState> AiInitializationCompleted;
 36  
 37          static App()
 38          {
 39              try
 40              {
 41                  // Initialize logger early (mirroring PowerOCR pattern)
 42                  Logger.InitializeLogger(LogSubFolder);
 43              }
 44              catch
 45              {
 46                  /* swallow logger init issues silently */
 47              }
 48  
 49              try
 50              {
 51                  string appLanguage = LanguageHelper.LoadLanguage();
 52                  if (!string.IsNullOrEmpty(appLanguage))
 53                  {
 54                      System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(appLanguage);
 55                  }
 56              }
 57              catch (CultureNotFoundException ex)
 58              {
 59                  Logger.LogError("CultureNotFoundException: " + ex.Message);
 60              }
 61  
 62              Console.InputEncoding = Encoding.Unicode;
 63          }
 64  
 65          protected override void OnStartup(StartupEventArgs e)
 66          {
 67              // Fix for .net 3.1.19 making Image Resizer not adapt to DPI changes.
 68              NativeMethods.SetProcessDPIAware();
 69  
 70              // TODO: Re-enable AI Super Resolution in next release by removing this #if block
 71              // Temporarily disable AI Super Resolution feature (hide from UI but keep code)
 72  #if true // Set to false to re-enable AI Super Resolution
 73              AiAvailabilityState = AiAvailabilityState.NotSupported;
 74              ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
 75  
 76              // Skip AI detection mode as well
 77              if (e?.Args?.Length > 0 && e.Args[0] == "--detect-ai")
 78              {
 79                  Services.AiAvailabilityCacheService.SaveCache(AiAvailabilityState.NotSupported);
 80                  Environment.Exit(0);
 81                  return;
 82              }
 83  #else
 84              // Check for AI detection mode (called by Runner in background)
 85              if (e?.Args?.Length > 0 && e.Args[0] == "--detect-ai")
 86              {
 87                  RunAiDetectionMode();
 88                  return;
 89              }
 90  #endif
 91  
 92              if (PowerToys.GPOWrapperProjection.GPOWrapper.GetConfiguredImageResizerEnabledValue() == PowerToys.GPOWrapperProjection.GpoRuleConfigured.Disabled)
 93              {
 94                  /* TODO: Add logs to ImageResizer.
 95                   * Logger.LogWarning("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
 96                   */
 97                  Logger.LogWarning("GPO policy disables ImageResizer. Exiting.");
 98                  Environment.Exit(0); // Current.Exit won't work until there's a window opened.
 99                  return;
100              }
101  
102              // AI Super Resolution is not supported on Windows 10 - skip cache check entirely
103              if (OSVersionHelper.IsWindows10())
104              {
105                  AiAvailabilityState = AiAvailabilityState.NotSupported;
106                  ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
107                  Logger.LogInfo("AI Super Resolution not supported on Windows 10");
108              }
109              else
110              {
111                  // Load AI availability from cache (written by Runner's background detection)
112                  var cachedState = Services.AiAvailabilityCacheService.LoadCache();
113  
114                  if (cachedState.HasValue)
115                  {
116                      AiAvailabilityState = cachedState.Value;
117                      Logger.LogInfo($"AI state loaded from cache: {AiAvailabilityState}");
118                  }
119                  else
120                  {
121                      // No valid cache - default to NotSupported (Runner will detect and cache for next startup)
122                      AiAvailabilityState = AiAvailabilityState.NotSupported;
123                      Logger.LogInfo("No AI cache found, defaulting to NotSupported");
124                  }
125  
126                  // If AI is potentially available, start background initialization (non-blocking)
127                  if (AiAvailabilityState == AiAvailabilityState.Ready)
128                  {
129                      _ = InitializeAiServiceAsync(); // Fire and forget - don't block UI
130                  }
131                  else
132                  {
133                      // AI not available - set NoOp service immediately
134                      ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
135                  }
136              }
137  
138              var batch = ResizeBatch.FromCommandLine(Console.In, e?.Args);
139  
140              // TODO: Add command-line parameters that can be used in lieu of the input page (issue #14)
141              var mainWindow = new MainWindow(new MainViewModel(batch, Settings.Default));
142              mainWindow.Show();
143  
144              // Temporary workaround for issue #1273
145              WindowHelpers.BringToForeground(new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle);
146          }
147  
148          /// <summary>
149          /// AI detection mode: perform detection, write to cache, and exit.
150          /// Called by Runner in background to avoid blocking ImageResizer UI startup.
151          /// </summary>
152          private void RunAiDetectionMode()
153          {
154              try
155              {
156                  Logger.LogInfo("Running AI detection mode...");
157  
158                  // AI Super Resolution is not supported on Windows 10
159                  if (OSVersionHelper.IsWindows10())
160                  {
161                      Logger.LogInfo("AI detection skipped: Windows 10 does not support AI Super Resolution");
162                      Services.AiAvailabilityCacheService.SaveCache(AiAvailabilityState.NotSupported);
163                      Environment.Exit(0);
164                      return;
165                  }
166  
167                  // Perform detection (reuse existing logic)
168                  var state = CheckAiAvailability();
169  
170                  // Write result to cache file
171                  Services.AiAvailabilityCacheService.SaveCache(state);
172  
173                  Logger.LogInfo($"AI detection complete: {state}");
174              }
175              catch (Exception ex)
176              {
177                  Logger.LogError($"AI detection failed: {ex.Message}");
178                  Services.AiAvailabilityCacheService.SaveCache(AiAvailabilityState.NotSupported);
179              }
180  
181              // Exit silently without showing UI
182              Environment.Exit(0);
183          }
184  
185          /// <summary>
186          /// Check AI Super Resolution availability on this system.
187          /// Performs architecture check and model availability check.
188          /// </summary>
189          private static AiAvailabilityState CheckAiAvailability()
190          {
191              // AI feature disabled - always return NotSupported
192              return AiAvailabilityState.NotSupported;
193          }
194  
195          /// <summary>
196          /// Initialize AI Super Resolution service asynchronously in background.
197          /// Runs without blocking UI startup - state change event notifies completion.
198          /// </summary>
199          private static async System.Threading.Tasks.Task InitializeAiServiceAsync()
200          {
201              AiAvailabilityState finalState;
202  
203              try
204              {
205                  // Create and initialize AI service using async factory
206                  var aiService = await Services.WinAiSuperResolutionService.CreateAsync();
207  
208                  if (aiService != null)
209                  {
210                      ResizeBatch.SetAiSuperResolutionService(aiService);
211                      Logger.LogInfo("AI Super Resolution service initialized successfully.");
212                      finalState = AiAvailabilityState.Ready;
213                  }
214                  else
215                  {
216                      // Initialization failed - use default NoOp service
217                      ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
218                      Logger.LogWarning("AI Super Resolution service initialization failed. Using default service.");
219                      finalState = AiAvailabilityState.NotSupported;
220                  }
221              }
222              catch (Exception ex)
223              {
224                  // Log error and use default NoOp service
225                  ResizeBatch.SetAiSuperResolutionService(Services.NoOpAiSuperResolutionService.Instance);
226                  Logger.LogError($"Exception during AI service initialization: {ex.Message}");
227                  finalState = AiAvailabilityState.NotSupported;
228              }
229  
230              // Update cached state and notify listeners
231              AiAvailabilityState = finalState;
232              AiInitializationCompleted?.Invoke(null, finalState);
233          }
234  
235          public void Dispose()
236          {
237              // Dispose AI Super Resolution service
238              ResizeBatch.DisposeAiSuperResolutionService();
239  
240              GC.SuppressFinalize(this);
241          }
242      }
243  }