001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer.imagery;
003
004import java.awt.image.BufferedImage;
005import java.util.Arrays;
006import java.util.List;
007import java.util.concurrent.CopyOnWriteArrayList;
008
009import org.openstreetmap.josm.tools.ImageProcessor;
010
011/**
012 * This class holds the filter settings for an imagery.
013 * @author Michael Zangl
014 * @since 10547
015 */
016public class ImageryFilterSettings implements ImageProcessor {
017
018    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
019    protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();
020    protected ColorfulImageProcessor colorfulnessImageProcessor = new ColorfulImageProcessor();
021    private final List<FilterChangeListener> filterChangeListeners = new CopyOnWriteArrayList<>();
022
023    /**
024     * Returns the currently set gamma value.
025     * @return the currently set gamma value
026     */
027    public double getGamma() {
028        return gammaImageProcessor.getGamma();
029    }
030
031    /**
032     * Sets a new gamma value, {@code 1} stands for no correction.
033     * @param gamma new gamma value
034     */
035    public void setGamma(double gamma) {
036        gammaImageProcessor.setGamma(gamma);
037        fireListeners();
038    }
039
040    /**
041     * Gets the current sharpen level.
042     * @return The sharpen level.
043     */
044    public double getSharpenLevel() {
045        return sharpenImageProcessor.getSharpenLevel();
046    }
047
048    /**
049     * Sets the sharpen level for the imagery.
050     * <code>1</code> means no change in sharpness.
051     * Values in range 0..1 blur the image.
052     * Values above 1 are used to sharpen the image.
053     * @param sharpenLevel The sharpen level.
054     */
055    public void setSharpenLevel(double sharpenLevel) {
056        sharpenImageProcessor.setSharpenLevel((float) sharpenLevel);
057        fireListeners();
058    }
059
060    /**
061     * Gets the colorfulness of this image.
062     * @return The colorfulness
063     */
064    public double getColorfulness() {
065        return colorfulnessImageProcessor.getColorfulness();
066    }
067
068    /**
069     * Sets the colorfulness of this image.
070     * 0 means grayscale.
071     * 1 means normal colorfulness.
072     * Values greater than 1 are allowed.
073     * @param colorfulness The colorfulness.
074     */
075    public void setColorfulness(double colorfulness) {
076        colorfulnessImageProcessor.setColorfulness(colorfulness);
077        fireListeners();
078    }
079
080    /**
081     * Gets the image processors for this setting.
082     * @return The processors in the order in which they should be applied.
083     */
084    public List<ImageProcessor> getProcessors() {
085        return Arrays.asList(colorfulnessImageProcessor, gammaImageProcessor, sharpenImageProcessor);
086    }
087
088    @Override
089    public BufferedImage process(BufferedImage image) {
090        for (ImageProcessor processor : getProcessors()) {
091            image = processor.process(image);
092        }
093        return image;
094    }
095
096    /**
097     * Adds a filter change listener
098     * @param l The listener
099     */
100    public void addFilterChangeListener(FilterChangeListener l) {
101        filterChangeListeners.add(l);
102    }
103
104    /**
105     * Removes a filter change listener
106     * @param l The listener
107     */
108    public void removeFilterChangeListener(FilterChangeListener l) {
109        filterChangeListeners.remove(l);
110    }
111
112    private void fireListeners() {
113        for (FilterChangeListener l : filterChangeListeners) {
114            l.filterChanged();
115        }
116    }
117
118    /**
119     * A listener that listens to filter changes
120     * @author Michael Zangl
121     * @since 10600 (functional interface)
122     */
123    @FunctionalInterface
124    public interface FilterChangeListener {
125        /**
126         * Invoked when the filter is changed.
127         */
128        void filterChanged();
129    }
130}