Changeset 19641 in josm


Ignore:
Timestamp:
2026-10-06T11:40:41+02:00 (96 minutes ago)
Author:
gaben
Message:

fix #18131 - antialias clipped SVG images (e.g. the JOSM logo)

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r19605 r19641  
    8383import com.github.weisj.jsvg.parser.LoaderContext;
    8484import com.github.weisj.jsvg.parser.SVGLoader;
     85import com.github.weisj.jsvg.renderer.SVGRenderingHints;
    8586
    8687/**
    … …  
    14781479        }
    14791480        return resizeMode.createBufferedImage(dim, new Dimension((int) sourceWidth, (int) sourceHeight), g -> {
     1481            // jsvg clips through Graphics2D#clip by default, which is not antialiased (jagged edges, see #18131).
     1482            // Soft clipping avoids that, but needs accurate mask/clip rendering, otherwise the clip is applied as a
     1483            // paint that the clipped elements' own paints override and parts of the image go missing.
     1484            g.setRenderingHint(SVGRenderingHints.KEY_SOFT_CLIPPING, SVGRenderingHints.VALUE_SOFT_CLIPPING_ON);
     1485            g.setRenderingHint(SVGRenderingHints.KEY_MASK_CLIP_RENDERING, SVGRenderingHints.VALUE_MASK_CLIP_RENDERING_ACCURACY);
    14801486            svg.render(null, g);
    14811487        }, null);
  • trunk/test/functional/org/openstreetmap/josm/tools/ImageProviderTest.java

    r19613 r19641  
    66import static org.junit.jupiter.api.Assertions.assertFalse;
    77import static org.junit.jupiter.api.Assertions.assertNotNull;
     8import static org.junit.jupiter.api.Assertions.assertTrue;
    89import static org.openstreetmap.josm.testutils.ImageTestUtils.assertImageEquals;
    910
    … …  
    129130        node.put("amenity", "fuel");
    130131        assertDoesNotThrow(() -> OsmPrimitiveImageProvider.getResource(node, Collections.emptyList()));
     132    }
     133
     134    /**
     135     * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/18131">#18131</a>
     136     * <p>
     137     * The JOSM logo is assembled from clipped paths. Unless the SVG renderer clips with antialiasing,
     138     * the outline of the logo shows jagged steps.
     139     */
     140    @Test
     141    void testTicket18131() {
     142        ImageIcon icon = new ImageProvider("logo").setSize(new Dimension(256, 256)).get();
     143        assertNotNull(icon);
     144        BufferedImage image = (BufferedImage) icon.getImage();
     145        // For every column, look at the topmost visible pixel: a fully opaque one means a hard, aliased edge
     146        int opaqueEdges = 0;
     147        int blendedEdges = 0;
     148        for (int x = 0; x < image.getWidth(); x++) {
     149            for (int y = 0; y < image.getHeight(); y++) {
     150                int alpha = image.getRGB(x, y) >>> 24;
     151                if (alpha == 0) {
     152                    continue;
     153                }
     154                if (alpha == 0xff) {
     155                    opaqueEdges++;
     156                } else {
     157                    blendedEdges++;
     158                }
     159                break;
     160            }
     161        }
     162        assertTrue(opaqueEdges * 4 < blendedEdges,
     163                "expected an antialiased logo outline, but found " + opaqueEdges + " aliased and "
     164                        + blendedEdges + " antialiased edge pixels");
    131165    }
    132166
Note: See TracChangeset for help on using the changeset viewer.