Subject: [PATCH] fix #18131 - antialias SVGs, including the logo
---
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/tools/ImageProvider.java b/src/org/openstreetmap/josm/tools/ImageProvider.java
|
a
|
b
|
|
| 82 | 82 | import com.github.weisj.jsvg.parser.DocumentLimits; |
| 83 | 83 | import com.github.weisj.jsvg.parser.LoaderContext; |
| 84 | 84 | import com.github.weisj.jsvg.parser.SVGLoader; |
| | 85 | import com.github.weisj.jsvg.renderer.SVGRenderingHints; |
| 85 | 86 | |
| 86 | 87 | /** |
| 87 | 88 | * Helper class to support the application with images. |
| … |
… |
|
| 1477 | 1478 | return null; |
| 1478 | 1479 | } |
| 1479 | 1480 | return resizeMode.createBufferedImage(dim, new Dimension((int) sourceWidth, (int) sourceHeight), g -> { |
| | 1481 | // Without soft clipping, jsvg applies clip paths through Graphics2D#clip, which is not antialiased and |
| | 1482 | // therefore produces jagged edges wherever an image uses clip-path, see #18131. Soft clipping requires |
| | 1483 | // accurate mask/clip rendering, otherwise the clip is realized as a paint that the clipped group's own |
| | 1484 | // paints override, which drops parts of the image. |
| | 1485 | g.setRenderingHint(SVGRenderingHints.KEY_SOFT_CLIPPING, SVGRenderingHints.VALUE_SOFT_CLIPPING_ON); |
| | 1486 | g.setRenderingHint(SVGRenderingHints.KEY_MASK_CLIP_RENDERING, SVGRenderingHints.VALUE_MASK_CLIP_RENDERING_ACCURACY); |
| 1480 | 1487 | svg.render(null, g); |
| 1481 | 1488 | }, null); |
| 1482 | 1489 | } |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/test/functional/org/openstreetmap/josm/tools/ImageProviderTest.java b/test/functional/org/openstreetmap/josm/tools/ImageProviderTest.java
|
a
|
b
|
|
| 5 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 6 | 6 | import static org.junit.jupiter.api.Assertions.assertFalse; |
| 7 | 7 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| | 8 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 8 | 9 | import static org.openstreetmap.josm.testutils.ImageTestUtils.assertImageEquals; |
| 9 | 10 | |
| 10 | 11 | import java.awt.Dimension; |
| … |
… |
|
| 130 | 131 | assertDoesNotThrow(() -> OsmPrimitiveImageProvider.getResource(node, Collections.emptyList())); |
| 131 | 132 | } |
| 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"); |
| | 165 | } |
| | 166 | |
| 133 | 167 | /** |
| 134 | 168 | * Test fetching an image using {@code data:} URL. |
| 135 | 169 | */ |