font converter

Here you can discuss and share functionality improvements and helper programs to make Context Free better.

Moderators: MtnViewJohn, chris, mtnviewmark

Post Reply
soMweg
Posts: 1
Joined: Thu Feb 15, 2007 8:07 am

font converter

Post by soMweg »

here is a little perl script, that converts svg embedded fonts to cfdg rules. in conjunction with a ttf->svg converter (i'm using the one from the batik svg toolkit), its possible to convert ttf fonts to cfdg outlines. its very rudimentary, but works for me.

usage from ttf to cfdg with the batik ttf2svg, goes something like this:

Code: Select all

java -jar batik-ttf2svg.jar font.ttf > font.svg
svgglyphs2cfdg.pl font.svg > font.cfdg #(svgglyphs2cfdg.pl beeing the attached script)
then you need to include the font.cfdg file and add two drawing rules, which could look like this:

Code: Select all

startshape txt 
rule txt {
	A_A{}
	B_A{x 1000}
	C_A{x 1900}
}
rule LINE{SQUARE{s 1.1 6}}
rule ADD{SQUARE{s 6 50 r 45 y 25}}
include font.cfdg
The script:

Code: Select all

#!/usr/bin/perl

use XML::Simple; #you need this library

$lineobject = "LINE";	#shape that is used as line (streched)
$addobject = "ADD";		#shape that is placed unscaled for each line
$res = 25;				#approx. line length; smaller number = bigger resolution
$rulesuffix = "_A"; 

$svg = XMLin($ARGV[0],keyattr => 'glyph-name'); 

if($#ARGV==0){
	foreach $k (sort(keys %{$svg->{"defs"}->{"font"}->{"glyph"}})) {
		printf "rule $k$rulesuffix\{\n";
		d2cfdg($svg->{"defs"}->{"font"}->{"glyph"}->{$k}->{"d"});
		printf "}\n";
	}
}else{
	for($ik=1;$ik<=$#ARGV;$ik++){
		$k=$ARGV[$ik];
		if(exists $svg->{"defs"}->{"font"}->{"glyph"}->{$k}){
			printf "rule $k$rulesuffix\{\n";
			d2cfdg($svg->{"defs"}->{"font"}->{"glyph"}->{$k}->{"d"});
			printf "}\n";
		}else{
			printf "#$k not found\n";
		}
	}
}

sub absrel {
	if($_[0]=~/[A-Z]/){
		return $_[1];
	}else{
		return $_[1] + $_[2];
	}
}

sub line{
	$x1 = shift;
	$y1 = shift;
	$x2 = shift;
	$y2 = shift;
	$norep = shift;
	
	$dx = $x2 - $x1;	
	$dy = $y2 - $y1;
	if($dx==0){
			$ly=abs($dy);
			if($ly==0){
				$n=1;
			}else{
				$n = int($ly/$res);
				$n = 1 if $n<1;
			}
			if($norep || $n <= 1){
				$ym = $y1 + $dy/2;
				printf "\t%s{s %.2f 1 x %.2f y %.2f r 90}\n",$lineobject,$ly,$x1,$ym;
				printf "\t%s{x %.2f y %.2f r 90}\n",$addobject,$x1,$ym if ($addobject);			
			}else{
				$step = $dy/$n;
				$ym = $y1 + $step/2;
				printf "\t%d*{y %.2f}%s{s %.2f 1 x %.2f y %.2f r 90}\n",$n,$step,$lineobject,abs($step),$x1,$ym;
				printf "\t%d*{y %.2f}%s{x %.2f y %.2f r 90}\n",$n,$step,$addobject,$x1,$ym if ($addobject);						
			}
	}elsif($dy==0){
			$lx=abs($dx);
			if($lx==0){
				$n = 1;
			}else{
				$n = int($lx/$res);
				$n = 1 if $n<1;
			}
			if($norep || $n <= 1){
				$xm = $x1 + $dx/2;
				printf "\t%s{s %.2f 1 x %.2f y %.2f}\n",$lineobject,$lx,$xm,$y1;	
				printf "\t%s{x %.2f y %.2f}\n",$addobject,$xm,$y1 if ($addobject); 
			}else{
				$step = $dx/$n;
				$xm = $x1 + $step/2;
				printf "\t%d*{x %.2f}%s{s %.2f 1 x %.2f y %.2f}\n",$n,$step,$lineobject,abs($step),$xm,$y1;
				printf "\t%d*{x %.2f}%s{x %.2f y %.2f}\n",$n,$step,$addobject,$xm,$y1 if ($addobject);						
			}
					
	}else{
		$r = atan2($dy,$dx)/3.1415*180;
		$l = sqrt(($dx*$dx)+($dy*$dy));
		if($l==0){
			$n = 1;
		}else{
			$n = int($l/$res);
			$n = 1 if $n<1;
		}
		if($norep || $n <= 1){
			$xm = $x1 + $dx/2;
			$ym = $y1 + $dy/2;		
			printf "\t%s{s %.2f 1 x %.2f y %.2f r %.2f}\n",$lineobject,$l,$xm,$ym,$r;
			printf "\t%s{x %.2f y %.2f r %.2f}\n",$addobject,$xm,$ym,$r if ($addobject);
		}else{
			$step = $l/$n;
			$stepx = $dx/$n;
			$stepy = $dy/$n;
			$xm = $x1 + $stepx/2;
			$ym = $y1 + $stepy/2;
			printf "\t%d*{x %.2f y %.2f}%s{s %.2f 1 x %.2f y %.2f r %.2f}\n",$n,$stepx,$stepy,$lineobject,$step,$xm,$ym,$r;
			printf "\t%d*{x %.2f y %.2f}%s{x %.2f y %.2f r %.2f}\n",$n,$stepx,$stepy,$addobject,$xm,$ym,$r if ($addobject);
			
		}
	}
	
}

sub qbezier{
	$xx1=shift;$yy1=shift;
	$xx2=shift;$yy2=shift;
	$xx3=shift;$yy3=shift;	

	$dx1 = $xx1 - $xx2;
	$dy1 = $yy1 - $yy2;
	$dx2 = $xx1 - $xx3;
	$dy2 = $yy1 - $yy3;
	
	$l = sqrt($dx2*$dx2+$dy2*$dy2);
	if($l==0){	
		$step = 1;
	}else{
		$step = $res/$l;
		$step = 1 if($step>0.5);
		$step = 1 if($step<=0);
	}
	if( $step<1 && (!($dx1==0&&$dx2==0)&&!($dy1==0&&$dy2==0))&& 
		(($dy1!=0&&$dy2==0)||($dy1==0&&$dy2!=0)||($dx1==0&&$dx2!=0)||($dx1!=0&&$dx2==0)
		|| abs($dx1/$dy1/$dx2*$dy2-1)>0.2)){
		
		$xo = $xx1;
		$yo = $yy1;
		for($t=$step;$t<1;$t+=$step){
			$xc=(1-$t)*(1-$t)*$xx1+2*$t*(1-$t)*$xx2+$t*$t*$xx3;
			$yc=(1-$t)*(1-$t)*$yy1+2*$t*(1-$t)*$yy2+$t*$t*$yy3;		
			line($xo,$yo,$xc,$yc,1);
			$xo = $xc;
			$yo = $yc;
		}
		line($xo,$yo,$xx3,$yy3,1);
	}else{
		line($xx1,$yy1,$xx3,$yy3);	
	}
	
}

sub d2cfdg {
	@l = $_[0] =~ /([-0-9]+|[MmZzLlHhVvCcSsQqTtAa])/g;
	for($i=0;$i<=$#l;$i++){
		$o=$l[$i];
		$_=$o;
		if(/[Mm]/){
			$px=absrel($o,$l[++$i],$px);
			$py=absrel($o,$l[++$i],$py);
		}elsif(/[Zz]/){
		}elsif(/[Ll]/){
			$x=absrel($o,$l[++$i],$px);
			$y=absrel($o,$l[++$i],$py);	
			line($px,$py,$x,$y);			
			$px = $x;
			$py = $y;				
		}elsif(/[Hh]/){
			$x=absrel($o,$l[++$i],$px);		
			line($px,$py,$x,$py);
			$px = $x;
		}elsif(/[Vv]/){
			$y=absrel($o,$l[++$i],$py);			
			line($px,$py,$px,$y);
			$py = $y;
		}elsif(/[Cc]/){
			$x1=absrel($o,$l[++$i],$px);			
			$y1=absrel($o,$l[++$i],$py);			
			$x2=absrel($o,$l[++$i],$px);			
			$y2=absrel($o,$l[++$i],$py);			
			$x=absrel($o,$l[++$i],$px);			
			$y=absrel($o,$l[++$i],$py);			
			line($px,$py,$x,$y);	#cubic bezier not implemented yet
			$px=$x;
			$py=$y;
		}elsif(/[Ss]/){
			$x1 = 2*$px-$x2;
			$y1 = 2*$py-$y2;	
			$x2=absrel($o,$l[++$i],$px);			
			$y2=absrel($o,$l[++$i],$py);			
			$x=absrel($o,$l[++$i],$px);			
			$y=absrel($o,$l[++$i],$py);	
			line($px,$py,$x,$y);	#cubic bezier not implemented yet		
			$px=$x;
			$py=$y;		
		}elsif(/[Qq]/){
			$x1=absrel($o,$l[++$i],$px);			
			$y1=absrel($o,$l[++$i],$py);			
			$x=absrel($o,$l[++$i],$px);			
			$y=absrel($o,$l[++$i],$py);	
			qbezier($px,$py,$x1,$y1,$x,$y);			
			$px=$x;
			$py=$y;		
		}elsif(/[Tt]/){
			$x1 = 2*$px-$x1;
			$y1 = 2*$py-$y1;
			$x=absrel($o,$l[++$i],$px);			
			$y=absrel($o,$l[++$i],$py);					
			qbezier($px,$py,$x1,$y1,$x,$y);			
			$px=$x;
			$py=$y;							
		}elsif(/[Aa]/){
			$rx=$l[++$i];			
			$ry=$l[++$i];					
			$xr=$l[++$i];					
			$la=$l[++$i];					
			$sf=$l[++$i];					
			$x=absrel($o,$l[++$i],$px);			
			$y=absrel($o,$l[++$i],$py);						
			printf "#ecllipse ($px,$py)->($x,$y) ($rx,$ry,$xr,$la,$sf)\n";
			$px=$x;
			$py=$y;							
		}else{
			printf "#problem parsing at $_\n";
		}
	}
}

arobert
Posts: 1
Joined: Mon Apr 09, 2007 10:25 pm
Contact:

Post by arobert »

great code, it is useful, Thanks.

Post Reply