منبع اصلی نوشتار زیر در این لینک قرار دارد

SVG manipulation using php and xpath

(This is not a KDE related post)
I\’ve had very little experiences with SVG manipulation on server side. So i thought i\’d better share it.
Following is a very little guide about creating a dynamic frame for your pictures. And its just supposed to show how cool stuff could be done using SVG, XPath, PHP and a SVG rendering tool, like rsvg.
You upload your family picture, it places it inside a very cool frame. Thats it.
Good thing about SVG is, you can do some real WYSIWYG. So, open your favourite svg editor, and create a cool frame.

(I suck at artistic stuff, so I borrowed the frame from this page.
Then, You should import an example picture which is supposed to be a placeholder for uploaded family photos.


To add a cool effect, i duplicated the image and stretched it a bit:

Then i added the blur effect to make it look cool and fancy.

SVG features a group feature, by which you can group a few elements togheter. We do it because later, it will allow us to transform the image painlessly.

There are many group\’s on the document. Later, we have to be able to find the one we want. So we use inkscape\’s XML editor feature and give our group (<g>) element the \’frame\’ id.


We should also fit our page to the whole frame. So we use inkscape\’s feature. Select the whole frame, then use the \’Fit page to selection\’ button inside the \’Document properties\’ dialog.



And, last, save your SVG file. Make sure you save it as plain SVG, not an inkscape SVG or any other modified SVG file.

Now save the following into an html file.

<html>
	<head>
		<title>SVG photo-frame</title>
	</head>
	<body>
		<form action=\"show.php\" enctype=\"multipart/form-data\" method=\"post\">
			Photo:
			<br />
			<input type=\"file\" name=\"photo\" />
			<br />
			<br />
 
			Rotate:
			<br />
			<input type=\"text\" name=\"rotate\" value=\"0\" />
			<br />
			<br />
 
			Size:
			<br />
			<input type=\"text\" name=\"size\" value=\"100\" /> %
			<br />
			<br />
 
			<input type=\"submit\" value=\"Daa it Co0l!\"/>
		</form>
	</body>
</html>

 
and here is show.php file. I explain it step by step.
 

<?php$document=new DomDocument;$document->loadXML(file_get_contents(\'/path/to/your/svg/frame\'));

 
DOMDocument, is a php class for accessing DOM objects. first, we create a DOMDocument. Then, in the second line, we load our SVG file onto it.
Now, we have to replace the placeholder (in our case, Griffin\’s family) with the uploaded one.
First, we save the uploaded one as a temporary file:

copy($_FILES[\'photo\'][\'tmp_name\'],\'temp.png\');

 
Remember some html? to embedd an image, we had to do the following:

<img src=\"/path/to/image.png\"...

 
in SVG, it has to be done this way:

<image xlink:href=\"/path/to/image.png\"...

 
We currently have two placeholder <image>\’s there. the main one and the blurred one.
So we have two of the following in our page:
 

<image xlink:href=\"/path/to/image/we/imported/in/our/svg/editor.jpg\">

 
We should find <image> elements. Thats where XPath comes in.
 

$xpath=new DOMXpath($document);$images=$xpath->query(\'//image\');

 
First, we create an XPath object from our DOMDocument.
Then, in the second line, we look for all <image> tags inside the whole document.
XPath object searches through provided DOMDocument and the query results are DOMElement\’s, which are inside the DOMDocument. So by altering the results of XPath query, we are actually manipulating our $document:
 

foreach($imagesas$image){// Each $image is represents one <image> element.$image->setAttribute(\'xlink:href\',\'temp.png\');}

 
we altered $document which now contains <image> elements whom link to uploaded image, not the placeholder.
Now images are replaced. We also got some Size and Rotate stuff on input. SVG, means Scalable Vector Graphics. We should be able to resize the image as much as we want.
to resize the image, we have to use some SVG features. Remember that we grouped our frame?
A group, in SVG file, is represented by a <g> element. Our <g> has the id=\’frame\’ so we could find it easily.

$group=$xpath->query(\"//group[@id=\'frame\']/0\")->item(0);

 
Now, $group, represents our <g> element.
<g> element in svg accepts a very cool attribute named transform. we can use the transform attribute to resize the whole group, or rotate it.
Like this:

<g id=\"foo\" transform=\"scale(2) rotate(30)\">

 
This will scale up the group by 2 times and rotate it 30 degrees. (notice that there is no ; between transform functions)
So we should apply user\’s input to our <g>.
 

$group->setAttribute(\'transform\',\"scale(\".$_POST[\'size\']/100.\") rotate(\".$_POST[\'rotate\'].\")\");

 
(Notice that scale should be between 0 and 1 where 1 means 100%)
But its not enough. Without doing any change, our document size fits our <g>\’s size.
But when we changed our <g>\’s size, they dont fit anymore. And we have to fix it.
 

$svg=$xpath->query(\'/svg\')->item(0);$width=($_POST[\'size\']/100)*$svg->getAttribute(\'width\');$height=($_POST[\'size\']/100)*$svg->getAttribute(\'height\'); 
$svg->setAttribute(\'width\',$width);$svg->setAttribute(\'height\',$height);

 
SVG\’s root element in and has width and height attributes.
Thats it. now we have to generate a png from our svg file.
I use the rsvg command to generate it.
usage is simple: rsvg input.svg output.png
as you see, it gets an input. so we have to save our manipulated svg file first:
 

$temp=fopen(\'temp.svg\',\'w+\');fwrite($temp,$document->saveXML());fclose($temp); 
exec(\'rsvg temp.svg out.png\');unlink(\'temp.png\');unlink(\'temp.svg\');?><img src=\"out.png\"/>

we save our svg file as temp.svg, then run the rsvg command to generate png file and then remove temporary files. at last, we show it.
 
This was just a demo. A lot more could be done using the techniques mentioned above.
And, this is the live working copy.