Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 8728)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 8729)
@@ -56,4 +56,5 @@
 import org.openstreetmap.josm.gui.SideButton;
 import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.JumpToMarkerActions;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -71,4 +72,5 @@
 import org.openstreetmap.josm.tools.MultikeyShortcutAction.MultikeyInfo;
 import org.openstreetmap.josm.tools.Shortcut;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -113,4 +115,5 @@
 
     private SideButton opacityButton;
+    private SideButton gammaButton;
 
     private ActivateLayerAction activateLayerAction;
@@ -261,4 +264,9 @@
         opacityButton = new SideButton(layerOpacityAction, false);
 
+        // -- layer gamma action
+        LayerGammaAction layerGammaAction = new LayerGammaAction();
+        adaptTo(layerGammaAction, selectionModel);
+        gammaButton = new SideButton(layerGammaAction, false);
+
         // -- delete layer action
         DeleteLayerAction deleteLayerAction = new DeleteLayerAction();
@@ -288,4 +296,5 @@
                 new SideButton(showHideLayerAction, false),
                 opacityButton,
+                gammaButton,
                 new SideButton(deleteLayerAction, false)
         ));
@@ -513,10 +522,59 @@
 
     /**
+     * Abstract action which allows to adjust a double value using a slider
+     */
+    public static abstract class AbstractLayerPropertySliderAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
+        protected final JPopupMenu popup;
+        protected final JSlider slider;
+        private final double factor;
+
+        public AbstractLayerPropertySliderAction(String name, final double factor) {
+            super(name);
+            this.factor = factor;
+            updateEnabledState();
+
+            popup = new JPopupMenu();
+            slider = new JSlider(JSlider.VERTICAL);
+            slider.addChangeListener(new ChangeListener() {
+                @Override
+                public void stateChanged(ChangeEvent e) {
+                    setValue((double) slider.getValue() / factor);
+                }
+            });
+            popup.add(slider);
+
+        }
+
+        protected abstract void setValue(double value);
+
+        protected abstract double getValue();
+
+        protected abstract SideButton getCorrespondingSideButton();
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            final SideButton sideButton = getCorrespondingSideButton();
+            slider.setValue((int) (getValue() * factor));
+            if (e.getSource() == sideButton) {
+                popup.show(sideButton, 0, sideButton.getHeight());
+            } else {
+                // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
+                // In that case, show it in the middle of screen (because opacityButton is not visible)
+                popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
+            }
+        }
+
+        @Override
+        public Component createMenuComponent() {
+            return new JMenuItem(this);
+        }
+
+    }
+
+    /**
      * Action which allows to change the opacity of one or more layers.
      */
-    public final class LayerOpacityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
+    public final class LayerOpacityAction extends AbstractLayerPropertySliderAction {
         private transient Layer layer;
-        private JPopupMenu popup;
-        private JSlider slider = new JSlider(JSlider.VERTICAL);
 
         /**
@@ -529,5 +587,4 @@
         public LayerOpacityAction(Layer layer) {
             this();
-            putValue(NAME, tr("Opacity"));
             CheckParameterUtil.ensureParameterNotNull(layer, "layer");
             this.layer = layer;
@@ -541,20 +598,11 @@
          */
         public LayerOpacityAction() {
-            putValue(NAME, tr("Opacity"));
+            super(tr("Opacity"), 100);
             putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
-            updateEnabledState();
-
-            popup = new JPopupMenu();
-            slider.addChangeListener(new ChangeListener() {
-                @Override
-                public void stateChanged(ChangeEvent e) {
-                    setOpacity((double) slider.getValue()/100);
-                }
-            });
-            popup.add(slider);
-        }
-
-        private void setOpacity(double value) {
+        }
+
+        @Override
+        protected void setValue(double value) {
             if (!isEnabled()) return;
             if (layer != null) {
@@ -567,5 +615,6 @@
         }
 
-        private double getOpacity() {
+        @Override
+        protected double getValue() {
             if (layer != null)
                 return layer.getOpacity();
@@ -581,13 +630,6 @@
 
         @Override
-        public void actionPerformed(ActionEvent e) {
-            slider.setValue((int) Math.round(getOpacity()*100));
-            if (e.getSource() == opacityButton) {
-                popup.show(opacityButton, 0, opacityButton.getHeight());
-            } else {
-                // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
-                // In that case, show it in the middle of screen (because opacityButton is not visible)
-                popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
-            }
+        protected SideButton getCorrespondingSideButton() {
+            return opacityButton;
         }
 
@@ -602,21 +644,45 @@
 
         @Override
-        public Component createMenuComponent() {
-            return new JMenuItem(this);
-        }
-
-        @Override
         public boolean supportLayers(List<Layer> layers) {
             return true;
         }
-
-        @Override
-        public boolean equals(Object obj) {
-            return obj instanceof LayerOpacityAction;
-        }
-
-        @Override
-        public int hashCode() {
-            return getClass().hashCode();
+    }
+
+    /**
+     * Action which allows to change the gamma of one imagery layer.
+     */
+    public final class LayerGammaAction extends AbstractLayerPropertySliderAction {
+
+        public LayerGammaAction() {
+            super(tr("Gamma"), 50);
+            putValue(SHORT_DESCRIPTION, tr("Adjust gamma value of the layer."));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "gamma"));
+        }
+
+        @Override
+        protected void setValue(double value) {
+            for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
+                imageryLayer.setGamma(value);
+            }
+        }
+
+        @Override
+        protected double getValue() {
+            return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma();
+        }
+
+        @Override
+        protected SideButton getCorrespondingSideButton() {
+            return gammaButton;
+        }
+
+        @Override
+        public void updateEnabledState() {
+            setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty());
+        }
+
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty();
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 8728)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 8729)
@@ -245,4 +245,10 @@
     }
 
+    @Override
+    public void setGamma(double gamma) {
+        super.setGamma(gamma);
+        redraw();
+    }
+
     /**
      * Marks layer as needing redraw on offset change
Index: /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 8728)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java	(revision 8729)
@@ -20,4 +20,6 @@
 import java.awt.image.ConvolveOp;
 import java.awt.image.Kernel;
+import java.awt.image.LookupOp;
+import java.awt.image.ShortLookupTable;
 import java.text.AttributedCharacterIterator;
 import java.text.AttributedString;
@@ -75,4 +77,6 @@
     protected double dy = 0.0;
 
+    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
+
     private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
 
@@ -92,4 +96,5 @@
         }
         addImageProcessor(createSharpener(PROP_SHARPEN_LEVEL.get()));
+        addImageProcessor(gammaImageProcessor);
     }
 
@@ -247,4 +252,64 @@
         BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
         return createImageProcessor(op, false);
+    }
+
+    /**
+     * 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 LookupOp op3 = new LookupOp(new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
+        private LookupOp op4 = new LookupOp(new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
+
+        /**
+         * Returns the currently set gamma value.
+         */
+        public double getGamma() {
+            return gamma;
+        }
+
+        /**
+         * Sets a new gamma value, {@code 1} stands for no correction.
+         */
+        public void setGamma(double gamma) {
+            this.gamma = gamma;
+            for (int i = 0; i < 256; i++) {
+                gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
+            }
+        }
+
+        private LookupOp getOp(int bands) {
+            if (gamma == 1) {
+                return null;
+            } else if (bands == 3) {
+                return op3;
+            } else if (bands == 4) {
+                return op4;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public BufferedImage process(BufferedImage image) {
+            final LookupOp op = getOp(image.getRaster().getNumBands());
+            final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
+            return op == null ? image : op.filter(image, to);
+        }
+    }
+
+    /**
+     * Returns the currently set gamma value.
+     */
+    public double getGamma() {
+        return gammaImageProcessor.getGamma();
+    }
+
+    /**
+     * Sets a new gamma value, {@code 1} stands for no correction.
+     */
+    public void setGamma(double gamma) {
+        gammaImageProcessor.setGamma(gamma);
     }
 
