Ticket #13159: patch-mapview-separate-tile-source.patch

File patch-mapview-separate-tile-source.patch, 49.9 KB (added by michael2402, 10 years ago)
  • src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java b/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java
    index 1c8a58f..538c714 100644
    a b import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel;  
    2828import org.openstreetmap.josm.gui.layer.ImageryLayer;
    2929import org.openstreetmap.josm.gui.layer.Layer;
    3030import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
     31import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
    3132import org.openstreetmap.josm.tools.GBC;
    3233import org.openstreetmap.josm.tools.ImageProvider;
    3334import org.openstreetmap.josm.tools.Utils;
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    306307     * This slider allows you to change the gamma value of a layer.
    307308     *
    308309     * @author Michael Zangl
    309      * @see ImageryLayer#setGamma(double)
     310     * @see ImageryFilterSettings#setGamma(double)
    310311     */
    311312    private class GammaFilterSlider extends FilterSlider<ImageryLayer> {
    312313
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    320321
    321322        @Override
    322323        protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
    323             double gamma = ((ImageryLayer) usedLayers.iterator().next()).getGamma();
     324            double gamma = ((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getGamma();
    324325            setRealValue(mapGammaToInterval(gamma));
    325326        }
    326327
    327328        @Override
    328329        protected void applyValueToLayer(ImageryLayer layer) {
    329             layer.setGamma(mapIntervalToGamma(getRealValue()));
     330            layer.getFilterSettings().setGamma(mapIntervalToGamma(getRealValue()));
    330331        }
    331332
    332333        @Override
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    365366     * This slider allows you to change the sharpness of a layer.
    366367     *
    367368     * @author Michael Zangl
    368      * @see ImageryLayer#setSharpenLevel(double)
     369     * @see ImageryFilterSettings#setSharpenLevel(double)
    369370     */
    370371    private class SharpnessSlider extends FilterSlider<ImageryLayer> {
    371372
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    379380
    380381        @Override
    381382        protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
    382             setRealValue(((ImageryLayer) usedLayers.iterator().next()).getSharpenLevel());
     383            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getSharpenLevel());
    383384        }
    384385
    385386        @Override
    386387        protected void applyValueToLayer(ImageryLayer layer) {
    387             layer.setSharpenLevel(getRealValue());
     388            layer.getFilterSettings().setSharpenLevel(getRealValue());
    388389        }
    389390
    390391        @Override
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    402403     * This slider allows you to change the colorfulness of a layer.
    403404     *
    404405     * @author Michael Zangl
    405      * @see ImageryLayer#setColorfulness(double)
     406     * @see ImageryFilterSettings#setColorfulness(double)
    406407     */
    407408    private class ColorfulnessSlider extends FilterSlider<ImageryLayer> {
    408409
    public final class LayerVisibilityAction extends AbstractAction implements IEnab  
    416417
    417418        @Override
    418419        protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
    419             setRealValue(((ImageryLayer) usedLayers.iterator().next()).getColorfulness());
     420            setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getColorfulness());
    420421        }
    421422
    422423        @Override
    423424        protected void applyValueToLayer(ImageryLayer layer) {
    424             layer.setColorfulness(getRealValue());
     425            layer.getFilterSettings().setColorfulness(getRealValue());
    425426        }
    426427
    427428        @Override
  • src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java b/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
    index 79fad29..929aff8 100644
    a b import org.openstreetmap.josm.gui.NavigatableComponent.ZoomChangeListener;  
    8181import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    8282import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    8383import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
     84import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings.FilterChangeListener;
    8485import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    8586import org.openstreetmap.josm.gui.util.GuiHelper;
    8687import org.openstreetmap.josm.io.WMSLayerImporter;
    import org.openstreetmap.josm.tools.GBC;  
    9899 * @since 8526 (copied from TMSLayer)
    99100 */
    100101public abstract class AbstractTileSourceLayer<T extends AbstractTMSTileSource> extends ImageryLayer
    101 implements ImageObserver, TileLoaderListener, ZoomChangeListener {
     102implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeListener {
    102103    private static final String PREFERENCE_PREFIX = "imagery.generic";
    103104
    104105    /** maximum zoom level supported */
    implements ImageObserver, TileLoaderListener, ZoomChangeListener {  
    174175        super(info);
    175176        setBackgroundLayer(true);
    176177        this.setVisible(true);
     178        getFilterSettings().addFilterChangeListener(this);
     179    }
     180
     181    @Override
     182    public void filterChanged() {
     183        redraw();
    177184    }
    178185
    179186    protected abstract TileLoaderFactory getTileLoaderFactory();
    implements ImageObserver, TileLoaderListener, ZoomChangeListener {  
    262269        if (isVisible()) Main.map.repaint();
    263270    }
    264271
    265     @Override
    266     public void setGamma(double gamma) {
    267         super.setGamma(gamma);
    268         redraw();
    269     }
    270 
    271     @Override
    272     public void setSharpenLevel(double sharpenLevel) {
    273         super.setSharpenLevel(sharpenLevel);
    274         redraw();
    275     }
    276 
    277     @Override
    278     public void setColorfulness(double colorfulness) {
    279         super.setColorfulness(colorfulness);
    280         redraw();
    281     }
    282 
    283272    /**
    284273     * Marks layer as needing redraw on offset change
    285274     */
  • src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java b/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
    index 4a6d290..3ab3633 100644
    a b import static org.openstreetmap.josm.tools.I18n.trc;  
    88import java.awt.Color;
    99import java.awt.Component;
    1010import java.awt.GridBagLayout;
    11 import java.awt.Rectangle;
    12 import java.awt.RenderingHints;
    13 import java.awt.Transparency;
    1411import java.awt.event.ActionEvent;
    15 import java.awt.geom.Point2D;
    16 import java.awt.geom.Rectangle2D;
    1712import java.awt.image.BufferedImage;
    1813import java.awt.image.BufferedImageOp;
    19 import java.awt.image.ColorModel;
    20 import java.awt.image.ConvolveOp;
    21 import java.awt.image.DataBuffer;
    22 import java.awt.image.DataBufferByte;
    23 import java.awt.image.Kernel;
    24 import java.awt.image.LookupOp;
    25 import java.awt.image.ShortLookupTable;
    2614import java.util.ArrayList;
    2715import java.util.List;
    2816
    import org.openstreetmap.josm.data.imagery.OffsetBookmark;  
    4533import org.openstreetmap.josm.data.preferences.ColorProperty;
    4634import org.openstreetmap.josm.data.preferences.IntegerProperty;
    4735import org.openstreetmap.josm.gui.MenuScroller;
     36import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
    4837import org.openstreetmap.josm.gui.widgets.UrlLabel;
    4938import org.openstreetmap.josm.tools.GBC;
    5039import org.openstreetmap.josm.tools.ImageProvider;
    public abstract class ImageryLayer extends Layer {  
    7564    protected double dx;
    7665    protected double dy;
    7766
    78     protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
    79     protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();
    80     protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor();
    81 
    8267    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
    8368
     69    private final ImageryFilterSettings filterSettings = new ImageryFilterSettings();
     70
    8471    /**
    8572     * Constructs a new {@code ImageryLayer}.
    8673     * @param info imagery info
    public abstract class ImageryLayer extends Layer {  
    9582        if (icon == null) {
    9683            icon = ImageProvider.get("imagery_small");
    9784        }
    98         addImageProcessor(collorfulnessImageProcessor);
    99         addImageProcessor(gammaImageProcessor);
    100         addImageProcessor(sharpenImageProcessor);
    101         sharpenImageProcessor.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);
     85        for (ImageProcessor processor : filterSettings.getProcessors()) {
     86            addImageProcessor(processor);
     87        }
     88        filterSettings.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);
    10289    }
    10390
    10491    public double getPPD() {
    public abstract class ImageryLayer extends Layer {  
    258245    }
    259246
    260247    /**
    261      * An image processor which adjusts the gamma value of an image.
    262      */
    263     public static class GammaImageProcessor implements ImageProcessor {
    264         private double gamma = 1;
    265         final short[] gammaChange = new short[256];
    266         private final LookupOp op3 = new LookupOp(
    267                 new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
    268         private final LookupOp op4 = new LookupOp(
    269                 new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
    270 
    271         /**
    272          * Returns the currently set gamma value.
    273          * @return the currently set gamma value
    274          */
    275         public double getGamma() {
    276             return gamma;
    277         }
    278 
    279         /**
    280          * Sets a new gamma value, {@code 1} stands for no correction.
    281          * @param gamma new gamma value
    282          */
    283         public void setGamma(double gamma) {
    284             this.gamma = gamma;
    285             for (int i = 0; i < 256; i++) {
    286                 gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
    287             }
    288         }
    289 
    290         @Override
    291         public BufferedImage process(BufferedImage image) {
    292             if (gamma == 1) {
    293                 return image;
    294             }
    295             try {
    296                 final int bands = image.getRaster().getNumBands();
    297                 if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 3) {
    298                     return op3.filter(image, null);
    299                 } else if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 4) {
    300                     return op4.filter(image, null);
    301                 }
    302             } catch (IllegalArgumentException ignore) {
    303                 Main.trace(ignore);
    304             }
    305             final int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
    306             final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), type);
    307             to.getGraphics().drawImage(image, 0, 0, null);
    308             return process(to);
    309         }
    310 
    311         @Override
    312         public String toString() {
    313             return "GammaImageProcessor [gamma=" + gamma + ']';
    314         }
    315     }
    316 
    317     /**
    318      * Sharpens or blurs the image, depending on the sharpen value.
    319      * <p>
    320      * A positive sharpen level means that we sharpen the image.
    321      * <p>
    322      * A negative sharpen level let's us blur the image. -1 is the most useful value there.
    323      *
    324      * @author Michael Zangl
    325      */
    326     public static class SharpenImageProcessor implements ImageProcessor {
    327         private float sharpenLevel;
    328         private ConvolveOp op;
    329 
    330         private static float[] KERNEL_IDENTITY = new float[] {
    331             0, 0, 0,
    332             0, 1, 0,
    333             0, 0, 0
    334         };
    335 
    336         private static float[] KERNEL_BLUR = new float[] {
    337             1f / 16, 2f / 16, 1f / 16,
    338             2f / 16, 4f / 16, 2f / 16,
    339             1f / 16, 2f / 16, 1f / 16
    340         };
    341 
    342         private static float[] KERNEL_SHARPEN = new float[] {
    343             -.5f, -1f, -.5f,
    344              -1f, 7, -1f,
    345             -.5f, -1f, -.5f
    346         };
    347 
    348         /**
    349          * Gets the current sharpen level.
    350          * @return The level.
    351          */
    352         public float getSharpenLevel() {
    353             return sharpenLevel;
    354         }
    355 
    356         /**
    357          * Sets the sharpening level.
    358          * @param sharpenLevel The level. Clamped to be positive or 0.
    359          */
    360         public void setSharpenLevel(float sharpenLevel) {
    361             if (sharpenLevel < 0) {
    362                 this.sharpenLevel = 0;
    363             } else {
    364                 this.sharpenLevel = sharpenLevel;
    365             }
    366 
    367             if (this.sharpenLevel < 0.95) {
    368                 op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR);
    369             } else if (this.sharpenLevel > 1.05) {
    370                 op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY);
    371             } else {
    372                 op = null;
    373             }
    374         }
    375 
    376         private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) {
    377             if (a.length != 9 || b.length != 9) {
    378                 throw new IllegalArgumentException("Illegal kernel array length.");
    379             }
    380             float[] values = new float[9];
    381             for (int i = 0; i < values.length; i++) {
    382                 values[i] = aFactor * a[i] + (1 - aFactor) * b[i];
    383             }
    384             return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null);
    385         }
    386 
    387         @Override
    388         public BufferedImage process(BufferedImage image) {
    389             if (op != null) {
    390                 return op.filter(image, null);
    391             } else {
    392                 return image;
    393             }
    394         }
    395 
    396         @Override
    397         public String toString() {
    398             return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + ']';
    399         }
    400     }
    401 
    402     /**
    403      * Adds or removes the colorfulness of the image.
    404      *
    405      * @author Michael Zangl
    406      */
    407     public static class ColorfulImageProcessor implements ImageProcessor {
    408         private ColorfulFilter op;
    409         private double colorfulness = 1;
    410 
    411         /**
    412          * Gets the colorfulness value.
    413          * @return The value
    414          */
    415         public double getColorfulness() {
    416             return colorfulness;
    417         }
    418 
    419         /**
    420          * Sets the colorfulness value. Clamps it to 0+
    421          * @param colorfulness The value
    422          */
    423         public void setColorfulness(double colorfulness) {
    424             if (colorfulness < 0) {
    425                 this.colorfulness = 0;
    426             } else {
    427                 this.colorfulness = colorfulness;
    428             }
    429 
    430             if (this.colorfulness < .95 || this.colorfulness > 1.05) {
    431                 op = new ColorfulFilter(this.colorfulness);
    432             } else {
    433                 op = null;
    434             }
    435         }
    436 
    437         @Override
    438         public BufferedImage process(BufferedImage image) {
    439             if (op != null) {
    440                 return op.filter(image, null);
    441             } else {
    442                 return image;
    443             }
    444         }
    445 
    446         @Override
    447         public String toString() {
    448             return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']';
    449         }
    450     }
    451 
    452     private static class ColorfulFilter implements BufferedImageOp {
    453         private final double colorfulness;
    454 
    455         /**
    456          * Create a new colorful filter.
    457          * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class.
    458          */
    459         ColorfulFilter(double colorfulness) {
    460             this.colorfulness = colorfulness;
    461         }
    462 
    463         @Override
    464         public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    465             if (src.getWidth() == 0 || src.getHeight() == 0) {
    466                 return src;
    467             }
    468 
    469             if (dest == null) {
    470                 dest = createCompatibleDestImage(src, null);
    471             }
    472             DataBuffer srcBuffer = src.getRaster().getDataBuffer();
    473             DataBuffer destBuffer = dest.getRaster().getDataBuffer();
    474             if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) {
    475                 Main.trace("Cannot apply color filter: Images do not use DataBufferByte.");
    476                 return src;
    477             }
    478 
    479             int type = src.getType();
    480             if (type != dest.getType()) {
    481                 Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')');
    482                 return src;
    483             }
    484             int redOffset, greenOffset, blueOffset, alphaOffset = 0;
    485             switch (type) {
    486             case BufferedImage.TYPE_3BYTE_BGR:
    487                 blueOffset = 0;
    488                 greenOffset = 1;
    489                 redOffset = 2;
    490                 break;
    491             case BufferedImage.TYPE_4BYTE_ABGR:
    492             case BufferedImage.TYPE_4BYTE_ABGR_PRE:
    493                 blueOffset = 1;
    494                 greenOffset = 2;
    495                 redOffset = 3;
    496                 break;
    497             case BufferedImage.TYPE_INT_ARGB:
    498             case BufferedImage.TYPE_INT_ARGB_PRE:
    499                 redOffset = 0;
    500                 greenOffset = 1;
    501                 blueOffset = 2;
    502                 alphaOffset = 3;
    503                 break;
    504             default:
    505                 Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ").");
    506                 return src;
    507             }
    508             doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset,
    509                     alphaOffset, src.getAlphaRaster() != null);
    510             return dest;
    511         }
    512 
    513         private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset,
    514                 int alphaOffset, boolean hasAlpha) {
    515             byte[] srcPixels = src.getData();
    516             byte[] destPixels = dest.getData();
    517             if (srcPixels.length != destPixels.length) {
    518                 Main.trace("Cannot apply color filter: Source/Dest lengths differ.");
    519                 return;
    520             }
    521             int entries = hasAlpha ? 4 : 3;
    522             for (int i = 0; i < srcPixels.length; i += entries) {
    523                 int r = srcPixels[i + redOffset] & 0xff;
    524                 int g = srcPixels[i + greenOffset] & 0xff;
    525                 int b = srcPixels[i + blueOffset] & 0xff;
    526                 double luminosity = r * .21d + g * .72d + b * .07d;
    527                 destPixels[i + redOffset] = mix(r, luminosity);
    528                 destPixels[i + greenOffset] = mix(g, luminosity);
    529                 destPixels[i + blueOffset] = mix(b, luminosity);
    530                 if (hasAlpha) {
    531                     destPixels[i + alphaOffset] = srcPixels[i + alphaOffset];
    532                 }
    533             }
    534         }
    535 
    536         private byte mix(int color, double luminosity) {
    537             int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity);
    538             if (val < 0) {
    539                 return 0;
    540             } else if (val > 0xff) {
    541                 return (byte) 0xff;
    542             } else {
    543                 return (byte) val;
    544             }
    545         }
    546 
    547         @Override
    548         public Rectangle2D getBounds2D(BufferedImage src) {
    549             return new Rectangle(src.getWidth(), src.getHeight());
    550         }
    551 
    552         @Override
    553         public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
    554             return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
    555         }
    556 
    557         @Override
    558         public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
    559             return (Point2D) srcPt.clone();
    560         }
    561 
    562         @Override
    563         public RenderingHints getRenderingHints() {
    564             return null;
    565         }
    566 
    567     }
    568 
    569     /**
    570      * Returns the currently set gamma value.
    571      * @return the currently set gamma value
    572      */
    573     public double getGamma() {
    574         return gammaImageProcessor.getGamma();
    575     }
    576 
    577     /**
    578      * Sets a new gamma value, {@code 1} stands for no correction.
    579      * @param gamma new gamma value
    580      */
    581     public void setGamma(double gamma) {
    582         gammaImageProcessor.setGamma(gamma);
    583     }
    584 
    585     /**
    586      * Gets the current sharpen level.
    587      * @return The sharpen level.
    588      */
    589     public double getSharpenLevel() {
    590         return sharpenImageProcessor.getSharpenLevel();
    591     }
    592 
    593     /**
    594      * Sets the sharpen level for the layer.
    595      * <code>1</code> means no change in sharpness.
    596      * Values in range 0..1 blur the image.
    597      * Values above 1 are used to sharpen the image.
    598      * @param sharpenLevel The sharpen level.
    599      */
    600     public void setSharpenLevel(double sharpenLevel) {
    601         sharpenImageProcessor.setSharpenLevel((float) sharpenLevel);
    602     }
    603 
    604     /**
    605      * Gets the colorfulness of this image.
    606      * @return The colorfulness
    607      */
    608     public double getColorfulness() {
    609         return collorfulnessImageProcessor.getColorfulness();
    610     }
    611 
    612     /**
    613      * Sets the colorfulness of this image.
    614      * 0 means grayscale.
    615      * 1 means normal colorfulness.
    616      * Values greater than 1 are allowed.
    617      * @param colorfulness The colorfulness.
     248     * Gets the settings for the filter that is applied to this layer.
     249     * @return The filter settings.
    618250     */
    619     public void setColorfulness(double colorfulness) {
    620         collorfulnessImageProcessor.setColorfulness(colorfulness);
     251    public ImageryFilterSettings getFilterSettings() {
     252        return filterSettings;
    621253    }
    622254
    623255    /**
  • new file src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java b/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java
    new file mode 100644
    index 0000000..dbb4023
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import java.awt.Rectangle;
     5import java.awt.RenderingHints;
     6import java.awt.geom.Point2D;
     7import java.awt.geom.Rectangle2D;
     8import java.awt.image.BufferedImage;
     9import java.awt.image.BufferedImageOp;
     10import java.awt.image.ColorModel;
     11import java.awt.image.DataBuffer;
     12import java.awt.image.DataBufferByte;
     13
     14import org.openstreetmap.josm.Main;
     15import org.openstreetmap.josm.gui.layer.ImageProcessor;
     16
     17/**
     18 * Adds or removes the colorfulness of the image.
     19 *
     20 * @author Michael Zangl
     21 */
     22public class ColorfulImageProcessor implements ImageProcessor {
     23    private ColorfulFilter op;
     24    private double colorfulness = 1;
     25
     26    /**
     27     * Gets the colorfulness value.
     28     * @return The value
     29     */
     30    public double getColorfulness() {
     31        return colorfulness;
     32    }
     33
     34    /**
     35     * Sets the colorfulness value. Clamps it to 0+
     36     * @param colorfulness The value
     37     */
     38    public void setColorfulness(double colorfulness) {
     39        if (colorfulness < 0) {
     40            this.colorfulness = 0;
     41        } else {
     42            this.colorfulness = colorfulness;
     43        }
     44
     45        if (this.colorfulness < .95 || this.colorfulness > 1.05) {
     46            op = new ColorfulFilter(this.colorfulness);
     47        } else {
     48            op = null;
     49        }
     50    }
     51
     52    @Override
     53    public BufferedImage process(BufferedImage image) {
     54        if (op != null) {
     55            return op.filter(image, null);
     56        } else {
     57            return image;
     58        }
     59    }
     60
     61    @Override
     62    public String toString() {
     63        return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']';
     64    }
     65
     66    static class ColorfulFilter implements BufferedImageOp {
     67        private final double colorfulness;
     68
     69        /**
     70         * Create a new colorful filter.
     71         * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class.
     72         */
     73        ColorfulFilter(double colorfulness) {
     74            this.colorfulness = colorfulness;
     75        }
     76
     77        @Override
     78        public BufferedImage filter(BufferedImage src, BufferedImage dest) {
     79            if (src.getWidth() == 0 || src.getHeight() == 0) {
     80                return src;
     81            }
     82
     83            if (dest == null) {
     84                dest = createCompatibleDestImage(src, null);
     85            }
     86            DataBuffer srcBuffer = src.getRaster().getDataBuffer();
     87            DataBuffer destBuffer = dest.getRaster().getDataBuffer();
     88            if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) {
     89                Main.trace("Cannot apply color filter: Images do not use DataBufferByte.");
     90                return src;
     91            }
     92
     93            int type = src.getType();
     94            if (type != dest.getType()) {
     95                Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')');
     96                return src;
     97            }
     98            int redOffset, greenOffset, blueOffset, alphaOffset = 0;
     99            switch (type) {
     100            case BufferedImage.TYPE_3BYTE_BGR:
     101                blueOffset = 0;
     102                greenOffset = 1;
     103                redOffset = 2;
     104                break;
     105            case BufferedImage.TYPE_4BYTE_ABGR:
     106            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
     107                blueOffset = 1;
     108                greenOffset = 2;
     109                redOffset = 3;
     110                break;
     111            case BufferedImage.TYPE_INT_ARGB:
     112            case BufferedImage.TYPE_INT_ARGB_PRE:
     113                redOffset = 0;
     114                greenOffset = 1;
     115                blueOffset = 2;
     116                alphaOffset = 3;
     117                break;
     118            default:
     119                Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ").");
     120                return src;
     121            }
     122            doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset,
     123                    alphaOffset, src.getAlphaRaster() != null);
     124            return dest;
     125        }
     126
     127        private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset,
     128                int alphaOffset, boolean hasAlpha) {
     129            byte[] srcPixels = src.getData();
     130            byte[] destPixels = dest.getData();
     131            if (srcPixels.length != destPixels.length) {
     132                Main.trace("Cannot apply color filter: Source/Dest lengths differ.");
     133                return;
     134            }
     135            int entries = hasAlpha ? 4 : 3;
     136            for (int i = 0; i < srcPixels.length; i += entries) {
     137                int r = srcPixels[i + redOffset] & 0xff;
     138                int g = srcPixels[i + greenOffset] & 0xff;
     139                int b = srcPixels[i + blueOffset] & 0xff;
     140                double luminosity = r * .21d + g * .72d + b * .07d;
     141                destPixels[i + redOffset] = mix(r, luminosity);
     142                destPixels[i + greenOffset] = mix(g, luminosity);
     143                destPixels[i + blueOffset] = mix(b, luminosity);
     144                if (hasAlpha) {
     145                    destPixels[i + alphaOffset] = srcPixels[i + alphaOffset];
     146                }
     147            }
     148        }
     149
     150        private byte mix(int color, double luminosity) {
     151            int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity);
     152            if (val < 0) {
     153                return 0;
     154            } else if (val > 0xff) {
     155                return (byte) 0xff;
     156            } else {
     157                return (byte) val;
     158            }
     159        }
     160
     161        @Override
     162        public Rectangle2D getBounds2D(BufferedImage src) {
     163            return new Rectangle(src.getWidth(), src.getHeight());
     164        }
     165
     166        @Override
     167        public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
     168            return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
     169        }
     170
     171        @Override
     172        public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
     173            return (Point2D) srcPt.clone();
     174        }
     175
     176        @Override
     177        public RenderingHints getRenderingHints() {
     178            return null;
     179        }
     180
     181    }
     182}
     183 No newline at end of file
  • new file src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java b/src/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessor.java
    new file mode 100644
    index 0000000..d72ae2a
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import java.awt.Transparency;
     5import java.awt.image.BufferedImage;
     6import java.awt.image.LookupOp;
     7import java.awt.image.ShortLookupTable;
     8
     9import org.openstreetmap.josm.Main;
     10import org.openstreetmap.josm.gui.layer.ImageProcessor;
     11
     12/**
     13 * An image processor which adjusts the gamma value of an image.
     14 */
     15public class GammaImageProcessor implements ImageProcessor {
     16    private double gamma = 1;
     17    final short[] gammaChange = new short[256];
     18    private final LookupOp op3 = new LookupOp(
     19            new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
     20    private final LookupOp op4 = new LookupOp(
     21            new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
     22
     23    /**
     24     * Returns the currently set gamma value.
     25     * @return the currently set gamma value
     26     */
     27    public double getGamma() {
     28        return gamma;
     29    }
     30
     31    /**
     32     * Sets a new gamma value, {@code 1} stands for no correction.
     33     * @param gamma new gamma value
     34     */
     35    public void setGamma(double gamma) {
     36        this.gamma = gamma;
     37        for (int i = 0; i < 256; i++) {
     38            gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
     39        }
     40    }
     41
     42    @Override
     43    public BufferedImage process(BufferedImage image) {
     44        if (gamma == 1) {
     45            return image;
     46        }
     47        try {
     48            final int bands = image.getRaster().getNumBands();
     49            if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 3) {
     50                return op3.filter(image, null);
     51            } else if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 4) {
     52                return op4.filter(image, null);
     53            }
     54        } catch (IllegalArgumentException ignore) {
     55            Main.trace(ignore);
     56        }
     57        final int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
     58        final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), type);
     59        to.getGraphics().drawImage(image, 0, 0, null);
     60        return process(to);
     61    }
     62
     63    @Override
     64    public String toString() {
     65        return "GammaImageProcessor [gamma=" + gamma + ']';
     66    }
     67}
     68 No newline at end of file
  • new file src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java b/src/org/openstreetmap/josm/gui/layer/imagery/ImageryFilterSettings.java
    new file mode 100644
    index 0000000..035aa4b
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import java.util.Arrays;
     5import java.util.List;
     6import java.util.concurrent.CopyOnWriteArrayList;
     7
     8import org.openstreetmap.josm.gui.layer.ImageProcessor;
     9
     10/**
     11 * This class holds the filter settings for an imagery layer.
     12 * @author Michael Zangl
     13 * @since xxx
     14 */
     15public class ImageryFilterSettings {
     16
     17    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
     18    protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();
     19    protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor();
     20    private List<FilterChangeListener> filterChangeListeners = new CopyOnWriteArrayList<>();
     21
     22    /**
     23     * Returns the currently set gamma value.
     24     * @return the currently set gamma value
     25     */
     26    public double getGamma() {
     27        return gammaImageProcessor.getGamma();
     28    }
     29
     30    /**
     31     * Sets a new gamma value, {@code 1} stands for no correction.
     32     * @param gamma new gamma value
     33     */
     34    public void setGamma(double gamma) {
     35        gammaImageProcessor.setGamma(gamma);
     36        fireListeners();
     37    }
     38
     39    /**
     40     * Gets the current sharpen level.
     41     * @return The sharpen level.
     42     */
     43    public double getSharpenLevel() {
     44        return sharpenImageProcessor.getSharpenLevel();
     45    }
     46
     47    /**
     48     * Sets the sharpen level for the layer.
     49     * <code>1</code> means no change in sharpness.
     50     * Values in range 0..1 blur the image.
     51     * Values above 1 are used to sharpen the image.
     52     * @param sharpenLevel The sharpen level.
     53     */
     54    public void setSharpenLevel(double sharpenLevel) {
     55        sharpenImageProcessor.setSharpenLevel((float) sharpenLevel);
     56        fireListeners();
     57    }
     58
     59    /**
     60     * Gets the colorfulness of this image.
     61     * @return The colorfulness
     62     */
     63    public double getColorfulness() {
     64        return collorfulnessImageProcessor.getColorfulness();
     65    }
     66
     67    /**
     68     * Sets the colorfulness of this image.
     69     * 0 means grayscale.
     70     * 1 means normal colorfulness.
     71     * Values greater than 1 are allowed.
     72     * @param colorfulness The colorfulness.
     73     */
     74    public void setColorfulness(double colorfulness) {
     75        collorfulnessImageProcessor.setColorfulness(colorfulness);
     76        fireListeners();
     77    }
     78
     79    /**
     80     * Gets the image processors for this setting.
     81     * @return The processors in the order in which they should be applied.
     82     */
     83    public List<ImageProcessor> getProcessors() {
     84        return Arrays.asList(collorfulnessImageProcessor, gammaImageProcessor, sharpenImageProcessor);
     85    }
     86
     87    /**
     88     * Adds a filter change listener
     89     * @param l The listener
     90     */
     91    public void addFilterChangeListener(FilterChangeListener l) {
     92        filterChangeListeners.add(l);
     93    }
     94
     95    /**
     96     * Removes a filter change listener
     97     * @param l The listener
     98     */
     99    public void removeFilterChangeListener(FilterChangeListener l) {
     100        filterChangeListeners.remove(l);
     101    }
     102
     103    private void fireListeners() {
     104        for (FilterChangeListener l : filterChangeListeners) {
     105            l.filterChanged();
     106        }
     107    }
     108
     109    /**
     110     * A listener that listens to filter changes
     111     * @author Michael Zangl
     112     * @since xxx
     113     */
     114    public interface FilterChangeListener {
     115        /**
     116         * Invoked when the filter is changed.
     117         */
     118        void filterChanged();
     119    }
     120}
  • new file src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java b/src/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessor.java
    new file mode 100644
    index 0000000..f459d4f
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import java.awt.image.BufferedImage;
     5import java.awt.image.ConvolveOp;
     6import java.awt.image.Kernel;
     7
     8import org.openstreetmap.josm.gui.layer.ImageProcessor;
     9
     10/**
     11 * Sharpens or blurs the image, depending on the sharpen value.
     12 * <p>
     13 * A positive sharpen level means that we sharpen the image.
     14 * <p>
     15 * A negative sharpen level let's us blur the image. -1 is the most useful value there.
     16 *
     17 * @author Michael Zangl
     18 */
     19public class SharpenImageProcessor implements ImageProcessor {
     20    private float sharpenLevel = 1;
     21    private ConvolveOp op;
     22
     23    private static float[] KERNEL_IDENTITY = new float[] {
     24        0, 0, 0,
     25        0, 1, 0,
     26        0, 0, 0
     27    };
     28
     29    private static float[] KERNEL_BLUR = new float[] {
     30        1f / 16, 2f / 16, 1f / 16,
     31        2f / 16, 4f / 16, 2f / 16,
     32        1f / 16, 2f / 16, 1f / 16
     33    };
     34
     35    private static float[] KERNEL_SHARPEN = new float[] {
     36        -.5f, -1f, -.5f,
     37         -1f, 7, -1f,
     38        -.5f, -1f, -.5f
     39    };
     40
     41    /**
     42     * Gets the current sharpen level.
     43     * @return The level.
     44     */
     45    public float getSharpenLevel() {
     46        return sharpenLevel;
     47    }
     48
     49    /**
     50     * Sets the sharpening level.
     51     * @param sharpenLevel The level. Clamped to be positive or 0.
     52     */
     53    public void setSharpenLevel(float sharpenLevel) {
     54        if (sharpenLevel < 0) {
     55            this.sharpenLevel = 0;
     56        } else {
     57            this.sharpenLevel = sharpenLevel;
     58        }
     59
     60        if (this.sharpenLevel < 0.95) {
     61            op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR);
     62        } else if (this.sharpenLevel > 1.05) {
     63            op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY);
     64        } else {
     65            op = null;
     66        }
     67    }
     68
     69    private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) {
     70        if (a.length != 9 || b.length != 9) {
     71            throw new IllegalArgumentException("Illegal kernel array length.");
     72        }
     73        float[] values = new float[9];
     74        for (int i = 0; i < values.length; i++) {
     75            values[i] = aFactor * a[i] + (1 - aFactor) * b[i];
     76        }
     77        return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null);
     78    }
     79
     80    @Override
     81    public BufferedImage process(BufferedImage image) {
     82        if (op != null) {
     83            return op.filter(image, null);
     84        } else {
     85            return image;
     86        }
     87    }
     88
     89    @Override
     90    public String toString() {
     91        return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + ']';
     92    }
     93}
     94 No newline at end of file
  • test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/ImageryLayerTest.java
    index 9194941..b5ce9d4 100644
    a b  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.gui.layer;
    33
    4 import static org.junit.Assert.assertEquals;
     4import static org.junit.Assert.assertNotNull;
     5import static org.junit.Assert.assertSame;
    56
    6 import org.junit.BeforeClass;
     7import org.junit.Rule;
    78import org.junit.Test;
    8 import org.openstreetmap.josm.JOSMFixture;
     9import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
     10import org.openstreetmap.josm.testutils.JOSMTestRules;
     11
     12import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    913
    1014/**
    1115 * Unit tests of {@link ImageryLayer} class.
    import org.openstreetmap.josm.JOSMFixture;  
    1317public class ImageryLayerTest {
    1418
    1519    /**
    16      * Setup tests
     20     * For creating layers
    1721     */
    18     @BeforeClass
    19     public static void setUpBeforeClass() {
    20         JOSMFixture.createUnitTestFixture().init(true);
    21     }
     22    @Rule
     23    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     24    public JOSMTestRules test = new JOSMTestRules().preferences();
    2225
    2326    /**
    24      * Unit test of {@link ImageryLayer.ColorfulImageProcessor#toString}
    25      *          and {@link ImageryLayer.GammaImageProcessor#toString()}.
    26      *          and {@link ImageryLayer.SharpenImageProcessor#toString()}.
     27     * Unit test of {@link ImageryLayer#getFilterSettings()}
    2728     */
    2829    @Test
    29     public void testToString() {
     30    public void testHasSettings() {
    3031        ImageryLayer layer = TMSLayerTest.createTmsLayer();
    31         assertEquals("ColorfulImageProcessor [colorfulness=1.0]", layer.collorfulnessImageProcessor.toString());
    32         assertEquals("GammaImageProcessor [gamma=1.0]", layer.gammaImageProcessor.toString());
    33         assertEquals("SharpenImageProcessor [sharpenLevel=1.0]", layer.sharpenImageProcessor.toString());
     32        ImageryFilterSettings settings = layer.getFilterSettings();
     33        assertNotNull(settings);
     34        assertSame(settings, layer.getFilterSettings());
    3435    }
    3536}
  • new file test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java b/test/unit/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessorTest.java
    new file mode 100644
    index 0000000..9c68244
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertTrue;
     6
     7import java.awt.Color;
     8import java.awt.Graphics2D;
     9import java.awt.image.BufferedImage;
     10
     11import org.junit.Rule;
     12import org.junit.Test;
     13import org.openstreetmap.josm.testutils.JOSMTestRules;
     14
     15import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     16
     17/**
     18 * Tests for the {@link ColorfulImageProcessor} class.
     19 * @author Michael Zangl
     20 * @since xxx
     21 */
     22public class ColorfulImageProcessorTest {
     23
     24    private static final int TEST_IMAGE_SIZE = 5;
     25
     26    /**
     27     * No special rules
     28     */
     29    @Rule
     30    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     31    public JOSMTestRules test = new JOSMTestRules();
     32
     33    /**
     34     * Test {@link ColorfulImageProcessor#setColorfulness(double)} and {@link ColorfulImageProcessor#getColorfulness()}
     35     */
     36    @Test
     37    public void testSetGet() {
     38        ColorfulImageProcessor processor = new ColorfulImageProcessor();
     39
     40        assertEquals(1, processor.getColorfulness(), 0.001);
     41
     42        processor.setColorfulness(2);
     43        assertEquals(2, processor.getColorfulness(), 0.001);
     44
     45        processor.setColorfulness(0);
     46        assertEquals(0, processor.getColorfulness(), 0.001);
     47
     48        processor.setColorfulness(0.78);
     49        assertEquals(0.78, processor.getColorfulness(), 0.001);
     50
     51        processor.setColorfulness(1);
     52        assertEquals(1, processor.getColorfulness(), 0.001);
     53
     54        processor.setColorfulness(-1);
     55        assertEquals(0, processor.getColorfulness(), 0.001);
     56
     57        processor.setColorfulness(5);
     58        assertEquals(5, processor.getColorfulness(), 0.001);
     59    }
     60
     61    /**
     62     *
     63     */
     64    @Test
     65    public void testProcessing() {
     66        for (ConversionData data : new ConversionData[] {
     67                new ConversionData(Color.BLACK, 1.5, Color.BLACK),
     68                new ConversionData(Color.WHITE, 0.5, Color.WHITE),
     69                new ConversionData(Color.GRAY, 0, Color.GRAY),
     70                new ConversionData(Color.GREEN, 1, Color.GREEN),
     71                new ConversionData(Color.RED, 1, Color.RED),
     72                new ConversionData(Color.BLUE, 1, Color.BLUE),
     73                new ConversionData(0x908050, 0, 0x808080),
     74                new ConversionData(0x908070, 1, 0x908070),
     75                new ConversionData(0x908070, 2, 0x9c7c5c),
     76                new ConversionData(0x908070, 2, 0x9c7c5c),
     77                new ConversionData(0xf02080, 2, 0xff00ac),
     78        }) {
     79            for (int type : new int[] {
     80                    BufferedImage.TYPE_3BYTE_BGR,
     81                    BufferedImage.TYPE_4BYTE_ABGR,
     82                    BufferedImage.TYPE_4BYTE_ABGR_PRE }) {
     83                assertTrue(runProcessing(data, type));
     84            }
     85        }
     86    }
     87
     88    private boolean runProcessing(ConversionData data, int type) {
     89        BufferedImage image = createImage(data.getOldColor(), type);
     90
     91        ColorfulImageProcessor processor = new ColorfulImageProcessor();
     92        processor.setColorfulness(data.getFactor());
     93        image = processor.process(image);
     94
     95        for (int x = 0; x < TEST_IMAGE_SIZE; x++) {
     96            for (int y = 0; y < TEST_IMAGE_SIZE; y++) {
     97                Color color = new Color(image.getRGB(x, y));
     98                assertEquals(data + ":" + type + ": red", data.getExpectedColor().getRed(), color.getRed(), 1.05);
     99                assertEquals(data + ":" + type + ": green", data.getExpectedColor().getGreen(), color.getGreen(), 1.05);
     100                assertEquals(data + ":" + type + ": blue", data.getExpectedColor().getBlue(), color.getBlue(), 1.05);
     101            }
     102        }
     103        return true;
     104    }
     105
     106    private BufferedImage createImage(Color color, int type) {
     107        BufferedImage image = new BufferedImage(TEST_IMAGE_SIZE, TEST_IMAGE_SIZE, type);
     108        Graphics2D graphics = image.createGraphics();
     109        graphics.setColor(color);
     110        graphics.fillRect(0, 0, TEST_IMAGE_SIZE, TEST_IMAGE_SIZE);
     111        return image;
     112    }
     113
     114    private static class ConversionData {
     115        private final Color oldColor;
     116        private final double factor;
     117        private final Color expectedColor;
     118
     119        ConversionData(Color oldColor, double factor, Color expectedColor) {
     120            super();
     121            this.oldColor = oldColor;
     122            this.factor = factor;
     123            this.expectedColor = expectedColor;
     124        }
     125
     126        public ConversionData(int oldColor, double factor, int expectedColor) {
     127            this(new Color(oldColor), factor, new Color(expectedColor));
     128        }
     129
     130        Color getOldColor() {
     131            return oldColor;
     132        }
     133
     134        double getFactor() {
     135            return factor;
     136        }
     137
     138        Color getExpectedColor() {
     139            return expectedColor;
     140        }
     141
     142        @Override
     143        public String toString() {
     144            return "ConversionData [oldColor=" + oldColor + ", factor=" + factor + "]";
     145        }
     146    }
     147
     148    /**
     149     * Test {@link ColorfulImageProcessor#toString()}
     150     */
     151    @Test
     152    public void testToString() {
     153        ColorfulImageProcessor processor = new ColorfulImageProcessor();
     154        assertEquals("ColorfulImageProcessor [colorfulness=1.0]", processor.toString());
     155    }
     156}
  • new file test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java b/test/unit/org/openstreetmap/josm/gui/layer/imagery/GammaImageProcessorTest.java
    new file mode 100644
    index 0000000..05b7c2b
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import static org.junit.Assert.assertEquals;
     5
     6import org.junit.Rule;
     7import org.junit.Test;
     8import org.openstreetmap.josm.testutils.JOSMTestRules;
     9
     10import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     11
     12/**
     13 * Tests for the {@link GammaImageProcessor} class.
     14 * @author Michael Zangl
     15 * @since xxx
     16 */
     17public class GammaImageProcessorTest {
     18
     19    /**
     20     * No special rules
     21     */
     22    @Rule
     23    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     24    public JOSMTestRules test = new JOSMTestRules();
     25
     26    /**
     27     * Test {@link GammaImageProcessor#setGamma(double)} and {@link GammaImageProcessor#getGamma()}
     28     */
     29    @Test
     30    public void testSetGet() {
     31        GammaImageProcessor processor = new GammaImageProcessor();
     32
     33        assertEquals(1, processor.getGamma(), 0.001);
     34
     35        processor.setGamma(2);
     36        assertEquals(2, processor.getGamma(), 0.001);
     37
     38        processor.setGamma(0);
     39        assertEquals(0, processor.getGamma(), 0.001);
     40
     41        processor.setGamma(0.78);
     42        assertEquals(0.78, processor.getGamma(), 0.001);
     43
     44        processor.setGamma(1);
     45        assertEquals(1, processor.getGamma(), 0.001);
     46
     47        processor.setGamma(-1);
     48        assertEquals(-1, processor.getGamma(), 0.001);
     49
     50        processor.setGamma(5);
     51        assertEquals(5, processor.getGamma(), 0.001);
     52    }
     53
     54    /**
     55     * Test {@link GammaImageProcessor#toString()}
     56     */
     57    @Test
     58    public void testToString() {
     59        GammaImageProcessor processor = new GammaImageProcessor();
     60        assertEquals("GammaImageProcessor [gamma=1.0]", processor.toString());
     61    }
     62}
  • new file test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java

    diff --git a/test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java b/test/unit/org/openstreetmap/josm/gui/layer/imagery/SharpenImageProcessorTest.java
    new file mode 100644
    index 0000000..85eb349
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.imagery;
     3
     4import static org.junit.Assert.assertEquals;
     5
     6import org.junit.Rule;
     7import org.junit.Test;
     8import org.openstreetmap.josm.testutils.JOSMTestRules;
     9
     10import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     11
     12/**
     13 * Tests for the {@link SharpenImageProcessor} class.
     14 * @author Michael Zangl
     15 * @since xxx
     16 */
     17public class SharpenImageProcessorTest {
     18
     19    /**
     20     * No special rules
     21     */
     22    @Rule
     23    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     24    public JOSMTestRules test = new JOSMTestRules();
     25
     26    /**
     27     * Test {@link SharpenImageProcessor#setSharpenLevel(float)} and {@link SharpenImageProcessor#getSharpenLevel()}
     28     */
     29    @Test
     30    public void testSetGet() {
     31        SharpenImageProcessor processor = new SharpenImageProcessor();
     32
     33        assertEquals(1, processor.getSharpenLevel(), 0.001);
     34
     35        processor.setSharpenLevel(2);
     36        assertEquals(2, processor.getSharpenLevel(), 0.001);
     37
     38        processor.setSharpenLevel(0);
     39        assertEquals(0, processor.getSharpenLevel(), 0.001);
     40
     41        processor.setSharpenLevel(0.78f);
     42        assertEquals(0.78, processor.getSharpenLevel(), 0.001);
     43
     44        processor.setSharpenLevel(1);
     45        assertEquals(1, processor.getSharpenLevel(), 0.001);
     46
     47        processor.setSharpenLevel(-1);
     48        assertEquals(-1, processor.getSharpenLevel(), 0.001);
     49
     50        processor.setSharpenLevel(5);
     51        assertEquals(5, processor.getSharpenLevel(), 0.001);
     52    }
     53
     54    /**
     55     * Test {@link SharpenImageProcessor#toString()}
     56     */
     57    @Test
     58    public void testToString() {
     59        SharpenImageProcessor processor = new SharpenImageProcessor();
     60        assertEquals("SharpenImageProcessor [gamma=1.0]", processor.toString());
     61    }
     62}