You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ki...@apache.org on 2022/01/16 02:03:03 UTC

[commons-imaging] 03/24: [IMAGING-159] Use ImagingParameters and define new classes as needed for other formats

This is an automated email from the ASF dual-hosted git repository.

kinow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-imaging.git

commit 9ab24f90ad987de5b9cd2c70b94c17c6a01a63db
Author: Bruno P. Kinoshita <ki...@users.noreply.github.com>
AuthorDate: Thu Apr 22 08:19:12 2021 +1200

    [IMAGING-159] Use ImagingParameters and define new classes as needed for other formats
---
 .../java/org/apache/commons/imaging/Imaging.java   |  27 +--
 .../apache/commons/imaging/ImagingConstants.java   |  22 ---
 .../imaging/formats/icns/IcnsImageParser.java      |  46 +----
 .../formats/icns/IcnsImagingParameters.java        |  26 +++
 .../imaging/formats/ico/IcoImageParser.java        |  33 +---
 .../imaging/formats/ico/IcoImagingParameters.java  |  26 +++
 .../imaging/formats/jpeg/JpegImageParser.java      |  28 ++-
 .../formats/jpeg/JpegImagingParameters.java        |  26 +++
 .../commons/imaging/formats/png/PngConstants.java  |  25 ---
 .../imaging/formats/png/PngImageParser.java        |  24 +--
 .../imaging/formats/png/PngImagingParameters.java  |  95 +++++++++++
 .../commons/imaging/formats/png/PngWriter.java     |  85 +++------
 .../imaging/formats/psd/PsdImageParser.java        |  15 +-
 .../imaging/formats/psd/PsdImagingParameters.java  |  28 +++
 .../imaging/formats/rgbe/RgbeImageParser.java      |  13 +-
 .../formats/rgbe/RgbeImagingParameters.java        |  26 +++
 .../imaging/formats/tiff/TiffCompression.java      |  22 +++
 .../imaging/formats/tiff/TiffDirectory.java        |  15 +-
 .../imaging/formats/tiff/TiffImageParser.java      | 102 +++++------
 .../formats/tiff/TiffImagingParameters.java        | 189 +++++++++++++++++++++
 .../commons/imaging/formats/tiff/TiffReader.java   |  21 +--
 .../formats/tiff/constants/TiffConstants.java      |  45 -----
 .../formats/tiff/write/TiffImageWriterBase.java    |  67 ++------
 .../tiff/write/TiffImageWriterLossless.java        |   3 +-
 .../imaging/formats/wbmp/WbmpImageParser.java      |  30 +---
 .../formats/wbmp/WbmpImagingParameters.java        |  26 +++
 .../imaging/formats/xbm/XbmImageParser.java        |  29 +---
 .../imaging/formats/xbm/XbmImagingParameters.java  |  26 +++
 28 files changed, 659 insertions(+), 461 deletions(-)

diff --git a/src/main/java/org/apache/commons/imaging/Imaging.java b/src/main/java/org/apache/commons/imaging/Imaging.java
index 8944a44..4fbea0d 100644
--- a/src/main/java/org/apache/commons/imaging/Imaging.java
+++ b/src/main/java/org/apache/commons/imaging/Imaging.java
@@ -718,13 +718,16 @@ public final class Imaging {
         return getImageInfo(file, null);
     }
 
-    private static ImageInfo getImageInfo(final ByteSource byteSource, final ImagingParameters params)
-            throws ImageReadException, IOException {
-        return getImageParser(byteSource).getImageInfo(byteSource, params);
+    // See getImageParser
+    @SuppressWarnings("unchecked")
+	private static ImageInfo getImageInfo(final ByteSource byteSource, final ImagingParameters params) throws ImageReadException, IOException {
+        return Imaging.getImageParser(byteSource).getImageInfo(byteSource, params);
     }
 
-    private static ImageParser<?> getImageParser(final ByteSource byteSource)
-            throws ImageReadException, IOException {
+    // TODO: We have no way of knowing whether the returned ImageParser will accept the ImagingParameters,
+    // even if we specified generic types for the static methods.
+    @SuppressWarnings("rawtypes")
+	private static ImageParser getImageParser(final ByteSource byteSource) throws ImageReadException, IOException {
         final ImageFormat format = guessFormat(byteSource);
         if (!format.equals(ImageFormats.UNKNOWN)) {
 
@@ -732,7 +735,7 @@ public final class Imaging {
 
             for (final ImageParser<?> imageParser : imageParsers) {
                 if (imageParser.canAcceptType(format)) {
-                    return (ImageParser<?>) imageParser;
+                    return (ImageParser) imageParser;
                 }
             }
         }
@@ -743,7 +746,7 @@ public final class Imaging {
 
             for (final ImageParser<?> imageParser : imageParsers) {
                 if (imageParser.canAcceptExtension(fileName)) {
-                    return (ImageParser<?>) imageParser;
+                    return (ImageParser) imageParser;
                 }
             }
         }
@@ -965,7 +968,9 @@ public final class Imaging {
      * @throws ImageReadException if it fails to parse the image
      * @throws IOException if it fails to read the image data
      */
-    public static String getXmpXml(final ByteSource byteSource, final ImagingParameters params)
+    // TODO: we have no way of knowing whether getImageParser will return a parser that is compatible with the ImagingParameters instance given
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static String getXmpXml(final ByteSource byteSource, final ImagingParameters params)
             throws ImageReadException, IOException {
         final ImageParser<?> imageParser = getImageParser(byteSource);
         if (imageParser instanceof XmpEmbeddable) {
@@ -1510,13 +1515,15 @@ public final class Imaging {
      * @throws IOException in the event of an unrecoverable I/O exception.
      * @see ImagingConstants
      */
-    public static <T extends ImagingParameters> void writeImage(final BufferedImage src, final OutputStream os,
+    // TODO: fix generics due to ImageParser retrieved via getAllImageParsers, and the given ImagingParameters type
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static void writeImage(final BufferedImage src, final OutputStream os,
             ImagingParameters params) throws ImageWriteException,
             IOException {
         Objects.requireNonNull(params, "You must provide a valid imaging parameters object.");
         final ImageParser<?>[] imageParsers = ImageParser.getAllImageParsers();
 
-        ImageParser<?> imageParser = null;
+		ImageParser imageParser = null;
         for (final ImageParser<?> imageParser2 : imageParsers) {
             if (imageParser2.canAcceptType(params.getImageFormat())) {
                 imageParser = imageParser2;
diff --git a/src/main/java/org/apache/commons/imaging/ImagingConstants.java b/src/main/java/org/apache/commons/imaging/ImagingConstants.java
index 80de12d..d2b48e7 100644
--- a/src/main/java/org/apache/commons/imaging/ImagingConstants.java
+++ b/src/main/java/org/apache/commons/imaging/ImagingConstants.java
@@ -41,17 +41,6 @@ public final class ImagingConstants {
     public static final String PARAM_KEY_COMPRESSION = "COMPRESSION";
 
     /**
-     * <p>Parameter key. Indicates whether to read embedded thumbnails.</p>
-     *
-     * <p>Only applies to read EXIF metadata from JPEG/JFIF files.</p>
-     *
-     * <p>Valid values: {@code Boolean.TRUE} and {@code Boolean.FALSE}.</p>
-     *
-     * @see org.apache.commons.imaging.formats.tiff.constants.TiffConstants
-     */
-    public static final String PARAM_KEY_READ_THUMBNAILS = "READ_THUMBNAILS";
-
-    /**
      * <p>Parameter key. Indicates whether to throw exceptions when parsing invalid
      * files, or whether to tolerate small problems.</p>
      *
@@ -63,17 +52,6 @@ public final class ImagingConstants {
     public static final String PARAM_KEY_STRICT = "STRICT";
 
     /**
-     * <p>Parameter key.</p>
-     *
-     * <p>Only used when writing images.</p>
-     *
-     * <p>Valid values: TiffOutputSet to write into the image's EXIF metadata.</p>
-     *
-     * @see org.apache.commons.imaging.formats.tiff.write.TiffOutputSet
-     */
-    public static final String PARAM_KEY_EXIF = "EXIF";
-
-    /**
      * Empty byte array.
      */
     public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
diff --git a/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImageParser.java b/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImageParser.java
index 18965f4..9cb7d63 100644
--- a/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImageParser.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.imaging.formats.icns;
 
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FORMAT;
 import static org.apache.commons.imaging.common.BinaryFunctions.read4Bytes;
 import static org.apache.commons.imaging.common.BinaryFunctions.readBytes;
 
@@ -28,9 +27,7 @@ import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.ImageFormat;
 import org.apache.commons.imaging.ImageFormats;
@@ -42,7 +39,7 @@ import org.apache.commons.imaging.common.BinaryOutputStream;
 import org.apache.commons.imaging.common.ImageMetadata;
 import org.apache.commons.imaging.common.bytesource.ByteSource;
 
-public class IcnsImageParser extends ImageParser {
+public class IcnsImageParser extends ImageParser<IcnsImagingParameters> {
     static final int ICNS_MAGIC = IcnsType.typeAsInt("icns");
     private static final String DEFAULT_EXTENSION = ".icns";
     private static final String[] ACCEPTED_EXTENSIONS = { ".icns", };
@@ -73,22 +70,14 @@ public class IcnsImageParser extends ImageParser {
 
     // FIXME should throw UOE
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final IcnsImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, IcnsImagingParameters params)
             throws ImageReadException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = params == null ? new HashMap<>() : new HashMap<>(params);
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageReadException("Unknown parameter: " + firstKey);
-        }
-
         final IcnsContents contents = readImage(byteSource);
         final List<BufferedImage> images = IcnsDecoder.decodeAllImages(contents.icnsElements);
         if (images.isEmpty()) {
@@ -104,16 +93,8 @@ public class IcnsImageParser extends ImageParser {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, IcnsImagingParameters params)
             throws ImageReadException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageReadException("Unknown parameter: " + firstKey);
-        }
-
         final IcnsContents contents = readImage(byteSource);
         final List<BufferedImage> images = IcnsDecoder.decodeAllImages(contents.icnsElements);
         if (images.isEmpty()) {
@@ -124,7 +105,7 @@ public class IcnsImageParser extends ImageParser {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final IcnsImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
@@ -244,7 +225,7 @@ public class IcnsImageParser extends ImageParser {
 
     @Override
     public final BufferedImage getBufferedImage(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final IcnsImagingParameters params) throws ImageReadException, IOException {
         final IcnsContents icnsContents = readImage(byteSource);
         final List<BufferedImage> result = IcnsDecoder.decodeAllImages(icnsContents.icnsElements);
         if (!result.isEmpty()) {
@@ -261,21 +242,8 @@ public class IcnsImageParser extends ImageParser {
     }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, IcnsImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        // clear format key.
-        if (params.containsKey(PARAM_KEY_FORMAT)) {
-            params.remove(PARAM_KEY_FORMAT);
-        }
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
-
         IcnsType imageType;
         if (src.getWidth() == 16 && src.getHeight() == 16) {
             imageType = IcnsType.ICNS_16x16_32BIT_IMAGE;
diff --git a/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImagingParameters.java
new file mode 100644
index 0000000..bbfd8c8
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/icns/IcnsImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.icns;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Icns format parameters.
+ * @since 1.0-alpha3
+ */
+public class IcnsImagingParameters extends ImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java b/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java
index 546e497..d6a4bd7 100644
--- a/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java
@@ -16,8 +16,6 @@
  */
 package org.apache.commons.imaging.formats.ico;
 
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FORMAT;
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_PIXEL_DENSITY;
 import static org.apache.commons.imaging.common.BinaryFunctions.read2Bytes;
 import static org.apache.commons.imaging.common.BinaryFunctions.read4Bytes;
 import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
@@ -33,9 +31,7 @@ import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.ImageFormat;
 import org.apache.commons.imaging.ImageFormats;
@@ -52,7 +48,7 @@ import org.apache.commons.imaging.formats.bmp.BmpImageParser;
 import org.apache.commons.imaging.palette.PaletteFactory;
 import org.apache.commons.imaging.palette.SimplePalette;
 
-public class IcoImageParser extends ImageParser {
+public class IcoImageParser extends ImageParser<IcoImagingParameters> {
     private static final String DEFAULT_EXTENSION = ".ico";
     private static final String[] ACCEPTED_EXTENSIONS = { ".ico", ".cur", };
 
@@ -83,28 +79,28 @@ public class IcoImageParser extends ImageParser {
 
     // TODO should throw UOE
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final IcoImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     // TODO should throw UOE
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final IcoImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     // TODO should throw UOE
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final IcoImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     // TODO should throw UOE
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final IcoImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
@@ -572,7 +568,7 @@ public class IcoImageParser extends ImageParser {
 
     @Override
     public final BufferedImage getBufferedImage(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final IcoImagingParameters params) throws ImageReadException, IOException {
         final ImageContents contents = readImage(byteSource);
         final FileHeader fileHeader = contents.fileHeader;
         if (fileHeader.iconCount > 0) {
@@ -624,22 +620,9 @@ public class IcoImageParser extends ImageParser {
     // }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, IcoImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        // clear format key.
-        if (params.containsKey(PARAM_KEY_FORMAT)) {
-            params.remove(PARAM_KEY_FORMAT);
-        }
-
-        final PixelDensity pixelDensity = (PixelDensity) params.remove(PARAM_KEY_PIXEL_DENSITY);
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
+        final PixelDensity pixelDensity = params.getPixelDensity();
 
         final PaletteFactory paletteFactory = new PaletteFactory();
         final SimplePalette palette = paletteFactory.makeExactRgbPaletteSimple(src, 256);
diff --git a/src/main/java/org/apache/commons/imaging/formats/ico/IcoImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/ico/IcoImagingParameters.java
new file mode 100644
index 0000000..d686bce
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/ico/IcoImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.ico;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Ico format parameters.
+ * @since 1.0-alpha3
+ */
+public class IcoImagingParameters extends ImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImageParser.java b/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImageParser.java
index 288c239..216e0eb 100644
--- a/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImageParser.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.imaging.formats.jpeg;
 
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_READ_THUMBNAILS;
 import static org.apache.commons.imaging.common.BinaryFunctions.remainingBytes;
 import static org.apache.commons.imaging.common.BinaryFunctions.startsWith;
 
@@ -30,9 +29,7 @@ import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -64,7 +61,7 @@ import org.apache.commons.imaging.formats.tiff.TiffImageParser;
 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
 import org.apache.commons.imaging.internal.Debug;
 
-public class JpegImageParser extends ImageParser implements XmpEmbeddable {
+public class JpegImageParser extends ImageParser<JpegImagingParameters> implements XmpEmbeddable<JpegImagingParameters> {
 
     private static final Logger LOGGER = Logger.getLogger(JpegImageParser.class.getName());
 
@@ -99,7 +96,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
 
     @Override
     public final BufferedImage getBufferedImage(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final JpegImagingParameters params) throws ImageReadException, IOException {
         final JpegDecoder jpegDecoder = new JpegDecoder();
         return jpegDecoder.decode(byteSource);
     }
@@ -290,7 +287,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final JpegImagingParameters params)
             throws ImageReadException, IOException {
         final List<Segment> segments = readSegments(byteSource,
                 new int[] { JpegConstants.JPEG_APP2_MARKER, }, false);
@@ -320,7 +317,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final JpegImagingParameters params)
             throws ImageReadException, IOException {
         final TiffImageMetadata exif = getExifMetadata(byteSource, params);
 
@@ -351,19 +348,14 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
         return result;
     }
 
-    public TiffImageMetadata getExifMetadata(final ByteSource byteSource, Map<String, Object> params)
+    public TiffImageMetadata getExifMetadata(final ByteSource byteSource, JpegImagingParameters params)
             throws ImageReadException, IOException {
         final byte[] bytes = getExifRawData(byteSource);
         if (null == bytes) {
             return null;
         }
 
-        if (params == null) {
-            params = new HashMap<>();
-        }
-        if (!params.containsKey(PARAM_KEY_READ_THUMBNAILS)) {
-            params.put(PARAM_KEY_READ_THUMBNAILS, Boolean.TRUE);
-        }
+        params.setReadThumbnails(Boolean.TRUE);
 
         return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes,
                 params);
@@ -542,7 +534,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
      * @return Xmp Xml as String, if present. Otherwise, returns null.
      */
     @Override
-    public String getXmpXml(final ByteSource byteSource, final Map<String, Object> params)
+    public String getXmpXml(final ByteSource byteSource, final JpegImagingParameters params)
             throws ImageReadException, IOException {
 
         final List<String> result = new ArrayList<>();
@@ -592,7 +584,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     public JpegPhotoshopMetadata getPhotoshopMetadata(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final JpegImagingParameters params) throws ImageReadException, IOException {
         final List<Segment> segments = readSegments(byteSource,
                 new int[] { JpegConstants.JPEG_APP13_MARKER, }, false);
 
@@ -621,7 +613,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final JpegImagingParameters params)
             throws ImageReadException, IOException {
         final List<Segment> segments = readSegments(byteSource, new int[] {
                 // kJFIFMarker,
@@ -655,7 +647,7 @@ public class JpegImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final JpegImagingParameters params)
             throws ImageReadException, IOException {
         // List allSegments = readSegments(byteSource, null, false);
 
diff --git a/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImagingParameters.java
new file mode 100644
index 0000000..d2083f3
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/jpeg/JpegImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.jpeg;
+
+import org.apache.commons.imaging.formats.tiff.TiffImagingParameters;
+
+/**
+ * Jpeg format parameters.
+ * @since 1.0-alpha3
+ */
+public class JpegImagingParameters extends TiffImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngConstants.java b/src/main/java/org/apache/commons/imaging/formats/png/PngConstants.java
index b1f1828..bbc460c 100644
--- a/src/main/java/org/apache/commons/imaging/formats/png/PngConstants.java
+++ b/src/main/java/org/apache/commons/imaging/formats/png/PngConstants.java
@@ -25,13 +25,6 @@ public final class PngConstants {
     public static final BinaryConstant PNG_SIGNATURE = new BinaryConstant(
             new byte[] { (byte) 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n', });
 
-    public static final String PARAM_KEY_PNG_BIT_DEPTH = "PNG_BIT_DEPTH";
-    public static final String PARAM_KEY_PNG_FORCE_INDEXED_COLOR = "PNG_FORCE_INDEXED_COLOR";
-    public static final String PARAM_KEY_PNG_FORCE_TRUE_COLOR = "PNG_FORCE_TRUE_COLOR";
-
-    // public static final Object PARAM_KEY_PNG_BIT_DEPTH_YES = "YES";
-    // public static final Object PARAM_KEY_PNG_BIT_DEPTH_NO = "NO";
-
     public static final byte COMPRESSION_TYPE_INFLATE_DEFLATE = 0;
     public static final byte FILTER_METHOD_ADAPTIVE = 0;
 
@@ -60,24 +53,6 @@ public final class PngConstants {
     public static final String XMP_KEYWORD = "XML:com.adobe.xmp";
 
     /**
-     * Parameter key.
-     *
-     * <p>Only used when writing Png images.</p>
-     *
-     * <p>Valid values: a list of WriteTexts.</p>
-     */
-    public static final String PARAM_KEY_PNG_TEXT_CHUNKS = "PNG_TEXT_CHUNKS";
-
-    /**
-     * Parameter key. Used in write operations to indicate the Physical Scale - sCAL.
-     *
-     * <p>Valid values: PhysicalScale</p>
-     *
-     * @see org.apache.commons.imaging.formats.png.PhysicalScale
-     */
-    public static final String PARAM_KEY_PHYSICAL_SCALE = "PHYSICAL_SCALE_CHUNK";
-
-    /**
      * Parameter key. Used to indicate the PNG compression level to be used.
      *
      * <p>For valid values, see {@link java.util.zip.Deflater}. If no value is specified, it will use
diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java b/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java
index 62709a8..67bd8a5 100644
--- a/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java
@@ -35,9 +35,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.InflaterInputStream;
@@ -71,7 +69,7 @@ import org.apache.commons.imaging.formats.png.transparencyfilters.TransparencyFi
 import org.apache.commons.imaging.formats.png.transparencyfilters.TransparencyFilterTrueColor;
 import org.apache.commons.imaging.icc.IccProfileParser;
 
-public class PngImageParser extends ImageParser  implements XmpEmbeddable {
+public class PngImageParser extends ImageParser<PngImagingParameters>  implements XmpEmbeddable<PngImagingParameters> {
 
     private static final Logger LOGGER = Logger.getLogger(PngImageParser.class.getName());
 
@@ -238,7 +236,7 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final PngImagingParameters params)
             throws ImageReadException, IOException {
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.iCCP },
                 true);
@@ -258,7 +256,7 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final PngImagingParameters params)
             throws ImageReadException, IOException {
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.IHDR, }, true);
 
@@ -276,7 +274,7 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final PngImagingParameters params)
             throws ImageReadException, IOException {
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.tEXt, ChunkType.zTXt, }, false);
 
@@ -328,7 +326,7 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final PngImagingParameters params)
             throws ImageReadException, IOException {
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] {
                 ChunkType.IHDR,
@@ -482,14 +480,8 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public BufferedImage getBufferedImage(final ByteSource byteSource, Map<String, Object> params)
+    public BufferedImage getBufferedImage(final ByteSource byteSource, PngImagingParameters params)
             throws ImageReadException, IOException {
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        // if (params.size() > 0) {
-        // Object firstKey = params.keySet().iterator().next();
-        // throw new ImageWriteException("Unknown parameter: " + firstKey);
-        // }
 
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] {
                 ChunkType.IHDR,
@@ -705,13 +697,13 @@ public class PngImageParser extends ImageParser  implements XmpEmbeddable {
     }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, final Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, final PngImagingParameters params)
             throws ImageWriteException, IOException {
         new PngWriter().writeImage(src, os, params);
     }
 
     @Override
-    public String getXmpXml(final ByteSource byteSource, final Map<String, Object> params)
+    public String getXmpXml(final ByteSource byteSource, final PngImagingParameters params)
             throws ImageReadException, IOException {
 
         final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.iTXt }, false);
diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/png/PngImagingParameters.java
new file mode 100644
index 0000000..3fdcc07
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/png/PngImagingParameters.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.png;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.imaging.common.XmpImagingParameters;
+
+/**
+ * Png format parameters.
+ * @since 1.0-alpha3
+ */
+public class PngImagingParameters extends XmpImagingParameters {
+
+	public static final byte DEFAULT_BIT_DEPTH = 8;
+
+	/**
+	 * Bit depth. Default value is {@literal 8}.
+	 */
+	private byte bitDepth = DEFAULT_BIT_DEPTH;
+
+	private boolean forceIndexedColor = false;
+
+	private boolean forceTrueColor = false;
+
+	/**
+     * Used in write operations to indicate the Physical Scale - sCAL.
+     *
+     * <p>Valid values: PhysicalScale</p>
+     *
+     * @see org.apache.commons.imaging.formats.png.PhysicalScale
+     */
+	private PhysicalScale physicalScale = null;
+
+	/**
+     * <p>Only used when writing Png images.</p>
+     *
+     * <p>Valid values: a list of WriteTexts.</p>
+     */
+	private List<PngText> textChunks = null;
+
+	public byte getBitDepth() {
+		return bitDepth;
+	}
+
+	public void setBitDepth(byte bitDepth) {
+		this.bitDepth = bitDepth;
+	}
+
+	public boolean isForceIndexedColor() {
+		return forceIndexedColor;
+	}
+
+	public void setForceIndexedColor(boolean forceIndexedColor) {
+		this.forceIndexedColor = forceIndexedColor;
+	}
+
+	public boolean isForceTrueColor() {
+		return forceTrueColor;
+	}
+
+	public void setForceTrueColor(boolean forceTrueColor) {
+		this.forceTrueColor = forceTrueColor;
+	}
+
+	public PhysicalScale getPhysicalScale() {
+		return physicalScale;
+	}
+
+	public void setPhysicalScale(PhysicalScale physicalScale) {
+		this.physicalScale = physicalScale;
+	}
+
+	public List<PngText> getTextChunks() {
+		return Collections.unmodifiableList(textChunks);
+	}
+
+	public void setTextChunks(List<PngText> textChunks) {
+		this.textChunks = textChunks;
+	}
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngWriter.java b/src/main/java/org/apache/commons/imaging/formats/png/PngWriter.java
index 627501e..ca32993 100644
--- a/src/main/java/org/apache/commons/imaging/formats/png/PngWriter.java
+++ b/src/main/java/org/apache/commons/imaging/formats/png/PngWriter.java
@@ -21,14 +21,11 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
 
 import org.apache.commons.imaging.ImageWriteException;
-import org.apache.commons.imaging.ImagingConstants;
 import org.apache.commons.imaging.PixelDensity;
 import org.apache.commons.imaging.internal.Debug;
 import org.apache.commons.imaging.palette.Palette;
@@ -45,7 +42,7 @@ class PngWriter {
      The remaining 14 chunk types are termed ancillary chunk types, which encoders may generate and decoders may interpret.
 
      1. Transparency information: tRNS (see 11.3.2: Transparency information).
-     2. Colour space information: cHRM, gAMA, iCCP, sBIT, sRGB (see 11.3.3: Colour space information).
+     2. Color space information: cHRM, gAMA, iCCP, sBIT, sRGB (see 11.3.3: Color space information).
      3. Textual information: iTXt, tEXt, zTXt (see 11.3.4: Textual information).
      4. Miscellaneous information: bKGD, hIST, pHYs, sPLT (see 11.3.5: Miscellaneous information).
      5. Time information: tIME (see 11.3.6: Time stamp information).
@@ -295,15 +292,10 @@ class PngWriter {
         writeChunk(os, ChunkType.sCAL, baos.toByteArray());
     }
 
-    private byte getBitDepth(final PngColorType pngColorType, final Map<String, Object> params) {
-        byte depth = 8;
+    private byte getBitDepth(final PngColorType pngColorType, final PngImagingParameters params) {
+        byte depth = params.getBitDepth();
 
-        final Object o = params.get(PngConstants.PARAM_KEY_PNG_BIT_DEPTH);
-        if (o instanceof Number) {
-            depth = ((Number) o).byteValue();
-        }
-
-        return pngColorType.isBitDepthAllowed(depth) ? depth : 8;
+        return pngColorType.isBitDepthAllowed(depth) ? depth : PngImagingParameters.DEFAULT_BIT_DEPTH;
     }
 
     /*
@@ -335,44 +327,9 @@ class PngWriter {
      tEXt   Yes None
      zTXt   Yes None
      */
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, PngImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = new HashMap<>(params);
-
-        // clear format key.
-        if (params.containsKey(ImagingConstants.PARAM_KEY_FORMAT)) {
-            params.remove(ImagingConstants.PARAM_KEY_FORMAT);
-        }
-
         int compressionLevel = Deflater.DEFAULT_COMPRESSION;
-        final Map<String, Object> rawParams = new HashMap<>(params);
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_FORCE_TRUE_COLOR)) {
-            params.remove(PngConstants.PARAM_KEY_PNG_FORCE_TRUE_COLOR);
-        }
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_FORCE_INDEXED_COLOR)) {
-            params.remove(PngConstants.PARAM_KEY_PNG_FORCE_INDEXED_COLOR);
-        }
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_BIT_DEPTH)) {
-            params.remove(PngConstants.PARAM_KEY_PNG_BIT_DEPTH);
-        }
-        if (params.containsKey(ImagingConstants.PARAM_KEY_XMP_XML)) {
-            params.remove(ImagingConstants.PARAM_KEY_XMP_XML);
-        }
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_TEXT_CHUNKS)) {
-            params.remove(PngConstants.PARAM_KEY_PNG_TEXT_CHUNKS);
-        }
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_COMPRESSION_LEVEL)) {
-            compressionLevel = (int) params.remove(PngConstants.PARAM_KEY_PNG_COMPRESSION_LEVEL);
-        }
-        params.remove(ImagingConstants.PARAM_KEY_PIXEL_DENSITY);
-        params.remove(PngConstants.PARAM_KEY_PHYSICAL_SCALE);
-        params.remove(PngConstants.PARAM_KEY_PNG_COMPRESSION_LEVEL);
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
-        params = rawParams;
 
         final int width = src.getWidth();
         final int height = src.getHeight();
@@ -386,8 +343,8 @@ class PngWriter {
 
         PngColorType pngColorType;
         {
-            final boolean forceIndexedColor =  Boolean.TRUE.equals(params.get(PngConstants.PARAM_KEY_PNG_FORCE_INDEXED_COLOR));
-            final boolean forceTrueColor = Boolean.TRUE.equals(params.get(PngConstants.PARAM_KEY_PNG_FORCE_TRUE_COLOR));
+            final boolean forceIndexedColor =  params.isForceIndexedColor();
+            final boolean forceTrueColor = params.isForceTrueColor();
 
             if (forceIndexedColor && forceTrueColor) {
                 throw new ImageWriteException(
@@ -456,7 +413,7 @@ class PngWriter {
             }
         }
 
-        final Object pixelDensityObj = params.get(ImagingConstants.PARAM_KEY_PIXEL_DENSITY);
+        final Object pixelDensityObj = params.getPixelDensity();
         if (pixelDensityObj instanceof PixelDensity) {
             final PixelDensity pixelDensity = (PixelDensity) pixelDensityObj;
             if (pixelDensity.isUnitless()) {
@@ -470,22 +427,23 @@ class PngWriter {
             }
         }
 
-        final Object physcialScaleObj = params.get(PngConstants.PARAM_KEY_PHYSICAL_SCALE);
-        if (physcialScaleObj instanceof PhysicalScale) {
-            final PhysicalScale physicalScale = (PhysicalScale)physcialScaleObj;
-            writeChunkSCAL(os, physicalScale.getHorizontalUnitsPerPixel(), physicalScale.getVerticalUnitsPerPixel(),
-                  physicalScale.isInMeters() ? (byte) 1 : (byte) 2);
+        final PhysicalScale physicalScale = params.getPhysicalScale();
+        if (physicalScale != null) {
+            writeChunkSCAL(
+            		os,
+            		physicalScale.getHorizontalUnitsPerPixel(),
+            		physicalScale.getVerticalUnitsPerPixel(),
+                    physicalScale.isInMeters() ? (byte) 1 : (byte) 2);
         }
 
-        if (params.containsKey(ImagingConstants.PARAM_KEY_XMP_XML)) {
-            final String xmpXml = (String) params.get(ImagingConstants.PARAM_KEY_XMP_XML);
+        final String xmpXml = params.getXmpXml();
+        if (xmpXml != null) {
             writeChunkXmpiTXt(os, xmpXml);
         }
 
-        if (params.containsKey(PngConstants.PARAM_KEY_PNG_TEXT_CHUNKS)) {
-            final List<?> outputTexts = (List<?>) params.get(PngConstants.PARAM_KEY_PNG_TEXT_CHUNKS);
-            for (final Object outputText : outputTexts) {
-                final PngText text = (PngText) outputText;
+        final List<PngText> outputTexts = params.getTextChunks();
+        if (outputTexts != null) {
+            for (final PngText text : outputTexts) {
                 if (text instanceof PngText.Text) {
                     writeChunktEXt(os, (PngText.Text) text);
                 } else if (text instanceof PngText.Ztxt) {
@@ -493,8 +451,7 @@ class PngWriter {
                 } else if (text instanceof PngText.Itxt) {
                     writeChunkiTXt(os, (PngText.Itxt) text);
                 } else {
-                    throw new ImageWriteException(
-                            "Unknown text to embed in PNG: " + text);
+                    throw new ImageWriteException("Unknown text to embed in PNG: " + text);
                 }
             }
         }
diff --git a/src/main/java/org/apache/commons/imaging/formats/psd/PsdImageParser.java b/src/main/java/org/apache/commons/imaging/formats/psd/PsdImageParser.java
index 997fb42..56c439d 100644
--- a/src/main/java/org/apache/commons/imaging/formats/psd/PsdImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/psd/PsdImageParser.java
@@ -33,7 +33,6 @@ import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.ImageFormat;
 import org.apache.commons.imaging.ImageFormats;
@@ -54,7 +53,7 @@ import org.apache.commons.imaging.formats.psd.datareaders.CompressedDataReader;
 import org.apache.commons.imaging.formats.psd.datareaders.DataReader;
 import org.apache.commons.imaging.formats.psd.datareaders.UncompressedDataReader;
 
-public class PsdImageParser extends ImageParser implements XmpEmbeddable {
+public class PsdImageParser extends ImageParser<PsdImagingParameters> implements XmpEmbeddable<PsdImagingParameters> {
     private static final String DEFAULT_EXTENSION = ".psd";
     private static final String[] ACCEPTED_EXTENSIONS = { DEFAULT_EXTENSION, };
     private static final int PSD_SECTION_HEADER = 0;
@@ -381,7 +380,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
         final List<ImageResourceBlock> blocks = readImageResourceBlocks(byteSource,
                 new int[] { IMAGE_RESOURCE_ID_ICC_PROFILE, }, 1);
@@ -399,7 +398,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
         final PsdHeaderInfo bhi = readHeader(byteSource);
 
@@ -408,7 +407,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
@@ -438,7 +437,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
         final PsdImageContents imageContents = readImageContents(byteSource);
         // ImageContents imageContents = readImage(byteSource, false);
@@ -545,7 +544,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public BufferedImage getBufferedImage(final ByteSource byteSource, final Map<String, Object> params)
+    public BufferedImage getBufferedImage(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
         final PsdImageContents imageContents = readImageContents(byteSource);
         // ImageContents imageContents = readImage(byteSource, false);
@@ -657,7 +656,7 @@ public class PsdImageParser extends ImageParser implements XmpEmbeddable {
      * @return Xmp Xml as String, if present. Otherwise, returns null.
      */
     @Override
-    public String getXmpXml(final ByteSource byteSource, final Map<String, Object> params)
+    public String getXmpXml(final ByteSource byteSource, final PsdImagingParameters params)
             throws ImageReadException, IOException {
 
         final PsdImageContents imageContents = readImageContents(byteSource);
diff --git a/src/main/java/org/apache/commons/imaging/formats/psd/PsdImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/psd/PsdImagingParameters.java
new file mode 100644
index 0000000..306069f
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/psd/PsdImagingParameters.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.imaging.formats.psd;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Psd format parameters.
+ * @since 1.0-alpha3
+ */
+public class PsdImagingParameters extends ImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImageParser.java b/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImageParser.java
index b7a6a77..a3219e7 100644
--- a/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImageParser.java
@@ -29,7 +29,6 @@ import java.awt.image.Raster;
 import java.io.IOException;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.Map;
 
 import org.apache.commons.imaging.ImageFormat;
 import org.apache.commons.imaging.ImageFormats;
@@ -44,7 +43,7 @@ import org.apache.commons.imaging.common.bytesource.ByteSource;
  *
  * @author <a href="mailto:peter@electrotank.com">peter royal</a>
  */
-public class RgbeImageParser extends ImageParser {
+public class RgbeImageParser extends ImageParser<RgbeImagingParameters> {
 
     public RgbeImageParser() {
         setByteOrder(ByteOrder.BIG_ENDIAN);
@@ -71,7 +70,7 @@ public class RgbeImageParser extends ImageParser {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final RgbeImagingParameters params)
             throws ImageReadException, IOException {
         try (RgbeInfo info = new RgbeInfo(byteSource)) {
             return info.getMetadata();
@@ -79,7 +78,7 @@ public class RgbeImageParser extends ImageParser {
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final RgbeImagingParameters params)
             throws ImageReadException, IOException {
         try (RgbeInfo info = new RgbeInfo(byteSource)) {
             return new ImageInfo(
@@ -93,7 +92,7 @@ public class RgbeImageParser extends ImageParser {
     }
 
     @Override
-    public BufferedImage getBufferedImage(final ByteSource byteSource, final Map<String, Object> params)
+    public BufferedImage getBufferedImage(final ByteSource byteSource, final RgbeImagingParameters params)
             throws ImageReadException, IOException {
         try (RgbeInfo info = new RgbeInfo(byteSource)) {
             // It is necessary to create our own BufferedImage here as the
@@ -114,7 +113,7 @@ public class RgbeImageParser extends ImageParser {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final RgbeImagingParameters params)
             throws ImageReadException, IOException {
         try (RgbeInfo info = new RgbeInfo(byteSource)) {
             return new Dimension(info.getWidth(), info.getHeight());
@@ -122,7 +121,7 @@ public class RgbeImageParser extends ImageParser {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final RgbeImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
diff --git a/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImagingParameters.java
new file mode 100644
index 0000000..9d1f6eb
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/rgbe/RgbeImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.rgbe;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Rgbe format parameters.
+ * @since 1.0-alpha3
+ */
+public class RgbeImagingParameters extends ImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffCompression.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffCompression.java
new file mode 100644
index 0000000..3db2290
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffCompression.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.imaging.formats.tiff;
+
+public enum TiffCompression {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
index d548365..b22b040 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
@@ -22,7 +22,6 @@ import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.ImageReadException;
 import org.apache.commons.imaging.common.ByteConversions;
@@ -189,18 +188,18 @@ public class TiffDirectory extends TiffElement {
      * Gets the image associated with the directory, if any. Note that not all
      * directories contain images.
      * <p>
-     * The optional parameters map can be used to specify image access or
+     * The optional parameters object can be used to specify image access or
      * rendering options such as reading only a part of the overall image (i.e.
      * reading a sub-image) or applying a custom photometric interpreter.
      *
-     * @param params a map containing optional parameters to be applied to the
+     * @param params an object containing optional parameters to be applied to the
      * read operation.
      * @return if successful, a valid BufferedImage instance.
      * @throws ImageReadException in the event of an invalid or incompatible
      * data format.
      * @throws IOException in the event of an I/O error.
      */
-    public BufferedImage getTiffImage(final Map<String, Object> params)
+    public BufferedImage getTiffImage(final TiffImagingParameters params)
         throws ImageReadException, IOException {
         if (null == tiffImageData) {
             return null;
@@ -226,7 +225,7 @@ public class TiffDirectory extends TiffElement {
      */
     public BufferedImage getTiffImage(final ByteOrder byteOrder) throws ImageReadException,
             IOException {
-        return getTiffImage(byteOrder, null);
+        return getTiffImage(byteOrder, new TiffImagingParameters());
     }
 
     /**
@@ -239,14 +238,14 @@ public class TiffDirectory extends TiffElement {
      * argument.
      *
      * @param byteOrder byte-order obtained from the containing TIFF file
-     * @param params a map containing optional parameters to be applied to the
+     * @param params an object containing optional parameters to be applied to the
      * read operation.
      * @return if successful, a valid BufferedImage instance.
      * @throws ImageReadException in the event of an invalid or incompatible
      * data format.
      * @throws IOException in the event of an I/O error.
      */
-    public BufferedImage getTiffImage(final ByteOrder byteOrder, final Map<String, Object> params)
+    public BufferedImage getTiffImage(final ByteOrder byteOrder, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         if (null == tiffImageData) {
             return null;
@@ -889,7 +888,7 @@ public class TiffDirectory extends TiffElement {
      * @throws IOException in the event of an I/O error
      */
     public TiffRasterData getRasterData(
-            final Map<String, Object> params)
+            final TiffImagingParameters params)
             throws ImageReadException, IOException {
 
         final TiffImageParser parser = new TiffImageParser();
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
index 04eb259..308362a 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
@@ -36,7 +36,6 @@ import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.FormatCompliance;
 import org.apache.commons.imaging.ImageFormat;
@@ -50,7 +49,6 @@ import org.apache.commons.imaging.common.ImageMetadata;
 import org.apache.commons.imaging.common.XmpEmbeddable;
 import org.apache.commons.imaging.common.bytesource.ByteSource;
 import org.apache.commons.imaging.formats.tiff.TiffDirectory.ImageDataElement;
-import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
 import org.apache.commons.imaging.formats.tiff.constants.TiffEpTagConstants;
 import org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
@@ -65,7 +63,7 @@ import org.apache.commons.imaging.formats.tiff.photometricinterpreters.Photometr
 import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreterYCbCr;
 import org.apache.commons.imaging.formats.tiff.write.TiffImageWriterLossy;
 
-public class TiffImageParser extends ImageParser implements XmpEmbeddable {
+public class TiffImageParser extends ImageParser<TiffImagingParameters> implements XmpEmbeddable<TiffImagingParameters> {
     private static final String DEFAULT_EXTENSION = ".tif";
     private static final String[] ACCEPTED_EXTENSIONS = { ".tif", ".tiff", };
 
@@ -91,7 +89,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
         final TiffContents contents = new TiffReader(isStrict(params)).readFirstDirectory(
@@ -103,7 +101,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
         final TiffContents contents = new TiffReader(isStrict(params)).readFirstDirectory(
@@ -126,10 +124,10 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
-        final TiffReader tiffReader = new TiffReader(isStrict(params));
+        final TiffReader tiffReader = new TiffReader(params.isStrict());
         final TiffContents contents = tiffReader.readContents(byteSource, params,
                 formatCompliance);
 
@@ -154,7 +152,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
         final TiffContents contents = new TiffReader(isStrict(params)).readDirectories(
@@ -311,7 +309,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public String getXmpXml(final ByteSource byteSource, final Map<String, Object> params)
+    public String getXmpXml(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
         final TiffContents contents = new TiffReader(isStrict(params)).readDirectories(
@@ -348,8 +346,9 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
             // try
             {
                 final FormatCompliance formatCompliance = FormatCompliance.getDefault();
+                final TiffImagingParameters params = null;
                 final TiffContents contents = new TiffReader(true).readContents(
-                        byteSource, null, formatCompliance);
+                        byteSource, params, formatCompliance);
 
                 final List<TiffDirectory> directories = contents.directories;
 
@@ -388,15 +387,16 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     public FormatCompliance getFormatCompliance(final ByteSource byteSource)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
-        new TiffReader(isStrict(null)).readContents(byteSource, null,
+        final TiffImagingParameters params = null;
+        new TiffReader(isStrict(params)).readContents(byteSource, params,
                 formatCompliance);
         return formatCompliance;
     }
 
-    public List<byte[]> collectRawImageData(final ByteSource byteSource, final Map<String, Object> params)
+    public List<byte[]> collectRawImageData(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
-        final TiffContents contents = new TiffReader(isStrict(params)).readDirectories(
+        final TiffContents contents = new TiffReader(params.isStrict()).readDirectories(
                 byteSource, true, formatCompliance);
 
         final List<byte[]> result = new ArrayList<>();
@@ -429,11 +429,11 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
      * as follows:</p>
      *
      * <pre>
-     *   HashMap&lt;String, Object&gt; params = new HashMap&lt;String, Object&gt;();
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_X, new Integer(x));
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_Y, new Integer(y));
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, new Integer(width));
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, new Integer(height));
+     *   TiffImagingParameters params = new TiffImagingParameters();
+     *   params.setSubImageX(x);
+     *   params.setSubImageY(y);
+     *   params.setSubImageWidth(width);
+     *   params.setSubImageHeight(height);
      * </pre>
      *
      * <p>Note that the arguments x, y, width, and height must specify a
@@ -452,7 +452,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
      * access operation.
      */
     @Override
-    public BufferedImage getBufferedImage(final ByteSource byteSource, final Map<String, Object> params)
+    public BufferedImage getBufferedImage(final ByteSource byteSource, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final FormatCompliance formatCompliance = FormatCompliance.getDefault();
         final TiffReader reader = new TiffReader(isStrict(params));
@@ -486,32 +486,13 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
         return results;
     }
 
-    private Integer getIntegerParameter(
-            final String key, final Map<String, Object>params)
-            throws ImageReadException {
-        if (params == null) {
-            return null;
-        }
-
-        if (!params.containsKey(key)) {
-            return null;
-        }
-
-        final Object obj = params.get(key);
-
-        if (obj instanceof Integer) {
-            return (Integer) obj;
-        }
-        throw new ImageReadException("Non-Integer parameter " + key);
-    }
-
     private Rectangle checkForSubImage(
-            final Map<String, Object> params)
+            final TiffImagingParameters params)
             throws ImageReadException {
-        final Integer ix0 = getIntegerParameter(TiffConstants.PARAM_KEY_SUBIMAGE_X, params);
-        final Integer iy0 = getIntegerParameter(TiffConstants.PARAM_KEY_SUBIMAGE_Y, params);
-        final Integer iwidth = getIntegerParameter(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, params);
-        final Integer iheight = getIntegerParameter(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, params);
+        final Integer ix0 = params.getSubImageX();
+        final Integer iy0 = params.getSubImageY();
+        final Integer iwidth = params.getSubImageWidth();
+        final Integer iheight = params.getSubImageHeight();
 
         if (ix0 == null && iy0 == null && iwidth == null && iheight == null) {
             return null;
@@ -539,7 +520,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     protected BufferedImage getBufferedImage(final TiffDirectory directory,
-            final ByteOrder byteOrder, final Map<String, Object> params)
+            final ByteOrder byteOrder, final TiffImagingParameters params)
             throws ImageReadException, IOException {
         final List<TiffField> entries = directory.entries;
 
@@ -655,13 +636,8 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
             }
         }
 
-        PhotometricInterpreter photometricInterpreter;
-        final Object test = params == null
-            ? null
-            : params.get(TiffConstants.PARAM_KEY_CUSTOM_PHOTOMETRIC_INTERPRETER);
-        if (test instanceof PhotometricInterpreter) {
-            photometricInterpreter = (PhotometricInterpreter) test;
-        } else {
+        PhotometricInterpreter photometricInterpreter = params.getCustomPhotometricInterpreter();
+        if (photometricInterpreter == null) {
             photometricInterpreter = getPhotometricInterpreter(
                 directory, photometricInterpretation, bitsPerPixel,
                 bitsPerSample, predictor, samplesPerPixel, width, height);
@@ -775,7 +751,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, final Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, final TiffImagingParameters params)
             throws ImageWriteException, IOException {
         new TiffImageWriterLossy().writeImage(src, os, params);
     }
@@ -784,20 +760,26 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
      * Reads the content of a TIFF file that contains numerical data samples
      * rather than image-related pixels.
      * <p>
+<<<<<<< HEAD
      * If desired, sub-image data can be read from the file by using a Java
      * {@code Map} instance to specify the subsection of the image that
      * is required. The following code illustrates the approach:
+=======
+     * If desired, sub-image data can be read from the file by using an {@code TiffImagingParameters}
+     * instance to specify the subsection of the image that is required. The
+     * following code illustrates the approach:
+>>>>>>> [IMAGING-159] Use ImagingParameters and define new classes as needed for other formats
      * <pre>
      *   int x; // coordinate (column) of corner of sub-image
      *   int y; // coordinate (row) of corner of sub-image
      *   int width; // width of sub-image
      *   int height; // height of sub-image
      *
-     *   Map&lt;String, Object&gt;params = new HashMap&lt;&gt;();
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_X, x);
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_Y, y);
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, width);
-     *   params.put(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, height);
+     *   TiffImagingParameters params = new TiffImagingParameters();
+     *   params.setSubImageX(x);
+     *   params.setSubImageY(y);
+     *   params.setSubImageWidth(width);
+     *   params.setSubImageHeight(height);
      *   TiffRasterData raster =
      *        readFloatingPointRasterData(directory, byteOrder, params);
      * </pre>
@@ -805,7 +787,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
      * @param directory the TIFF directory pointing to the data to be extracted
      * (TIFF files may contain multiple directories)
      * @param byteOrder the byte order of the data to be extracted
-     * @param params an optional parameter map instance
+     * @param params an optional parameter object instance
      * @return a valid instance
      * @throws ImageReadException in the event of incompatible or malformed data
      * @throws IOException in the event of an I/O error
@@ -813,7 +795,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
     TiffRasterData getRasterData(
             final TiffDirectory directory,
             final ByteOrder byteOrder,
-            Map<String, Object> params)
+            TiffImagingParameters params)
             throws ImageReadException, IOException {
         final List<TiffField> entries = directory.entries;
 
@@ -822,7 +804,7 @@ public class TiffImageParser extends ImageParser implements XmpEmbeddable {
         }
 
         if (params == null) {
-            params = new HashMap<>();
+            params = this.getDefaultParameters();
         }
 
         final short[] sSampleFmt = directory.getFieldValue(
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImagingParameters.java
new file mode 100644
index 0000000..b61bfde
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImagingParameters.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.tiff;
+
+import org.apache.commons.imaging.common.XmpImagingParameters;
+import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
+import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
+
+/**
+ * Tiff format parameters.
+ * @since 1.0-alpha3
+ */
+public class TiffImagingParameters extends XmpImagingParameters {
+
+	/**
+	 * Indicates whether to read embedded thumbnails or not. Only applies to read EXIF metadata from JPEG/JFIF files.
+	 *
+	 * <p>Default value is {@code true}.</p>
+	 */
+	private boolean readThumbnails = true;
+
+	/**
+	 * User provided {@code TiffOutputSet} used to write into the image's EXIF metadata.
+	 */
+	private TiffOutputSet exif = null;
+
+	/**
+	 * X-coordinate of a sub-image.
+	 */
+	private Integer subImageX = null;
+
+	/**
+	 * Y-coordinate of a sub-image.
+	 */
+	private Integer subImageY = null;
+
+	/**
+	 * Width of a sub-image.
+	 */
+	private Integer subImageWidth = null;
+
+	/**
+	 * Height of a sub-image.
+	 */
+	private Integer subImageHeight = null;
+
+	/**
+	 * Specifies that an application-specified photometric interpreter
+     * is to be used when reading TIFF files to convert raster data samples
+     * to RGB values for the output image.
+     *
+     * <p>The value supplied with this key should be a valid instance of
+     * a class that implements PhotometricInterpreter.</p>
+	 */
+	private PhotometricInterpreter customPhotometricInterpreter = null;
+
+	/**
+	 * TIFF compression algorithm, if any.
+	 */
+	private Integer compression = null;
+
+	/**
+     * Specifies the amount of memory in bytes to be used for a strip
+     * or tile size when employing LZW compression.  The default is
+     * 8000 (roughly 8K). Minimum value is 8000.
+     */
+	private Integer lzwCompressionBlockSize = null;
+
+	/**
+     * Used in write operations to indicate the desired T.4 options to
+     * use when using TIFF_COMPRESSION_CCITT_GROUP_3.
+     *
+     * <p>Valid values: any Integer containing a mixture of the
+     * TIFF_FLAG_T4_OPTIONS_2D, TIFF_FLAG_T4_OPTIONS_UNCOMPRESSED_MODE,
+     * and TIFF_FLAG_T4_OPTIONS_FILL flags.</p>
+     */
+	private Integer t4Options = null;
+
+	/**
+     * Used in write operations to indicate the desired T.6 options to
+     * use when using TIFF_COMPRESSION_CCITT_GROUP_4.
+     *
+     * <p>Valid values: any Integer containing either zero or
+     * TIFF_FLAG_T6_OPTIONS_UNCOMPRESSED_MODE.</p>
+     */
+	private Integer t6Options = null;
+
+	public boolean isReadThumbnails() {
+		return readThumbnails;
+	}
+
+	public void setReadThumbnails(boolean readThumbnails) {
+		this.readThumbnails = readThumbnails;
+	}
+
+	public TiffOutputSet getExif() {
+		return exif;
+	}
+
+	public void setExif(TiffOutputSet exif) {
+		this.exif = exif;
+	}
+
+	public Integer getSubImageX() {
+		return subImageX;
+	}
+
+	public void setSubImageX(Integer subImageX) {
+		this.subImageX = subImageX;
+	}
+
+	public Integer getSubImageY() {
+		return subImageY;
+	}
+
+	public void setSubImageY(Integer subImageY) {
+		this.subImageY = subImageY;
+	}
+
+	public Integer getSubImageWidth() {
+		return subImageWidth;
+	}
+
+	public void setSubImageWidth(Integer subImageWidth) {
+		this.subImageWidth = subImageWidth;
+	}
+
+	public Integer getSubImageHeight() {
+		return subImageHeight;
+	}
+
+	public void setSubImageHeight(Integer subImageHeight) {
+		this.subImageHeight = subImageHeight;
+	}
+
+	public PhotometricInterpreter getCustomPhotometricInterpreter() {
+		return customPhotometricInterpreter;
+	}
+
+	public void setCustomPhotometricInterpreter(PhotometricInterpreter customPhotometricInterpreter) {
+		this.customPhotometricInterpreter = customPhotometricInterpreter;
+	}
+
+	public Integer getCompression() {
+		return compression;
+	}
+
+	public void setCompression(Integer compression) {
+		this.compression = compression;
+	}
+
+	public Integer getLzwCompressionBlockSize() {
+		return lzwCompressionBlockSize;
+	}
+
+	public void setLzwCompressionBlockSize(Integer lzwCompressionBlockSize) {
+		this.lzwCompressionBlockSize = lzwCompressionBlockSize;
+	}
+
+	public Integer getT4Options() {
+		return t4Options;
+	}
+
+	public void setT4Options(Integer t4Options) {
+		this.t4Options = t4Options;
+	}
+
+	public Integer getT6Options() {
+		return t6Options;
+	}
+
+	public void setT6Options(Integer t6Options) {
+		this.t6Options = t6Options;
+	}
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java
index 68029fc..b312032 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java
@@ -27,13 +27,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.commons.imaging.FormatCompliance;
 import org.apache.commons.imaging.ImageReadException;
-import org.apache.commons.imaging.ImagingConstants;
 import org.apache.commons.imaging.common.BinaryFileParser;
 import org.apache.commons.imaging.common.ByteConversions;
 import org.apache.commons.imaging.common.bytesource.ByteSource;
@@ -294,12 +291,8 @@ public class TiffReader extends BinaryFileParser {
             this(null);
         }
 
-        Collector(final Map<String, Object> params) {
-            boolean tmpReadThumbnails = true;
-            if (params != null && params.containsKey(ImagingConstants.PARAM_KEY_READ_THUMBNAILS)) {
-                tmpReadThumbnails = Boolean.TRUE.equals(params.get(ImagingConstants.PARAM_KEY_READ_THUMBNAILS));
-            }
-            this.readThumbnails = tmpReadThumbnails;
+        Collector(final TiffImagingParameters params) {
+            this.readThumbnails = params.isReadThumbnails();
         }
 
         @Override
@@ -374,7 +367,7 @@ public class TiffReader extends BinaryFileParser {
 //        }
 //    }
 
-    public TiffContents readFirstDirectory(final ByteSource byteSource, final Map<String, Object> params,
+    public TiffContents readFirstDirectory(final ByteSource byteSource, final TiffImagingParameters params,
             final boolean readImageData, final FormatCompliance formatCompliance)
             throws ImageReadException, IOException {
         final Collector collector = new FirstDirectoryCollector(readImageData);
@@ -390,8 +383,8 @@ public class TiffReader extends BinaryFileParser {
     public TiffContents readDirectories(final ByteSource byteSource,
             final boolean readImageData, final FormatCompliance formatCompliance)
             throws ImageReadException, IOException {
-        final Map<String, Object> params = Collections.singletonMap(
-          ImagingConstants.PARAM_KEY_READ_THUMBNAILS, readImageData);
+        final TiffImagingParameters params = new TiffImagingParameters();
+        params.setReadThumbnails(readImageData);
         final Collector collector = new Collector(params);
         readDirectories(byteSource, formatCompliance, collector);
         final TiffContents contents = collector.getContents();
@@ -402,7 +395,7 @@ public class TiffReader extends BinaryFileParser {
         return contents;
     }
 
-    public TiffContents readContents(final ByteSource byteSource, final Map<String, Object> params,
+    public TiffContents readContents(final ByteSource byteSource, final TiffImagingParameters params,
             final FormatCompliance formatCompliance) throws ImageReadException,
             IOException {
 
@@ -411,7 +404,7 @@ public class TiffReader extends BinaryFileParser {
         return collector.getContents();
     }
 
-    public void read(final ByteSource byteSource, final Map<String, Object> params,
+    public void read(final ByteSource byteSource, final TiffImagingParameters params,
             final FormatCompliance formatCompliance, final Listener listener)
             throws ImageReadException, IOException {
         // TiffContents contents =
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffConstants.java b/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffConstants.java
index 42505bf..16ca42f 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffConstants.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffConstants.java
@@ -44,56 +44,11 @@ public final class TiffConstants {
     public static final int TIFF_COMPRESSION_DEFLATE_PKZIP = 32946;
     public static final int TIFF_COMPRESSION_DEFLATE_ADOBE = 8;
 
-    /**
-     * Parameter key. Used in write operations to indicate the desired
-     * T.4 options to use when using TIFF_COMPRESSION_CCITT_GROUP_3.
-     * <p>
-     * Valid values: any Integer containing a mixture of the
-     * TIFF_FLAG_T4_OPTIONS_2D, TIFF_FLAG_T4_OPTIONS_UNCOMPRESSED_MODE,
-     * and TIFF_FLAG_T4_OPTIONS_FILL flags.
-     */
-    public static final String PARAM_KEY_T4_OPTIONS = "T4_OPTIONS";
-
-    /**
-     * Parameter key. Used in write operations to indicate the desired
-     * T.6 options to use when using TIFF_COMPRESSION_CCITT_GROUP_4.
-     * <p>
-     * Valid values: any Integer containing either zero or
-     * TIFF_FLAG_T6_OPTIONS_UNCOMPRESSED_MODE.
-     */
-    public static final String PARAM_KEY_T6_OPTIONS = "T6_OPTIONS";
-
     public static final int TIFF_FLAG_T4_OPTIONS_2D = 1;
     public static final int TIFF_FLAG_T4_OPTIONS_UNCOMPRESSED_MODE = 2;
     public static final int TIFF_FLAG_T4_OPTIONS_FILL = 4;
     public static final int TIFF_FLAG_T6_OPTIONS_UNCOMPRESSED_MODE = 2;
 
-
-    public static final String PARAM_KEY_SUBIMAGE_X = "SUBIMAGE_X";
-    public static final String PARAM_KEY_SUBIMAGE_Y = "SUBIMAGE_Y";
-    public static final String PARAM_KEY_SUBIMAGE_WIDTH = "SUBIMAGE_WIDTH";
-    public static final String PARAM_KEY_SUBIMAGE_HEIGHT = "SUBIMAGE_HEIGHT";
-
-
-    /**
-     * Specifies that an application-specified photometric interpreter
-     * is to be used when reading TIFF files to convert raster data samples
-     * to RGB values for the output image.
-     * <p>
-     * The value supplied with this key should be a valid instance of
-     * a class that implements PhotometricInterpreter.
-     */
-    public static final String PARAM_KEY_CUSTOM_PHOTOMETRIC_INTERPRETER
-        = "CUSTOM_PHOTOMETRIC_INTERPRETER";
-
-    /**
-     * Specifies the amount of memory in bytes to be used for a strip
-     * or tile size when employing LZW compression.  The default is
-     * 8000 (roughly 8K). Minimum value is 8000.
-     */
-    public static final String PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE =
-            "PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE";
-
     /**
      * Specifies a larger strip-size to be used for compression. This setting
      * generally produces smaller output files, but requires a slightly longer
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterBase.java b/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterBase.java
index 775ecd2..696cede 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterBase.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterBase.java
@@ -17,9 +17,6 @@
 package org.apache.commons.imaging.formats.tiff.write;
 
 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.DEFAULT_TIFF_BYTE_ORDER;
-import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE;
-import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.PARAM_KEY_T4_OPTIONS;
-import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.PARAM_KEY_T6_OPTIONS;
 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_1D;
 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_3;
 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_COMPRESSION_CCITT_GROUP_4;
@@ -44,7 +41,6 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.imaging.ImageWriteException;
-import org.apache.commons.imaging.ImagingConstants;
 import org.apache.commons.imaging.PixelDensity;
 import org.apache.commons.imaging.common.BinaryOutputStream;
 import org.apache.commons.imaging.common.PackBits;
@@ -54,6 +50,7 @@ import org.apache.commons.imaging.common.mylzw.MyLzwCompressor;
 import org.apache.commons.imaging.common.ZlibDeflate;
 import org.apache.commons.imaging.formats.tiff.TiffElement;
 import org.apache.commons.imaging.formats.tiff.TiffImageData;
+import org.apache.commons.imaging.formats.tiff.TiffImagingParameters;
 import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
 import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants;
 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
@@ -303,29 +300,13 @@ public abstract class TiffImageWriterBase {
         }
     }
 
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, TiffImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = new HashMap<>(params);
+        TiffOutputSet userExif = params.getExif();
 
-        // clear format key.
-        if (params.containsKey(ImagingConstants.PARAM_KEY_FORMAT)) {
-            params.remove(ImagingConstants.PARAM_KEY_FORMAT);
-        }
-
-        TiffOutputSet userExif = null;
-        if (params.containsKey(ImagingConstants.PARAM_KEY_EXIF)) {
-            userExif = (TiffOutputSet) params.remove(ImagingConstants.PARAM_KEY_EXIF);
-        }
+        String xmpXml = params.getXmpXml();
 
-        String xmpXml = null;
-        if (params.containsKey(ImagingConstants.PARAM_KEY_XMP_XML)) {
-            xmpXml = (String) params.get(ImagingConstants.PARAM_KEY_XMP_XML);
-            params.remove(ImagingConstants.PARAM_KEY_XMP_XML);
-        }
-
-        PixelDensity pixelDensity = (PixelDensity) params.remove(
-                ImagingConstants.PARAM_KEY_PIXEL_DENSITY);
+        PixelDensity pixelDensity = params.getPixelDensity();
         if (pixelDensity == null) {
             pixelDensity = PixelDensity.createFromPixelsPerInch(72, 72);
         }
@@ -358,41 +339,19 @@ public abstract class TiffImageWriterBase {
         short predictor = TiffTagConstants.PREDICTOR_VALUE_NONE;
 
         int stripSizeInBits = 64000; // the default from legacy implementation
-        if (params.containsKey(ImagingConstants.PARAM_KEY_COMPRESSION)) {
-            final Object value = params.get(ImagingConstants.PARAM_KEY_COMPRESSION);
-            if (value != null) {
-                if (!(value instanceof Number)) {
-                    throw new ImageWriteException(
-                            "Invalid compression parameter, must be numeric: "
-                                    + value);
-                }
-                compression = ((Number) value).intValue();
-            }
-            params.remove(ImagingConstants.PARAM_KEY_COMPRESSION);
-            if (params.containsKey(PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE)) {
-                final Object bValue =
-                    params.get(PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE);
-                if (!(bValue instanceof Number)) {
-                    throw new ImageWriteException(
-                            "Invalid compression block-size parameter: " + value);
-                }
-                final int stripSizeInBytes = ((Number) bValue).intValue();
+        Integer compressionParameter = params.getCompression();
+        if (compressionParameter != null) {
+        	compression = compressionParameter.intValue();
+        	final Integer stripSizeInBytes = params.getLzwCompressionBlockSize();
+            if (stripSizeInBytes != null) {
                 if (stripSizeInBytes < 8000) {
                     throw new ImageWriteException(
                             "Block size parameter " + stripSizeInBytes
                             + " is less than 8000 minimum");
                 }
-                stripSizeInBits = stripSizeInBytes*8;
-                params.remove(PARAM_KEY_LZW_COMPRESSION_BLOCK_SIZE);
+                stripSizeInBits = stripSizeInBytes * 8;
             }
         }
-        final HashMap<String, Object> rawParams = new HashMap<>(params);
-        params.remove(PARAM_KEY_T4_OPTIONS);
-        params.remove(PARAM_KEY_T6_OPTIONS);
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
 
         int samplesPerPixel;
         int bitsPerSample;
@@ -428,7 +387,7 @@ public abstract class TiffImageWriterBase {
                         strips[i], width, strips[i].length / ((width + 7) / 8));
             }
         } else if (compression == TIFF_COMPRESSION_CCITT_GROUP_3) {
-            final Integer t4Parameter = (Integer) rawParams.get(PARAM_KEY_T4_OPTIONS);
+            final Integer t4Parameter = params.getT4Options();
             if (t4Parameter != null) {
                 t4Options = t4Parameter.intValue();
             }
@@ -452,7 +411,7 @@ public abstract class TiffImageWriterBase {
                 }
             }
         } else if (compression == TIFF_COMPRESSION_CCITT_GROUP_4) {
-            final Integer t6Parameter = (Integer) rawParams.get(PARAM_KEY_T6_OPTIONS);
+            final Integer t6Parameter = params.getT6Options();
             if (t6Parameter != null) {
                 t6Options = t6Parameter.intValue();
             }
diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java b/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java
index b98fb53..7f1b921 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/write/TiffImageWriterLossless.java
@@ -42,6 +42,7 @@ import org.apache.commons.imaging.formats.tiff.TiffElement;
 import org.apache.commons.imaging.formats.tiff.TiffElement.DataElement;
 import org.apache.commons.imaging.formats.tiff.TiffField;
 import org.apache.commons.imaging.formats.tiff.TiffImageData;
+import org.apache.commons.imaging.formats.tiff.TiffImagingParameters;
 import org.apache.commons.imaging.formats.tiff.TiffReader;
 import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
 
@@ -65,7 +66,7 @@ public class TiffImageWriterLossless extends TiffImageWriterBase {
             final ByteSource byteSource = new ByteSourceArray(exifBytes);
             final FormatCompliance formatCompliance = FormatCompliance.getDefault();
             final TiffContents contents = new TiffReader(false).readContents(
-                    byteSource, null, formatCompliance);
+                    byteSource, new TiffImagingParameters(), formatCompliance);
 
             final List<TiffElement> elements = new ArrayList<>();
 
diff --git a/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImageParser.java b/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImageParser.java
index 343d806..d71ab43 100644
--- a/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImageParser.java
@@ -14,7 +14,6 @@
  */
 package org.apache.commons.imaging.formats.wbmp;
 
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FORMAT;
 import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
 import static org.apache.commons.imaging.common.BinaryFunctions.readBytes;
 
@@ -30,8 +29,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Properties;
 
 import org.apache.commons.imaging.ImageFormat;
@@ -43,7 +40,7 @@ import org.apache.commons.imaging.ImageWriteException;
 import org.apache.commons.imaging.common.ImageMetadata;
 import org.apache.commons.imaging.common.bytesource.ByteSource;
 
-public class WbmpImageParser extends ImageParser {
+public class WbmpImageParser extends ImageParser<WbmpImagingParameters> {
     private static final String DEFAULT_EXTENSION = ".wbmp";
     private static final String[] ACCEPTED_EXTENSIONS = { ".wbmp", };
 
@@ -69,13 +66,13 @@ public class WbmpImageParser extends ImageParser {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final WbmpImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final WbmpImagingParameters params)
             throws ImageReadException, IOException {
         final WbmpHeader wbmpHeader = readWbmpHeader(byteSource);
         return new ImageInfo("WBMP", 1, new ArrayList<String>(),
@@ -87,14 +84,14 @@ public class WbmpImageParser extends ImageParser {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final WbmpImagingParameters params)
             throws ImageReadException, IOException {
         final WbmpHeader wbmpHeader = readWbmpHeader(byteSource);
         return new Dimension(wbmpHeader.width, wbmpHeader.height);
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final WbmpImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
@@ -208,7 +205,7 @@ public class WbmpImageParser extends ImageParser {
 
     @Override
     public final BufferedImage getBufferedImage(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final WbmpImagingParameters params) throws ImageReadException, IOException {
         try (InputStream is = byteSource.getInputStream()) {
             final WbmpHeader wbmpHeader = readWbmpHeader(is);
             return readImage(wbmpHeader, is);
@@ -216,21 +213,8 @@ public class WbmpImageParser extends ImageParser {
     }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, WbmpImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        // clear format key.
-        if (params.containsKey(PARAM_KEY_FORMAT)) {
-            params.remove(PARAM_KEY_FORMAT);
-        }
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
-
         writeMultiByteInteger(os, 0); // typeField
         os.write(0); // fixHeaderField
         writeMultiByteInteger(os, src.getWidth());
diff --git a/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImagingParameters.java
new file mode 100644
index 0000000..00af50d
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/wbmp/WbmpImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.wbmp;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Wbmp format parameters.
+ * @since 1.0-alpha3
+ */
+public class WbmpImagingParameters extends ImagingParameters {
+
+}
diff --git a/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImageParser.java b/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImageParser.java
index 0e17654..51113de 100644
--- a/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImageParser.java
@@ -14,8 +14,6 @@
  */
 package org.apache.commons.imaging.formats.xbm;
 
-import static org.apache.commons.imaging.ImagingConstants.PARAM_KEY_FORMAT;
-
 import java.awt.Dimension;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
@@ -48,7 +46,7 @@ import org.apache.commons.imaging.common.BasicCParser;
 import org.apache.commons.imaging.common.ImageMetadata;
 import org.apache.commons.imaging.common.bytesource.ByteSource;
 
-public class XbmImageParser extends ImageParser {
+public class XbmImageParser extends ImageParser<XbmImagingParameters> {
     private static final String DEFAULT_EXTENSION = ".xbm";
     private static final String[] ACCEPTED_EXTENSIONS = { ".xbm", };
 
@@ -74,13 +72,13 @@ public class XbmImageParser extends ImageParser {
     }
 
     @Override
-    public ImageMetadata getMetadata(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageMetadata getMetadata(final ByteSource byteSource, final XbmImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
 
     @Override
-    public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String, Object> params)
+    public ImageInfo getImageInfo(final ByteSource byteSource, final XbmImagingParameters params)
             throws ImageReadException, IOException {
         final XbmHeader xbmHeader = readXbmHeader(byteSource);
         return new ImageInfo("XBM", 1, new ArrayList<String>(),
@@ -91,14 +89,14 @@ public class XbmImageParser extends ImageParser {
     }
 
     @Override
-    public Dimension getImageSize(final ByteSource byteSource, final Map<String, Object> params)
+    public Dimension getImageSize(final ByteSource byteSource, final XbmImagingParameters params)
             throws ImageReadException, IOException {
         final XbmHeader xbmHeader = readXbmHeader(byteSource);
         return new Dimension(xbmHeader.width, xbmHeader.height);
     }
 
     @Override
-    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String, Object> params)
+    public byte[] getICCProfileBytes(final ByteSource byteSource, final XbmImagingParameters params)
             throws ImageReadException, IOException {
         return null;
     }
@@ -310,7 +308,7 @@ public class XbmImageParser extends ImageParser {
 
     @Override
     public final BufferedImage getBufferedImage(final ByteSource byteSource,
-            final Map<String, Object> params) throws ImageReadException, IOException {
+            final XbmImagingParameters params) throws ImageReadException, IOException {
         final XbmParseResult result = parseXbmHeader(byteSource);
         return readXbmImage(result.xbmHeader, result.cParser);
     }
@@ -339,21 +337,8 @@ public class XbmImageParser extends ImageParser {
     }
 
     @Override
-    public void writeImage(final BufferedImage src, final OutputStream os, Map<String, Object> params)
+    public void writeImage(final BufferedImage src, final OutputStream os, XbmImagingParameters params)
             throws ImageWriteException, IOException {
-        // make copy of params; we'll clear keys as we consume them.
-        params = (params == null) ? new HashMap<>() : new HashMap<>(params);
-
-        // clear format key.
-        if (params.containsKey(PARAM_KEY_FORMAT)) {
-            params.remove(PARAM_KEY_FORMAT);
-        }
-
-        if (!params.isEmpty()) {
-            final Object firstKey = params.keySet().iterator().next();
-            throw new ImageWriteException("Unknown parameter: " + firstKey);
-        }
-
         final String name = randomName();
 
         os.write(("#define " + name + "_width " + src.getWidth() + "\n").getBytes(StandardCharsets.US_ASCII));
diff --git a/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImagingParameters.java b/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImagingParameters.java
new file mode 100644
index 0000000..a86d539
--- /dev/null
+++ b/src/main/java/org/apache/commons/imaging/formats/xbm/XbmImagingParameters.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+package org.apache.commons.imaging.formats.xbm;
+
+import org.apache.commons.imaging.ImagingParameters;
+
+/**
+ * Xbm format parameters.
+ * @since 1.0-alpha3
+ */
+public class XbmImagingParameters extends ImagingParameters {
+
+}