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


Ignore:
Timestamp:
2016-07-17T13:07:14+02:00 (8 years ago)
Author:
Don-vip
Message:

fix #13159 - Move image processors out of imagery layer (patch by michael2402) - gsoc-core + fix checkstyle violations

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
5 added
4 edited

Legend:

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

    r10428 r10547  
    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;
     
    307308     *
    308309     * @author Michael Zangl
    309      * @see ImageryLayer#setGamma(double)
     310     * @see ImageryFilterSettings#setGamma(double)
    310311     */
    311312    private class GammaFilterSlider extends FilterSlider<ImageryLayer> {
     
    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        }
     
    327328        @Override
    328329        protected void applyValueToLayer(ImageryLayer layer) {
    329             layer.setGamma(mapIntervalToGamma(getRealValue()));
     330            layer.getFilterSettings().setGamma(mapIntervalToGamma(getRealValue()));
    330331        }
    331332
     
    366367     *
    367368     * @author Michael Zangl
    368      * @see ImageryLayer#setSharpenLevel(double)
     369     * @see ImageryFilterSettings#setSharpenLevel(double)
    369370     */
    370371    private class SharpnessSlider extends FilterSlider<ImageryLayer> {
     
    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
     
    403404     *
    404405     * @author Michael Zangl
    405      * @see ImageryLayer#setColorfulness(double)
     406     * @see ImageryFilterSettings#setColorfulness(double)
    406407     */
    407408    private class ColorfulnessSlider extends FilterSlider<ImageryLayer> {
     
    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
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r10545 r10547  
    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;
     
    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
     
    175176        setBackgroundLayer(true);
    176177        this.setVisible(true);
     178        getFilterSettings().addFilterChangeListener(this);
     179    }
     180
     181    @Override
     182    public void filterChanged() {
     183        redraw();
    177184    }
    178185
     
    261268        needRedraw = true;
    262269        if (isVisible()) Main.map.repaint();
    263     }
    264 
    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();
    281270    }
    282271
     
    12081197
    12091198    private final class MapWrappingTileSet extends TileSet {
    1210             private MapWrappingTileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
    1211                 this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
    1212             }
    1213 
    1214             private MapWrappingTileSet(LatLon topLeft, LatLon botRight, int zoom) {
    1215                 super(topLeft, botRight, zoom);
    1216                 double centerLon = getShiftedLatLon(Main.map.mapView.getCenter()).lon();
    1217 
    1218                 if (topLeft.lon() > centerLon) {
    1219                     x0 = tileSource.getTileXMin(zoom);
    1220                 }
    1221                 if (botRight.lon() < centerLon) {
    1222                     x1 = tileSource.getTileXMax(zoom);
    1223                 }
    1224                 sanitize();
    1225             }
     1199        private MapWrappingTileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
     1200            this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
     1201        }
     1202
     1203        private MapWrappingTileSet(LatLon topLeft, LatLon botRight, int zoom) {
     1204            super(topLeft, botRight, zoom);
     1205            double centerLon = getShiftedLatLon(Main.map.mapView.getCenter()).lon();
     1206
     1207            if (topLeft.lon() > centerLon) {
     1208                x0 = tileSource.getTileXMin(zoom);
     1209            }
     1210            if (botRight.lon() < centerLon) {
     1211                x1 = tileSource.getTileXMax(zoom);
     1212            }
     1213            sanitize();
     1214        }
    12261215    }
    12271216
     
    12361225         * @param zoom zoom level
    12371226         */
    1238         private TileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
     1227        protected TileSet(EastNorth topLeft, EastNorth botRight, int zoom) {
    12391228            this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom);
    12401229        }
     
    12461235         * @param zoom zoom level
    12471236         */
    1248         private TileSet(LatLon topLeft, LatLon botRight, int zoom) {
     1237        protected TileSet(LatLon topLeft, LatLon botRight, int zoom) {
    12491238            this.zoom = zoom;
    12501239            if (zoom == 0)
     
    12601249            sanitize();
    12611250
    1262         }
    1263 
    1264         private TileSet(Tile topLeft, Tile botRight, int zoom) {
    12651251        }
    12661252
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r10467 r10547  
    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;
     
    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;
     
    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);
     68
     69    private final ImageryFilterSettings filterSettings = new ImageryFilterSettings();
    8370
    8471    /**
     
    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
     
    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.
    618      */
    619     public void setColorfulness(double colorfulness) {
    620         collorfulnessImageProcessor.setColorfulness(colorfulness);
     248     * Gets the settings for the filter that is applied to this layer.
     249     * @return The filter settings.
     250     * @since 10547
     251     */
     252    public ImageryFilterSettings getFilterSettings() {
     253        return filterSettings;
    621254    }
    622255
  • trunk/src/org/openstreetmap/josm/gui/widgets/ButtonColumn.java

    r10542 r10547  
    4040    public ButtonColumn(Action action, String buttonName) {
    4141        this(action);
    42         this.buttonName  = buttonName;
     42        this.buttonName = buttonName;
    4343    }
    4444
Note: See TracChangeset for help on using the changeset viewer.