PerfectVector
Autor: Irene Kim9 min czytania

Obrazy SVG w Graphviz: zadbaj o przenośność grafiki węzłów

Dodaj grafikę SVG do węzła Graphviz, sprawdź odwołanie do obrazu i przetestuj kompletny pakiet zasobów, porównując go z przeniesionym diagramem oraz samowystarczalną kopią do przekazania.

Na tej stronie

Diagram Graphviz może zawierać wektorowe węzły i strzałki, a niestandardowa grafika węzłów nadal może odwoływać się do osobnego pliku obrazu. Jeśli ta grafika znika po przeniesieniu SVG, sprawdź wygenerowane odwołanie do obrazu, zanim zmienisz rysunek. Brakującym elementem może być pakiet do przekazania.

W przetestowanym poniżej wyjściowym pliku SVG Graphviz zachowuje odwołanie do osobnego pliku obrazu motif.svg. Kompletny pakiet go wyświetla; diagram przeniesiony samodzielnie go traci. Kopia przygotowana z jawnym dołączeniem danych grafiki zawiera jej bajty i wyświetla ją w tym samym teście w przeglądarce. Ten etap przygotowania pakietu nadal pozostawia element obrazu SVG, zamiast zamieniać motyw w natywne ścieżki grafu.

Zachowaj źródło DOT z nazwami węzłów i relacjami. Przechowuj osobno plik wzorcowy grafiki i przetestuj dokładnie ten wynik w docelowym programie do wyświetlania lub procesie publikacji.

Rozróżnij węzeł, jego grafikę i odwołanie do jej pliku

Atrybut image w Graphviz wskazuje grafikę wyświetlaną wewnątrz węzła. Nie zastępuje tożsamości węzła w grafie ani jego relacji. Dokumentacja wymaga wymiarów źródłowych; dla obrazów SVG podaj jawnie width i height z odpowiednimi jednostkami.

Użyty tutaj oryginalny motyw to rysunek złożony z dwóch ścieżek, z przestrzenią współrzędnych 96 na 64. Jego wymiary zewnętrzne to 96pt na 64pt. Otaczający go węzeł i strzałka należą do Graphviz.

ElementGdzie jest utrzymywanyCo może pójść nie tak
Nazwy węzłów, etykiety i krawędzieŹródło DOTNieprawidłowe relacje w grafie lub treść
Niestandardowy motywWzorcowy plik SVG grafikiBrak wymiarów, nieodpowiedni poziom szczegółowości lub złe proporcje
Odwołanie z diagramu do motywuOdwołanie do obrazu w wyeksportowanym SVGBrak grafiki pod ścieżką wynikającą z odwołania
Końcowe położenie i rozmiarWynik renderowania i docelowy program do wyświetlaniaPrzycięcie, rozciągnięcie lub nieobsługiwane zależności

Element obrazu może wskazywać grafikę SVG lub piksele. Aby zbadać źródło rastrowe, skorzystaj z osobnego poradnika diagnozowania obrazów osadzonych w SVG. Nazwa pliku kończąca się na .svg nie wystarcza, by ustalić zawartość któregokolwiek z plików.

Uruchom mały przykład z jawnie wybranym rendererem

Użyliśmy @viz-js/viz 3.31.0, kompilacji WebAssembly zgłaszającej Graphviz 16.1.0, z silnikiem układu dot i wbudowanym wyjściem SVG. To test tej kompilacji i tego renderera, a nie stwierdzenie, że każda instalacja Graphviz wczytuje obrazy w identyczny sposób.

W nowym folderze projektu Node.js zainstaluj pakiet w ustalonej wersji:

npm install @viz-js/viz@3.31.0

Zapisz oryginalną grafikę jako motif.svg:

<svg xmlns="http://www.w3.org/2000/svg"
     width="96pt" height="64pt" viewBox="0 0 96 64">
  <path fill="#173b40" fill-rule="evenodd"
    d="M48 4C70 4 88 17 88 32S70 60 48 60S8 47 8 32S26 4 48 4Z
       M48 14C31 14 19 22 19 32S31 50 48 50S77 42 77 32S65 14 48 14Z"/>
  <path fill="#28bfa3"
    d="M43 20H53V27H60V37H53V44H43V37H36V27H43Z"/>
</svg>

Zapisz graf jako diagram.dot:

digraph G {
  graph [rankdir=LR, bgcolor="white", margin=0.1];
  node [shape=box, fontname="Arial", fontsize=16,
        color="#173b40", penwidth=1.5,
        fixedsize=true, width=1.8, height=1.1];
  artwork [label="", image="motif.svg", imagescale=true];
  review [label="Review"];
  artwork -> review [color="#173b40", penwidth=1.5];
}

Następnie zapisz poniższy kod jako render.mjs i uruchom node render.mjs z tego folderu:

import { instance } from '@viz-js/viz';
import fs from 'node:fs';
 
const viz = await instance();
const dot = fs.readFileSync('diagram.dot', 'utf8');
const svg = viz.renderString(dot, {
  engine: 'dot',
  format: 'svg',
  images: [{ name: 'motif.svg', width: '96pt', height: '64pt' }]
});
 
fs.mkdirSync('bundle', { recursive: true });
fs.copyFileSync('motif.svg', 'bundle/motif.svg');
fs.writeFileSync('bundle/diagram.svg', svg);
process.stdout.write(`Graphviz ${viz.graphvizVersion}\n`);

Dokumentacja API Viz.js opisuje opcję images jako informacje o rozmiarze obrazu. Podanie jej przekazuje mechanizmowi układu informacje o grafice o tej nazwie; nie umieszcza bajtów pliku w wyniku. Jawne jednostki zapobiegają traktowaniu liczby bez jednostki jako pikseli CSS. API używa punktów dla wymiarów bez jednostek.

W przypadku natywnej instalacji Graphviz oficjalna dokumentacja image opisuje lokalne zasoby obrazów i wymiary odczytywane z pliku źródłowego. Nie kopiuj konfiguracji metadanych z WebAssembly do natywnego polecenia, zakładając, że korzysta ono z tego samego mechanizmu wczytywania.

Sprawdź, co zapisał renderer

Nasz wygenerowany SVG zawiera ten element:

<image xlink:href="motif.svg"
       width="118.8px" height="79.2px"
       preserveAspectRatio="xMinYMin meet"
       x="5.4" y="-79.2"/>

Wymiary i położenie to wartości zaobserwowane w tym przykładzie testowym. O przekazaniu zasobów decyduje fragment xlink:href="motif.svg": wynik nadal wymaga zasobu pod tą względną ścieżką.

Skopiuj tylko diagram.svg do innego folderu, pozostawiając grafikę w dotychczasowym miejscu. Porównaj go z kompletnym pakietem. Udostępniliśmy oba foldery przez lokalny serwer HTTP i wyświetliliśmy każdy SVG jako dokument za pomocą elementu HTML object.

Trzy rzeczywiste diagramy SVG z Graphviz: grafika obecna w kompletnym pakiecie zasobów, brakująca po przeniesieniu samego diagramu i obecna w kopii z osadzonymi bajtami obrazu SVG
Środkowy plik ma taką samą geometrię grafu i odwołanie do grafiki jak plik po lewej. Jego motywu brakuje pod ścieżką wynikającą z odwołania. Kopia po prawej jawnie zawiera tę grafikę jako adres URL danych SVG.

Wygenerowane prostokąty węzłów i strzałka pozostają widoczne, gdy brakuje motywu wskazywanego przez odwołanie. Ponowne wygenerowanie układu grafu nie dostarcza brakującego pliku. Przywróć oczekiwaną lokalizację zasobu, przekaż cały pakiet lub wybierz sposób dołączenia zasobów odpowiedni dla miejsca docelowego.

Otwarcie SVG jako dokumentu i wyświetlenie go przez element HTML img to różne testy. Poradnik MDN dotyczący SVG jako obrazu wyjaśnia, że konteksty obrazu mogą ograniczać zasoby zewnętrzne, natomiast adresy URL danych pozwalają umieszczać je bezpośrednio w pliku. Opisane tam ograniczenia kontekstu obrazu nie dotyczą dokumentów SVG otwieranych bezpośrednio ani osadzania dokumentów przez object i iframe. Sprawdź kontekst, w którym faktycznie udostępniasz plik.

Jawnie dołącz ten prosty motyw do pliku

W przypadku tego oryginalnego, samowystarczalnego motywu poniższy skrypt zastępuje dokładnie jedno znane odwołanie bajtami SVG z pliku. Zapisz go jako package.mjs i uruchom po renderowaniu:

import fs from 'node:fs';
 
const svg = fs.readFileSync('bundle/diagram.svg', 'utf8');
const needle = 'xlink:href="motif.svg"';
if (svg.split(needle).length !== 2) {
  throw new Error('Expected exactly one motif reference');
}
 
const data = 'data:image/svg+xml;base64,' +
  fs.readFileSync('bundle/motif.svg').toString('base64');
const packaged = svg.replace(needle, `xlink:href="${data}"`);
fs.writeFileSync('self-contained.svg', packaged);

To przykład dołączenia zasobu przeznaczony do konkretnego przypadku, a nie ogólne narzędzie do osadzania zasobów SVG. Obsługuje znane odwołanie w tym wyniku oraz motyw, który nie ma zewnętrznych fontów, obrazów, arkuszy stylów ani innych zależności. Bardziej złożona grafika wymaga osobnego sprawdzenia zależności.

Kopia z dołączonymi danymi wyświetliła motyw w naszym teście w przeglądarce. Porównanie obu wynikowych ciągów tekstowych po zamaskowaniu wartości odwołania do obrazu wykazało identyczną geometrię grafu. Plik nadal zawiera jeden element obrazu; jego odwołanie zaczyna się teraz od data:image/svg+xml;base64,.

Osadzenie bajtów obrazu SVG może usunąć tę zależność od ścieżki pliku, zachowując wektorowe źródło grafiki. Nie zmienia tej grafiki w natywny kształt węzła Graphviz, nie dodaje wewnątrz niej punktów połączeń ani nie gwarantuje, że inny edytor udostępni jej ścieżki bezpośrednio. Przetestuj sposób importowania w narzędziu odbiorcy.

Unikaj też mylenia svg_inline z osadzaniem obrazów. Dokumentacja wyjścia SVG Graphviz opisuje ten tryb jako wyjście bez nagłówka, przeznaczone do umieszczenia w HTML. Dla tego samego grafu wybranie svg_inline nadal powodowało wygenerowanie odwołania do motif.svg. Ten tryb wyjścia nie dołączył grafiki.

Rozpatruj wymiary i skalowanie oddzielnie od przenośności

Opis imagescale w Graphviz rozróżnia dopasowanie obrazu do wnętrza węzła i naturalny rozmiar źródła. W tym przykładzie imagescale=true skaluje go proporcjonalnie, aby się zmieścił. Opcja both skaluje szerokość i wysokość oddzielnie, co może zmieniać proporcje.

Jeśli motyw jest widoczny, ale rozciągnięty, sprawdź opcję skalowania. Jeśli widać tylko jego część, sprawdź jego własne granice i dostępną przestrzeń w węźle. Jeśli znika po przeniesieniu pliku, najpierw sprawdź ścieżkę zasobu. Poradnik dotyczący rozmiaru SVG wyjaśnia różnicę między zadeklarowanym rozmiarem a współrzędnymi rysunku.

ObjawCo sprawdzić najpierwJaką poprawkę wypróbować
Grafika znika po przeniesieniu diagramuWygenerowane odwołanie do obrazu i względna lokalizacja zasobuPrzywróć pakiet lub jawnie dołącz przetestowane źródło
Układ grafu jest generowany, ale grafiki brakujeWymiary źródła i konfigurację obrazów właściwą dla danej kompilacjiSprawdź, czy dostępne są plik i metadane obrazu wymagane przez tę kompilację
Motyw wygląda na rozciągniętyUstawienie imagescale i zamierzone proporcjeUżyj dopasowania proporcjonalnego, jeśli nie chcesz zniekształceń
SVG działa po otwarciu bezpośrednio, ale nie działa na stronie internetowejCzy strona używa kontekstu obrazu, czy dokumentuPrzetestuj obsługiwany sposób osadzania i jego zasady dostępu do zasobów
Wynik różni się po zmianie rendereraWybrany renderer i strukturę jego SVGPonownie sprawdź wyeksportowany XML i końcowy wygląd

Oficjalna strona dotycząca wyjścia SVG wskazuje, że wynik Cairo może różnić się od wbudowanego wyjścia SVG pod względem czytelności XML i możliwości przekształcania. Nie testowaliśmy tutaj Cairo. W projekcie umożliwiającym odtworzenie wyniku wybieraj renderer jawnie i powtórz sprawdzenie dołączania zasobów, gdy go zmienisz.

Odzyskaj grafikę na etapie przygotowania, gdy utracisz jej źródło

PerfectVector może pomóc, gdy odpowiedni motyw ilustracyjny zachował się tylko jako PNG lub skan. Proces odzyskiwania grafiki naukowej dostarcza propozycję grafiki wektorowej do sprawdzenia przed użyciem. Przytnij obraz do motywu, sprawdź jego sylwetkę i puste przestrzenie, a następnie zweryfikuj granice i wymiary pobranego SVG, zanim dodasz go do grafu.

Takie odzyskiwanie nie odtwarza relacji między węzłami, znaczenia strzałek ani etykiet DOT. Zachowaj je w źródle grafu. Użyj oryginalnego SVG, jeśli jest dostępny, przerysuj prosty symbol, gdy łatwiej będzie go utrzymywać, a fotografie zachowaj jako obrazy rastrowe. Omówienie wektoryzacji obrazów wyjaśnia granice odzyskiwania.

Inne narzędzia do diagramów inaczej dołączają niestandardową grafikę. Poradnik dotyczący ikon Mermaid omawia zarejestrowane dane ikon, natomiast artykuł o niestandardowej grafice SVG w draw.io rozróżnia zaimportowany obraz i natywny szablon kształtu. Uwzględnij wymagania narzędzia docelowego podczas przygotowywania grafiki.

Najczęściej zadawane pytania

Czy wyjście SVG z Graphviz automatycznie zawiera obraz mojego węzła? W przetestowanym wbudowanym wyjściu SVG diagram zawiera odwołanie do obrazu w osobnym pliku motif.svg. Sprawdź własny wynik i przekaż jego zależności lub zastosuj przetestowany etap dołączania zasobów.

Czy svg_inline scala ścieżki obrazu SVG z grafem? Nie. To tryb wyjścia bez nagłówka, przeznaczony do umieszczenia w HTML. W naszym teście zachował zewnętrzne odwołanie do motif.svg.

Czy samowystarczalny SVG to to samo co natywna, edytowalna geometria węzła? Nie. Przykład z dołączonymi danymi zachowuje element obrazu zawierający bajty SVG. Struktura grafu pozostaje w DOT, a edytor odbiorcy decyduje o tym, jak udostępnia tę grafikę.

Źródła

  1. Graphviz — image — Lokalne zasoby obrazów węzłów i wymagane wymiary SVG.
  2. Graphviz — imagescale — Dopasowanie proporcjonalne i niezależne skalowanie szerokości oraz wysokości.
  3. Graphviz — SVG output — Wbudowane wyjście i wyjście Cairo oraz znaczenie svg_inline.
  4. Viz.js — API — Metadane rozmiaru obrazu, jawne jednostki i wywołania renderowania SVG.
  5. MDN — SVG as an image — Ograniczenia zasobów zewnętrznych w kontekstach obrazu i różnica względem osadzania dokumentów.

Przetestuj jeden węzeł w docelowym procesie przekazywania, zanim przygotujesz całą bibliotekę grafiki. Jeśli pozostał tylko motyw rastrowy, przygotuj propozycję grafiki SVG, sprawdź jej prześwity i proporcje, a następnie dodaj ją do grafu DOT i zweryfikuj przeniesiony wynik lub wynik z dołączonymi zasobami w docelowym programie do wyświetlania.

Więcej z bloga

Zacznij od czystszego SVG,
który łatwiej edytować