How to properly show generated SVG from PHP - php

I am generating svg qr codes via php and getting result in php file the following code:
generate-svg.php
<?
include("../qrcode/qrlib.php");
QRcode::svg('Example');
?>
And I see in HTML code in browser:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" width="111" height="111" viewBox="0 0 111 111">
<desc></desc>
<rect width="111" height="111" fill="#ffffff" cx="0" cy="0" />
<defs>
<rect id="p" width="3" height="3" />
</defs>
<g fill="#000000">
<use x="12" y="12" xlink:href="#p" />
</g>
</svg>
Then I need to paste this svg code as an image into another php file. I do it like this:
svg.php
<?
echo '<object type="image/svg+xml" data="generate-svg.php" class="icon-qr"></object>';
?>
But I need to get the svg code and paste it as a picture. How can I do that?
If I use
echo file_get_contents('generate-svg.php');
I see this HTML code:
<!--?
include("../qrcode/qrlib.php");
QRcode::svg('Example');
?-->
<html><head></head><body></body></html>

One of the ways is to display the SVG by echoing the generated SVG thru the PHP file_get_contents command
So say if the generate-svg.php is like the following (As an example, I generate a red circle):
DEMO
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" width="111" height="111" viewBox="0 0 111 111">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
Then use the following to display it (along with other things you want to display):
DEMO
<?php
echo "This is a line <br>";
echo file_get_contents("generate-svg.php");
echo "<br>This is another line <br>";
?>
[Additional Point]
If you are rendering the SVG thru a PHP script, then if you use file_get_contents on a local file it will faithfully display the PHP script instead of executing it unless you use a URL starting with http:// or https://. You can choose to use something like (assuming that the php script is named as generate-svg2.php) the following :
echo '<img src="generate-svg2.php">';
So, the generate-svg2.php can be:
DEMO
<?php
include('./phpqrcode-master/qrlib.php');
// outputs image directly into browser, as PNG stream
echo QRcode::svg('SO is good');
?>
then the script to display it (along with other HTML elements) can be :
DEMO
<?php
echo "This is a line <br>";
//echo file_get_contents("generate-svg.php");
echo '<img src="generate-svg2.php">';
echo "<br>This is another line x<br>";
?>

First something with Output Control Functions:
ob_start();
require 'generate-svg.php';
$svg = ob_get_clean();
file_put_contents('svgs/generated-svg.svg', $svg);
Then:
<img src="/svgs/generated-svg.svg" height="200" width="200" alt="QR code">

Related

problems using php and dompdf to output svg

I'm trying to display some SVG as a PDF with Dompdf, but the PDF output is blank. Can someone tell me what I need to change?
Here is some example code which produces the error.
<?php
use Dompdf\Dompdf;
$dompdf = new Dompdf();
$statement = '
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: boxes_and_circles Pages: 1 -->
<svg width="422pt" height="448pt"
viewBox="0.00 0.00 421.50 448.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 444)">
<title>boxes_and_circles</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-444 417.5,-444 417.5,4 -4,4"/>
<!-- A -->
<g id="node1" class="node">
<title>A</title>
<polygon fill="none" stroke="#000000" points="136,-353.5 82,-353.5 82,-317.5 136,-317.5 136,-353.5"/>
<text text-anchor="middle" x="109" y="-331.3" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#000000">A</text>
</g>
<!-- 1 -->
<g id="node7" class="node">
<title>1</title>
<ellipse fill="none" stroke="#000000" cx="102" cy="-234.5" rx="32.5" ry="32.5"/>
<text text-anchor="middle" x="102" y="-230.3" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#000000">1</text>
</g>
<!-- A->1 -->
<g id="edge1" class="edge">
<title>A->1</title>
<path fill="none" stroke="#000000" d="M107.7485,-317.4432C106.9701,-306.2112 105.9343,-291.266 104.9565,-277.1578"/>
<polygon fill="#000000" stroke="#000000" points="108.4424,-276.8319 104.2593,-267.0979 101.4591,-277.316 108.4424,-276.8319"/>
</g>
</svg>
';
$dompdf->loadHtml($statement);
// Render the HTML as PDF
$dompdf->render();
//echo($statement);
// Output the generated PDF to Browser
$dompdf->stream();
?>
If I run echo($statement), the browser outputs this :
The PDF output by Dompdf is completely blank.
If I instead use $statement = "hello, world!", Dompdf correctly outputs hello, world! in the PDF.
What do I need to do to output this SVG image as PDF with Dompdf?
I got it to work by deleting the first line <?xml version="1.0" encoding="UTF-8" standalone="no"?>
Also, in the real code, I had to delete all links that were embedded in the svg.
Furthermore, I had to put the svg into an img tag, and add this base64_encode part as follows :
$html = '<img src="data:image/svg+xml base64,'.base64_encode($statement).'" width="100" height="100" />';
$dompdf->loadHtml($html);
$dompdf->render();
$dompdf->stream();
This was from trial and error, and through reading another post Dompdf not generating pdf properly from SVG

SVG xlink:href always pulling image from the last record in a Wordpress loop

I'm using an image pulled from a user entry to fill an SVG element - i.e. staff portrait on a team page. Currently the image displayed is always from the last user entry in the (Wordpress) loop.
Here's the relevant part of my template:
foreach ( $allusers as $user ):
$image = get_field('headshot', $user );
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 221 300" style="enable-background:new 0 0 221 300;" xml:space="preserve">
<style type="text/css">
.st4{fill:url(#img-<?php echo $user->ID; ?>);}
</style>
<defs>
<pattern id="img-<?php echo $user->ID; ?>" height="100%" width="100%" patternContentUnits="objectBoundingBox" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid slice">
<image xlink:href="<?php echo $image['url']; ?>" width="1" height="1" preserveAspectRatio="xMidYMid slice" />
</pattern>
</defs>
<circle class="st4" cx="110.5" cy="150.4" r="78.5"/>
</svg>
If I simply do a:
<img src="<?php echo $image['url']; ?>">
This shows the correct image for each entry, so I'm assuming it's to do with the xlink:href part.
How can I get the correct image to show in the SVG element?

SVG in PHP Error: Opening and ending tag mismatch: meta line 0 and head

I have a problem when i try to create an SVG in PHP. I manage to create SVG when i set the string manually (like: $string = "Hello";), but when i try to get a string from another page using sessions i get the error "error on line 3 at column 8: Opening and ending tag mismatch: meta line 0 and head".
<?php
//$string = "HEEEIA"; <--- It works when i manually insert the string text
$string = $_SESSION['text-from-last-page'];
header('Content-type: image/svg+xml');
echo '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
<text x="80" y="90" style="font:size: 8">' . $string . '</text>
</svg>';
?>

Load SVG file on PHP server side

I want to load the svg file based on a parameter.
e.g., if Parameter = A then load A.svg, if parameter = B then load B.svg, and so on..
For this case, I'm using Codeigniter, so on Model I load the svg file like this:
Model.php
$svgTag = '<div id="svg-content" >'
. '<input type="radio" name="test"/>'
. file_get_contents( APPPATH. 'views/svg/'.$param.'.svg', TRUE)
. '</div>'
After that, I load the $svgTag on view.
View.php
<html>
<body>
<?php echo $svgTag; ?>
</body>
</html>
My expectation is the svg file will be loaded in the div#svg-content, but the actual result is that svg is loaded after tag <body> like this:RESULT
<html>
<body>
<svg>........</svg> <!-- Loaded SVG File -->
<div id="svg-content" >
<input type="radio" name="test"/>
</div>
</body>
</html>
I wanna add the event on radio button, IF it's clicked, then change the color of SVG image.
IF I use <object> I cannot apply this style.
NOTE: This is the content of file that I try to load:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1280 800" enable-background="new 0 0 1280 800" xml:space="preserve">
<g>
<polygon points="358.3,524.2 328.3,524.2 328.3,665 415,665 415,640 358.3,640 "/>
</g>
</svg>
Is there any way to get the result like this..?
<html>
<body>
<div id="svg-content" >
<input type="radio" name="test"/>
<svg>........</svg> <!-- Loaded SVG File -->
</div>
</body>
</html>
Use the <img> tag to embed it in page, this will give you full controle of placement in html
$svgTag = '<div id="svg-content" >'
. '<input type="radio" name="test"/>'
. '<img src="'.APPPATH. 'views/svg/'.$param.'.svg'.'" alt="">'
. '</div>'
Here is awesome answer on which to use <img>, <object>, or <embed> for SVG files?
Finally I found the answer.
It should be use fread() function to load the SVG file.So, it should be like this:
$fh = fopen(APPPATH. 'views/svg/'.$param.'.svg', 'r');
$svg_file = fread($fh, 25000);
$svgTag = '<div id="svg-content" >'
. '<input type="radio" name="test"/>'
. $svg_file
. '</div>'

Imagick SVG cannot load the image

I am getting the trouble about converting the SVG to image by PHP Imagick library.
Here is my code:
$svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg style="overflow: hidden; position: relative;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="754" version="1.1" height="565">
<defs></defs>
<image transform="matrix(1,0,0,1,0,0)" preserveAspectRatio="none" x="0" y="0" width="754" height="565" xlink:href="http://1439.demo.tekk3.com/wp-content/uploads/2012/10/capapix_Harley_Davidson_FLSTCI_-_Heritage_Classic.jpg"></image>
</svg>';
$im = new Imagick();
$im->readImageBlob($svg);
$im->setImageFormat("jpeg");
$im->writeimage($attached_file);
$im->clear();
$im->destroy();
And the result is an image with only white background. There are no any other images as SVG showing.
If i put the text tag into the SVG string, only the text rendered in the white background. The image is still missing.
I have installed the php5-imagick, libxml2, librsvg2-bin
Are there any other extensions that i need to install to get the correct result?
Or is there any problem in my code?
I found workaround. I use base64 image content instand of image path.
$svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="754" version="1.1" height="565">
<image x="0" y="0" width="754" height="565" xlink:href="'.imageToBase64('icons-weather_01.png').'"></image>
</svg>';
function imageToBase64($path) {
$type = pathinfo($path, PATHINFO_EXTENSION);
$data = file_get_contents($path);
return 'data:image/' . $type . ';base64,' . base64_encode($data);
}
It if possible to use local image or web url.
You should not use link to the image if you want Imagick to consider your images when converting.
instead use the base64 encoded data corresponding to those images. this will work.
I had this problem and ended up here, didn't see the solution in the comment (had to click on 'show more comments') until I'd fixed it myself anyway, so thought it might be worth posting it as an answer (as well as upvoting):
As #Phuc-Pham discovered, the problem is that Imagick wants the whole server path, not a path relative to CWD or HTTP document root in the href attribute.
So using his code above the solution should be something along the lines of:
$svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg style="overflow: hidden; position: relative;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="754" version="1.1" height="565">
<defs></defs>
<image transform="matrix(1,0,0,1,0,0)" preserveAspectRatio="none" x="0" y="0" width="754" height="565" xlink:href="/path/to/htdocs/wp-content/uploads/2012/10/capapix_Harley_Davidson_FLSTCI_-_Heritage_Classic.jpg"></image>
</svg>';
Hope that's useful.

Categories