Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java	(revision 10546)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java	(revision 10547)
@@ -29,4 +29,5 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
+import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -307,5 +308,5 @@
      *
      * @author Michael Zangl
-     * @see ImageryLayer#setGamma(double)
+     * @see ImageryFilterSettings#setGamma(double)
      */
     private class GammaFilterSlider extends FilterSlider<ImageryLayer> {
@@ -321,5 +322,5 @@
         @Override
         protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
-            double gamma = ((ImageryLayer) usedLayers.iterator().next()).getGamma();
+            double gamma = ((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getGamma();
             setRealValue(mapGammaToInterval(gamma));
         }
@@ -327,5 +328,5 @@
         @Override
         protected void applyValueToLayer(ImageryLayer layer) {
-            layer.setGamma(mapIntervalToGamma(getRealValue()));
+            layer.getFilterSettings().setGamma(mapIntervalToGamma(getRealValue()));
         }
 
@@ -366,5 +367,5 @@
      *
      * @author Michael Zangl
-     * @see ImageryLayer#setSharpenLevel(double)
+     * @see ImageryFilterSettings#setSharpenLevel(double)
      */
     private class SharpnessSlider extends FilterSlider<ImageryLayer> {
@@ -380,10 +381,10 @@
         @Override
         protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
-            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getSharpenLevel());
+            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getSharpenLevel());
         }
 
         @Override
         protected void applyValueToLayer(ImageryLayer layer) {
-            layer.setSharpenLevel(getRealValue());
+            layer.getFilterSettings().setSharpenLevel(getRealValue());
         }
 
@@ -403,5 +404,5 @@
      *
      * @author Michael Zangl
-     * @see ImageryLayer#setColorfulness(double)
+     * @see ImageryFilterSettings#setColorfulness(double)
      */
     private class ColorfulnessSlider extends FilterSlider<ImageryLayer> {
@@ -417,10 +418,10 @@
         @Override
         protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
-            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getColorfulness());
+            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getColorfulness());
         }
 
         @Override
         protected void applyValueToLayer(ImageryLayer layer) {
-            layer.setColorfulness(getRealValue());
+            layer.getFilterSettings().setColorfulness(getRealValue());
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 10546)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 10547)
@@ -82,4 +82,5 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
+import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings.FilterChangeListener;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -99,5 +100,5 @@
  */
 public abstract class AbstractTileSourceLayer<T extends AbstractTMSTileSource> extends ImageryLayer
-implements ImageObserver, TileLoaderListener, ZoomChangeListener {
+implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeListener {
     private static final String PREFERENCE_PREFIX = "imagery.generic";
 
@@ -175,4 +176,10 @@
         setBackgroundLayer(true);
         this.setVisible(true);
+        getFilterSettings().addFilterChangeListener(this);
+    }
+
+    @Override
+    public void filterChanged() {
+        redraw();
     }
 
@@ -261,22 +268,4 @@
         needRedraw = true;
         if (isVisible()) Main.map.repaint();
-    }
-
-    @Override
-    public void setGamma(double gamma) {
-        super.setGamma(gamma);
-        redraw();
-    }
-
-    @Override
-    public void setSharpenLevel(double sharpenLevel) {
-        super.setSharpenLevel(sharpenLevel);
-        redraw();
-    }
-
-    @Override
-    public void setColorfulness(double colorfulness) {
-        super.setColorfulness(colorfulness);
-        redraw();
     }
 
@@ -1208,20 +1197,20 @@
 
     private final class MapWrappingTileSet extends TileSet {
-            private MapWrappingTileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
-                this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
-            }
-
-            private MapWrappingTileSet(LatLon topLeft, LatLon botRight, int zoom) {
-                super(topLeft, botRight, zoom);
-                double centerLon = getShiftedLatLon(Main.map.mapView.getCenter()).lon();
-
-                if (topLeft.lon() > centerLon) {
-                    x0 = tileSource.getTileXMin(zoom);
-                }
-                if (botRight.lon() < centerLon) {
-                    x1 = tileSource.getTileXMax(zoom);
-                }
-                sanitize();
-            }
+        private MapWrappingTileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
+            this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
+        }
+
+        private MapWrappingTileSet(LatLon topLeft, LatLon botRight, int zoom) {
+            super(topLeft, botRight, zoom);
+            double centerLon = getShiftedLatLon(Main.map.mapView.getCenter()).lon();
+
+            if (topLeft.lon() > centerLon) {
+                x0 = tileSource.getTileXMin(zoom);
+            }
+            if (botRight.lon() < centerLon) {
+                x1 = tileSource.getTileXMax(zoom);
+            }
+            sanitize();
+        }
     }
 
@@ -1236,5 +1225,5 @@
          * @param zoom zoom level
          */
-        private TileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
+        protected TileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
             this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
         }
@@ -1246,5 +1235,5 @@
          * @param zoom zoom level
          */
-        private TileSet(LatLon topLeft, LatLon botRight, int zoom) {
+        protected TileSet(LatLon topLeft, LatLon botRight, int zoom) {
             this.zoom = zoom;
             if (zoom == 0)
@@ -1260,7 +1249,4 @@
             sanitize();
 
-        }
-
-        private TileSet(Tile topLeft, Tile botRight, int zoom) {
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 10546)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 10547)
@@ -9,19 +9,7 @@
 import java.awt.Component;
 import java.awt.GridBagLayout;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Transparency;
 import java.awt.event.ActionEvent;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImageOp;
-import java.awt.image.ColorModel;
-import java.awt.image.ConvolveOp;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.Kernel;
-import java.awt.image.LookupOp;
-import java.awt.image.ShortLookupTable;
 import java.util.ArrayList;
 import java.util.List;
@@ -46,4 +34,5 @@
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
 import org.openstreetmap.josm.gui.MenuScroller;
+import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
 import org.openstreetmap.josm.gui.widgets.UrlLabel;
 import org.openstreetmap.josm.tools.GBC;
@@ -76,9 +65,7 @@
     protected double dy;
 
-    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
-    protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();
-    protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor();
-
     private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
+
+    private final ImageryFilterSettings filterSettings = new ImageryFilterSettings();
 
     /**
@@ -96,8 +83,8 @@
             icon = ImageProvider.get("imagery_small");
         }
-        addImageProcessor(collorfulnessImageProcessor);
-        addImageProcessor(gammaImageProcessor);
-        addImageProcessor(sharpenImageProcessor);
-        sharpenImageProcessor.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);
+        for (ImageProcessor processor : filterSettings.getProcessors()) {
+            addImageProcessor(processor);
+        }
+        filterSettings.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);
     }
 
@@ -259,364 +246,10 @@
 
     /**
-     * An image processor which adjusts the gamma value of an image.
-     */
-    public static class GammaImageProcessor implements ImageProcessor {
-        private double gamma = 1;
-        final short[] gammaChange = new short[256];
-        private final LookupOp op3 = new LookupOp(
-                new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
-        private final LookupOp op4 = new LookupOp(
-                new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
-
-        /**
-         * Returns the currently set gamma value.
-         * @return the currently set gamma value
-         */
-        public double getGamma() {
-            return gamma;
-        }
-
-        /**
-         * Sets a new gamma value, {@code 1} stands for no correction.
-         * @param gamma new gamma value
-         */
-        public void setGamma(double gamma) {
-            this.gamma = gamma;
-            for (int i = 0; i < 256; i++) {
-                gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
-            }
-        }
-
-        @Override
-        public BufferedImage process(BufferedImage image) {
-            if (gamma == 1) {
-                return image;
-            }
-            try {
-                final int bands = image.getRaster().getNumBands();
-                if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 3) {
-                    return op3.filter(image, null);
-                } else if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 4) {
-                    return op4.filter(image, null);
-                }
-            } catch (IllegalArgumentException ignore) {
-                Main.trace(ignore);
-            }
-            final int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
-            final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), type);
-            to.getGraphics().drawImage(image, 0, 0, null);
-            return process(to);
-        }
-
-        @Override
-        public String toString() {
-            return "GammaImageProcessor [gamma=" + gamma + ']';
-        }
-    }
-
-    /**
-     * Sharpens or blurs the image, depending on the sharpen value.
-     * <p>
-     * A positive sharpen level means that we sharpen the image.
-     * <p>
-     * A negative sharpen level let's us blur the image. -1 is the most useful value there.
-     *
-     * @author Michael Zangl
-     */
-    public static class SharpenImageProcessor implements ImageProcessor {
-        private float sharpenLevel;
-        private ConvolveOp op;
-
-        private static float[] KERNEL_IDENTITY = new float[] {
-            0, 0, 0,
-            0, 1, 0,
-            0, 0, 0
-        };
-
-        private static float[] KERNEL_BLUR = new float[] {
-            1f / 16, 2f / 16, 1f / 16,
-            2f / 16, 4f / 16, 2f / 16,
-            1f / 16, 2f / 16, 1f / 16
-        };
-
-        private static float[] KERNEL_SHARPEN = new float[] {
-            -.5f, -1f, -.5f,
-             -1f, 7, -1f,
-            -.5f, -1f, -.5f
-        };
-
-        /**
-         * Gets the current sharpen level.
-         * @return The level.
-         */
-        public float getSharpenLevel() {
-            return sharpenLevel;
-        }
-
-        /**
-         * Sets the sharpening level.
-         * @param sharpenLevel The level. Clamped to be positive or 0.
-         */
-        public void setSharpenLevel(float sharpenLevel) {
-            if (sharpenLevel < 0) {
-                this.sharpenLevel = 0;
-            } else {
-                this.sharpenLevel = sharpenLevel;
-            }
-
-            if (this.sharpenLevel < 0.95) {
-                op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR);
-            } else if (this.sharpenLevel > 1.05) {
-                op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY);
-            } else {
-                op = null;
-            }
-        }
-
-        private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) {
-            if (a.length != 9 || b.length != 9) {
-                throw new IllegalArgumentException("Illegal kernel array length.");
-            }
-            float[] values = new float[9];
-            for (int i = 0; i < values.length; i++) {
-                values[i] = aFactor * a[i] + (1 - aFactor) * b[i];
-            }
-            return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null);
-        }
-
-        @Override
-        public BufferedImage process(BufferedImage image) {
-            if (op != null) {
-                return op.filter(image, null);
-            } else {
-                return image;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + ']';
-        }
-    }
-
-    /**
-     * Adds or removes the colorfulness of the image.
-     *
-     * @author Michael Zangl
-     */
-    public static class ColorfulImageProcessor implements ImageProcessor {
-        private ColorfulFilter op;
-        private double colorfulness = 1;
-
-        /**
-         * Gets the colorfulness value.
-         * @return The value
-         */
-        public double getColorfulness() {
-            return colorfulness;
-        }
-
-        /**
-         * Sets the colorfulness value. Clamps it to 0+
-         * @param colorfulness The value
-         */
-        public void setColorfulness(double colorfulness) {
-            if (colorfulness < 0) {
-                this.colorfulness = 0;
-            } else {
-                this.colorfulness = colorfulness;
-            }
-
-            if (this.colorfulness < .95 || this.colorfulness > 1.05) {
-                op = new ColorfulFilter(this.colorfulness);
-            } else {
-                op = null;
-            }
-        }
-
-        @Override
-        public BufferedImage process(BufferedImage image) {
-            if (op != null) {
-                return op.filter(image, null);
-            } else {
-                return image;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']';
-        }
-    }
-
-    private static class ColorfulFilter implements BufferedImageOp {
-        private final double colorfulness;
-
-        /**
-         * Create a new colorful filter.
-         * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class.
-         */
-        ColorfulFilter(double colorfulness) {
-            this.colorfulness = colorfulness;
-        }
-
-        @Override
-        public BufferedImage filter(BufferedImage src, BufferedImage dest) {
-            if (src.getWidth() == 0 || src.getHeight() == 0) {
-                return src;
-            }
-
-            if (dest == null) {
-                dest = createCompatibleDestImage(src, null);
-            }
-            DataBuffer srcBuffer = src.getRaster().getDataBuffer();
-            DataBuffer destBuffer = dest.getRaster().getDataBuffer();
-            if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) {
-                Main.trace("Cannot apply color filter: Images do not use DataBufferByte.");
-                return src;
-            }
-
-            int type = src.getType();
-            if (type != dest.getType()) {
-                Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')');
-                return src;
-            }
-            int redOffset, greenOffset, blueOffset, alphaOffset = 0;
-            switch (type) {
-            case BufferedImage.TYPE_3BYTE_BGR:
-                blueOffset = 0;
-                greenOffset = 1;
-                redOffset = 2;
-                break;
-            case BufferedImage.TYPE_4BYTE_ABGR:
-            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
-                blueOffset = 1;
-                greenOffset = 2;
-                redOffset = 3;
-                break;
-            case BufferedImage.TYPE_INT_ARGB:
-            case BufferedImage.TYPE_INT_ARGB_PRE:
-                redOffset = 0;
-                greenOffset = 1;
-                blueOffset = 2;
-                alphaOffset = 3;
-                break;
-            default:
-                Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ").");
-                return src;
-            }
-            doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset,
-                    alphaOffset, src.getAlphaRaster() != null);
-            return dest;
-        }
-
-        private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset,
-                int alphaOffset, boolean hasAlpha) {
-            byte[] srcPixels = src.getData();
-            byte[] destPixels = dest.getData();
-            if (srcPixels.length != destPixels.length) {
-                Main.trace("Cannot apply color filter: Source/Dest lengths differ.");
-                return;
-            }
-            int entries = hasAlpha ? 4 : 3;
-            for (int i = 0; i < srcPixels.length; i += entries) {
-                int r = srcPixels[i + redOffset] & 0xff;
-                int g = srcPixels[i + greenOffset] & 0xff;
-                int b = srcPixels[i + blueOffset] & 0xff;
-                double luminosity = r * .21d + g * .72d + b * .07d;
-                destPixels[i + redOffset] = mix(r, luminosity);
-                destPixels[i + greenOffset] = mix(g, luminosity);
-                destPixels[i + blueOffset] = mix(b, luminosity);
-                if (hasAlpha) {
-                    destPixels[i + alphaOffset] = srcPixels[i + alphaOffset];
-                }
-            }
-        }
-
-        private byte mix(int color, double luminosity) {
-            int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity);
-            if (val < 0) {
-                return 0;
-            } else if (val > 0xff) {
-                return (byte) 0xff;
-            } else {
-                return (byte) val;
-            }
-        }
-
-        @Override
-        public Rectangle2D getBounds2D(BufferedImage src) {
-            return new Rectangle(src.getWidth(), src.getHeight());
-        }
-
-        @Override
-        public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
-            return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
-        }
-
-        @Override
-        public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
-            return (Point2D) srcPt.clone();
-        }
-
-        @Override
-        public RenderingHints getRenderingHints() {
-            return null;
-        }
-
-    }
-
-    /**
-     * Returns the currently set gamma value.
-     * @return the currently set gamma value
-     */
-    public double getGamma() {
-        return gammaImageProcessor.getGamma();
-    }
-
-    /**
-     * Sets a new gamma value, {@code 1} stands for no correction.
-     * @param gamma new gamma value
-     */
-    public void setGamma(double gamma) {
-        gammaImageProcessor.setGamma(gamma);
-    }
-
-    /**
-     * Gets the current sharpen level.
-     * @return The sharpen level.
-     */
-    public double getSharpenLevel() {
-        return sharpenImageProcessor.getSharpenLevel();
-    }
-
-    /**
-     * Sets the sharpen level for the layer.
-     * <code>1</code> means no change in sharpness.
-     * Values in range 0..1 blur the image.
-     * Values above 1 are used to sharpen the image.
-     * @param sharpenLevel The sharpen level.
-     */
-    public void setSharpenLevel(double sharpenLevel) {
-        sharpenImageProcessor.setSharpenLevel((float) sharpenLevel);
-    }
-
-    /**
-     * Gets the colorfulness of this image.
-     * @return The colorfulness
-     */
-    public double getColorfulness() {
-        return collorfulnessImageProcessor.getColorfulness();
-    }
-
-    /**
-     * Sets the colorfulness of this image.
-     * 0 means grayscale.
-     * 1 means normal colorfulness.
-     * Values greater than 1 are allowed.
-     * @param colorfulness The colorfulness.
-     */
-    public void setColorfulness(double colorfulness) {
-        collorfulnessImageProcessor.setColorfulness(colorfulness);
+     * Gets the settings for the filter that is applied to this layer.
+     * @return The filter settings.
+     * @since 10547
+     */
+    public ImageryFilterSettings getFilterSettings() {
+        return filterSettings;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java	(revision 10547)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java	(revision 10547)
@@ -0,0 +1,182 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.ImageProcessor;
+
+/**
+ * Adds or removes the colorfulness of the image.
+ *
+ * @author Michael Zangl
+ * @since 10547
+ */
+public class ColorfulImageProcessor implements ImageProcessor {
+    private ColorfulFilter op;
+    private double colorfulness = 1;
+
+    /**
+     * Gets the colorfulness value.
+     * @return The value
+     */
+    public double getColorfulness() {
+        return colorfulness;
+    }
+
+    /**
+     * Sets the colorfulness value. Clamps it to 0+
+     * @param colorfulness The value
+     */
+    public void setColorfulness(double colorfulness) {
+        if (colorfulness < 0) {
+            this.colorfulness = 0;
+        } else {
+            this.colorfulness = colorfulness;
+        }
+
+        if (this.colorfulness < .95 || this.colorfulness > 1.05) {
+            op = new ColorfulFilter(this.colorfulness);
+        } else {
+            op = null;
+        }
+    }
+
+    @Override
+    public BufferedImage process(BufferedImage image) {
+        if (op != null) {
+            return op.filter(image, null);
+        } else {
+            return image;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']';
+    }
+
+    static class ColorfulFilter implements BufferedImageOp {
+        private final double colorfulness;
+
+        /**
+         * Create a new colorful filter.
+         * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class.
+         */
+        ColorfulFilter(double colorfulness) {
+            this.colorfulness = colorfulness;
+        }
+
+        @Override
+        public BufferedImage filter(BufferedImage src, BufferedImage dest) {
+            if (src.getWidth() == 0 || src.getHeight() == 0) {
+                return src;
+            }
+
+            if (dest == null) {
+                dest = createCompatibleDestImage(src, null);
+            }
+            DataBuffer srcBuffer = src.getRaster().getDataBuffer();
+            DataBuffer destBuffer = dest.getRaster().getDataBuffer();
+            if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) {
+                Main.trace("Cannot apply color filter: Images do not use DataBufferByte.");
+                return src;
+            }
+
+            int type = src.getType();
+            if (type != dest.getType()) {
+                Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')');
+                return src;
+            }
+            int redOffset, greenOffset, blueOffset, alphaOffset = 0;
+            switch (type) {
+            case BufferedImage.TYPE_3BYTE_BGR:
+                blueOffset = 0;
+                greenOffset = 1;
+                redOffset = 2;
+                break;
+            case BufferedImage.TYPE_4BYTE_ABGR:
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+                blueOffset = 1;
+                greenOffset = 2;
+                redOffset = 3;
+                break;
+            case BufferedImage.TYPE_INT_ARGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+                redOffset = 0;
+                greenOffset = 1;
+                blueOffset = 2;
+                alphaOffset = 3;
+                break;
+            default:
+                Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ").");
+                return src;
+            }
+            doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset,
+                    alphaOffset, src.getAlphaRaster() != null);
+            return dest;
+        }
+
+        private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset,
+                int alphaOffset, boolean hasAlpha) {
+            byte[] srcPixels = src.getData();
+            byte[] destPixels = dest.getData();
+            if (srcPixels.length != destPixels.length) {
+                Main.trace("Cannot apply color filter: Source/Dest lengths differ.");
+                return;
+            }
+            int entries = hasAlpha ? 4 : 3;
+            for (int i = 0; i < srcPixels.length; i += entries) {
+                int r = srcPixels[i + redOffset] & 0xff;
+                int g = srcPixels[i + greenOffset] & 0xff;
+                int b = srcPixels[i + blueOffset] & 0xff;
+                double luminosity = r * .21d + g * .72d + b * .07d;
+                destPixels[i + redOffset] = mix(r, luminosity);
+                destPixels[i + greenOffset] = mix(g, luminosity);
+                destPixels[i + blueOffset] = mix(b, luminosity);
+                if (hasAlpha) {
+                    destPixels[i + alphaOffset] = srcPixels[i + alphaOffset];
+                }
+            }
+        }
+
+        private byte mix(int color, double luminosity) {
+            int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity);
+            if (val < 0) {
+                return 0;
+            } else if (val > 0xff) {
+                return (byte) 0xff;
+            } else {
+                return (byte) val;
+            }
+        }
+
+        @Override
+        public Rectangle2D getBounds2D(BufferedImage src) {
+            return new Rectangle(src.getWidth(), src.getHeight());
+        }
+
+        @Override
+        public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
+            return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
+        }
+
+        @Override
+        public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
+            return (Point2D) srcPt.clone();
+        }
+
+        @Override
+        public RenderingHints getRenderingHints() {
+            return null;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java	(revision 10547)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java	(revision 10547)
@@ -0,0 +1,68 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.awt.image.LookupOp;
+import java.awt.image.ShortLookupTable;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.ImageProcessor;
+
+/**
+ * An image processor which adjusts the gamma value of an image.
+ * @since 10547
+ */
+public class GammaImageProcessor implements ImageProcessor {
+    private double gamma = 1;
+    final short[] gammaChange = new short[256];
+    private final LookupOp op3 = new LookupOp(
+            new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
+    private final LookupOp op4 = new LookupOp(
+            new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
+
+    /**
+     * Returns the currently set gamma value.
+     * @return the currently set gamma value
+     */
+    public double getGamma() {
+        return gamma;
+    }
+
+    /**
+     * Sets a new gamma value, {@code 1} stands for no correction.
+     * @param gamma new gamma value
+     */
+    public void setGamma(double gamma) {
+        this.gamma = gamma;
+        for (int i = 0; i < 256; i++) {
+            gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
+        }
+    }
+
+    @Override
+    public BufferedImage process(BufferedImage image) {
+        if (gamma == 1) {
+            return image;
+        }
+        try {
+            final int bands = image.getRaster().getNumBands();
+            if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 3) {
+                return op3.filter(image, null);
+            } else if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 4) {
+                return op4.filter(image, null);
+            }
+        } catch (IllegalArgumentException ignore) {
+            Main.trace(ignore);
+        }
+        final int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
+        final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), type);
+        to.getGraphics().drawImage(image, 0, 0, null);
+        return process(to);
+    }
+
+    @Override
+    public String toString() {
+        return "GammaImageProcessor [gamma=" + gamma + ']';
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java	(revision 10547)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java	(revision 10547)
@@ -0,0 +1,119 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.openstreetmap.josm.gui.layer.ImageProcessor;
+
+/**
+ * This class holds the filter settings for an imagery layer.
+ * @author Michael Zangl
+ * @since 10547
+ */
+public class ImageryFilterSettings {
+
+    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
+    protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();
+    protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor();
+    private List<FilterChangeListener> filterChangeListeners = new CopyOnWriteArrayList<>();
+
+    /**
+     * Returns the currently set gamma value.
+     * @return the currently set gamma value
+     */
+    public double getGamma() {
+        return gammaImageProcessor.getGamma();
+    }
+
+    /**
+     * Sets a new gamma value, {@code 1} stands for no correction.
+     * @param gamma new gamma value
+     */
+    public void setGamma(double gamma) {
+        gammaImageProcessor.setGamma(gamma);
+        fireListeners();
+    }
+
+    /**
+     * Gets the current sharpen level.
+     * @return The sharpen level.
+     */
+    public double getSharpenLevel() {
+        return sharpenImageProcessor.getSharpenLevel();
+    }
+
+    /**
+     * Sets the sharpen level for the layer.
+     * <code>1</code> means no change in sharpness.
+     * Values in range 0..1 blur the image.
+     * Values above 1 are used to sharpen the image.
+     * @param sharpenLevel The sharpen level.
+     */
+    public void setSharpenLevel(double sharpenLevel) {
+        sharpenImageProcessor.setSharpenLevel((float) sharpenLevel);
+        fireListeners();
+    }
+
+    /**
+     * Gets the colorfulness of this image.
+     * @return The colorfulness
+     */
+    public double getColorfulness() {
+        return collorfulnessImageProcessor.getColorfulness();
+    }
+
+    /**
+     * Sets the colorfulness of this image.
+     * 0 means grayscale.
+     * 1 means normal colorfulness.
+     * Values greater than 1 are allowed.
+     * @param colorfulness The colorfulness.
+     */
+    public void setColorfulness(double colorfulness) {
+        collorfulnessImageProcessor.setColorfulness(colorfulness);
+        fireListeners();
+    }
+
+    /**
+     * Gets the image processors for this setting.
+     * @return The processors in the order in which they should be applied.
+     */
+    public List<ImageProcessor> getProcessors() {
+        return Arrays.asList(collorfulnessImageProcessor, gammaImageProcessor, sharpenImageProcessor);
+    }
+
+    /**
+     * Adds a filter change listener
+     * @param l The listener
+     */
+    public void addFilterChangeListener(FilterChangeListener l) {
+        filterChangeListeners.add(l);
+    }
+
+    /**
+     * Removes a filter change listener
+     * @param l The listener
+     */
+    public void removeFilterChangeListener(FilterChangeListener l) {
+        filterChangeListeners.remove(l);
+    }
+
+    private void fireListeners() {
+        for (FilterChangeListener l : filterChangeListeners) {
+            l.filterChanged();
+        }
+    }
+
+    /**
+     * A listener that listens to filter changes
+     * @author Michael Zangl
+     */
+    public interface FilterChangeListener {
+        /**
+         * Invoked when the filter is changed.
+         */
+        void filterChanged();
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java	(revision 10547)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java	(revision 10547)
@@ -0,0 +1,94 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+
+import org.openstreetmap.josm.gui.layer.ImageProcessor;
+
+/**
+ * Sharpens or blurs the image, depending on the sharpen value.
+ * <p>
+ * A positive sharpen level means that we sharpen the image.
+ * <p>
+ * A negative sharpen level let's us blur the image. -1 is the most useful value there.
+ *
+ * @author Michael Zangl
+ * @since 10547
+ */
+public class SharpenImageProcessor implements ImageProcessor {
+    private float sharpenLevel = 1;
+    private ConvolveOp op;
+
+    private static float[] KERNEL_IDENTITY = new float[] {
+        0, 0, 0,
+        0, 1, 0,
+        0, 0, 0
+    };
+
+    private static float[] KERNEL_BLUR = new float[] {
+        1f / 16, 2f / 16, 1f / 16,
+        2f / 16, 4f / 16, 2f / 16,
+        1f / 16, 2f / 16, 1f / 16
+    };
+
+    private static float[] KERNEL_SHARPEN = new float[] {
+        -.5f, -1f, -.5f,
+         -1f, 7, -1f,
+        -.5f, -1f, -.5f
+    };
+
+    /**
+     * Gets the current sharpen level.
+     * @return The level.
+     */
+    public float getSharpenLevel() {
+        return sharpenLevel;
+    }
+
+    /**
+     * Sets the sharpening level.
+     * @param sharpenLevel The level. Clamped to be positive or 0.
+     */
+    public void setSharpenLevel(float sharpenLevel) {
+        if (sharpenLevel < 0) {
+            this.sharpenLevel = 0;
+        } else {
+            this.sharpenLevel = sharpenLevel;
+        }
+
+        if (this.sharpenLevel < 0.95) {
+            op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR);
+        } else if (this.sharpenLevel > 1.05) {
+            op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY);
+        } else {
+            op = null;
+        }
+    }
+
+    private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) {
+        if (a.length != 9 || b.length != 9) {
+            throw new IllegalArgumentException("Illegal kernel array length.");
+        }
+        float[] values = new float[9];
+        for (int i = 0; i < values.length; i++) {
+            values[i] = aFactor * a[i] + (1 - aFactor) * b[i];
+        }
+        return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null);
+    }
+
+    @Override
+    public BufferedImage process(BufferedImage image) {
+        if (op != null) {
+            return op.filter(image, null);
+        } else {
+            return image;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + ']';
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/widgets/ButtonColumn.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/widgets/ButtonColumn.java	(revision 10546)
+++ /trunk/src/org/openstreetmap/josm/gui/widgets/ButtonColumn.java	(revision 10547)
@@ -40,5 +40,5 @@
     public ButtonColumn(Action action, String buttonName) {
         this(action);
-        this.buttonName  = buttonName;
+        this.buttonName = buttonName;
     }
 
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java	(revision 10546)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java	(revision 10547)
@@ -2,9 +2,13 @@
 package org.openstreetmap.josm.gui.layer;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 
-import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
-import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
@@ -14,22 +18,19 @@
 
     /**
-     * Setup tests
+     * For creating layers
      */
-    @BeforeClass
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init(true);
-    }
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().preferences();
 
     /**
-     * Unit test of {@link ImageryLayer.ColorfulImageProcessor#toString}
-     *          and {@link ImageryLayer.GammaImageProcessor#toString()}.
-     *          and {@link ImageryLayer.SharpenImageProcessor#toString()}.
+     * Unit test of {@link ImageryLayer#getFilterSettings()}
      */
     @Test
-    public void testToString() {
+    public void testHasSettings() {
         ImageryLayer layer = TMSLayerTest.createTmsLayer();
-        assertEquals("ColorfulImageProcessor [colorfulness=1.0]", layer.collorfulnessImageProcessor.toString());
-        assertEquals("GammaImageProcessor [gamma=1.0]", layer.gammaImageProcessor.toString());
-        assertEquals("SharpenImageProcessor [sharpenLevel=1.0]", layer.sharpenImageProcessor.toString());
+        ImageryFilterSettings settings = layer.getFilterSettings();
+        assertNotNull(settings);
+        assertSame(settings, layer.getFilterSettings());
     }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java	(revision 10547)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java	(revision 10547)
@@ -0,0 +1,155 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Tests for the {@link ColorfulImageProcessor} class.
+ * @author Michael Zangl
+ */
+public class ColorfulImageProcessorTest {
+
+    private static final int TEST_IMAGE_SIZE = 5;
+
+    /**
+     * No special rules
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Test {@link ColorfulImageProcessor#setColorfulness(double)} and {@link ColorfulImageProcessor#getColorfulness()}
+     */
+    @Test
+    public void testSetGet() {
+        ColorfulImageProcessor processor = new ColorfulImageProcessor();
+
+        assertEquals(1, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(2);
+        assertEquals(2, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(0);
+        assertEquals(0, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(0.78);
+        assertEquals(0.78, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(1);
+        assertEquals(1, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(-1);
+        assertEquals(0, processor.getColorfulness(), 0.001);
+
+        processor.setColorfulness(5);
+        assertEquals(5, processor.getColorfulness(), 0.001);
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testProcessing() {
+        for (ConversionData data : new ConversionData[] {
+                new ConversionData(Color.BLACK, 1.5, Color.BLACK),
+                new ConversionData(Color.WHITE, 0.5, Color.WHITE),
+                new ConversionData(Color.GRAY, 0, Color.GRAY),
+                new ConversionData(Color.GREEN, 1, Color.GREEN),
+                new ConversionData(Color.RED, 1, Color.RED),
+                new ConversionData(Color.BLUE, 1, Color.BLUE),
+                new ConversionData(0x908050, 0, 0x808080),
+                new ConversionData(0x908070, 1, 0x908070),
+                new ConversionData(0x908070, 2, 0x9c7c5c),
+                new ConversionData(0x908070, 2, 0x9c7c5c),
+                new ConversionData(0xf02080, 2, 0xff00ac),
+        }) {
+            for (int type : new int[] {
+                    BufferedImage.TYPE_3BYTE_BGR,
+                    BufferedImage.TYPE_4BYTE_ABGR,
+                    BufferedImage.TYPE_4BYTE_ABGR_PRE }) {
+                assertTrue(runProcessing(data, type));
+            }
+        }
+    }
+
+    private boolean runProcessing(ConversionData data, int type) {
+        BufferedImage image = createImage(data.getOldColor(), type);
+
+        ColorfulImageProcessor processor = new ColorfulImageProcessor();
+        processor.setColorfulness(data.getFactor());
+        image = processor.process(image);
+
+        for (int x = 0; x < TEST_IMAGE_SIZE; x++) {
+            for (int y = 0; y < TEST_IMAGE_SIZE; y++) {
+                Color color = new Color(image.getRGB(x, y));
+                assertEquals(data + ":" + type + ": red", data.getExpectedColor().getRed(), color.getRed(), 1.05);
+                assertEquals(data + ":" + type + ": green", data.getExpectedColor().getGreen(), color.getGreen(), 1.05);
+                assertEquals(data + ":" + type + ": blue", data.getExpectedColor().getBlue(), color.getBlue(), 1.05);
+            }
+        }
+        return true;
+    }
+
+    private BufferedImage createImage(Color color, int type) {
+        BufferedImage image = new BufferedImage(TEST_IMAGE_SIZE, TEST_IMAGE_SIZE, type);
+        Graphics2D graphics = image.createGraphics();
+        graphics.setColor(color);
+        graphics.fillRect(0, 0, TEST_IMAGE_SIZE, TEST_IMAGE_SIZE);
+        return image;
+    }
+
+    private static class ConversionData {
+        private final Color oldColor;
+        private final double factor;
+        private final Color expectedColor;
+
+        ConversionData(Color oldColor, double factor, Color expectedColor) {
+            super();
+            this.oldColor = oldColor;
+            this.factor = factor;
+            this.expectedColor = expectedColor;
+        }
+
+        ConversionData(int oldColor, double factor, int expectedColor) {
+            this(new Color(oldColor), factor, new Color(expectedColor));
+        }
+
+        Color getOldColor() {
+            return oldColor;
+        }
+
+        double getFactor() {
+            return factor;
+        }
+
+        Color getExpectedColor() {
+            return expectedColor;
+        }
+
+        @Override
+        public String toString() {
+            return "ConversionData [oldColor=" + oldColor + ", factor=" + factor + "]";
+        }
+    }
+
+    /**
+     * Test {@link ColorfulImageProcessor#toString()}
+     */
+    @Test
+    public void testToString() {
+        ColorfulImageProcessor processor = new ColorfulImageProcessor();
+        assertEquals("ColorfulImageProcessor [colorfulness=1.0]", processor.toString());
+    }
+}
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java	(revision 10547)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java	(revision 10547)
@@ -0,0 +1,61 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Tests for the {@link GammaImageProcessor} class.
+ * @author Michael Zangl
+ */
+public class GammaImageProcessorTest {
+
+    /**
+     * No special rules
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Test {@link GammaImageProcessor#setGamma(double)} and {@link GammaImageProcessor#getGamma()}
+     */
+    @Test
+    public void testSetGet() {
+        GammaImageProcessor processor = new GammaImageProcessor();
+
+        assertEquals(1, processor.getGamma(), 0.001);
+
+        processor.setGamma(2);
+        assertEquals(2, processor.getGamma(), 0.001);
+
+        processor.setGamma(0);
+        assertEquals(0, processor.getGamma(), 0.001);
+
+        processor.setGamma(0.78);
+        assertEquals(0.78, processor.getGamma(), 0.001);
+
+        processor.setGamma(1);
+        assertEquals(1, processor.getGamma(), 0.001);
+
+        processor.setGamma(-1);
+        assertEquals(-1, processor.getGamma(), 0.001);
+
+        processor.setGamma(5);
+        assertEquals(5, processor.getGamma(), 0.001);
+    }
+
+    /**
+     * Test {@link GammaImageProcessor#toString()}
+     */
+    @Test
+    public void testToString() {
+        GammaImageProcessor processor = new GammaImageProcessor();
+        assertEquals("GammaImageProcessor [gamma=1.0]", processor.toString());
+    }
+}
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java	(revision 10547)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java	(revision 10547)
@@ -0,0 +1,61 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.imagery;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Tests for the {@link SharpenImageProcessor} class.
+ * @author Michael Zangl
+ */
+public class SharpenImageProcessorTest {
+
+    /**
+     * No special rules
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Test {@link SharpenImageProcessor#setSharpenLevel(float)} and {@link SharpenImageProcessor#getSharpenLevel()}
+     */
+    @Test
+    public void testSetGet() {
+        SharpenImageProcessor processor = new SharpenImageProcessor();
+
+        assertEquals(1, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(2);
+        assertEquals(2, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(0);
+        assertEquals(0, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(0.78f);
+        assertEquals(0.78, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(1);
+        assertEquals(1, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(-1);
+        assertEquals(-1, processor.getSharpenLevel(), 0.001);
+
+        processor.setSharpenLevel(5);
+        assertEquals(5, processor.getSharpenLevel(), 0.001);
+    }
+
+    /**
+     * Test {@link SharpenImageProcessor#toString()}
+     */
+    @Test
+    public void testToString() {
+        SharpenImageProcessor processor = new SharpenImageProcessor();
+        assertEquals("SharpenImageProcessor [gamma=1.0]", processor.toString());
+    }
+}
