docs: add SVG design guide and update PDF and XML asset files

This commit is contained in:
Claudecio Martins
2026-10-12 13:40:07 -03:00
parent ef44d34944
commit 5551d9e667
8 changed files with 185 additions and 384 deletions
@@ -523,8 +523,11 @@ public final class AssetManager {
double fs = parseDouble(el.getAttribute("font-size"), 12);
String fw = el.getAttribute("font-weight");
t.setFont(Font.font("Segoe UI", "bold".equalsIgnoreCase(fw) ? FontWeight.BOLD : FontWeight.NORMAL, fs));
if (el.hasAttribute("fill")) {
t.setFill(parsePaint(el.getAttribute("fill"), defsMap, Color.BLACK));
Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of();
String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null);
if (fillVal != null) {
t.setFill(parsePaint(fillVal, defsMap, Color.BLACK));
}
if ("middle".equalsIgnoreCase(el.getAttribute("text-anchor"))) {
t.setTextOrigin(javafx.geometry.VPos.CENTER);
@@ -558,19 +561,46 @@ public final class AssetManager {
return null;
}
private static Map<String, String> parseStyleAttribute(String styleAttr) {
Map<String, String> styleMap = new HashMap<>();
if (styleAttr == null || styleAttr.isBlank()) {
return styleMap;
}
String[] declarations = styleAttr.split(";");
for (String decl : declarations) {
int colonIdx = decl.indexOf(':');
if (colonIdx > 0) {
String prop = decl.substring(0, colonIdx).trim().toLowerCase();
String val = decl.substring(colonIdx + 1).trim();
styleMap.put(prop, val);
}
}
return styleMap;
}
private static void applyShapeStyles(Element el, Shape shape, Map<String, Paint> defsMap) {
if (el.hasAttribute("fill")) {
shape.setFill(parsePaint(el.getAttribute("fill"), defsMap, Color.TRANSPARENT));
Map<String, String> inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of();
String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null);
if (fillVal != null) {
shape.setFill(parsePaint(fillVal, defsMap, Color.TRANSPARENT));
} else if (shape instanceof Line) {
shape.setFill(Color.TRANSPARENT);
}
if (el.hasAttribute("stroke")) {
shape.setStroke(parsePaint(el.getAttribute("stroke"), defsMap, Color.TRANSPARENT));
String strokeVal = inlineStyle.getOrDefault("stroke", el.hasAttribute("stroke") ? el.getAttribute("stroke") : null);
if (strokeVal != null) {
shape.setStroke(parsePaint(strokeVal, defsMap, Color.TRANSPARENT));
}
if (el.hasAttribute("stroke-width")) {
shape.setStrokeWidth(parseDouble(el.getAttribute("stroke-width"), 1.0));
String strokeWidthVal = inlineStyle.getOrDefault("stroke-width", el.hasAttribute("stroke-width") ? el.getAttribute("stroke-width") : null);
if (strokeWidthVal != null) {
shape.setStrokeWidth(parseDouble(strokeWidthVal, 1.0));
}
String opacityVal = inlineStyle.getOrDefault("opacity", el.hasAttribute("opacity") ? el.getAttribute("opacity") : null);
if (opacityVal != null) {
shape.setOpacity(parseDouble(opacityVal, 1.0));
}
if (el.hasAttribute("fill-rule") && shape instanceof SVGPath sp) {
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 996 B

@@ -1,97 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 48 48"
width="48"
height="48"
version="1.1"
id="svg4"
sodipodi:docname="xml.svg"
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs4" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="16.8125"
inkscape:cx="23.97026"
inkscape:cy="24"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
<!-- Folha de documento com dobra -->
<path
d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z"
fill="#ffffff"
stroke="#0288d1"
stroke-width="2.5"
stroke-linejoin="round"
id="path1" />
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
<!-- Dobra de canto -->
<path
d="M 32 4 L 32 14 L 42 14 Z"
fill="#b3e5fc"
stroke="#0288d1"
stroke-width="2"
stroke-linejoin="round"
id="path2" />
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
<!-- Linhas de texto representativas -->
<line
x1="12.3"
y1="17.20446"
x2="26.299999"
y2="17.20446"
stroke="#b0bec5"
stroke-width="2"
stroke-linecap="round"
id="line2" />
<line
x1="12.3"
y1="20.747211"
x2="34.299999"
y2="20.747211"
stroke="#b0bec5"
stroke-width="2"
stroke-linecap="round"
id="line3" />
<line
x1="12.3"
y1="24.289963"
x2="34.299999"
y2="24.289963"
stroke="#b0bec5"
stroke-width="2"
stroke-linecap="round"
id="line4" />
<line x1="13" y1="18" x2="27" y2="18" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<line x1="13" y1="22" x2="35" y2="22" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<line x1="13" y1="26" x2="35" y2="26" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
<!-- Etiqueta azul com sigla XML -->
<rect
x="11.3"
y="30.799257"
width="28"
height="11"
rx="3"
fill="#0288d1"
id="rect4" />
<text
x="25.296093"
y="39.100037"
font-family="'Segoe UI', Arial, sans-serif"
font-size="8px"
font-weight="bold"
fill="#ffffff"
text-anchor="middle"
id="text4">&lt;XML&gt;</text>
<rect x="11" y="31" width="28" height="11" rx="3" fill="#0288d1"/>
<text x="25" y="39" font-family="'Segoe UI', Arial, sans-serif" font-size="8px" font-weight="bold" fill="#ffffff" text-anchor="middle">&lt;XML&gt;</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1000 B

@@ -55,4 +55,22 @@ class AssetManagerTest {
assertThat(SvgIcons.refreshIcon(16)).isNotNull();
assertThat(SvgIcons.createAppCrystalLogo(48)).isNotNull();
}
@Test
@DisplayName("Deve interpretar atributos style inline no padrão de exportação do Inkscape/Figma")
void shouldParseSvgWithInlineStyles() {
String svgWithStyle = """
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
<rect x="10" y="10" width="28" height="28" style="fill:#d32f2f;stroke:#0288d1;stroke-width:2.5;opacity:0.9"/>
<text x="24" y="24" style="fill:#ffffff;font-size:10px">OK</text>
</svg>
""";
try (var in = new java.io.ByteArrayInputStream(svgWithStyle.getBytes(java.nio.charset.StandardCharsets.UTF_8))) {
Node node = AssetManager.parseSvgToNode(in, 48, 48);
assertThat(node).isNotNull();
assertThat(node).isInstanceOf(javafx.scene.layout.Pane.class);
} catch (Exception e) {
org.junit.jupiter.api.Assertions.fail("Falha ao analisar SVG com estilo inline: " + e.getMessage());
}
}
}