Skip to content

feat(engines): offline AI image upscaling and super-resolution up to 4x (NCNN) - #1064

Open
rohitLovesKrishna wants to merge 8 commits into
KnifeLemon:mainfrom
rohitLovesKrishna:feature/upscale-image
Open

rohitLovesKrishna wants to merge 8 commits into
KnifeLemon:mainfrom
rohitLovesKrishna:feature/upscale-image

Conversation

@rohitLovesKrishna

Copy link
Copy Markdown
Contributor
2026-11-03.19-49-47_compressed.mp4

Hi @KnifeLemon,

This PR adds offline AI image upscaling and super-resolution (up to 4x) using local Vulkan/NCNN neural network models, bringing high-fidelity local image enhancement to Filee while strictly upholding Filee's offline privacy promise.

What this adds

  1. 100% Offline AI Super-Resolution Engine (Filee.Engines.Upscale):

    • Executes entirely on the local machine via Vulkan GPU acceleration or CPU mode using upscayl-bin (NCNN).
    • Never makes network connections during inference; all computation is in-process/local child process.
    • Probes hardware capabilities automatically (Vulkan GPU adapter detection with graceful CPU fallback and recommendations).
    • Supports 1x to 4x scaling across all standard image formats: PNG, JPG, JPEG, WEBP, ICO, HEIC, AVIF, BMP, and TIFF.
  2. Curated Model Catalog (UpscaleModelInfo):

    • Curated list of 10 image-focused super-resolution models from open-source projects (upscayl/custom-models):
      • CPU & iGPU friendly: 4xLSDIRCompactC3, RealESRGAN_General_x4_v3, RealESRGAN_General_WDN_x4_v3.
      • Dedicated GPU / High Fidelity: 4x_NMKD-Siax_200k, 4x_NMKD-Superscale-SP_178000_G, 4xLSDIR, 4xLSDIRplusC, 4xNomos8kSC, 4xHFA2k, uniscale_restore.
    • Models are stored locally in %LOCALAPPDATA%\Filee\engines\upscaler-models\.
  3. Engines Page Integration (Settings → Engines):

    • Added an Image Quality Models card with status indicator and a Download Models button.
    • Opens the dedicated UpscaleModelManagerWindow:
      • Real-time search filter.
      • Individual download progress bars and size indicators.
      • Single-click "Download Recommended" for compact models.
      • Safe deletion with destructive confirmation prompt (WindowService.ConfirmAsync) and localized error handling.
  4. Donut Wheel & Interactive Workflow (UpscaleWindow):

    • Added an Upscale preset slice to image profiles with clean font sizing (≤ 11.0 px) so text never clips.
    • Interactive modal opens on trigger:
      • Model selection dropdown with model sizes and target descriptions.
      • Scale slider (1x to 4x).
      • Live resolution preview: e.g. 300 x 400 px → 1200 x 1600 px (4x).
      • Output format choices (keep source format or convert to png/jpg/webp/ico).
      • Persistent Upscale Now button in the footer for quick comparisons, with an inline Open Folder button in the success card.
  5. Presets Page & Preset Editor (Settings → Presets):

    • Registered "tool-upscale" (UpscaleTool) so it can be managed and configured in Settings.
    • PresetEditorView displays an Upscale options card allowing users to configure default models and scales with full model descriptions and a shortcut to the model manager.
  6. Localisation & Attribution:

    • Strictly additive keys across all 19 language files (src/Filee.App/Assets/i18n/*.json), maintaining exact formatting conventions (it.json non-indented, Korean in standard polite ~해요 tone).
    • Full license attribution added to THIRD-PARTY-NOTICES.md for upscayl-bin / upscayl-ncnn and Upscayl Custom Models.
    • Documented in docs/ENGINES.md under ## Image Quality Models (Offline AI Upscaler).

Tests & Verification

  • Added 20 automated unit tests in tests/Filee.Engines.Tests/UpscalerTests.cs verifying catalog metadata, GPU detection heuristics, argument generation, CLI path resolution, cancellation tokens, and full upscale cycles.
  • dotnet test passing (20/20).
  • dotnet format --verify-no-changes --severity warn clean with 0 warnings.
  • Rebased on top of upstream/main (d4d4c066) with zero conflicts.
Screenshot 2026-11-03 195154 Screenshot 2026-11-03 195125 Screenshot 2026-11-03 195108 Screenshot 2026-11-03 195057 Screenshot 2026-11-03 195043

@github-actions github-actions Bot added the feature New features label Nov 3, 2026
@rohitLovesKrishna
rohitLovesKrishna force-pushed the feature/upscale-image branch 2 times, most recently from 01fe528 to a66f29d Compare November 3, 2026 15:24

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @rohitLovesKrishna. Offline AI upscaling is a good fit for Filee: it runs locally, nothing leaves the PC, and the model choice with its live size preview is well thought out. The direction is good. Before it can merge, a few parts need to follow how Filee already handles engines, downloads and presets.

Timing: the next release is planned for around 17:00 UTC today (November 3). To make it into that release, the changes below would need to be pushed by 16:20 UTC. If that's too tight (it's a big PR), no problem: it goes into the following release.

Must fix

1. Pin every download with a SHA-256

UpscaleModelService downloads an executable (upscayl-bin) and ten models without checking what arrives. The models also come from the main branch of upscayl/custom-models, which can change at any time. Every other engine Filee downloads is pinned by version and SHA-256:

  • programs in src/Filee.Engines/Infrastructure/engines.json, installed by EngineInstaller;
  • per-item data (the Tesseract languages) in ocr-languages.json, with a URL pinned to a tag or commit and a SHA-256 per file.

Please do the same:

  • The binary: add upscayl-bin as an engine package (one component per platform) in engines.json.
  • The models: add an upscale-models.json pinned to a commit of custom-models (not main), with the size and SHA-256 of each .bin and .param.

2. Use the existing engine installer, not a second one

The new download service and model-manager window duplicate EngineInstaller and Settings → Engines. As a package there, the upscaler gets what the rest already has:

  • the install / remove / update buttons and their progress;
  • locking against a second Filee;
  • clean removal of an engine in use, and no leftover .part files (#1058);
  • the busy message in every language;
  • filee engines on the command line.

The models can then work like the OCR languages: downloaded on first use, or from a small list in the engine's card.

3. Run the program through ProcessRunner

UpscalerEngine builds one argument string ($"-i \"{actualInput}\" …") and starts Process itself. Please use ProcessRunner.RunAsync with an argument list instead. It escapes each argument (a path with a quote in it breaks today's string), and it applies a time limit, cancellation that ends the whole process tree, lower priority and captured output.

Also:

  • Work folder: put the temporary PNGs in step.WorkDirectory, not Path.GetTempPath(). The job cleans its work folder up; the system temp folder keeps whatever a crash leaves.
  • Thread safety: outputLines is a plain List written from two output threads.

4. Read pictures with ImageReader

new MagickImage(inputPath) skips what ImageReader.Read does for camera RAW, layered PSD/XCF, HEIC, LIVP, KRA and the rest. Please read the source through it (with ImageEncoder.SelectFrames), as the other picture tools do.

5. Licences, per model

  • upscayl-bin: it's AGPL-3.0. That's fine as a separate program downloaded on demand, which is how Ghostscript comes in. Please say so in THIRD-PARTY-NOTICES.md the same way, without the "/ BSD-3-Clause".
  • The models: "various open-source licenses" isn't enough. Some upscaling models are non-commercial (CC BY-NC…), which Filee shouldn't offer as a plain download. Please list each model's licence in the catalog and in the notices, and leave out any that aren't free to use.

6. Existing users: a settings schema step

UpscalePresets() only reaches new libraries. Existing users need a migration step that adds the tool to the library, palette only, no donut slot (#806). main is at 63 (#1062), so take 64.

7. No special case in DonutMenu

The change in DonutMenu.cs makes the label smaller only when the id is tool-upscale or the text is "Upscale". Labels fit by their length in every language, so please drop this. If "Upscale" doesn't fit somewhere, the label sizing should be fixed for every slice, in its own PR.

Smaller

  • ARM64: the release has windows, macos and linux zips. Please check which architectures they hold. Where there's no build (Windows ARM64, Linux ARM64), the engine should say "not available on this PC" (EngineDownloads.UnavailableReason) rather than fail.
  • Tests: keep anything that needs the real program or network behind Assert.SkipUnless(...), as the other engine tests do, so CI doesn't download it.

Happy to look again as soon as it's pushed.

@rohitLovesKrishna

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review and guidance, @KnifeLemon! All requested changes have been addressed:

  1. Pinned downloads & SHA-256:

    • upscayl-bin is registered as an engine package in src/Filee.Engines/Infrastructure/engines.json across windows-x64, linux-x64, osx-x64, and osx-arm64, pinned with exact byte sizes and SHA-256 hashes.
    • upscale-models.json pins each model's .bin and .param to commit 4b6d2cfa59c7442af115dfc6e50fd8d7d40b96ef of upscayl/custom-models with individual SHA-256 checksums.
  2. Existing engine installer integration:

    • Removed the duplicate UpscaleModelService and manager window. upscayl-bin is now managed like any other engine in Settings → Engines via EngineInstaller (with install/remove/update, progress, locking, and clean folder cleanup).
    • Models are managed similarly to OCR languages via UpscaleModels, downloading on first use with hash checks, temporary files, and atomic file moves. Model deletion prompts confirmation via WindowService.
  3. ProcessRunner:

    • UpscalerEngine now runs via ProcessRunner.RunAsync with argument lists, stores temporary files inside step.WorkDirectory, and handles progress reporting thread-safely.
  4. ImageReader integration:

    • Source pictures are loaded through ImageReader.Read and ImageEncoder.SelectFrames(..., "png"), unlocking camera RAW, PSD, XCF, HEIC, LIVP, KRA, and multipage formats for upscaling.
  5. Licenses per model:

    • Removed uniscale_restore (non-commercial CC-BY-NC-SA-4.0), unknown-2.0.1, and video models.
    • Updated THIRD-PARTY-NOTICES.md with AGPL-3.0 for upscayl-bin and explicit attribution / license notices for each curated model (WTFPL, BSD-3-Clause, CC-BY-4.0).
  6. Settings schema 64:

    • Schema version bumped to 64. Existing libraries have the "Upscale Image" tool added to their palette immediately after Annotate (tool-annotate) without altering any default donut profile slots.
  7. DonutMenu clean-up:

    • Reverted custom label sizing in DonutMenu.cs.
  8. Platform availability & Tests:

    • Linux and Windows ARM64 report as unavailable with explanatory messages.
    • Added UpscaleToolTests and guarded real execution tests in UpscalerTests with Assert.SkipUnless.

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @rohitLovesKrishna, a big step forward. Much of the review is done well:

  • Pins: I downloaded every pinned file (the three upscayl-bin zips and all 18 model files at commit 4b6d2cfa…). Each size and SHA-256 matches, and the zips hold x64 Windows, x64 Linux and universal macOS binaries.
  • ProcessRunner, ImageReader and schema 64: in place. Schema 64 is palette only, with tests, and merges cleanly with main.
  • Cleanup: the non-commercial model and the DonutMenu special case are gone, and CI is green.

It won't make today's 2.3.0 release, though: a few things still need to change, one of which breaks an existing feature.

Must fix

  1. Whisper is broken by the installer change. In EngineInstaller, case "model": now falls into the new ncnn-param / ncnn-bin block (on main it fell into "bin"). whisper-model has "kind": "model", so it gets a .whisper-model marker and returns early. Marker() then looks for .filee-component, so Whisper never counts as installed and re-downloads its 148 MB every time. Please keep "model" with "bin" and give the NCNN files their own kinds only. A test that installs a kind: "model" component would catch it.
  2. The Windows binary needs VCOMP140.DLL, which isn't in the zip. On a PC without the VC++ Redistributable it won't start. Add the vcruntime component to the package (as Ghostscript does) and make sure that DLL is copied next to upscayl-bin.exe.
  3. Upscaling isn't a real conversion step. UpscalerConverter's edges are plain DirectOnly edges with no planner flag, so a preset with Upscale.Enabled that goes through JobQueue routes via ImageMagick and is never upscaled. The window also calls UpscalerEngine itself, with its own output path, so there's no toast, no history and no output rules. Please hand the job to the conversion service like the other tools do (XTool.ConversionOf(...)), with a flag on the edge (as Translate, OCR and Captions have) so only upscale presets take it.
  4. Format ids: "Same format" uses the file's extension as the format id (UpscaleViewModel.cs:214). .jpeg, .tif and camera RAW extensions then reach ImageReader.Read / ImageEncoder.ToMagickFormat, which throws. Use FormatRegistry.Detect(...).Id, and UpscaleTool.TargetFor (PNG for sources Filee can't write). The converter's format list also has "jpeg", which isn't a format id.
  5. Deleting a model can crash Filee: UpscaleWindow.axaml.cs deletes in an async void handler with no try / catch. An EngineBusyException or IOException there ends the app.
  6. Closing the window doesn't stop the job: the title-bar ✕ (and opening a second window) leaves upscayl-bin running hidden until its 15-minute limit. Cancel on close and dispose the view model.
  7. Notices and docs: the NMKD models are by nmkd (not Philip Hofmann), and their two OpenModelDB links return 404. docs/ENGINES.md still lists uniscale_restore and the removed model manager.
  8. Leftover keys: 17 keys from the removed manager window are unused in all 19 files (engines.upscaler.manage, modal_title, search_placeholder, hardware_*, recommended_*, download*, delete_*, no_models, upscale.no_models_installed, engine.reason.needs_models). Please remove them.

Smaller

  • Windows on ARM: on Windows 11 ARM64 the x64 zip is offered (the runtime maps to win-x64), not "unavailable" as the PR says. Whether it runs there under emulation with Vulkan is untested, so please say which you intend.
  • Scale: the binary takes 2, 3 or 4 (-s), but the UI allows 1×.
  • Output: the output is written with a bare MagickImage.Write, so the preset's quality is ignored. Use the image encoder, which also handles ICO's size limit.
  • Small fixes: the model download shows no progress, and the window hard-codes colours instead of theme resources.

Happy to look again for the next release.

@KnifeLemon KnifeLemon mentioned this pull request Nov 4, 2026
7 of 12 tasks
@rohitLovesKrishna
rohitLovesKrishna force-pushed the feature/upscale-image branch 2 times, most recently from ea61387 to 0d630cb Compare November 4, 2026 04:32
# Conflicts:
#	src/Filee.Core/Presets/BuiltInData.cs
#	src/Filee.Core/Presets/Preset.cs
#	src/Filee.Core/Settings/UserDataStore.cs
#	tests/Filee.App.Tests/ToolbarPaletteViewTests.cs

# Conflicts:
#	src/Filee.Core/Settings/UserDataStore.cs
@rohitLovesKrishna

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @KnifeLemon! All points have been addressed in the latest commit:

  1. Whisper installer fix: Restored case "model": to fall into case "bin": in EngineInstaller.cs so .filee-component is created and Whisper models stay installed. Added a unit test (Model_components_are_copied_and_marked_installed) in EngineInstallerTests.cs to guard against regressions.
  2. VC++ runtime on Windows (VCOMP140.DLL): Added vcruntime to the upscayl-bin package on Windows in EngineDownloads.cs and updated EngineInstaller.CopyRuntime to copy runtime DLLs to zip components so vcomp140.dll sits next to upscayl-bin.exe.
  3. Conversion step & JobQueue routing: Added an Upscale: true flag to ConversionEdge, RouteStep, ConversionStep, and RouteRequest. Edges are excluded from normal routes and only taken when Upscale.Enabled is set on the preset. UpscaleViewModel now delegates conversion to ConversionService.Start using UpscaleTool.ConversionOf(...), routing through JobQueue with standard toasts, history, output rules, and recycle bin support. The Upscale window also remains accessible so users can run additional conversions with other models in the same session.
  4. Format IDs: Replaced file extension lookups with FormatRegistry.Detect(...).Id and UpscaleTool.TargetFor(...) (falling back to PNG for camera RAW and unwriteable formats). Removed "jpeg" from UpscalerConverter's format list.
  5. Model deletion safety & UI: Wrapped model deletion in a try / catch handling EngineBusyException and IOException with an error dialog. Added the Material delete trash icon StreamGeometry resource so the delete icon displays and is functional on downloaded models.
  6. Cancellation & window closing: Implemented IDisposable on UpscaleViewModel and hooked into the window's Closing event to cancel the token source on close or when opening another window, terminating any running upscayl-bin process.
  7. Scale factor & output encoding: Restricted scale factor to 2×, 3×, and 4×. Replaced bare MagickImage.Write with ImageEncoder.ApplyOptions and ImageEncoder.WriteImage to respect preset image quality and ICO constraints.
  8. Theme resources & download progress: Replaced hardcoded hex colors with dynamic theme resources ({DynamicResource SuccessBrush}, {DynamicResource DangerBrush}, etc.) and added progress percentage feedback during model downloads.
  9. Docs & Notices: Updated NMKD models author to nmkd in THIRD-PARTY-NOTICES.md (and removed dead links). Removed uniscale_restore and references to the old manager window in docs/ENGINES.md. Clarified Windows on ARM behavior.
  10. i18n cleanup: Removed all 17 unused leftover keys across all 19 language files while maintaining formatting and it.json styling.

@rohitLovesKrishna
rohitLovesKrishna force-pushed the feature/upscale-image branch 2 times, most recently from 80195a8 to f51e07f Compare November 4, 2026 05:40
- Restore case 'model' to bin extraction in EngineInstaller to prevent Whisper regression
- Add unit test verifying kind 'model' component installation
- Add vcruntime to upscayl-bin on Windows and ensure VCOMP140.DLL is copied next to binary
- Add Upscale flag to ConversionEdge, RoutePlanner, and route jobs via JobQueue
- Use FormatRegistry.Detect and UpscaleTool.TargetFor to avoid raw extensions as format IDs
- Remove 'jpeg' from upscaler supported format IDs
- Safely handle model deletion with try/catch and error dialog
- Add Material trash icon StreamGeometry and fix delete button visibility for installed models
- Cancel token and dispose view model on window closing
- Use ImageEncoder to respect preset quality and icon constraints
- Show live progress percentage during model download in dialog
- Use dynamic theme brushes in UpscaleWindow instead of hardcoded hex values
- Update NMKD notices author to nmkd and clean up docs/ENGINES.md
- Remove 17 leftover keys across all 19 language files

@KnifeLemon KnifeLemon left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @rohitLovesKrishna. A lot of this is much better now: everything in the first review is done, the schema step (v69) sits cleanly on main's 68, the zip pins match, the arguments use list form, and all 22 keys are in all 20 languages. CI is green too, but these need fixing, because CI can't reach any of them.

Must fix

1. VCOMP140.DLL is still not installed (EngineDownloads.cs:57)

This is the one from my last review. vc14_runtime leaves it out on purpose: conda-forge's packaging skips vcomp*.dll, and the package depends on vcomp14 for it. So on a PC without the VC++ Redistributable, upscayl-bin won't start. Add vcomp14 (the -h818238b_41 build that goes with the runtime you pin) and copy it in CopyRuntime.

2. Portrait photos come out sideways (UpscalerEngine.cs:52-58)

The frame is written to the temp PNG without AutoOrient, and ImageReader doesn't rotate. PNG has no orientation for ApplyOptions to see later, so a phone's portrait JPEG ends up on its side. EXIF and ICC are dropped there too, whatever KeepMetadata says. Please orient first and copy the profiles to the result.

3. The default "Same format" fails for many pictures (UpscaleTool.cs:29, UpscalerConverter.cs:13)

TargetFor returns any writable format, but the converter has edges for only 8. GIF, JXL, TGA, JP2 and PSD are writable, get their own id back and end in error.no_route. Fall back to PNG unless the id is one of the targets, or add the edges.

4. The window says it worked before anything ran (UpscaleViewModel.cs:214-221)

_start only enqueues, and straight after it the window shows upscale.success, even if the job fails later. Clicking again queues the same pictures again. Please close the window after starting and let the toast report the result.

5. Removing Upscayl can break Ghostscript's status (EngineDownloads.cs:57, EngineInstaller.cs:174)

vcruntime is now shared. Removing one package moves that folder away, so IsInstalled for the other turns false, and Ghostscript shows as not installed (and the other way round). Components that another installed package still uses have to stay.

6. No Vulkan means raw English stderr (UpscalerEngine.cs:93, docs/ENGINES.md:1919)

From its source (main.cpp:1193), upscayl-bin has no CPU mode: with no Vulkan device it exits -1. The user then sees its stderr untranslated, and the docs still claim a CPU route. Refuse with a translated ConversionRefusedException and correct the docs.

Smaller

  • UpscaleViewModel.cs:114: common.files_count doesn't exist, so several pictures show the raw key. home.files is the one.
  • PresetEditorView.axaml:302: the slider allows 1×, which saves 1 and reopens at 4×. Minimum 2.
  • UpscalerEngine.cs:48-49: fixed temp names in the job's work folder. If a later file exits 0 without output, it gets the previous file's picture. Use unique names.
  • UpscalerEngine.cs:17: a 15-minute total limit can kill slow runs that are still working. A stall timeout fits better, like calibre's.
  • upscale-models.json:10,25: the author still says "Philip Hofmann (NMKD)", from the last review.
  • Unused: GpuId (Preset.cs:1700) and upscale.processing in the language files.
  • Comments say schema 65 (BuiltInData.cs:334,338, Preset.cs:285, UpscaleToolTests.cs:2).
  • Unrelated to this PR: ClipWindowTests.cs:919 triples a wait, and there are stray blank lines in AppHost.cs, EnginesPageViewModel.cs and EnginesPage.axaml.cs.
  • UpscalerTests: Assert.NotNull(status) proves nothing. Items 2 and 3 and the PNG fallback need real tests.

Question still open

Is Windows on ARM meant to work? Please say either way, so we know whether it needs a refusal or an arm64 build.

Most of this was found by reading the code, not by running upscayl-bin, so tell me if something behaves differently on your machine.

- Add vcomp14 conda package to upscayl-bin Windows components and copy OpenMP runtime in CopyRuntime
- Auto-orient frames before upscaling and preserve EXIF and ICC profiles on results
- Fall back unsupported writable target formats to PNG in UpscaleTool.TargetFor
- Connect UpscalerConverter edges from all readable image sources to supported target formats
- Close upscale dialog immediately upon job start and delegate progress/completion to conversion toast
- Retain shared package components (like vcruntime) during package uninstallation in EngineInstaller
- Check AppLocalRuntime for missing DLLs and refuse cleanly when Vulkan GPU is absent
- Replace fixed timeout with stall/inactivity timeout and use unique temp file names
- Set PresetEditorView scale slider minimum to 2 and use home.files localization key in UpscaleViewModel
- Remove unused GpuId property, remove unused upscale.processing key, and update schema 69 comments
- Clarify offline Vulkan requirement in docs/ENGINES.md and remove inaccurate CPU claims
- Add unit tests for shared component uninstallation, auto-orient, profile preservation, and format fallback
- Revert out-of-scope edits in ClipWindowTests, AppHost, EnginesPageViewModel, and EnginesPage
@rohitLovesKrishna

rohitLovesKrishna commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author
2026-11-04.20-14-31_compressed.mp4

Thanks for the thorough review, @KnifeLemon! All points have been addressed in the latest commit:

Must Fix

  1. vcomp14 & VCOMP140.DLL:
    • Pinned vcomp14 (14.44.35208-h818238b_41) from conda-forge in engines.json and added it to upscayl-bin's Windows components in EngineDownloads.cs.
    • Updated CopyRuntime in EngineInstaller.cs to copy DLLs from both vcruntime and vcomp14 next to upscayl-bin.exe.
  2. Portrait Orientation & Profile Preservation:
    • Applied frame.AutoOrient() before writing the temporary input PNG in UpscalerEngine.cs.
    • Preserved EXIF and ICC profiles from the input and re-attached them to the upscaled result according to preset.Image.KeepMetadata / KeepColorProfile, stripping old thumbnails to avoid stale orientation.
  3. Target Format Fallback:
    • In UpscaleTool.TargetFor, checked against the 8 supported target IDs (png, jpg, webp, avif, heic, ico, bmp, tiff); non-target writable formats (GIF, JXL, TGA, JP2, PSD, camera RAWs) now cleanly fall back to "png".
    • Connected UpscalerConverter.Edges from all readable image sources (ImageEncoder.Sources) to the 8 supported target formats.
  4. Dialog Enqueue & Close Behavior:
    • UpscaleViewModel now invokes a CloseRequested event immediately upon enqueueing conversions to ConversionService, letting the toast report the background conversion progress and completion. Removed premature success banner.
  5. Shared Component Retention on Uninstall:
    • EngineInstaller.Uninstall now inspects other installed packages and leaves shared components (such as vcruntime) intact when another installed engine still depends on them.
    • Added a unit test in EngineInstallerTests.cs verifying shared component retention across multiple packages.
  6. Vulkan GPU Refusal & Documentation:
    • Added check for missing DLLs (AppLocalRuntime.ThrowIfMissing) and caught exit code -1 / Vulkan device initialization errors, cleanly throwing ConversionRefusedException("error.upscale_needs_vulkan"). Added the localized message across all 20 language files.
    • Updated docs/ENGINES.md to remove references to CPU mode / donut placement, clarifying the direct Vulkan GPU requirement and palette placement.

Smaller Items & Cleanups

  • Changed common.files_count to home.files in UpscaleViewModel.cs:114.
  • Set slider minimum to 2 in PresetEditorView.axaml:302.
  • Used unique temp file names (Guid.NewGuid()) in UpscalerEngine.cs and cleaned them up in a finally block.
  • Replaced fixed 15-minute timeout with stallTimeout: StallTimeout (5-minute inactivity limit).
  • Updated author to "Philip Hofmann" in upscale-models.json.
  • Removed unused GpuId from Preset.cs and unused upscale.processing key across all 20 language files.
  • Updated schema comment references from 65 to 69 in BuiltInData.cs, Preset.cs, and UpscaleToolTests.cs.
  • Reverted out-of-scope edits in ClipWindowTests.cs, AppHost.cs, EnginesPageViewModel.cs, and EnginesPage.axaml.cs.
  • Added unit tests in UpscalerTests.cs covering AutoOrient, profile preservation, and format fallback.

Regarding Windows on ARM (win-arm64):

upscayl-bin should be reported as unavailable on win-arm64:

  • The upstream project publishes x64 binaries only for Windows (there is no native Windows ARM64 build).
  • While Windows 11 on ARM provides an x64 emulation layer (Prism), the Qualcomm Adreno Vulkan driver (vulkan-1.dll / ICD) is native ARM64 only. The emulation layer does not support x64-to-ARM64 Vulkan ICD thunking, so vkCreateInstance fails during process startup.
  • In EngineDownloads.cs, upscayl-bin is now restricted on Windows to non-ARM64 architectures (RuntimeInformation.ProcessArchitecture != Architecture.Arm64), cleanly reporting Upscale is not available on this PC (win-arm64).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants