Index: src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
===================================================================
--- src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java   (revision 19552)
+++ src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java   (working copy)
@@ -21,6 +21,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;

@@ -277,12 +278,16 @@
         File arch = TaggingPresetReader.getZipIcons();
         final Collection<String> s = TaggingPresets.ICON_SOURCES.get();
         this.iconFuture = new CompletableFuture<>();
-        new ImageProvider(iconName)
+        final ImageProvider provider = new ImageProvider(iconName)
             .setDirs(s)
             .setId("presets")
             .setArchive(arch)
-            .setOptional(true)
-            .getResourceAsync(result -> {
+            .setOptional(true);
+        final Executor fetcher = ImageProvider.getImageFetchExecutor();
+        // Explicitly dispatch to the image fetch executor so that even local JAR-bundled icons
+        // are loaded asynchronously, keeping expensive SVG pre-rendering off the startup thread.
+        CompletableFuture.supplyAsync(provider::getResource, fetcher)
+            .thenAcceptAsync(result -> {
                 if (result != null) {
                     // Pre-render off EDT to avoid flooding the event queue with expensive SVG rendering
                     ImageIcon small = result.getImageIcon(ImageProvider.ImageSizes.SMALLICON.getImageDimension());
@@ -303,7 +308,7 @@
                     Logging.warn(toString() + ": " + PRESET_ICON_ERROR_MSG_PREFIX + iconName);
                     iconFuture.complete(null);
                 }
-            });
+            }, fetcher);
     }

     /**
Index: src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- src/org/openstreetmap/josm/tools/ImageProvider.java (revision 19552)
+++ src/org/openstreetmap/josm/tools/ImageProvider.java (working copy)
@@ -44,6 +44,7 @@
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.function.Consumer;
@@ -717,7 +718,8 @@
     /**
      * Load the image in a background thread.
      * <p>
-     * This method returns immediately and runs the image request asynchronously.
+     * This method returns immediately and runs the image request asynchronously for remote resources.
+     * For local resources, the request is executed synchronously in the current thread.
      * @param action the action that will deal with the image
      *
      * @return the future of the requested image
@@ -724,10 +726,22 @@
      * @since 13252
      */
     public CompletableFuture<Void> getResourceAsync(Consumer<? super ImageResource> action) {
-        return CompletableFuture.supplyAsync(this::getResource, IMAGE_FETCHER).thenAcceptAsync(action, IMAGE_FETCHER);
+        return isRemote()
+                ? CompletableFuture.supplyAsync(this::getResource, IMAGE_FETCHER).thenAcceptAsync(action, IMAGE_FETCHER)
+                : CompletableFuture.completedFuture(getResource()).thenAccept(action);
     }

     /**
+     * Returns the executor used for background image fetching.
+     * Callers that need to force asynchronous loading even for local resources
+     * (e.g. to off-load expensive SVG pre-rendering) may use this executor directly.
+     * @return the image fetch executor
+     */
+    public static Executor getImageFetchExecutor() {
+        return IMAGE_FETCHER;
+    }
+
+    /**
      * Load an image with a given file name.
      *
      * @param subdir subdirectory the image lies in
