diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatProvider.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatProvider.java
new file mode 100644
index 000000000..e159358a7
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatProvider.java
@@ -0,0 +1,72 @@
+/*
+ * @(#)ImageFormatProvider.java
+ *
+ * Copyright (c) 2025 The authors and contributors of JHotDraw.
+ * You may not use, copy or modify this file, except in compliance with the
+ * accompanying license terms.
+ */
+package org.jhotdraw.draw.io;
+
+import org.jhotdraw.draw.figure.ImageHolderFigure;
+
+/**
+ * A provider interface for image format support.
+ *
+ *
Implementations of this interface define how to create input and output
+ * formats for specific image types (PNG, JPEG, GIF, etc.).
+ *
+ * To add support for a new image format:
+ *
+ * - Implement this interface
+ * - Register with {@link ImageFormatRegistry#registerProvider(ImageFormatProvider)}
+ * - Or add to META-INF/services/org.jhotdraw.draw.io.ImageFormatProvider for SPI
+ *
+ *
+ * @author JHotDraw
+ * @version $Id$
+ */
+public interface ImageFormatProvider {
+
+ /**
+ * Returns the format name (e.g., "PNG", "JPEG").
+ *
+ * @return the format name
+ */
+ String getFormatName();
+
+ /**
+ * Returns a human-readable description of the format.
+ *
+ * @return the format description
+ */
+ String getDescription();
+
+ /**
+ * Returns the file extensions supported by this format.
+ *
+ * @return array of file extensions (without dots)
+ */
+ String[] getFileExtensions();
+
+ /**
+ * Returns the MIME types supported by this format.
+ *
+ * @return array of MIME types
+ */
+ String[] getMimeTypes();
+
+ /**
+ * Creates an input format for reading images of this type.
+ *
+ * @param prototype the prototype figure for holding the image
+ * @return an InputFormat instance
+ */
+ InputFormat createInputFormat(ImageHolderFigure prototype);
+
+ /**
+ * Creates an output format for writing images of this type.
+ *
+ * @return an OutputFormat instance, or null if output is not supported
+ */
+ OutputFormat createOutputFormat();
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatRegistry.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatRegistry.java
new file mode 100644
index 000000000..7a5ca9f7e
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/ImageFormatRegistry.java
@@ -0,0 +1,129 @@
+/*
+ * @(#)ImageFormatRegistry.java
+ *
+ * Copyright (c) 2025 The authors and contributors of JHotDraw.
+ * You may not use, copy or modify this file, except in compliance with the
+ * accompanying license terms.
+ */
+package org.jhotdraw.draw.io;
+
+import org.jhotdraw.draw.figure.ImageHolderFigure;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ServiceLoader;
+
+/**
+ * A registry for image format handlers that provides a modular way to
+ * add support for various image formats (PNG, JPEG, GIF, etc.).
+ *
+ * This class uses the Service Provider Interface (SPI) pattern to allow
+ * dynamic registration of image format handlers.
+ *
+ * Usage:
+ *
+ * // Get all registered input formats for a prototype figure
+ * List<InputFormat> formats = ImageFormatRegistry.getInputFormats(myImageFigure);
+ * drawing.getInputFormats().addAll(formats);
+ *
+ *
+ * @author JHotDraw
+ * @version $Id$
+ */
+public final class ImageFormatRegistry {
+
+ private static final List providers = new ArrayList<>();
+
+ static {
+ // Register default providers
+ registerProvider(new PngFormatProvider());
+ registerProvider(new JpegFormatProvider());
+
+ // Load additional providers via SPI
+ ServiceLoader loader = ServiceLoader.load(ImageFormatProvider.class);
+ for (ImageFormatProvider provider : loader) {
+ registerProvider(provider);
+ }
+ }
+
+ private ImageFormatRegistry() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Registers a new image format provider.
+ *
+ * @param provider the provider to register
+ */
+ public static void registerProvider(ImageFormatProvider provider) {
+ if (provider != null && !providers.contains(provider)) {
+ providers.add(provider);
+ }
+ }
+
+ /**
+ * Unregisters an image format provider.
+ *
+ * @param provider the provider to unregister
+ */
+ public static void unregisterProvider(ImageFormatProvider provider) {
+ providers.remove(provider);
+ }
+
+ /**
+ * Returns all registered providers.
+ *
+ * @return an unmodifiable list of providers
+ */
+ public static List getProviders() {
+ return Collections.unmodifiableList(providers);
+ }
+
+ /**
+ * Creates input formats for all registered image format providers.
+ *
+ * @param prototype the prototype figure to use for creating image holders
+ * @return a list of input formats
+ */
+ public static List createInputFormats(ImageHolderFigure prototype) {
+ List formats = new ArrayList<>();
+ for (ImageFormatProvider provider : providers) {
+ formats.add(provider.createInputFormat(prototype));
+ }
+ return formats;
+ }
+
+ /**
+ * Creates output formats for all registered image format providers.
+ *
+ * @return a list of output formats
+ */
+ public static List createOutputFormats() {
+ List formats = new ArrayList<>();
+ for (ImageFormatProvider provider : providers) {
+ OutputFormat format = provider.createOutputFormat();
+ if (format != null) {
+ formats.add(format);
+ }
+ }
+ return formats;
+ }
+
+ /**
+ * Checks if a specific format is supported.
+ *
+ * @param extension the file extension (e.g., "png", "jpg")
+ * @return true if the format is supported
+ */
+ public static boolean isFormatSupported(String extension) {
+ String ext = extension.toLowerCase();
+ for (ImageFormatProvider provider : providers) {
+ for (String supported : provider.getFileExtensions()) {
+ if (supported.equalsIgnoreCase(ext)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/JpegFormatProvider.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/JpegFormatProvider.java
new file mode 100644
index 000000000..894a77a4c
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/JpegFormatProvider.java
@@ -0,0 +1,64 @@
+/*
+ * @(#)JpegFormatProvider.java
+ *
+ * Copyright (c) 2025 The authors and contributors of JHotDraw.
+ * You may not use, copy or modify this file, except in compliance with the
+ * accompanying license terms.
+ */
+package org.jhotdraw.draw.io;
+
+import org.jhotdraw.draw.figure.ImageHolderFigure;
+import java.awt.image.BufferedImage;
+
+/**
+ * Provider for JPEG (Joint Photographic Experts Group) image format.
+ *
+ * JPEG uses lossy compression, making it ideal for photographs
+ * and images with smooth color gradients. Supports both .jpg and .jpeg extensions.
+ *
+ * @author JHotDraw
+ * @version $Id$
+ */
+public class JpegFormatProvider implements ImageFormatProvider {
+
+ @Override
+ public String getFormatName() {
+ return "JPEG";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Joint Photographic Experts Group (JPEG)";
+ }
+
+ @Override
+ public String[] getFileExtensions() {
+ return new String[]{"jpg", "jpeg"};
+ }
+
+ @Override
+ public String[] getMimeTypes() {
+ return new String[]{"image/jpeg", "image/jpg"};
+ }
+
+ @Override
+ public InputFormat createInputFormat(ImageHolderFigure prototype) {
+ return new ImageInputFormat(
+ prototype,
+ getFormatName(),
+ getDescription(),
+ getFileExtensions(),
+ getMimeTypes()
+ );
+ }
+
+ @Override
+ public OutputFormat createOutputFormat() {
+ return new ImageOutputFormat(
+ "JPG",
+ getDescription(),
+ "jpg",
+ BufferedImage.TYPE_INT_RGB
+ );
+ }
+}
diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/PngFormatProvider.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/PngFormatProvider.java
new file mode 100644
index 000000000..e5d0c23b7
--- /dev/null
+++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/io/PngFormatProvider.java
@@ -0,0 +1,64 @@
+/*
+ * @(#)PngFormatProvider.java
+ *
+ * Copyright (c) 2025 The authors and contributors of JHotDraw.
+ * You may not use, copy or modify this file, except in compliance with the
+ * accompanying license terms.
+ */
+package org.jhotdraw.draw.io;
+
+import org.jhotdraw.draw.figure.ImageHolderFigure;
+import java.awt.image.BufferedImage;
+
+/**
+ * Provider for PNG (Portable Network Graphics) image format.
+ *
+ * PNG supports lossless compression and transparency (alpha channel),
+ * making it ideal for graphics with sharp edges or text.
+ *
+ * @author JHotDraw
+ * @version $Id$
+ */
+public class PngFormatProvider implements ImageFormatProvider {
+
+ @Override
+ public String getFormatName() {
+ return "PNG";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Portable Network Graphics (PNG)";
+ }
+
+ @Override
+ public String[] getFileExtensions() {
+ return new String[]{"png"};
+ }
+
+ @Override
+ public String[] getMimeTypes() {
+ return new String[]{"image/png"};
+ }
+
+ @Override
+ public InputFormat createInputFormat(ImageHolderFigure prototype) {
+ return new ImageInputFormat(
+ prototype,
+ getFormatName(),
+ getDescription(),
+ getFileExtensions(),
+ getMimeTypes()
+ );
+ }
+
+ @Override
+ public OutputFormat createOutputFormat() {
+ return new ImageOutputFormat(
+ getFormatName(),
+ getDescription(),
+ "png",
+ BufferedImage.TYPE_INT_ARGB
+ );
+ }
+}
diff --git a/jhotdraw-core/src/test/java/org/jhotdraw/draw/io/ImageFormatRegistryTest.java b/jhotdraw-core/src/test/java/org/jhotdraw/draw/io/ImageFormatRegistryTest.java
new file mode 100644
index 000000000..bf0cfa2aa
--- /dev/null
+++ b/jhotdraw-core/src/test/java/org/jhotdraw/draw/io/ImageFormatRegistryTest.java
@@ -0,0 +1,98 @@
+/*
+ * @(#)ImageFormatRegistryTest.java
+ *
+ * Copyright (c) 2025 The authors and contributors of JHotDraw.
+ * You may not use, copy or modify this file, except in compliance with the
+ * accompanying license terms.
+ */
+package org.jhotdraw.draw.io;
+
+import org.jhotdraw.draw.figure.ImageFigure;
+import org.testng.annotations.Test;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+/**
+ * Tests for the modular ImageFormatRegistry.
+ */
+public class ImageFormatRegistryTest {
+
+ @Test
+ public void testPngFormatSupported() {
+ assertTrue(ImageFormatRegistry.isFormatSupported("png"),
+ "PNG format should be supported");
+ assertTrue(ImageFormatRegistry.isFormatSupported("PNG"),
+ "PNG format should be supported (uppercase)");
+ }
+
+ @Test
+ public void testJpegFormatSupported() {
+ assertTrue(ImageFormatRegistry.isFormatSupported("jpg"),
+ "JPG format should be supported");
+ assertTrue(ImageFormatRegistry.isFormatSupported("jpeg"),
+ "JPEG format should be supported");
+ }
+
+ @Test
+ public void testGifFormatSupported() {
+ assertTrue(ImageFormatRegistry.isFormatSupported("gif"),
+ "GIF format should be supported");
+ }
+
+ @Test
+ public void testBmpFormatSupported() {
+ assertTrue(ImageFormatRegistry.isFormatSupported("bmp"),
+ "BMP format should be supported");
+ }
+
+ @Test
+ public void testUnsupportedFormat() {
+ assertFalse(ImageFormatRegistry.isFormatSupported("xyz"),
+ "XYZ format should not be supported");
+ }
+
+ @Test
+ public void testCreateInputFormats() {
+ ImageFigure prototype = new ImageFigure();
+ List formats = ImageFormatRegistry.createInputFormats(prototype);
+
+ assertNotNull(formats, "Input formats should not be null");
+ assertTrue(formats.size() >= 4,
+ "Should have at least 4 input formats (PNG, JPEG, GIF, BMP)");
+ }
+
+ @Test
+ public void testCreateOutputFormats() {
+ List formats = ImageFormatRegistry.createOutputFormats();
+
+ assertNotNull(formats, "Output formats should not be null");
+ assertTrue(formats.size() >= 4,
+ "Should have at least 4 output formats (PNG, JPEG, GIF, BMP)");
+ }
+
+ @Test
+ public void testProviderCount() {
+ List providers = ImageFormatRegistry.getProviders();
+
+ assertNotNull(providers, "Providers should not be null");
+ assertTrue(providers.size() >= 4, "Should have at least 4 providers");
+ }
+
+ @Test
+ public void testPngProvider() {
+ PngFormatProvider provider = new PngFormatProvider();
+
+ assertEquals(provider.getFormatName(), "PNG");
+ assertEquals(provider.getFileExtensions(), new String[]{"png"});
+ assertEquals(provider.getMimeTypes(), new String[]{"image/png"});
+ }
+
+ @Test
+ public void testJpegProvider() {
+ JpegFormatProvider provider = new JpegFormatProvider();
+
+ assertEquals(provider.getFormatName(), "JPEG");
+ assertEquals(provider.getFileExtensions(), new String[]{"jpg", "jpeg"});
+ }
+}