PerfectVector
โดย Irene Kimอ่าน 4 นาที

ภาพ SVG ใน Graphviz: ย้ายภาพในโหนดได้ครบ

เพิ่มภาพ SVG ในโหนด Graphviz ตรวจการอ้างอิงภาพ และทดสอบชุดแอสเซ็ตครบถ้วนเทียบกับแผนภาพที่ย้ายเดี่ยวและสำเนาส่งมอบที่มีข้อมูลครบในตัว

ในหน้านี้

แผนภาพ Graphviz อาจมีโหนดและลูกศรเป็นเวกเตอร์ ขณะที่ภาพที่กำหนดเองในโหนดยังคงอ้างอิงไฟล์ภาพแยก หากภาพนั้นหายหลังย้าย SVG ให้ตรวจการอ้างอิงภาพที่สร้างขึ้นก่อนเปลี่ยนตัวภาพ สิ่งที่ขาดอาจเป็นชุดไฟล์สำหรับส่งมอบ

ในผลลัพธ์ SVG ที่ทดสอบด้านล่าง Graphviz เก็บ motif.svg เป็นภาพที่ลิงก์ไว้ ชุดไฟล์ครบถ้วนแสดงภาพได้ แต่เมื่อย้ายเฉพาะแผนภาพ ภาพจะหาย สำเนาที่จัดแพ็กเกจอย่างชัดเจนบรรจุไบต์ของภาพและแสดงได้ในการทดสอบเบราว์เซอร์เดียวกัน ขั้นตอนจัดแพ็กเกจนี้ยังคงองค์ประกอบ image ของ SVG ไว้ ไม่ได้เปลี่ยนลวดลายเป็นพาธของกราฟโดยตรง

เก็บต้นทาง DOT ไว้สำหรับชื่อโหนดและความสัมพันธ์ เก็บไฟล์ภาพต้นฉบับแยก แล้วทดสอบผลลัพธ์จริงผ่านโปรแกรมดูหรือกระบวนการเผยแพร่ที่จะรับไฟล์นั้น

แยกโหนด ภาพในโหนด และการอ้างอิงไฟล์

แอตทริบิวต์ image ของ Graphviz ระบุชื่อภาพที่แสดงภายในโหนด ไม่ได้แทนตัวตนหรือความสัมพันธ์ของโหนดในกราฟ เอกสารกำหนดให้ต้นทางมีขนาด สำหรับภาพ SVG ให้ระบุ width และ height ชัดเจนพร้อมหน่วยที่เหมาะสม

ลวดลายต้นฉบับนี้วาดด้วยสองพาธในพื้นที่พิกัด 96 คูณ 64 ขนาดภายนอกคือ 96pt คูณ 64pt ส่วนโหนดที่ครอบภาพและลูกศรเป็นสิ่งที่ Graphviz สร้าง

ส่วนเก็บรักษาในปัญหาที่อาจเกิด
ชื่อโหนด ป้ายข้อความ และเส้นเชื่อมต้นทาง DOTความสัมพันธ์หรือข้อความในกราฟผิด
ลวดลายที่กำหนดเองไฟล์ SVG ต้นฉบับของภาพไม่มีขนาด รายละเอียดไม่เหมาะ หรือสัดส่วนผิด
ลิงก์จากแผนภาพไปยังลวดลายการอ้างอิง image ใน SVG ที่ส่งออกไม่มีภาพที่พาธปลายทางซึ่งการอ้างอิงชี้ไป
ตำแหน่งและขนาดสุดท้ายผลลัพธ์ตัวเรนเดอร์และโปรแกรมดูปลายทางถูกครอบ ยืด หรือมีสิ่งที่อ้างอิงซึ่งไม่รองรับ

องค์ประกอบ image อาจอ้างอิงภาพ SVG หรือพิกเซลก็ได้ หากต้องตรวจต้นทางราสเตอร์ ให้ใช้คู่มือวินิจฉัยภาพฝังใน SVG แยกต่างหาก ชื่อไฟล์ที่ลงท้าย .svg ไม่เพียงพอจะยืนยันเนื้อหาของทั้งสองไฟล์

รันตัวอย่างเล็กด้วยตัวเรนเดอร์ที่ระบุชัด

เราใช้ @viz-js/viz 3.31.0 ซึ่งเป็น WebAssembly build ที่รายงาน Graphviz 16.1.0 ร่วมกับเอนจินจัดวาง dot และผลลัพธ์ SVG ในตัว นี่เป็นการทดสอบ build และตัวเรนเดอร์นั้น ไม่ได้อ้างว่าการติดตั้ง Graphviz ทุกแบบโหลดภาพเหมือนกัน

ในโฟลเดอร์โครงการ Node.js ใหม่ ติดตั้งแพ็กเกจเวอร์ชันที่กำหนด:

npm install @viz-js/viz@3.31.0

บันทึกภาพต้นฉบับเป็น 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>

บันทึกกราฟเป็น 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];
}

จากนั้นบันทึกโค้ดนี้เป็น render.mjs และรัน node render.mjs จากโฟลเดอร์นั้น:

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`);

เอกสาร API ของ Viz.js อธิบายตัวเลือก images ว่าเป็นข้อมูลขนาดภาพ การส่งข้อมูลนี้บอกระบบจัดวางเกี่ยวกับภาพชื่อนี้ ไม่ได้ใส่ไบต์ของไฟล์ลงในผลลัพธ์ หน่วยที่ระบุชัดช่วยเลี่ยงการตีความตัวเลขที่ไม่มีหน่วยเป็นพิกเซล CSS โดย API ใช้พอยต์สำหรับขนาดที่ไม่มีหน่วย

สำหรับ Graphviz ที่ติดตั้งแบบ native เอกสาร image ทางการอธิบายทรัพยากรภาพในเครื่องและขนาดที่อ่านจากไฟล์ต้นทาง อย่าคัดลอกการตั้งค่าเมทาดาทาของ WebAssembly ไปใช้กับคำสั่ง native แล้วคิดว่ามีกลไกโหลดเหมือนกัน

ตรวจสิ่งที่ตัวเรนเดอร์เขียนออกมา

SVG ที่เราสร้างมีองค์ประกอบนี้:

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

ขนาดและตำแหน่งเป็นค่าที่สังเกตจากตัวอย่างนี้ ส่วนที่กำหนดความต้องการในการส่งมอบคือ xlink:href="motif.svg" ผลลัพธ์ยังต้องมีทรัพยากรที่พาธสัมพัทธ์นั้น

คัดลอกเฉพาะ diagram.svg ไปอีกโฟลเดอร์โดยไม่ย้ายภาพตาม แล้วเปรียบเทียบกับชุดไฟล์ครบถ้วน เราให้บริการทั้งสองโฟลเดอร์ผ่าน HTTP ในเครื่อง และแสดง SVG แต่ละไฟล์เป็นเอกสารผ่านองค์ประกอบ HTML object

แผนภาพ SVG จาก Graphviz จริงสามแบบ: มีภาพในชุดแอสเซ็ตครบ ภาพหายหลังย้ายเฉพาะแผนภาพ และมีภาพในสำเนาที่ฝังไบต์ภาพ SVG
ไฟล์กลางมีเรขาคณิตกราฟและการอ้างอิงภาพเหมือนไฟล์ซ้าย แต่ไม่มีลวดลายที่พาธที่อ้างถึง สำเนาด้านขวาบรรจุภาพนั้นอย่างชัดเจนเป็น data URL ของ SVG

กรอบโหนดและลูกศรที่สร้างขึ้นยังอยู่เมื่อภาพที่ลิงก์หาย การสร้างการจัดวางกราฟใหม่ไม่ได้เติมไฟล์ที่ขาด ให้คืนแอสเซ็ตไปยังตำแหน่งที่คาด ส่งมอบทั้งชุด หรือเลือกขั้นตอนจัดแพ็กเกจที่เหมาะกับปลายทาง

การเปิด SVG เป็นเอกสารกับการแสดงผ่าน HTML img เป็นการทดสอบคนละแบบ คำแนะนำ SVG ในฐานะภาพของ MDN อธิบายว่าบริบทภาพอาจจำกัดทรัพยากรภายนอก ขณะที่ data URL ฝังข้อมูลไว้ภายในได้ ข้อจำกัดของบริบทภาพที่เอกสารอธิบายไม่ใช้กับเอกสาร SVG ที่เปิดโดยตรง หรือการฝังเอกสารผ่าน object และ iframe ตรวจบริบทการส่งมอบที่ใช้งานจริง

จัดแพ็กเกจลวดลายง่าย ๆ นี้อย่างชัดเจน

สำหรับลวดลายต้นฉบับที่มีข้อมูลครบในตัวนี้ สคริปต์ต่อไปนี้แทนการอ้างอิงที่ทราบแน่นอนหนึ่งตำแหน่งด้วยไบต์ SVG ของไฟล์ บันทึกเป็น package.mjs แล้วรันหลังเรนเดอร์:

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

นี่คือตัวอย่างจัดแพ็กเกจแบบเจาะจง ไม่ใช่ตัวฝัง SVG ทั่วไป โดยจัดการการอ้างอิงที่ทราบในผลลัพธ์นี้และลวดลายที่ไม่มีฟอนต์ ภาพ สไตล์ชีต หรือสิ่งที่อ้างอิงภายนอกอื่น ภาพที่ซับซ้อนกว่านี้ต้องตรวจสิ่งที่อ้างอิงของตนเอง

สำเนาที่จัดแพ็กเกจแสดงลวดลายได้ในการทดสอบเบราว์เซอร์ของเรา เมื่อเปรียบเทียบสตริงผลลัพธ์สองชุดโดยปิดบังค่าอ้างอิงภาพ พบว่าเรขาคณิตกราฟเหมือนกัน ไฟล์ยังมีองค์ประกอบ image หนึ่งตัว แต่การอ้างอิงเริ่มด้วย data:image/svg+xml;base64, แล้ว

การฝังไบต์ภาพ SVG อาจกำจัดการพึ่งพาพาธไฟล์นี้ โดยคงต้นทางเวกเตอร์ของภาพไว้ แต่ไม่ได้ทำให้ภาพเป็นรูปร่างโหนด Graphviz โดยตรง ไม่ได้เพิ่มจุดเชื่อมต่อภายใน และไม่ได้รับประกันว่าโปรแกรมแก้ไขอื่นจะเปิดพาธให้แก้โดยตรงได้ ทดสอบพฤติกรรมการนำเข้าของผู้รับ

อย่าสับสน svg_inline กับการฝังภาพ เอกสารผลลัพธ์ SVG ของ Graphviz อธิบายว่าเป็นผลลัพธ์ไม่มีส่วนหัวสำหรับใส่ใน HTML ในกราฟเดียวกันของเรา การเลือก svg_inline ยังสร้างการอ้างอิง motif.svg โหมดผลลัพธ์ไม่ได้จัดแพ็กเกจภาพให้

แยกขนาดและสเกลออกจากความสามารถในการย้ายไฟล์

เอกสารอ้างอิง imagescale ของ Graphviz แยกการปรับภาพให้พอดีโหนดออกจากขนาดตามธรรมชาติของต้นทาง ในตัวอย่างนี้ imagescale=true ปรับสเกลเท่ากันทุกทิศเพื่อให้พอดี ตัวเลือก both ปรับความกว้างและความสูงแยกกัน จึงอาจเปลี่ยนสัดส่วน

หากลวดลายแสดงแต่ยืด ให้ตรวจตัวเลือกสเกล หากแสดงเพียงบางส่วน ให้ตรวจขอบเขตของภาพเองและพื้นที่ในโหนด หากหายหลังย้ายไฟล์ ให้ตรวจพาธทรัพยากรก่อน คู่มือขนาด SVG อธิบายความต่างระหว่างขนาดที่ประกาศกับพิกัดภาพ

อาการสิ่งที่ตรวจเป็นอันดับแรกวิธีแก้ที่ควรลอง
ภาพหายหลังย้ายแผนภาพการอ้างอิง image ที่สร้างและตำแหน่งแอสเซ็ตสัมพัทธ์คืนชุดไฟล์หรือจัดแพ็กเกจต้นทางที่ทดสอบแล้วอย่างชัดเจน
การจัดวางกราฟทำงาน แต่ไม่มีภาพขนาดต้นทางและการตั้งค่าภาพเฉพาะ buildยืนยันไฟล์และเมทาดาทาภาพที่ build นั้นต้องการ
ลวดลายดูยืดการตั้ง imagescale และสัดส่วนที่ตั้งใจใช้การปรับให้พอดีแบบรักษาสัดส่วนหากไม่ต้องการความบิดเบี้ยว
SVG ใช้โดยตรงได้ แต่ไม่แสดงในเว็บหน้าใช้บริบทภาพหรือบริบทเอกสารทดสอบวิธีฝังที่รองรับและนโยบายทรัพยากรของวิธีนั้น
ผลลัพธ์ต่างหลังเปลี่ยนตัวเรนเดอร์ตัวเรนเดอร์ที่เลือกและโครงสร้าง SVGตรวจ XML ที่ส่งออกและรูปลักษณ์สุดท้ายใหม่

หน้าผลลัพธ์ SVG ทางการระบุว่าผลลัพธ์ Cairo อาจอ่าน XML และนำไปแปลงพิกัดได้ต่างจาก SVG ในตัว เราไม่ได้ทดสอบ Cairo ในบทความนี้ ระบุตัวเรนเดอร์ให้ชัดในโครงการที่ต้องทำซ้ำได้ และตรวจการจัดแพ็กเกจใหม่เมื่อเปลี่ยนตัวเรนเดอร์

สร้างภาพกลับขึ้นมาก่อนใช้งานเมื่อต้นทางสูญหาย

PerfectVector ช่วยได้เมื่อลวดลายภาพประกอบที่เหมาะสมเหลือเพียง PNG หรือภาพสแกน กระบวนการกู้ภาพประกอบวิทยาศาสตร์ ให้เวกเตอร์สำหรับตรวจประเมินก่อนใช้ ครอบเฉพาะลวดลาย ตรวจขอบรูปและพื้นที่ว่าง แล้วตรวจขอบเขตและขนาดของ SVG ที่ดาวน์โหลดก่อนเพิ่มในกราฟ

การสร้างกลับนี้ไม่ได้คืนความสัมพันธ์โหนด ความหมายของลูกศร หรือป้าย DOT เก็บสิ่งเหล่านั้นในต้นทางกราฟ ใช้ SVG ต้นฉบับเมื่อมี วาดสัญลักษณ์ง่าย ๆ ใหม่หากดูแลได้สะดวกกว่า และเก็บภาพถ่ายเป็นราสเตอร์ ภาพรวมการแปลงภาพเป็นเวกเตอร์ อธิบายขอบเขตของการสร้างกลับ

เครื่องมือแผนภาพอื่นจัดแพ็กเกจภาพที่กำหนดเองต่างกัน คู่มือไอคอน Mermaid อธิบายข้อมูลไอคอนที่ลงทะเบียน ส่วนภาพ SVG ที่กำหนดเองใน draw.io แยกภาพนำเข้าออกจาก stencil ของโปรแกรม นำข้อกำหนดปลายทางมาพิจารณาตั้งแต่เตรียมภาพ

คำถามที่พบบ่อย

ผลลัพธ์ SVG ของ Graphviz รวมภาพในโหนดให้อัตโนมัติหรือไม่? ในผลลัพธ์ SVG ในตัวที่ทดสอบ แผนภาพมีการอ้างอิง image ไปยังไฟล์ motif.svg แยก ตรวจผลลัพธ์ของคุณเอง แล้วส่งมอบไฟล์ที่ต้องอ้างอิงหรือใช้ขั้นตอนจัดแพ็กเกจที่ทดสอบแล้ว

svg_inline ผสานพาธของภาพ SVG เข้าในกราฟหรือไม่? ไม่ เป็นโหมดผลลัพธ์ไม่มีส่วนหัวสำหรับใส่ใน HTML ในการทดสอบของเรายังคงการอ้างอิง motif.svg ภายนอกไว้

SVG ที่มีข้อมูลครบในตัวเหมือนกับเรขาคณิตโหนดที่แก้ไขได้โดยตรงหรือไม่? ไม่ ตัวอย่างที่จัดแพ็กเกจยังคงองค์ประกอบ image ที่บรรจุไบต์ SVG โครงสร้างกราฟอยู่ใน DOT และโปรแกรมแก้ไขปลายทางเป็นผู้กำหนดว่าจะเปิดภาพนั้นให้ใช้งานอย่างไร

แหล่งอ้างอิง

  1. Graphviz — image — ทรัพยากรภาพโหนดในเครื่องและขนาด SVG ที่จำเป็น
  2. Graphviz — imagescale — การปรับให้พอดีแบบรักษาสัดส่วนและการปรับความกว้าง/ความสูงแยกกัน
  3. Graphviz — ผลลัพธ์ SVG — ผลลัพธ์ในตัวกับ Cairo และความหมายของ svg_inline
  4. Viz.js — API — เมทาดาทาขนาดภาพ หน่วยชัดเจน และการเรียกเรนเดอร์ SVG
  5. MDN — SVG ในฐานะภาพ — ข้อจำกัดทรัพยากรภายนอกในบริบทภาพและความต่างจากการฝังเอกสาร

ทดสอบโหนดหนึ่งผ่านกระบวนการส่งมอบก่อนเตรียมคลังภาพทั้งชุด หากเหลือเพียงลวดลายราสเตอร์ เตรียมภาพ SVG สำหรับประเมิน ตรวจช่องว่างและสัดส่วน แล้วเพิ่มในกราฟ DOT และตรวจผลลัพธ์ที่ย้ายหรือจัดแพ็กเกจแล้วในโปรแกรมดูปลายทาง

เพิ่มเติมจากบล็อก

เริ่มต้นด้วย SVG ที่เรียบร้อยขึ้น
และแก้ไขได้ง่ายกว่า