Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 19552)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 19553)
@@ -22,4 +22,5 @@
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -278,10 +279,14 @@
         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
@@ -304,5 +309,5 @@
                     iconFuture.complete(null);
                 }
-            });
+            }, fetcher);
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 19552)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 19553)
@@ -45,4 +45,5 @@
 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;
@@ -718,5 +719,6 @@
      * 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
      *
@@ -725,5 +727,18 @@
      */
     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
+     * @since 19553
+     */
+    public static Executor getImageFetchExecutor() {
+        return IMAGE_FETCHER;
     }
 
