From 88a635704b78efb6265ed4c918bcc5d13634cdb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20St=C3=B6ckel?= Date: Wed, 18 Jan 2017 15:11:00 +0100 Subject: [PATCH 1/2] GraphViz: add charset option to base64 image string. --- src/GraphViz.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/GraphViz.php b/src/GraphViz.php index 152d473..8149f25 100644 --- a/src/GraphViz.php +++ b/src/GraphViz.php @@ -38,13 +38,16 @@ class GraphViz * @see GraphViz::createScript() */ private $formatIndent = ' '; + + private $charset; const DELAY_OPEN = 2.0; const EOL = PHP_EOL; - public function __construct() + public function __construct($charset = "UTF-8") { + $this->charset = $charset; if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $this->executable = 'dot.exe'; } @@ -157,7 +160,7 @@ public function createImageSrc(Graph $graph) { $format = ($this->format === 'svg' || $this->format === 'svgz') ? 'svg+xml' : $this->format; - return 'data:image/' . $format . ';base64,' . base64_encode($this->createImageData($graph)); + return 'data:image/' . $format . ';base64;charset=' . $this->charset. ',' . base64_encode($this->createImageData($graph)); } /** From 115e65ee4390f6b5f79786a87d3975d3d6092a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Tue, 9 Oct 2018 12:56:11 +0200 Subject: [PATCH 2/2] Use UTF-8 encoding (Unicode) by default and respect charset attribute --- .travis.yml | 5 +++++ README.md | 23 ++++++++++++++++++++--- examples/02-html.php | 25 +++++++++++++++++++++++++ examples/02-html.png | Bin 0 -> 5767 bytes src/GraphViz.php | 13 ++++++------- tests/GraphVizTest.php | 30 ++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 examples/02-html.php create mode 100644 examples/02-html.png diff --git a/.travis.yml b/.travis.yml index 30be35b..14eeac7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,11 @@ matrix: sudo: false +addons: + apt: + packages: + - graphviz + install: - composer install --no-interaction diff --git a/README.md b/README.md index 91f25dc..47499ac 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,10 @@ GraPHP attributes as documented below. For the full list of all GraphViz attributes, please refer to the [GraphViz documentation](https://graphviz.gitlab.io/_pages/doc/info/attrs.html). -Note that all [attributes](#attributes) will be quoted and escaped by default, -so a `>` will appear as-is and will not be interpreted as HTML. See also -[HTML-like labels](#html-like-labels) below for more details. +Note that all attributes use UTF-8 encoding (Unicode) and will be quoted and +escaped by default, so a `ö` and `>` will appear as-is and will not be +interpreted as HTML. See also [HTML-like labels](#html-like-labels) below for +more details. ### Graph attributes @@ -82,6 +83,22 @@ $graph->setAttribute('graphviz.graph.bgcolor', 'transparent'); is done for consistency reasons with respect to default vertex and edge attributes as documented below. +For example, the `rankdir` attribute can be used to change the orientation to +horizontal mode (left to right) like this: + +```php +$graph = new Fhaculty\Graph\Graph(); +$graph->setAttribute('graphviz.graph.rankdir', 'LR'); + +$hello = $graph->createVertex('hello'); +$world = $graph->createVertex('wörld'); +$hello->createEdgeTo($world); +``` + +![html graph example](examples/02-html.png) + +See also the [examples](examples/). + ### Vertex attributes GraphViz supports a number of attributes on each vertex instance (GraphViz calls diff --git a/examples/02-html.php b/examples/02-html.php new file mode 100644 index 0000000..0207520 --- /dev/null +++ b/examples/02-html.php @@ -0,0 +1,25 @@ +setAttribute('graphviz.graph.rankdir', 'LR'); + +$hello = $graph->createVertex('hello'); +$world = $graph->createVertex('wörld'); +$hello->createEdgeTo($world); + +$graphviz = new Graphp\GraphViz\GraphViz(); +$graphviz->setFormat('svg'); + +echo ' + + +hello wörld + +' . $graphviz->createImageHtml($graph) . ' + + +'; diff --git a/examples/02-html.png b/examples/02-html.png new file mode 100644 index 0000000000000000000000000000000000000000..847cb2a220c62049b9c5112443e54498788c49cb GIT binary patch literal 5767 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 literal 0 HcmV?d00001 diff --git a/src/GraphViz.php b/src/GraphViz.php index 8149f25..a31eb22 100644 --- a/src/GraphViz.php +++ b/src/GraphViz.php @@ -6,7 +6,6 @@ use Graphp\Algorithms\Groups; use Graphp\Algorithms\Degree; use Fhaculty\Graph\Exception\UnexpectedValueException; -use Fhaculty\Graph\Exception\InvalidArgumentException; use Fhaculty\Graph\Edge\Base as Edge; use \stdClass; use Fhaculty\Graph\Attribute\AttributeBagNamespaced; @@ -38,16 +37,13 @@ class GraphViz * @see GraphViz::createScript() */ private $formatIndent = ' '; - - private $charset; const DELAY_OPEN = 2.0; const EOL = PHP_EOL; - public function __construct($charset = "UTF-8") + public function __construct() { - $this->charset = $charset; if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $this->executable = 'dot.exe'; } @@ -158,9 +154,12 @@ public function createImageData(Graph $graph) */ public function createImageSrc(Graph $graph) { - $format = ($this->format === 'svg' || $this->format === 'svgz') ? 'svg+xml' : $this->format; + $format = $this->format; + if ($this->format === 'svg' || $this->format === 'svgz') { + $format = 'svg+xml;charset=' . $graph->getAttribute('graphviz.graph.charset', 'UTF-8'); + } - return 'data:image/' . $format . ';base64;charset=' . $this->charset. ',' . base64_encode($this->createImageData($graph)); + return 'data:image/' . $format . ';base64,' . base64_encode($this->createImageData($graph)); } /** diff --git a/tests/GraphVizTest.php b/tests/GraphVizTest.php index a73300a..bf76a41 100644 --- a/tests/GraphVizTest.php +++ b/tests/GraphVizTest.php @@ -227,4 +227,34 @@ public function testEdgeLabels() $this->assertEquals($expected, $this->graphViz->createScript($graph)); } + + public function testCreateImageSrcWillExportPngDefaultFormat() + { + $graph = new Graph(); + + $src = $this->graphViz->createImageSrc($graph); + + $this->assertStringStartsWith('data:image/png;base64,', $src); + } + + public function testCreateImageSrcAsSvgWithUtf8DefaultCharset() + { + $graph = new Graph(); + + $this->graphViz->setFormat('svg'); + $src = $this->graphViz->createImageSrc($graph); + + $this->assertStringStartsWith('data:image/svg+xml;charset=UTF-8;base64,', $src); + } + + public function testCreateImageSrcAsSvgzWithExplicitIsoCharsetLatin1() + { + $graph = new Graph(); + $graph->setAttribute('graphviz.graph.charset', 'iso-8859-1'); + + $this->graphViz->setFormat('svgz'); + $src = $this->graphViz->createImageSrc($graph); + + $this->assertStringStartsWith('data:image/svg+xml;charset=iso-8859-1;base64,', $src); + } }