Changeset 8729 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2015-09-04T10:32:05+02:00 (9 years ago)
Author:
simon04
Message:

fix #10417 - Selectable Gamma value for background imagery

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    r8728 r8729  
    5656import org.openstreetmap.josm.gui.SideButton;
    5757import org.openstreetmap.josm.gui.help.HelpUtil;
     58import org.openstreetmap.josm.gui.layer.ImageryLayer;
    5859import org.openstreetmap.josm.gui.layer.JumpToMarkerActions;
    5960import org.openstreetmap.josm.gui.layer.Layer;
     
    7172import org.openstreetmap.josm.tools.MultikeyShortcutAction.MultikeyInfo;
    7273import org.openstreetmap.josm.tools.Shortcut;
     74import org.openstreetmap.josm.tools.Utils;
    7375
    7476/**
     
    113115
    114116    private SideButton opacityButton;
     117    private SideButton gammaButton;
    115118
    116119    private ActivateLayerAction activateLayerAction;
     
    261264        opacityButton = new SideButton(layerOpacityAction, false);
    262265
     266        // -- layer gamma action
     267        LayerGammaAction layerGammaAction = new LayerGammaAction();
     268        adaptTo(layerGammaAction, selectionModel);
     269        gammaButton = new SideButton(layerGammaAction, false);
     270
    263271        // -- delete layer action
    264272        DeleteLayerAction deleteLayerAction = new DeleteLayerAction();
     
    288296                new SideButton(showHideLayerAction, false),
    289297                opacityButton,
     298                gammaButton,
    290299                new SideButton(deleteLayerAction, false)
    291300        ));
     
    513522
    514523    /**
     524     * Abstract action which allows to adjust a double value using a slider
     525     */
     526    public static abstract class AbstractLayerPropertySliderAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
     527        protected final JPopupMenu popup;
     528        protected final JSlider slider;
     529        private final double factor;
     530
     531        public AbstractLayerPropertySliderAction(String name, final double factor) {
     532            super(name);
     533            this.factor = factor;
     534            updateEnabledState();
     535
     536            popup = new JPopupMenu();
     537            slider = new JSlider(JSlider.VERTICAL);
     538            slider.addChangeListener(new ChangeListener() {
     539                @Override
     540                public void stateChanged(ChangeEvent e) {
     541                    setValue((double) slider.getValue() / factor);
     542                }
     543            });
     544            popup.add(slider);
     545
     546        }
     547
     548        protected abstract void setValue(double value);
     549
     550        protected abstract double getValue();
     551
     552        protected abstract SideButton getCorrespondingSideButton();
     553
     554        @Override
     555        public void actionPerformed(ActionEvent e) {
     556            final SideButton sideButton = getCorrespondingSideButton();
     557            slider.setValue((int) (getValue() * factor));
     558            if (e.getSource() == sideButton) {
     559                popup.show(sideButton, 0, sideButton.getHeight());
     560            } else {
     561                // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
     562                // In that case, show it in the middle of screen (because opacityButton is not visible)
     563                popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
     564            }
     565        }
     566
     567        @Override
     568        public Component createMenuComponent() {
     569            return new JMenuItem(this);
     570        }
     571
     572    }
     573
     574    /**
    515575     * Action which allows to change the opacity of one or more layers.
    516576     */
    517     public final class LayerOpacityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
     577    public final class LayerOpacityAction extends AbstractLayerPropertySliderAction {
    518578        private transient Layer layer;
    519         private JPopupMenu popup;
    520         private JSlider slider = new JSlider(JSlider.VERTICAL);
    521579
    522580        /**
     
    529587        public LayerOpacityAction(Layer layer) {
    530588            this();
    531             putValue(NAME, tr("Opacity"));
    532589            CheckParameterUtil.ensureParameterNotNull(layer, "layer");
    533590            this.layer = layer;
     
    541598         */
    542599        public LayerOpacityAction() {
    543             putValue(NAME, tr("Opacity"));
     600            super(tr("Opacity"), 100);
    544601            putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
    545602            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
    546             updateEnabledState();
    547 
    548             popup = new JPopupMenu();
    549             slider.addChangeListener(new ChangeListener() {
    550                 @Override
    551                 public void stateChanged(ChangeEvent e) {
    552                     setOpacity((double) slider.getValue()/100);
    553                 }
    554             });
    555             popup.add(slider);
    556         }
    557 
    558         private void setOpacity(double value) {
     603        }
     604
     605        @Override
     606        protected void setValue(double value) {
    559607            if (!isEnabled()) return;
    560608            if (layer != null) {
     
    567615        }
    568616
    569         private double getOpacity() {
     617        @Override
     618        protected double getValue() {
    570619            if (layer != null)
    571620                return layer.getOpacity();
     
    581630
    582631        @Override
    583         public void actionPerformed(ActionEvent e) {
    584             slider.setValue((int) Math.round(getOpacity()*100));
    585             if (e.getSource() == opacityButton) {
    586                 popup.show(opacityButton, 0, opacityButton.getHeight());
    587             } else {
    588                 // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
    589                 // In that case, show it in the middle of screen (because opacityButton is not visible)
    590                 popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
    591             }
     632        protected SideButton getCorrespondingSideButton() {
     633            return opacityButton;
    592634        }
    593635
     
    602644
    603645        @Override
    604         public Component createMenuComponent() {
    605             return new JMenuItem(this);
    606         }
    607 
    608         @Override
    609646        public boolean supportLayers(List<Layer> layers) {
    610647            return true;
    611648        }
    612 
    613         @Override
    614         public boolean equals(Object obj) {
    615             return obj instanceof LayerOpacityAction;
    616         }
    617 
    618         @Override
    619         public int hashCode() {
    620             return getClass().hashCode();
     649    }
     650
     651    /**
     652     * Action which allows to change the gamma of one imagery layer.
     653     */
     654    public final class LayerGammaAction extends AbstractLayerPropertySliderAction {
     655
     656        public LayerGammaAction() {
     657            super(tr("Gamma"), 50);
     658            putValue(SHORT_DESCRIPTION, tr("Adjust gamma value of the layer."));
     659            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "gamma"));
     660        }
     661
     662        @Override
     663        protected void setValue(double value) {
     664            for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
     665                imageryLayer.setGamma(value);
     666            }
     667        }
     668
     669        @Override
     670        protected double getValue() {
     671            return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma();
     672        }
     673
     674        @Override
     675        protected SideButton getCorrespondingSideButton() {
     676            return gammaButton;
     677        }
     678
     679        @Override
     680        public void updateEnabledState() {
     681            setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty());
     682        }
     683
     684        @Override
     685        public boolean supportLayers(List<Layer> layers) {
     686            return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty();
    621687        }
    622688    }
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r8723 r8729  
    245245    }
    246246
     247    @Override
     248    public void setGamma(double gamma) {
     249        super.setGamma(gamma);
     250        redraw();
     251    }
     252
    247253    /**
    248254     * Marks layer as needing redraw on offset change
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r8723 r8729  
    2020import java.awt.image.ConvolveOp;
    2121import java.awt.image.Kernel;
     22import java.awt.image.LookupOp;
     23import java.awt.image.ShortLookupTable;
    2224import java.text.AttributedCharacterIterator;
    2325import java.text.AttributedString;
     
    7577    protected double dy = 0.0;
    7678
     79    protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();
     80
    7781    private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
    7882
     
    9296        }
    9397        addImageProcessor(createSharpener(PROP_SHARPEN_LEVEL.get()));
     98        addImageProcessor(gammaImageProcessor);
    9499    }
    95100
     
    247252        BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
    248253        return createImageProcessor(op, false);
     254    }
     255
     256    /**
     257     * An image processor which adjusts the gamma value of an image.
     258     */
     259    public static class GammaImageProcessor implements ImageProcessor {
     260        private double gamma = 1;
     261        final short[] gammaChange = new short[256];
     262        private LookupOp op3 = new LookupOp(new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null);
     263        private LookupOp op4 = new LookupOp(new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null);
     264
     265        /**
     266         * Returns the currently set gamma value.
     267         */
     268        public double getGamma() {
     269            return gamma;
     270        }
     271
     272        /**
     273         * Sets a new gamma value, {@code 1} stands for no correction.
     274         */
     275        public void setGamma(double gamma) {
     276            this.gamma = gamma;
     277            for (int i = 0; i < 256; i++) {
     278                gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma));
     279            }
     280        }
     281
     282        private LookupOp getOp(int bands) {
     283            if (gamma == 1) {
     284                return null;
     285            } else if (bands == 3) {
     286                return op3;
     287            } else if (bands == 4) {
     288                return op4;
     289            } else {
     290                return null;
     291            }
     292        }
     293
     294        @Override
     295        public BufferedImage process(BufferedImage image) {
     296            final LookupOp op = getOp(image.getRaster().getNumBands());
     297            final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
     298            return op == null ? image : op.filter(image, to);
     299        }
     300    }
     301
     302    /**
     303     * Returns the currently set gamma value.
     304     */
     305    public double getGamma() {
     306        return gammaImageProcessor.getGamma();
     307    }
     308
     309    /**
     310     * Sets a new gamma value, {@code 1} stands for no correction.
     311     */
     312    public void setGamma(double gamma) {
     313        gammaImageProcessor.setGamma(gamma);
    249314    }
    250315
Note: See TracChangeset for help on using the changeset viewer.