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 }