Ticket #16733: 16733-v2.patch

File 16733-v2.patch, 30.4 KB (added by simon04, 5 years ago)
  • build.xml

    diff --git a/build.xml b/build.xml
    index 8146da263..1b9be0763 100644
    a b Build-Date: ${build.tstamp}  
    905905        </taskdef>
    906906        <checkstyle config="${checkstyle.dir}/josm_checks.xml">
    907907            <fileset dir="${base.dir}/src/org/openstreetmap/josm" includes="**/*.java"
    908                 excludes="gui/mappaint/mapcss/parsergen/*.java"/>
     908                excludes="gui/mappaint/mapcss/parsergen/*.java,images/**"/>
    909909            <fileset dir="${base.dir}/test" includes="**/*.java"/>
    910910            <fileset dir="${base.dir}/scripts" includes="**/*.java"/>
    911911            <formatter type="plain"/>
    Build-Date: ${build.tstamp}  
    11481148        <ivy:retrieve pattern="${lib.dir}/compile/[artifact]-[type].[ext]" conf="compile"/>
    11491149        <ivy:retrieve pattern="${lib.dir}/runtime/[artifact]-[type].[ext]" conf="runtime"/>
    11501150        <ivy:retrieve pattern="${lib.dir}/sources/[artifact]-[type].[ext]" conf="sources"/>
     1151        <ivy:retrieve file="${tools.ivy}" pattern="${lib.dir}/radiance-photon/[artifact]-[type].[ext]" conf="radiance-photon"/>
    11511152        <ivy:retrieve pattern="${lib.dir}/tools/[artifact]-[type].[ext]" conf="javacc,checkstyle" file="${tools.ivy}"/>
    11521153    </target>
     1154    <target name="transform-svg" depends="resolve">
     1155        <ivy:cachepath file="${tools.ivy}" pathid="radiance-photon.classpath" conf="radiance-photon"/>
     1156        <mkdir dir="src/org/openstreetmap/josm/images"/>
     1157        <java classname="org.pushingpixels.photon.api.transcoder.SvgDeepBatchConverter" failonerror="true">
     1158            <classpath refid="radiance-photon.classpath"/>
     1159            <classpath path="${tools.dir}/radiance-photon"/>
     1160            <arg value="sourceRootFolder=resources/images/"/>
     1161            <arg value="outputRootFolder=src/org/openstreetmap/josm/images"/>
     1162            <arg value="outputRootPackageName=org.openstreetmap.josm.images"/>
     1163            <arg value="outputClassNamePrefix=img_"/>
     1164            <arg value="outputLanguage=java"/>
     1165            <arg value="templateFile=/JosmSvgIcon.templ"/>
     1166        </java>
     1167    </target>
    11531168</project>
  • ivy.xml

    diff --git a/ivy.xml b/ivy.xml
    index e9888acb7..f0febed81 100644
    a b  
    2626        <dependency org="org.tukaani" name="xz" rev="1.8" conf="api->default"/>
    2727        <dependency org="com.drewnoakes" name="metadata-extractor" rev="2.13.0" conf="api->default"/>
    2828        <dependency org="ch.poole" name="OpeningHoursParser" rev="0.21.1" conf="api->default"/>
     29        <dependency org="org.pushing-pixels" name="radiance-neon" rev="3.0-SNAPSHOT" conf="api->default"/>
    2930        <!-- sources->sources -->
    3031        <dependency org="org.openstreetmap.jmapviewer" name="jmapviewer" rev="2.13" conf="sources->sources"/>
    3132        <dependency org="javax.json" name="javax.json-api" rev="1.1.4" conf="sources->sources"/>
  • ivysettings.xml

    diff --git a/ivysettings.xml b/ivysettings.xml
    index c8451d120..f77ea6a6f 100644
    a b  
    22<!-- License: GPL. For details, see LICENSE file. -->
    33<ivysettings>
    44  <settings defaultResolver="chain"/>
     5  <property name="m2-pattern" value="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]" override="false" />
    56  <resolvers>
    67    <chain name="chain">
     8      <filesystem name="local-maven2" m2compatible="true" >
     9        <artifact pattern="${m2-pattern}"/>
     10        <ivy pattern="${m2-pattern}"/>
     11      </filesystem>
    712      <ibiblio name="josm-nexus" m2compatible="true" root="https://josm.openstreetmap.de/nexus/content/repositories/public/" />
    813      <ibiblio name="josm-nexus-snapshots" m2compatible="true" root="https://josm.openstreetmap.de/nexus/content/repositories/snapshots/" />
    914      <ibiblio name="jcenter" m2compatible="true" root="https://jcenter.bintray.com/" />
  • src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    diff --git a/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java b/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
    index c477314de..9b6dad7b7 100644
    a b  
    8686import org.openstreetmap.josm.tools.HiDPISupport;
    8787import org.openstreetmap.josm.tools.ImageProvider;
    8888import org.openstreetmap.josm.tools.JosmRuntimeException;
     89import org.openstreetmap.josm.tools.JosmSvgIcon;
    8990import org.openstreetmap.josm.tools.Logging;
    9091import org.openstreetmap.josm.tools.ShapeClipper;
    9192import org.openstreetmap.josm.tools.Utils;
    private void drawIcon(MapViewPoint p, MapImage img, boolean disabled, boolean se  
    839840        temporaryGraphics.rotate(theta);
    840841        int drawX = -img.getWidth() / 2 + img.offsetX;
    841842        int drawY = -img.getHeight() / 2 + img.offsetY;
    842         temporaryGraphics.drawImage(img.getImage(disabled), drawX, drawY, nc);
     843        final JosmSvgIcon icon = img.getJosmSvgIcon();
     844        if (icon != null) {
     845            Logging.trace("drawIcon {0}", icon);
     846            icon.paintIcon(nc, temporaryGraphics, drawX, drawY);
     847        } else {
     848            temporaryGraphics.drawImage(img.getImage(disabled), drawX, drawY, nc);
     849        }
    843850        if (selected || member) {
    844851            selectionDrawer.accept(temporaryGraphics, new Rectangle2D.Double(drawX - 2d, drawY - 2d, img.getWidth() + 4d, img.getHeight() + 4d));
    845852        }
  • src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java

    diff --git a/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java b/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
    index 22944e1f7..a3678c34e 100644
    a b  
    2424import org.openstreetmap.josm.io.FileWatcher;
    2525import org.openstreetmap.josm.spi.preferences.Config;
    2626import org.openstreetmap.josm.tools.ImageProvider;
     27import org.openstreetmap.josm.tools.ImageResource;
    2728import org.openstreetmap.josm.tools.ListenerList;
    2829import org.openstreetmap.josm.tools.Logging;
    2930import org.openstreetmap.josm.tools.Stopwatch;
    public static ImageIcon getIcon(IconReference ref, int width, int height) {  
    199200     *   - josm's default icon
    200201     *  can be null if the defaults are turned off by user
    201202     */
    202     public static ImageIcon getNoIconIcon(StyleSource source) {
     203    public static ImageResource getNoIconIcon(StyleSource source) {
    203204        return new ImageProvider("presets/misc/no_icon")
    204205                .setDirs(getIconSourceDirs(source))
    205206                .setId("mappaint."+source.getPrefName())
    206207                .setArchive(source.zipIcons)
    207208                .setInArchiveDir(source.getZipEntryDirName())
    208                 .setOptional(true).get();
     209                .setOptional(true).getResource();
    209210    }
    210211
    211212    /**
  • src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java

    diff --git a/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java b/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java
    index 6bc869d67..a5823e62a 100644
    a b  
    1313import java.util.concurrent.ExecutionException;
    1414import java.util.function.Consumer;
    1515
    16 import javax.swing.ImageIcon;
    17 
    1816import org.openstreetmap.josm.gui.MainApplication;
    1917import org.openstreetmap.josm.gui.MapView;
    2018import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
     
    2422import org.openstreetmap.josm.gui.util.GuiHelper;
    2523import org.openstreetmap.josm.tools.ImageProvider;
    2624import org.openstreetmap.josm.tools.ImageResource;
     25import org.openstreetmap.josm.tools.JosmSvgIcon;
    2726import org.openstreetmap.josm.tools.Logging;
    2827import org.openstreetmap.josm.tools.Utils;
    2928
     
    3332public class MapImage {
    3433
    3534    private static final int MAX_SIZE = 48;
     35    private static final ImageResource TEMPORARY = new ImageProvider("clock").getResource();
    3636
    3737    /**
    38      * ImageIcon can change while the image is loading.
     38     * {@link ImageResource} can change while the image is loading.
    3939     */
    40     private Image img;
    41     private ImageResource imageResource;
     40    private ImageResource imageResource = TEMPORARY;
    4241
    4342    /**
    4443     * The alpha (opacity) value of the image. It is multiplied to the image alpha channel.
     
    7473     */
    7574    public int offsetY;
    7675
    77     private boolean temporary;
    78 
    7976    /**
    8077     * A cache that holds a disabled (gray) version of this image
    8178     */
    public ImageResource getImageResource() {  
    134131        return imageResource;
    135132    }
    136133
     134    public JosmSvgIcon getJosmSvgIcon() {
     135        return imageResource.getJosmSvgIcon();
     136    }
     137
    137138    private Image getDisabled() {
    138139        if (disabledImgCache != null)
    139140            return disabledImgCache;
    140         if (img == null)
     141        if (isTemporary())
    141142            getImage(); // fix #7498 ?
    142         Image disImg = GuiHelper.getDisabledImage(img);
     143        Image disImg = GuiHelper.getDisabledImage(getImage());
    143144        if (disImg instanceof BufferedImage) {
    144145            disabledImgCache = (BufferedImage) disImg;
    145146        } else {
    private Image getDisabled() {  
    152153    }
    153154
    154155    private Image getImage() {
    155         if (img != null)
    156             return img;
    157         temporary = false;
    158         loadImage();
    159         synchronized (this) {
    160             if (img == null) {
    161                 img = ImageProvider.get("clock").getImage();
    162                 temporary = true;
    163             }
     156        if (isTemporary()) {
     157            loadImage();
    164158        }
    165         return img;
     159        return rescale(imageResource.getImageIcon(new Dimension(width, height)).getImage());
    166160    }
    167161
    168162    private CompletableFuture<Void> load(Consumer<? super ImageResource> action) {
    private Image getImage() {  
    183177    private CompletableFuture<Void> loadImage() {
    184178        return load(result -> {
    185179            synchronized (this) {
    186                 imageResource = result;
    187                 if (result == null) {
    188                     source.logWarning(tr("Failed to locate image ''{0}''", name));
    189                     ImageIcon noIcon = MapPaintStyles.getNoIconIcon(source);
    190                     img = noIcon == null ? null : noIcon.getImage();
    191                 } else {
    192                     img = rescale(result.getImageIcon(new Dimension(width, height)).getImage());
    193                 }
     180                final boolean temporary = isTemporary(); // setImageResource changes isTemporary
     181                setImageResource(result);
    194182                if (temporary) {
    195183                    disabledImgCache = null;
    196184                    MapView mapView = MainApplication.getMap().mapView;
    197185                    mapView.preferenceChanged(null); // otherwise repaint is ignored, because layer hasn't changed
    198186                    mapView.repaint();
    199187                }
    200                 temporary = false;
    201188            }
    202189        });
    203190    }
    private Image getImage() {  
    210197    private CompletableFuture<Void> loadImageResource() {
    211198        return load(result -> {
    212199            synchronized (this) {
    213                 imageResource = result;
    214                 if (result == null) {
    215                     source.logWarning(tr("Failed to locate image ''{0}''", name));
    216                 }
     200                setImageResource(result);
    217201            }
    218202        });
    219203    }
    220204
     205    private void setImageResource(ImageResource result) {
     206        if (result == null) {
     207            source.logWarning(tr("Failed to locate image ''{0}''", name));
     208            imageResource = MapPaintStyles.getNoIconIcon(source);
     209        } else {
     210            imageResource = result;
     211        }
     212    }
     213
    221214    /**
    222215     * Gets the image width
    223216     * @return The real image width
    224217     */
    225218    public int getWidth() {
     219        final JosmSvgIcon icon = getJosmSvgIcon();
     220        if (icon != null) {
     221            return icon.getIconWidth();
     222        }
    226223        return getImage().getWidth(null);
    227224    }
    228225
    public int getWidth() {  
    231228     * @return The real image height
    232229     */
    233230    public int getHeight() {
     231        final JosmSvgIcon icon = getJosmSvgIcon();
     232        if (icon != null) {
     233            return icon.getIconHeight();
     234        }
    234235        return getImage().getHeight(null);
    235236    }
    236237
    public float getAlphaFloat() {  
    247248     * @return {@code true} if image is not completely loaded and getImage() returns a temporary image
    248249     */
    249250    public boolean isTemporary() {
    250         return temporary;
     251        return imageResource == TEMPORARY;
    251252    }
    252253
    253254    protected class MapImageBoxProvider implements BoxProvider {
    254255        @Override
    255256        public BoxProviderResult get() {
    256             return new BoxProviderResult(box(), temporary);
     257            return new BoxProviderResult(box(), isTemporary());
    257258        }
    258259
    259260        private Rectangle box() {
    public boolean equals(Object obj) {  
    281282            if (obj instanceof MapImageBoxProvider) {
    282283                MapImageBoxProvider other = (MapImageBoxProvider) obj;
    283284                return MapImage.this.equals(other.getParent());
    284             } else if (temporary) {
     285            } else if (isTemporary()) {
    285286                return false;
    286287            } else {
    287288                final BoxProvider other = (BoxProvider) obj;
  • src/org/openstreetmap/josm/tools/ImageProvider.java

    diff --git a/src/org/openstreetmap/josm/tools/ImageProvider.java b/src/org/openstreetmap/josm/tools/ImageProvider.java
    index 89de2b570..2b167c594 100644
    a b  
    1515import java.awt.RenderingHints;
    1616import java.awt.Toolkit;
    1717import java.awt.Transparency;
     18import java.awt.geom.Dimension2D;
    1819import java.awt.image.BufferedImage;
    1920import java.awt.image.ColorModel;
    2021import java.awt.image.FilteredImageSource;
    private ImageResource getIfAvailableImpl() {  
    853854        // for example in loops in map entries (ie freeze when such entry is retrieved)
    854855
    855856        String prefix = isDisabled ? "dis:" : "";
     857
     858        if (Utils.hasExtension(name, "svg")) {
     859            final ImageResource ir = getJosmSvgIcon();
     860            if (ir != null) {
     861                cache.put(prefix + name, ir);
     862                return ir;
     863            }
     864        }
     865
    856866        if (name.startsWith("data:")) {
    857867            String url = name;
    858868            ImageResource ir = cache.get(prefix + url);
    private ImageResource getIfAvailableImpl() {  
    955965        return null;
    956966    }
    957967
     968    private ImageResource getJosmSvgIcon() {
     969        try {
     970            // rewrite foo/bar/baz.svg to org.openstreetmap.josm.images.foo.bar.img_baz (class is prefixed with img_)
     971            final String[] nameParts = name.replaceAll("[ -]", "_").split("/");
     972            nameParts[nameParts.length - 1] = "img_" + nameParts[nameParts.length - 1].replaceFirst(".svg$", "");
     973            final String className = "org.openstreetmap.josm.images." + String.join(".", nameParts);
     974            final Class<?> imageClass = Class.forName(className);
     975            final JosmSvgIcon icon = (JosmSvgIcon) imageClass.getConstructor(int.class, int.class).newInstance(16, 16);
     976
     977            Logging.trace("ImageProvider: For image {0}, using {1}", name, imageClass);
     978            return new ImageResource(icon);
     979
     980        } catch (Exception ex) {
     981            Logging.warn(ex);
     982        }
     983        return null;
     984    }
     985
    958986    /**
    959987     * Internal implementation of the image request for URL's.
    960988     *
    public static BufferedImage createImageFromSvg(SVGDiagram svg, Dimension dim) {  
    16401668        }
    16411669        final float sourceWidth = svg.getWidth();
    16421670        final float sourceHeight = svg.getHeight();
    1643         final float realWidth;
    1644         final float realHeight;
    1645         if (dim.width >= 0) {
    1646             realWidth = dim.width;
    1647             if (dim.height >= 0) {
    1648                 realHeight = dim.height;
    1649             } else {
    1650                 realHeight = sourceHeight * realWidth / sourceWidth;
    1651             }
    1652         } else if (dim.height >= 0) {
    1653             realHeight = dim.height;
    1654             realWidth = sourceWidth * realHeight / sourceHeight;
    1655         } else {
    1656             realWidth = GuiSizesHelper.getSizeDpiAdjusted(sourceWidth);
    1657             realHeight = GuiSizesHelper.getSizeDpiAdjusted(sourceHeight);
    1658         }
    16591671
    1660         int roundedWidth = Math.round(realWidth);
    1661         int roundedHeight = Math.round(realHeight);
     1672        final Dimension2D realDimension = new ComputedDimension(dim, sourceWidth, sourceHeight);
     1673        int roundedWidth = (int) Math.round(realDimension.getWidth());
     1674        int roundedHeight = (int) Math.round(realDimension.getHeight());
    16621675        if (roundedWidth <= 0 || roundedHeight <= 0 || roundedWidth >= Integer.MAX_VALUE || roundedHeight >= Integer.MAX_VALUE) {
    1663             Logging.error("createImageFromSvg: {0} {1} realWidth={2} realHeight={3}",
    1664                     svg.getXMLBase(), dim, Float.toString(realWidth), Float.toString(realHeight));
     1676            Logging.error("createImageFromSvg: {0} {1} realDimension={2}", svg.getXMLBase(), dim, realDimension);
    16651677            return null;
    16661678        }
    16671679        BufferedImage img = new BufferedImage(roundedWidth, roundedHeight, BufferedImage.TYPE_INT_ARGB);
    16681680        Graphics2D g = img.createGraphics();
    16691681        g.setClip(0, 0, img.getWidth(), img.getHeight());
    1670         g.scale(realWidth / sourceWidth, realHeight / sourceHeight);
     1682        g.scale((float) realDimension.getWidth() / sourceWidth, (float) realDimension.getHeight() / sourceHeight);
    16711683        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    16721684        try {
    16731685            synchronized (getSvgUniverse()) {
    public String toString() {  
    21232135                + (archive != null ? "archive=" + archive + ", " : "")
    21242136                + (inArchiveDir != null && !inArchiveDir.isEmpty() ? "inArchiveDir=" + inArchiveDir : "") + ']').replaceAll(", \\]", "]");
    21252137    }
     2138
     2139    static class ComputedDimension extends Dimension2D {
     2140        private final float realWidth;
     2141        private final float realHeight;
     2142
     2143        ComputedDimension(Dimension dim, float sourceWidth, float sourceHeight) {
     2144            dim = GuiSizesHelper.getDimensionDpiAdjusted(dim);
     2145            if (dim.width >= 0) {
     2146                realWidth = dim.width;
     2147                if (dim.height >= 0) {
     2148                    realHeight = dim.height;
     2149                } else {
     2150                    realHeight = sourceHeight * realWidth / sourceWidth;
     2151                }
     2152            } else if (dim.height >= 0) {
     2153                realHeight = dim.height;
     2154                realWidth = sourceWidth * realHeight / sourceHeight;
     2155            } else {
     2156                realWidth = GuiSizesHelper.getSizeDpiAdjusted(sourceWidth);
     2157                realHeight = GuiSizesHelper.getSizeDpiAdjusted(sourceHeight);
     2158            }
     2159        }
     2160
     2161        @Override
     2162        public double getWidth() {
     2163            return realWidth;
     2164        }
     2165
     2166        @Override
     2167        public double getHeight() {
     2168            return realHeight;
     2169        }
     2170
     2171        @Override
     2172        public void setSize(double width, double height) {
     2173            throw new UnsupportedOperationException();
     2174        }
     2175
     2176        @Override
     2177        public String toString() {
     2178            return "ComputedDimension{realWidth=" + realWidth + ", realHeight=" + realHeight + '}';
     2179        }
     2180    }
    21262181}
  • src/org/openstreetmap/josm/tools/ImageResource.java

    diff --git a/src/org/openstreetmap/josm/tools/ImageResource.java b/src/org/openstreetmap/josm/tools/ImageResource.java
    index 56f5d4f87..482be937b 100644
    a b  
    33
    44import java.awt.Dimension;
    55import java.awt.Image;
     6import java.awt.geom.Dimension2D;
    67import java.awt.image.BufferedImage;
    78import java.util.List;
    89import java.util.Map;
    910import java.util.concurrent.ConcurrentHashMap;
     11import java.util.function.Consumer;
    1012
    1113import javax.swing.AbstractAction;
    1214import javax.swing.Action;
     
    3537     * SVG diagram information in case of SVG vector image.
    3638     */
    3739    private SVGDiagram svg;
     40
     41    private JosmSvgIcon josmSvgIcon;
    3842    /**
    3943     * Use this dimension to request original file dimension.
    4044     */
    public ImageResource(SVGDiagram svg) {  
    7074        this.svg = svg;
    7175    }
    7276
     77    public ImageResource(JosmSvgIcon josmSvgIcon) {
     78        CheckParameterUtil.ensureParameterNotNull(josmSvgIcon);
     79        this.josmSvgIcon = josmSvgIcon;
     80    }
     81
    7382    /**
    7483     * Constructs a new {@code ImageResource} from another one and sets overlays.
    7584     * @param res the existing resource
    public ImageResource(SVGDiagram svg) {  
    7887     */
    7988    public ImageResource(ImageResource res, List<ImageOverlay> overlayInfo) {
    8089        this.svg = res.svg;
     90        this.josmSvgIcon = res.josmSvgIcon;
    8191        this.baseImage = res.baseImage;
    8292        this.overlayInfo = overlayInfo;
    8393    }
    public ImageResource setDisabled(boolean disabled) {  
    94104        return this;
    95105    }
    96106
     107    private void attachImageIcon(ImageProvider.ImageSizes size, Consumer<Icon> iconConsumer) {
     108        iconConsumer.accept(josmSvgIcon != null
     109                ? josmSvgIcon.withDimension(size.getVirtualWidth(), size.getVirtualHeight())
     110                : getImageIconBounded(size.getImageDimension()));
     111    }
     112
    97113    /**
    98114     * Set both icons of an Action
    99115     * @param a The action for the icons
    100116     * @since 10369
    101117     */
    102118    public void attachImageIcon(AbstractAction a) {
    103         Dimension iconDimension = ImageProvider.ImageSizes.SMALLICON.getImageDimension();
    104         ImageIcon icon = getImageIconBounded(iconDimension);
    105         a.putValue(Action.SMALL_ICON, icon);
    106 
    107         iconDimension = ImageProvider.ImageSizes.LARGEICON.getImageDimension();
    108         icon = getImageIconBounded(iconDimension);
    109         a.putValue(Action.LARGE_ICON_KEY, icon);
     119        attachImageIcon(ImageProvider.ImageSizes.SMALLICON, icon -> a.putValue(Action.SMALL_ICON, icon));
     120        attachImageIcon(ImageProvider.ImageSizes.LARGEICON, icon -> a.putValue(Action.LARGE_ICON_KEY, icon));
    110121    }
    111122
    112123    /**
    public ImageIcon getImageIcon(Dimension dim, boolean multiResolution) {  
    158169                () -> dim + " is invalid");
    159170        BufferedImage img = imgCache.get(dim);
    160171        if (img == null) {
    161             if (svg != null) {
    162                 Dimension realDim = GuiSizesHelper.getDimensionDpiAdjusted(dim);
    163                 img = ImageProvider.createImageFromSvg(svg, realDim);
     172            if (josmSvgIcon != null) {
     173                final Dimension2D dimension = new ImageProvider.ComputedDimension(
     174                        dim, josmSvgIcon.getIconWidth(), josmSvgIcon.getIconHeight());
     175                img = josmSvgIcon.withDimension((int) dimension.getWidth(), (int) dimension.getHeight()).toImage();
     176            } else if (svg != null) {
     177                img = ImageProvider.createImageFromSvg(svg, dim);
    164178                if (img == null) {
    165179                    return null;
    166180                }
    public ImageIcon getImageIconBounded(Dimension maxSize, boolean multiResolution)  
    248262        float sourceHeight;
    249263        int maxWidth = maxSize.width;
    250264        int maxHeight = maxSize.height;
    251         if (svg != null) {
     265        if (josmSvgIcon != null) {
     266            sourceHeight = josmSvgIcon.getIconHeight();
     267            sourceWidth = josmSvgIcon.getIconWidth();
     268        } else if (svg != null) {
    252269            sourceWidth = svg.getWidth();
    253270            sourceHeight = svg.getHeight();
    254271        } else {
    public ImageIcon getPaddedIcon(Dimension iconSize) {  
    292309        return new ImageIcon(image);
    293310    }
    294311
     312    public JosmSvgIcon getJosmSvgIcon() {
     313        return josmSvgIcon;
     314    }
     315
    295316    @Override
    296317    public String toString() {
    297318        return "ImageResource ["
  • new file src/org/openstreetmap/josm/tools/JosmSvgIcon.java

    diff --git a/src/org/openstreetmap/josm/tools/JosmSvgIcon.java b/src/org/openstreetmap/josm/tools/JosmSvgIcon.java
    new file mode 100644
    index 000000000..a1deadfaf
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.tools;
     3
     4import java.awt.image.BufferedImage;
     5
     6import javax.swing.Icon;
     7
     8import org.pushingpixels.neon.api.NeonCortex;
     9
     10/**
     11 * An SVG icon as compiled Java class.
     12 */
     13public interface JosmSvgIcon extends Icon {
     14
     15    /**
     16     * Creates a copy this this icon with the specified dimension.
     17     *
     18     * @param width  the width of the copy
     19     * @param height the height of the copy
     20     * @return a copy this this icon with the specified dimension.
     21     */
     22    JosmSvgIcon withDimension(int width, int height);
     23
     24    /**
     25     * Returns the X of the bounding box of the original SVG image.
     26     *
     27     * @return The X of the bounding box of the original SVG image.
     28     */
     29    double getOrigX();
     30
     31    /**
     32     * Returns the Y of the bounding box of the original SVG image.
     33     *
     34     * @return The Y of the bounding box of the original SVG image.
     35     */
     36    double getOrigY();
     37
     38    /**
     39     * Returns the width of the bounding box of the original SVG image.
     40     *
     41     * @return The width of the bounding box of the original SVG image.
     42     */
     43    double getOrigWidth();
     44
     45    /**
     46     * Returns the height of the bounding box of the original SVG image.
     47     *
     48     * @return The height of the bounding box of the original SVG image.
     49     */
     50    double getOrigHeight();
     51
     52    default BufferedImage toImage() {
     53        BufferedImage result = NeonCortex.getBlankImage(this.getIconWidth(), this.getIconHeight());
     54        this.paintIcon(null, result.getGraphics(), 0, 0);
     55        return result;
     56    }
     57}
  • tools/ivy.xml

    diff --git a/tools/ivy.xml b/tools/ivy.xml
    index dd4fc3b9b..f3c990041 100644
    a b  
    88        <conf name="proguard" description="Everything needed for running ProGuard"/>
    99        <conf name="pmd" description="Everything needed for running PMD"/>
    1010        <conf name="spotbugs" description="Everything needed for running SpotBugs"/>
     11        <conf name="radiance-photon" description="Everything needed for running radiance-photon"/>
    1112    </configurations>
    1213    <dependencies>
    1314        <!-- javacc->default -->
     
    2627        <!-- spotbugs->default -->
    2728        <dependency org="com.github.spotbugs" name="spotbugs" rev="3.1.12" conf="spotbugs->default"/>
    2829        <dependency org="com.github.spotbugs" name="spotbugs-ant" rev="3.1.12" conf="spotbugs->default"/>
     30        <!-- radiance-photon->default -->
     31        <dependency org="org.pushing-pixels" name="radiance-photon" rev="3.0-SNAPSHOT" conf="radiance-photon->default"/>
     32        <dependency org="org.apache.xmlgraphics" name="batik-all" rev="1.12" conf="radiance-photon->default">
     33            <artifact name="batik-all" type="pom" ext="pom"/>
     34        </dependency>
    2935    </dependencies>
    3036</ivy-module>
  • new file tools/radiance-photon/JosmSvgIcon.templ

    diff --git a/tools/radiance-photon/JosmSvgIcon.templ b/tools/radiance-photon/JosmSvgIcon.templ
    new file mode 100644
    index 000000000..b06a68356
    - +  
     1TOKEN_PACKAGE
     2
     3import java.awt.*;
     4import java.awt.geom.*;
     5import java.awt.image.BufferedImage;
     6import java.io.*;
     7import java.lang.ref.WeakReference;
     8import java.util.Base64;
     9import java.util.Stack;
     10import javax.imageio.ImageIO;
     11
     12/**
     13 * This class has been automatically generated using <a
     14 * href="https://github.com/kirill-grouchnikov/radiance">Photon SVG transcoder</a>.
     15 */
     16public class TOKEN_CLASSNAME implements org.openstreetmap.josm.tools.JosmSvgIcon {
     17    private Shape shape = null;
     18    private GeneralPath generalPath = null;
     19    private Paint paint = null;
     20    private Stroke stroke = null;
     21    private Shape clip = null;
     22    private Stack<AffineTransform> transformsStack = new Stack<>();
     23
     24    TOKEN_RASTER_CODE
     25
     26    TOKEN_PAINTING_CODE
     27
     28    @SuppressWarnings("unused")
     29    private void innerPaint(Graphics2D g) {
     30        float origAlpha = 1.0f;
     31        Composite origComposite = g.getComposite();
     32        if (origComposite instanceof AlphaComposite) {
     33            AlphaComposite origAlphaComposite =
     34                    (AlphaComposite) origComposite;
     35            if (origAlphaComposite.getRule() == AlphaComposite.SRC_OVER) {
     36                origAlpha = origAlphaComposite.getAlpha();
     37            }
     38        }
     39
     40        TOKEN_PAINTING_INVOCATIONS
     41
     42        shape = null;
     43        generalPath = null;
     44        paint = null;
     45        stroke = null;
     46        clip = null;
     47        transformsStack.clear();
     48    }
     49
     50    @Override
     51    public double getOrigX() {
     52        return TOKEN_ORIG_X;
     53    }
     54
     55    @Override
     56    public double getOrigY() {
     57        return TOKEN_ORIG_Y;
     58    }
     59
     60    @Override
     61    public double getOrigWidth() {
     62        return TOKEN_ORIG_WIDTH;
     63    }
     64
     65    @Override
     66    public double getOrigHeight() {
     67        return TOKEN_ORIG_HEIGHT;
     68    }
     69
     70    /**
     71     * The current width of this resizable icon.
     72     */
     73    private final int width;
     74
     75    /**
     76     * The current height of this resizable icon.
     77     */
     78    private final int height;
     79
     80    /**
     81     * Creates a new transcoded SVG image with the original dimension.
     82     */
     83    public TOKEN_CLASSNAME() {
     84        this.width = (int) getOrigWidth();
     85        this.height = (int) getOrigHeight();
     86    }
     87
     88    /**
     89     * Creates a new transcoded SVG image with the specified dimension.
     90     *
     91     * @param width  the width of the icon
     92     * @param height the height of the icon
     93     */
     94    public TOKEN_CLASSNAME(int width, int height) {
     95        this.width = width;
     96        this.height = height;
     97    }
     98
     99    @Override
     100    public int getIconHeight() {
     101        return height;
     102    }
     103
     104    @Override
     105    public int getIconWidth() {
     106        return width;
     107    }
     108
     109    @Override
     110    public void paintIcon(Component c, Graphics g, int x, int y) {
     111        g.translate(x, y);
     112
     113        double coef1 = (double) this.width / getOrigWidth();
     114        double coef2 = (double) this.height / getOrigHeight();
     115        double coef = Math.min(coef1, coef2);
     116        g.clipRect(0, 0, this.width, this.height);
     117        ((Graphics2D) g).scale(coef, coef);
     118        ((Graphics2D) g).translate(-getOrigX(), -getOrigY());
     119        if (coef1 != coef2) {
     120            if (coef1 < coef2) {
     121                int extraDy = (int) ((getOrigWidth() - getOrigHeight()) / 2.0);
     122                g.translate(0, extraDy);
     123            } else {
     124                int extraDx = (int) ((getOrigHeight() - getOrigWidth()) / 2.0);
     125                g.translate(extraDx, 0);
     126            }
     127        }
     128        Graphics2D gInner = (Graphics2D) g.create();
     129        innerPaint(gInner);
     130        gInner.dispose();
     131        g.dispose();
     132    }
     133
     134    @Override
     135    public TOKEN_CLASSNAME withDimension(int width, int height) {
     136        return new TOKEN_CLASSNAME(width, height);
     137    }
     138}