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
pull/1239/head
viknesh-ai 4 weeks ago
parent 21151309da
commit cddee5c9da

@ -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.

@ -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.

@ -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
```

@ -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

@ -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!")

@ -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=<<font point-size="12"><b>person</b></font><br/><font point-size="9">[External Person]<br/></font>> fillcolor=gray60 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style="rounded,filled" width=2]
"014123c46da848ae8f700dfaeeeaed28" [label=<<font point-size="12"><b>external</b></font><br/><font point-size="9">[External System]<br/></font>> fillcolor=gray60 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
}

@ -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=<<font point-size="12"><b>container1</b></font><br/><font point-size="9">[Container]<br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
"2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<<font point-size="12"><b>container2</b></font><br/><font point-size="9">[Container]<br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
"3c58e1471ef6411ebaf38d367a8d259f" -> "2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<<font point-size="10">depends on</font>> color=gray60 dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 style=dashed]
"3c58e1471ef6411ebaf38d367a8d259f" -> "2cefb5aa2e8149bea9c8c4dc7994d46b" [label=<<font point-size="10">is depended on by</font>> color=gray60 dir=back fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 style=dashed]
}

@ -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=<<font point-size="12"><b>system 1</b></font><br/><font point-size="9">[System]<br/></font>> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
"4d45c7c34b4d4b2ca0d8612edbc370a9" [label=<<font point-size="12"><b>system 2</b></font><br/><font point-size="9">[System]<br/></font>> 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]
}

@ -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=<<font point-size="12"><b>person</b></font><br/><font point-size="9">[Person]<br/></font><br/><font point-size="10">A person.<br/><br/></font>> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style="rounded,filled" width=2.6]
"9a9be51209cf49c1b4a9733b8d73ed12" [label=<<font point-size="12"><b>container</b></font><br/><font point-size="9">[Container: Java application]<br/></font><br/><font point-size="10">The application.<br/><br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6]
"671efd01cb324573a3e3345a41d16228" [label=<<font point-size="12"><b>database</b></font><br/><font point-size="9">[Database: Oracle database]<br/></font><br/><font point-size="10">Stores information.<br/><br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=b shape=cylinder style=filled width=2.6]
}

@ -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=<<font point-size="12"><b>container1</b></font><br/><font point-size="9">[Container]<br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
"428291d5765342429ced394f65fbb463" [label=<<font point-size="12"><b>container2</b></font><br/><font point-size="9">[Container]<br/></font>> 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]
}

@ -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=<<font point-size="12"><b>system</b></font><br/><font point-size="9">[System]<br/></font><br/><font point-size="10">The internal system.<br/><br/></font>> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6]
"616f387771ae4dac9c707fcacb7f6810" [label=<<font point-size="12"><b>unknown</b></font><br/><font point-size="9">[System]<br/></font>> fillcolor=dodgerblue4 fixedsize=true fontcolor=white height=1 labelloc=c shape=rect style=filled width=2]
}

@ -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=<<font point-size="12"><b>container</b></font><br/><font point-size="9">[Container: type]<br/></font><br/><font point-size="10">description<br/><br/></font>> fillcolor=dodgerblue3 fixedsize=true fontcolor=white height=1.6 labelloc=c shape=rect style=filled width=2.6]
}
}

@ -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

@ -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)

Loading…
Cancel
Save