Forum Samples, Tips and Tricks

text width and vertical text with SVG

jacobfogg
After many laborious hours I have come up with a method of determining the approximate width/height needed for creating SVG for vertical text on the fly... I figured I'd share it with everyone else... This may not be perfect, and there may be another way, however this seems to work well for what I need.

Also, this is all written in PHP...

So to begin with I have create a file called svgfunc.php:

<?php
function get_text_width($text,$font,$fontSize){
	//I start by counting the width, giving each character a modifying value
	$count = 0;
	$count = $count + ((strlen($text) - strlen(str_replace(array("i","j","l"),"",$text)))*0.23);//ijl
	$count = $count + ((strlen($text) - strlen(str_replace(array("f"),"",$text)))*0.27);//f
	$count = $count + ((strlen($text) - strlen(str_replace(array("t","I"),"",$text)))*0.28);//tI
	$count = $count + ((strlen($text) - strlen(str_replace(array("r"),"",$text)))*0.34);//r
	$count = $count + ((strlen($text) - strlen(str_replace(array("1"),"",$text)))*0.49);//1
	$count = $count + ((strlen($text) - strlen(str_replace(array("c","k","s","v","x","y","z","J"),"",$text)))*0.5);//cksvxyzJ
	$count = $count + ((strlen($text) - strlen(str_replace(array("a","b","d","e","g","h","n","o","p","q","u","L","0","2","3","4","5","6","7","8","9"),"",$text)))*0.56);//abdeghnopquL023456789
	$count = $count + ((strlen($text) - strlen(str_replace(array("F","T","Z"),"",$text)))*0.61);//FTZ
	$count = $count + ((strlen($text) - strlen(str_replace(array("A","B","E","K","P","S","V","X","Y"),"",$text)))*0.67);//ABEKPSVXY
	$count = $count + ((strlen($text) - strlen(str_replace(array("w","C","D","H","N","R","U"),"",$text)))*0.73);//wCDHNRU
	$count = $count + ((strlen($text) - strlen(str_replace(array("G","O","Q"),"",$text)))*0.78);//GOQ
	$count = $count + ((strlen($text) - strlen(str_replace(array("m","M"),"",$text)))*0.84);//mM
	$count = $count + ((strlen($text) - strlen(str_replace("W","",$text)))*.95);//W
	$count = $count + ((strlen($text) - strlen(str_replace(" ","",$text)))*.28);//" "
	$text = str_replace(" ","",$text);//remove the " "'s
	$count = $count + (strlen(preg_replace("/[a-z0-9]/i","",$text))*0.3); //all other chrs
	
	//then I adjust the value based on the fontsize*count and the modifer based on the type of font
	return ceil(adjust_font($count*$fontSize,$font));
}
function adjust_font($textWidth,$font){
	//you will need to add additional modifiers for other fonts..
	//  start with a string containing all lower alpha, upper alpha, numbers and a space
	//  continue adjusting till it's slightly larger (2-5 pixels) than it needs to be
	
	$modifier = 1;
	$font = strtolower($font);
	switch($font){
		//no modifier for arial and sans-serif
		case 'arial':
		case 'sans-serif':
			break;
		//.92 modifer for time, serif, brushscriptstd, and californian fb
		case 'times':
		case 'serif':
		case 'brushscriptstd':
		case 'californian fb':
			$modifier = .92;
			break;
		//1.23 modifier for broadway
		case 'broadway':
			$modifier = 1.23;
			break;
	}
	return ceil($textWidth*$modifier);
}
?>


Next, I created a file called svg.php:

<?php 
header("Content-type: image/svg+xml"); 
include( "svgfunc.php" );
$text = $_REQUEST['text'];
$fontSize = $_REQUEST['fontSize'];
$font = ($_REQUEST['font'])?$_REQUEST['font']:'Arial';
$textWidth = get_text_width($text,$font,$fontSize);
?>

<svg xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
	version="1.1"
	baseProfile="full"
	viewBox="0 0 <?= $fontSize+1; ?> <?= $textWidth+1; ?>"
	width="<?= $fontSize+1; ?>px"
	height="<?= $textWidth+1; ?>px">
	<text x="-<?= $textWidth+1; ?>px" y="<?= ceil($fontSize*0.8); ?>px" fill="red icc-color(#CMYK, 0,100,100,0)" font-family="<?= $font; ?>" font-size="<?= $fontSize; ?>px" transform="rotate(270)">
		<?= $text; ?>
	</text>
</svg>


It expects a query string like: svg.php?text=this is a test&amp;fontSize=16$amp;font=serif

Don't forget Prince needs you to use &amp; instead of just &

Finally, I created a file called testsvg.php which has the following:

<?

$text = $_REQUEST['text'];
$fontSize = $_REQUEST['fontSize'];
$fontFamily = $_REQUEST['fontFamily'];

include( "svgfunc.php" );//I include the svgfunc.php to get the text width for the height of the svg
$height = get_text_width($text,$fontFamily,$fontSize);

//then I build the svg link
$src = "svg.php?text=".$text."&fontSize=".$fontSize."&font=".$fontFamily;
$src = str_replace(" ","%20",$src);

?>

<html>
<head></head>
<body>
<table border="1" cellspacing="0">
	<tr>
		<td style="vertical-align:bottom;">
			Hello
		</td>
		<td>
<!-- here is the embed method -->
			<embed width="<?= $fontSize+1; ?>" height="<?= $height+2; ?>" src="<?= $src; ?>"  type="image/svg+xml"></embed>
		</td>
		<td>
<!-- here is the object method -->
			<object width="<?= $fontSize+1; ?>" height="<?= $height+2; ?>" data="<?= $src; ?>" type="image/svg+xml"></object>
		</td>
		<td style="vertical-align:bottom;">
			Goodbye
		</td>
	</tr>
</table>
<br><br>
Enter some text, a font-size, and a font-family to see the dynamic SVG in action... please note that the height of the text box is currently only correctly calculated for arial/sans-serif font face... The others could also be calculated fairly easily... Currently FireFox's implementation of <a href="http://www.mozilla.org/projects/svg/status.html">SVG</a> does not support embeding other fonts.
<br><br>
<form action="testsvg.php" method="get">
Text:<input type="text" name="text" id="text" value="<?= $text; ?>"><br>
Font Size:<input type="text" name="fontSize" id="fontSize" value="<?= $fontSize; ?>"><br>
Font-Family:<input type="text" name="fontFamily" id="fontFamily" value="<?= $fontFamily; ?>"> (Arial (sans-serif), Times (serif), Fantasy, Monospace, Bakersville (only IE), & Symbol)<br>
<input type="submit">
</form>
</body>
</html>



Remember, this is still a work in progress... Hope this helps someone out!!! If you have a better method, please share it!

Jake
mikeday
That's very clever! :)

So how could Prince make this process easier for you? Or would you still need to do this for browsers?
popcornmanager
Instead of calculating all the font size stuff yourself, why not use the PHP function imagettfbbox (Description: Give the bounding box of a text using TrueType fonts). Of course, if the font you have isn't true type or open type then you can't use it.

Otherwise, looks good. Instead of your solution I was dynamically generating vertical images using PHP. SVG is the way of the future though!
jbarrus
Is there a way to do this with xsl? Say need to have something such as the line below that I need to display vertically. The "some strings" are of variable length. How do I determine the location of the image and the size of the whole svg if all I have to work with is xsl?

some string (an image) some string