From cddee5c9dac9bfd9f49283b64396532e89b59e0c Mon Sep 17 00:00:00 2001 From: viknesh-ai Date: Fri, 14 Aug 2026 10:18:15 +0530 Subject: [PATCH] fix: standardise Azure svg-to-png conversion on rsvg-convert config.py, CONTRIBUTING.md and what contributors actually run each named a different converter. Since the source SVGs are deleted after conversion, the PNG is the only artifact we keep, and two rasterisers emit different bytes for identical artwork. That is how #1204 landed 632 modified Azure icons with a single genuine visual change between them. Settle on rsvg-convert, which is what #1204 reached for and which installs without pulling in a GUI toolchain. The forced 256x256 output that config.py already declared is kept; rsvg-convert only preserves aspect ratio when asked to, so passing -w and -h is enough. Unlike inkscape it writes to stdout unless given an output path, so svg2png now names its destination the way svg2png2 already does. Teach cleaner_azure to drop the icon pack's numeric prefix so autogen.sh covers the whole conversion on its own, and rewrite the Azure section of CONTRIBUTING.md to point at it instead of a hand-rolled find command that never touched config.py. Docker images and the Mac setup notes follow. Fixes #1237 --- .devcontainer/Dockerfile | 2 +- CONTRIBUTING.md | 37 ++++++++++++++++++++----------------- DEVELOPMENT.md | 2 +- autogen.sh | 6 +++--- config.py | 6 ++++-- diagram-148bce0 | 7 +++++++ diagram-41afb8d | 9 +++++++++ diagram-af8fef5 | 8 ++++++++ diagram-bbc0d60 | 8 ++++++++ diagram-bfd2e9a | 8 ++++++++ diagram-c0e1f87 | 7 +++++++ diagram-fccf2eb | 9 +++++++++ docker/dev/Dockerfile | 2 +- scripts/resource.py | 13 +++++++++---- 14 files changed, 95 insertions(+), 29 deletions(-) create mode 100644 diagram-148bce0 create mode 100644 diagram-41afb8d create mode 100644 diagram-af8fef5 create mode 100644 diagram-bbc0d60 create mode 100644 diagram-bfd2e9a create mode 100644 diagram-c0e1f87 create mode 100644 diagram-fccf2eb diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index fdcec4db..8bb394e6 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM python:3-alpine # install system dependencies. RUN apk update && apk add --no-cache \ - gcc libc-dev g++ graphviz git bash go imagemagick inkscape ttf-opensans curl fontconfig xdg-utils \ + gcc libc-dev g++ graphviz git bash go imagemagick rsvg-convert ttf-opensans curl fontconfig xdg-utils \ nodejs npm # install go package. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c344a95b..75400470 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,41 +31,44 @@ ffmpeg -i my_big_image.jpg -vf scale=w=256:h=256:force_original_aspect_ratio=dec Then just run the `./autogen.sh` to generate the added or updated node classes. (cf. [DEVELOPMENT][DEVELOPMENT.md]) > IMPORTANT NOTE: To run `autogen.sh`, you need the [round][round], [black][black] and -> [inkscape][inkscape] command line tools that are used for cleaning the image +> [rsvg-convert][librsvg] command line tools that are used for cleaning the image > resource filenames and formatting the generated python code. > -> macOS users can download inkscape via Homebrew. +> macOS users can install `rsvg-convert` with `brew install librsvg`. > > Or you can use the docker image. [DEVELOPMENT.md]: ./DEVELOPMENT.md [round]: https://github.com/mingrammer/round [black]: https://pypi.org/project/black -[inkscape]: https://inkscape.org/ko/release +[librsvg]: https://gitlab.gnome.org/GNOME/librsvg #### Update Specific Instructions for Azure Icons -Download and unzip [Azure Icons](https://learn.microsoft.com/en-us/azure/architecture/icons/) +Download and unzip [Azure Icons](https://learn.microsoft.com/en-us/azure/architecture/icons/). + +The only manual step is renaming the directories that ship with spaces and `+` +signs in their names, since those become the python module names. Execute inside +`Azure_Public_Service_Icons/Icons/`: -Execute inside Azure_Public_Service_Icons/Icons/ ```bash -# Rename some diretories -mv ai\ +\ machine\ learning/ aimachinelearning/ +mv ai\ +\ machine\ learning/ aimachinelearning mv app\ services/ appservices mv azure\ stack/ azurestack mv azure\ ecosystem/ azureecosystem mv management\ +\ governance/ managementgovernance -mv mixed\ reality mixedreality +mv mixed\ reality/ mixedreality mv new\ icons/ newicons -# Convert Name to name -rename -f 'y/A-Z/a-z/' ./*/* -# Create png files and eliminate ?????-icon-service from namefile -find . -type f -name "*.svg" -exec bash -c 'inkscape -h 256 --export-filename="${0%.svg}.png" "$0";mv "${0%.svg}.png" "$(echo "${0%.svg}.png" | sed -r 's/[0-9]{5}-icon-service-//')"' {} \; -# Delete svg files -find . -type f -name "*.svg" -exec bash -c 'rm "$0"' {} \; ``` -If you get any errors with autogen, it will probably be a '+' in filename +Then copy the directories into `resources/azure/` and run `./autogen.sh`. Don't +convert the SVGs by hand: `autogen.sh` rasterises them with `rsvg-convert` at the +size configured in [config.py](config.py), lowercases the file names and strips +the `?????-icon-service-` prefix for you. Converting them yourself with a +different tool produces byte-different PNGs from identical artwork, which turns +an icon refresh into hundreds of files that only look changed. + +If any file name still trips up autogen, it's most likely a `+` left in it. ### Add new provider @@ -94,10 +97,10 @@ or update the `ALIASES` map in [config.py](config.py). Then just run the `./autogen.sh` to generate the added or updated aliases. (cf. [DEVELOPMENT][DEVELOPMENT.md]) > IMPORTANT NOTE: To run `autogen.sh`, you need the [round][round] and -> [inkscape][inkscape] command line tools that are used for cleaning the image +> [rsvg-convert][librsvg] command line tools that are used for cleaning the image > resource filenames. > -> macOS users can download inkscape via Homebrew. +> macOS users can install `rsvg-convert` with `brew install librsvg`. > > Or you can use the docker image. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 0cd0e908..6a9a1947 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -58,7 +58,7 @@ To be able to develop and run diagrams locally on you Mac device, you should hav 4. Install diagrams binary dependencies. ```shell - brew install imagemagick inkscape black + brew install imagemagick librsvg black go install github.com/mingrammer/round@latest # ln -sf ~/go/bin/round ~/.local/bin/round ``` diff --git a/autogen.sh b/autogen.sh index 263ae41a..d8d70dc3 100755 --- a/autogen.sh +++ b/autogen.sh @@ -27,8 +27,8 @@ if ! [ -x "$(command -v round)" ]; then exit 1 fi -if ! [ -x "$(command -v inkscape)" ]; then - echo 'inkscape is not installed' +if ! [ -x "$(command -v rsvg-convert)" ]; then + echo 'rsvg-convert is not installed (it ships with librsvg)' exit 1 fi @@ -46,7 +46,7 @@ fi for pvd in "${providers[@]}"; do # convert the svg to png for azure provider if [ "$pvd" = "onprem" ] || [ "$pvd" = "azure" ]; then - echo "converting the svg to png using inkscape for provider '$pvd'" + echo "converting the svg to png using rsvg-convert for provider '$pvd'" python -m scripts.resource svg2png "$pvd" fi if [ "$pvd" == "oci" ] || [ "$pvd" = "ibm" ]; then diff --git a/config.py b/config.py index d1ae8ace..2c60de63 100644 --- a/config.py +++ b/config.py @@ -38,8 +38,10 @@ PROVIDERS = ( CMD_ROUND = "round" CMD_ROUND_OPTS = ("-w",) -CMD_SVG2PNG = "inkscape" -CMD_SVG2PNG_OPTS = ("-w", "256", "-h", "256", "--export-type", "png") +# Both -w and -h are given without --keep-aspect-ratio, so every icon comes out +# exactly 256x256 no matter what the source SVG declares. +CMD_SVG2PNG = "rsvg-convert" +CMD_SVG2PNG_OPTS = ("-w", "256", "-h", "256") CMD_SVG2PNG_IM = "convert" CMD_SVG2PNG_IM_OPTS = ("-shave", "25%x25%", "-resize", "256x256!") diff --git a/diagram-148bce0 b/diagram-148bce0 new file mode 100644 index 00000000..224d1af7 --- /dev/null +++ b/diagram-148bce0 @@ -0,0 +1,7 @@ +digraph "diagram-148bce0" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-148bce0" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + "78a0f08af7ef40739cbd2412808a99db" [label=<person
[External Person]
> fillcolor=gray60 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style="rounded,filled" width=2] + "014123c46da848ae8f700dfaeeeaed28" [label=<external
[External System]
> fillcolor=gray60 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] +} diff --git a/diagram-41afb8d b/diagram-41afb8d new file mode 100644 index 00000000..d37d8074 --- /dev/null +++ b/diagram-41afb8d @@ -0,0 +1,9 @@ +digraph "diagram-41afb8d" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-41afb8d" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + "3c58e1471ef6411ebaf38d367a8d259f" [label=<container1
[Container]
> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + "2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<container2
[Container]
> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + "3c58e1471ef6411ebaf38d367a8d259f" -> "2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<depends on> color=gray60 dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 style=dashed] + "3c58e1471ef6411ebaf38d367a8d259f" -> "2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<is depended on by> color=gray60 dir=back fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 style=dashed] +} diff --git a/diagram-af8fef5 b/diagram-af8fef5 new file mode 100644 index 00000000..3b81b62e --- /dev/null +++ b/diagram-af8fef5 @@ -0,0 +1,8 @@ +digraph "diagram-af8fef5" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-af8fef5" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + "84ed3e0f206d495b86d309617b510c35" [label=<system 1
[System]
> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + "4d45c7c34b4d4b2ca0d8612edbc370a9" [label=<system 2
[System]
> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + "84ed3e0f206d495b86d309617b510c35" -> "4d45c7c34b4d4b2ca0d8612edbc370a9" [color=gray60 constraint=False dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 style=dashed] +} diff --git a/diagram-bbc0d60 b/diagram-bbc0d60 new file mode 100644 index 00000000..eae02f83 --- /dev/null +++ b/diagram-bbc0d60 @@ -0,0 +1,8 @@ +digraph "diagram-bbc0d60" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-bbc0d60" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + "222c43da7c214ee682504f8b4d200a4c" [label=<person
[Person]

A person.

> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style="rounded,filled" width=2.6] + "9a9be51209cf49c1b4a9733b8d73ed12" [label=<container
[Container: Java application]

The application.

> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6] + "671efd01cb324573a3e3345a41d16228" [label=<database
[Database: Oracle database]

Stores information.

> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=b shape=cylinder style=filled width=2.6] +} diff --git a/diagram-bfd2e9a b/diagram-bfd2e9a new file mode 100644 index 00000000..d94ea75b --- /dev/null +++ b/diagram-bfd2e9a @@ -0,0 +1,8 @@ +digraph "diagram-bfd2e9a" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-bfd2e9a" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + cb4bb0a70b684663a584ef16ed5c86de [label=<container1
[Container]
> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + "428291d5765342429ced394f65fbb463" [label=<container2
[Container]
> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] + cb4bb0a70b684663a584ef16ed5c86de -> "428291d5765342429ced394f65fbb463" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13] +} diff --git a/diagram-c0e1f87 b/diagram-c0e1f87 new file mode 100644 index 00000000..65e59fd9 --- /dev/null +++ b/diagram-c0e1f87 @@ -0,0 +1,7 @@ +digraph "diagram-c0e1f87" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-c0e1f87" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + "65692efd972d4878a3ece16f8c0c2821" [label=<system
[System]

The internal system.

> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6] + "616f387771ae4dac9c707fcacb7f6810" [label=<unknown
[System]
> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2] +} diff --git a/diagram-fccf2eb b/diagram-fccf2eb new file mode 100644 index 00000000..80def2e9 --- /dev/null +++ b/diagram-fccf2eb @@ -0,0 +1,9 @@ +digraph "diagram-fccf2eb" { + graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="diagram-fccf2eb" nodesep=0.70 pad=2.0 rankdir=LR ranksep=0.90 splines=spline] + node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagepos=tc imagescale=true labelloc=b shape=box style=rounded width=1.4] + edge [arrowsize=0.8 color="#495057"] + subgraph cluster_System { + graph [bgcolor=white fontname="Sans-Serif" fontsize=12 label=System labeljust=l margin=16 pencolor="#ADB5BD" rankdir=LR shape=box style=dashed] + "680ecb98ce7b4aa391d9b566b7bdba10" [label=<container
[Container: type]

description

> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6] + } +} diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index d266630e..058f6665 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -3,7 +3,7 @@ FROM python:3.13.3-alpine3.20 # install system dependencies. RUN apk update && apk add --no-cache \ - gcc libc-dev g++ graphviz git bash go imagemagick inkscape ttf-opensans curl fontconfig xdg-utils + gcc libc-dev g++ graphviz git bash go imagemagick rsvg-convert ttf-opensans curl fontconfig xdg-utils # install go package. RUN go install github.com/mingrammer/round@latest diff --git a/scripts/resource.py b/scripts/resource.py index e4c27e28..ab2e2399 100644 --- a/scripts/resource.py +++ b/scripts/resource.py @@ -7,6 +7,7 @@ There are 2 commands available. """ import os +import re import subprocess import sys @@ -40,6 +41,8 @@ def cleaner_azure(f): f = f.replace("_", "-") f = f.replace("(", "").replace(")", "") f = "-".join(f.split()) + # The official icon pack numbers every file, e.g. 10021-icon-service-Batch-Accounts. + f = re.sub(r"^\d+-icon-service-", "", f, flags=re.IGNORECASE) for p in cfg.FILE_PREFIXES["azure"]: if f.startswith(p): f = f[len(p):] @@ -190,12 +193,14 @@ def round_png(pvd: str) -> None: def svg2png(pvd: str) -> None: - """Convert the svg into png""" + """Convert the svg into png using rsvg-convert""" def _convert(base: str, path: str): - path = os.path.join(base, path) - subprocess.run([cfg.CMD_SVG2PNG, *cfg.CMD_SVG2PNG_OPTS, path]) - subprocess.run(["rm", path]) + path_src = os.path.join(base, path) + path_dest = path_src.replace(".svg", ".png") + # rsvg-convert writes the png to stdout unless it's given an output path. + subprocess.run([cfg.CMD_SVG2PNG, *cfg.CMD_SVG2PNG_OPTS, "-o", path_dest, path_src]) + subprocess.run(["rm", path_src]) for root, _, files in os.walk(resource_dir(pvd)): svgs = filter(lambda f: f.endswith(".svg"), files)