POV-Ray : Newsgroups : povray.general : text paths? Server Time
29 Jul 2024 18:21:30 EDT (-0400)
  text paths? (Message 1 to 7 of 7)  
From: Thomas A  Fine
Subject: text paths?
Date: 16 Nov 2010 14:48:19
Message: <4ce2e003@news.povray.org>
Hi,

Is it possible in POV-Ray to get to the paths used in text ttf objects?
Can I easily make a wireframe letter, for example?

Or do I have to dig into the ttf font and convert the data there into
something by hand (or by script more accurately)?

    tom


Post a reply to this message

From: Patrick Elliott
Subject: Re: text paths?
Date: 16 Nov 2010 20:48:19
Message: <4ce33463$1@news.povray.org>
On 11/16/2010 12:48 PM, Thomas A. Fine wrote:
> Hi,
>
> Is it possible in POV-Ray to get to the paths used in text ttf objects?
> Can I easily make a wireframe letter, for example?
>
> Or do I have to dig into the ttf font and convert the data there into
> something by hand (or by script more accurately)?
>
>      tom
>
I think.. Unless I missed something, while the fonts are computed as 
splines, there is no function available to say.. warp the resulting 
spline. Something like that could, in principle, change the 
characteristics of the font to *match* the actual curve. Instead, you 
produce a bit of text, then you rotate it, via various functions, to get 
it "lined up" with where it should be. While this is OK for some 
applications, its wrong for others.

But, no, POV-Ray creates an "internal" object which handles the text, 
which you can position, rotate, size, etc., but not actually "warp" in 
any way. So, you could place it on a path, but not bend it to fit one. 
Kind of wish we had some sort of function, where you could feed and 
existing spline into it (like a letter/letters), then bend it any which 
way you wanted, based on, say.. where the "start" and "end" corners, and 
the curve between, ended up. In other words, you could, with such a 
thing, leave the bottom along, but bend, twist, and stretch, the top, by 
telling the function to do that.

At the moment, to get this you have to put your text into something 
else, which will produce a mesh from the result, do you changed there, 
then export to POV-Ray. No way to do it in script, unless you defined a 
mesh, then made your own code to handle the mutation of the points. 
Still means making your text outside, in something else, then importing 
a mesh though.

-- 
void main () {

     if version = "Vista" {
       call slow_by_half();
       call DRM_everything();
     }
     call functional_code();
   }
   else
     call crash_windows();
}

<A HREF='http://www.daz3d.com/index.php?refid=16130551'>Get 3D Models, 
3D Content, and 3D Software at DAZ3D!</A>


Post a reply to this message

From: Alain
Subject: Re: text paths?
Date: 17 Nov 2010 13:39:04
Message: <4ce42148@news.povray.org>

> Hi,
>
> Is it possible in POV-Ray to get to the paths used in text ttf objects?
> Can I easily make a wireframe letter, for example?
>
> Or do I have to dig into the ttf font and convert the data there into
> something by hand (or by script more accurately)?
>
>      tom
>

A ttf is effectively a bezier spline forming the leters. What POV-Ray 
does is to use that spline and extrude it along the Z axis to give a prism.

You can't easily turn it into a wireframe. There is just no provision 
for that. In fact, outside a few primitives (mesh, mesh2, height_field 
and bicubic_patch) POV-Ray never use a mesh or whireframe.


You may dig into the ttf. It's not trivial and version 3.6 may not be 
able to do it at all.



Alain


Post a reply to this message

From: bart
Subject: Re: text paths?
Date: 17 Nov 2010 15:20:36
Message: <4ce43914$1@news.povray.org>
On 11/16/2010 07:48 PM, Thomas A. Fine wrote:
> Hi,
>
> Is it possible in POV-Ray to get to the paths used in text ttf objects?
> Can I easily make a wireframe letter, for example?
>
> Or do I have to dig into the ttf font and convert the data there into
> something by hand (or by script more accurately)?
>
Inkscape can export text outline as a POV-Ray Bezier-spline prism;
and other output formats that also could be used to extract text paths 
information, like .svg or .ps.


Post a reply to this message

From: Sherry Shaw
Subject: Re: text paths?
Date: 18 Nov 2010 13:02:16
Message: <4ce56a28$1@news.povray.org>
I wonder if Elefont would help you get where you're going.  You can get 
it here:

http://www.armanisoft.ch/webdesign/elefont/Elefont.html

It's rather old and cranky, but it still mostly works.  IIRC the POV 
export function never did work, but you can export to DXF and then run 
around the barn a time or two to get the format you want.

--Sherry Shaw

-- 
#macro T(E,N)sphere{x,.4rotate z*E*60translate y*N pigment{wrinkles scale
.3}finish{ambient 1}}#end#local I=0;#while(I<5)T(I,1)T(1-I,-1)#local I=I+
1;#end camera{location-5*z}plane{z,37 pigment{granite color_map{[.7rgb 0]
[1rgb 1]}}finish{ambient 2}}//                                   TenMoons


Post a reply to this message

From: bart
Subject: Re: text paths?
Date: 18 Nov 2010 15:11:58
Message: <4ce5888e$1@news.povray.org>
On 11/18/2010 06:02 PM, Sherry Shaw wrote:
> I wonder if Elefont would help you get where you're going. You can get
> it here:
>
> http://www.armanisoft.ch/webdesign/elefont/Elefont.html
>
Another worth looking at is FontForge.
Format of exported .eps file for a glyph is in plain text
and easy to analyse. For example, the paths sequence
for the POV-Ray logo looks like:
%%Page ".notdef" 1
gsave newpath
	170 429 moveto
	 188 429 203.5 422.5 216.5 409.5 curveto
	 229.5 396.5 236 381 236 363 curveto
	 236 344.333 229.5 328.667 216.5 316 curveto
	 203.5 303.333 188 297 170 297 curveto
	 152 297 136.5 303.333 123.5 316 curveto
	 110.5 328.667 104 344.333 104 363 curveto
	 104 381 110.5 396.5 123.5 409.5 curveto
	 136.5 422.5 152 429 170 429 curveto
	closepath
	89 317 moveto
	 97 303 108.167 291.5 122.5 282.5 curveto
	 136.833 273.5 152.667 269 170 269 curveto
	 173.333 269 179 269.667 187 271 curveto
	 170 246 lineto
	 204.667 250 234 262.833 258 284.5 curveto
	 282 306.167 294 331.333 294 360 curveto
	 294 392 279.333 419.333 250 442 curveto
	 220.667 464.667 185 476 143 476 curveto
	 111 476 82.3333 469 57 455 curveto
	 31.6667 441 13.6667 423.333 3 402 curveto
	 12.3333 434 32.5 460.5 63.5 481.5 curveto
	 94.5 502.5 130.333 513 171 513 curveto
	 218.333 513 259 498.333 293 469 curveto
	 327 439.667 344 404.667 344 364 curveto
	 344 322.667 327 287.5 293 258.5 curveto
	 259 229.5 218.333 215 171 215 curveto
	 161 215 153.667 215.333 149 216 curveto
	 1 1 lineto
	 69 243 lineto
	 45 257.667 26.3333 277 13 301 curveto
	 27 283 45.3333 269.333 68 260 curveto
	 69.3333 258.667 71 258 73 258 curveto
	 89 317 lineto
	closepath
fill grestore


Post a reply to this message

From: Thomas A  Fine
Subject: Re: text paths?
Date: 19 Nov 2010 13:49:24
Message: <4ce6c6b4$1@news.povray.org>
Well, I dug into the TTF format, and wrote a script that can pull out
the data for any glyph (and possibly for any traditional ascii-encoded
character).

So now it's a simple matter to write another script that turns this
data into whatever particular structure I want.  I believe that the
curves used in TTF fonts are compatible with the curves used in
sphere_sweep.  If that's the case, the rest should be incredibly
straight-forward.

The script is a real mess.  It might be reliable for pulling glyphs
out by glyph number, but there's no guaranteed ordering so that may
be trial and error to find your glyph.  It can lookup based on ascii
(or roman or ISO-whatever you want to call it) characters, but only
if the first encoding table in the CMAP section of the font happens
to contain that kind of encoding.

I could say "I'll clean it up and post it when it's nicer" -  but we
all know how that goes.   So I'm just going to append it here, FWIW.

ttfgetchar TTF_fontfile character
ttfgetchar TTF_fontfile -g glyphnumber

	tom

#!/usr/bin/perl

@platformID = ("Unicode", "Macintosh", "<reserved>", "Microsoft");
$specificID[1] = ["Roman", "Japanese", "Traditional Chinese", "Korean", "Arabic",
"Hebrew", "Greek", "Russian", "RSymbol", "Devanagari", "Gurmukhi", "Gujarati",
"Oriya", "Bengali", "Tamil", "Telugu", "Kannada", "Malayalam", "Sinhalese", "Burmese",
"Khmer", "Thai", "Laotian", "Georgian", "Armenian", "Simplified Chinese", "Tibetan",
"Mongolian", "Geez", "Slavic", "Vietnamese", "Sindhi", "(Uninterpreted)",];
$specificID[0] = ["Default semantics", "Version 1.1 semantics", "ISO 10646 1993
semantics (deprecated)", "Unicode 2.0 or later semantics"];

#http://developer.apple.com/fonts/ttrefman/RM06/Chap6.html

#TTF format
#  font directory
#    offset subtable
#      uint32 type { 'true' | 'typ1' | ... }
#      uint16 numTables number of tables
#      uint16 searchRange (base 2 order of mag table size, e.g. 128-255 = 8)*16
#      uint16 entrySelector log2 (searchRange)*16
#      uint16 rangeShift (numTables*16-searchRange)
#    table directory
#      repeated instances of
#        uint32 tag { cmap | glyf | head | hhea | hmtx | loca | maxp | name | post |
... }
#        uint32 checkSum
#        uint32 offset from beginning of sfnt (file?)
#        uint32 length (bytes, unpadded length)
#
#  cmap table
#    cmap index
#      uint16 version 0
#      uint16 numSubtables
#    encoding subtable
#      repeated instances of
#        uint16 platformID
#        uint16 platformSpecificID
#        uint32 offset of the mapping table
#    mapping tables of various formats based on offsets above?
#
#  loca table  - where is each glyf in the glyf table?
#    The size is based on data in the "head" table?
#
#  glyf data
#
# table types
#cmap - character to glyph mapping
#glyf - glyph data
#head - font header
#hhea - horizontal header
#hmtx - horizontal metrics
#loca - index to location
#maxp - maximum profile
#name - naming
#post - postscript
#cvt  - control value
#fpgm - font program
#hdmx - horizontal device metrics
#kern - kerning
#OS/2 - OS/2
#prep - control value program

$fontfile=shift(@ARGV);

if ($#ARGV == 1 && $ARGV[0] eq "-g") {
  $glyph_num=shift(@ARGV);
} elsif ($#ARGV == 0) {
  $char=shift(@ARGV);
  $ascii=ord($char);
} else {
  print "usage: $0 font char\n";
  print "       $0 font -g glyphindex\n";
  exit(1);
}

#uncomment to show debugging info
#open(DEBUG,">&STDERR");

open (TTF,$fontfile);
  $fonttype=str32();
  if ($fonttype eq '') { $fonttype = "Windows"; }
  $numTables=uint16();
  $searchRange=uint16();
  $entreySelector=uint16();
  $rangeShift=uint16();
  print DEBUG "$fonttype $numTables\n";
  for ($i=0; $i<$numTables; ++$i) {
    $tag=str32();
    $checksum=uint32();
    $offset=uint32();
    $length=uint32();
    $tableOff{$tag}=$offset;
    $tableLen{$tag}=$length;
    print DEBUG "$tag $offset:$length\n";
  }

  print DEBUG "\nhead\n";
  seek(TTF,$tableOff{'head'},SEEK_SET);
  print DEBUG "offset $tableOff{'head'}, ", tell(TTF), "\n";
  $version=str32();
  if ($version != "") { print "Bad header version!?", $version,"\n"; }
  skip32(); skip32();
  $magicnumber=uint32();
  if ($magicnumber != 0x5F0F3CF5) { printf("Bad magic!? %x\n", $magicnumber); }
  $headflags=uint16();
  skip16();
  skip32(); $created=uint32();
  skip32(); $modified=uint32();
  $fxmin=int16();     # should be signed
  $fymin=int16();     # should be signed
  $fxmax=int16();     # should be signed
  $fymax=int16();     # should be signed
  print DEBUG "BB $fxmin,$fymin - $fxmax,$fymax\n";
  $macStyle=uint16();
  skip16(); skip16();
  $indexToLocFormat=uint16();   #zero for short (16 bits), 1 for long (32 bits)
  skip16();

  print DEBUG "\ncmap\n";
  seek(TTF,$tableOff{'cmap'},SEEK_SET);
  print DEBUG "offset $tableOff{'cmap'}, ", tell(TTF), "\n";
  $cmap_verision = uint16();
  $numCmaps = uint16();
  print DEBUG "$numCmaps cmaps\n";
  for ($i=0; $i<$numCmaps; ++$i) {
    $platID = uint16();
    $platSpecID = uint16();
    $cmapOffset[$i] = uint32();
    print DEBUG "CMAP ";
    if (defined($platformID[$platID])) {
      print DEBUG "$platformID[$platID] ";
    } else {
      print DEBUG "$platID ";
    }
    if (defined(${$specificID[$platID]}[$platSpecID])) {
      print DEBUG ${$specificID[$platID]}[$platSpeciID], ", ";
    } else {
      print DEBUG "$platID ";
    }
    print DEBUG "$cmapOffset[$i]\n";
  }
  #OVER-ASSUMING - first subtable will be format 0 cmap that we want
  $format=uint16();
  $cSubLen=uint16();
  $lang=uint16();
  if ($format == 0) {
    for ($i=0; $i<256; ++$i) {
      $ascii2glyph[$i] = uint8();
    }
    ++$asciiOK;
  } else {
    print DEBUG "These are not the droids we're looking for\n";
  }

  #This is the offset into the glyf table for each glyph.
  # (relative to the glyf table, not the font file)
  print DEBUG "\nloca\n";
  seek(TTF,$tableOff{'loca'},SEEK_SET);
  if ($indexToLocFormat) {
    for ($i=0; $i<$tableLen{'loca'}/4; ++$i) {
      $goff[$i]=uint32();
      #print DEBUG "  $i - $goff[$i]\n";
    }
  } else {
    for ($i=0; $i<$tableLen{'loca'}/2; ++$i) {
      #note the *2 - for short tables, offset is in words not bytes
      $goff[$i]=uint16()*2;
      #print DEBUG "  $i - $goff[$i]\n";
    }
  }

  if (defined($ascii)) {
    if (! $asciiOK) {
      print STDERR "Couldn't find correct glyph table!\n";
      exit(1);
    }
    $glyph_num = $ascii2glyph[$ascii];
  }

  print DEBUG "\nglyf #$glyph_num\n";
  seek(TTF,$tableOff{'glyf'}+$goff[$glyph_num],SEEK_SET);
  $numContours=int16();
  print DEBUG "Contours: $numContours\n";
  $xmin=int16();     # should be signed
  $ymin=int16();     # should be signed
  $xmax=int16();     # should be signed
  $ymax=int16();     # should be signed
  print DEBUG "BB $xmin,$ymin - $xmax,$ymax\n";
  $lastEnd = -1;
  for ($i=0; $i<$numContours; ++$i) {
    $endPtsOfContours[$i] = uint16();
    $contourLen[$i] = $endPtsOfContours[$i] - $lastEnd;
    $lastEnd=$endPtsOfContours[$i];
    print DEBUG "Contour $i: end is $endPtsOfContours[$i]\n";
  }
  $instLen = uint16();
  for ($i=0; $i<$instLen; ++$i) {
    $instrs[$i] = uint8();
  }
  for ($i=0,$n=0; $i<$numContours; ++$i) {
    for ($j=0; $j<$contourLen[$i]; ++$j,++$n) {
      if ($repeating) {
        $flags{$i,$j} = $repeatflag;
	print DEBUG "repeating $repeating\n";
	--$repeating;
      } else {
        $flags{$i,$j} = uint8();
	if ($flags{$i,$j} & 0x8) {
	  $repeating = uint8();
	  $repeatflag = $flags{$i,$j};
	}
      }
      print DEBUG sprintf("flags($i,$j) = %08b\n",$flags{$i,$j});
    }
  }
  for ($i=0,$n=0; $i<$numContours; ++$i) {
    for ($j=0; $j<$contourLen[$i]; ++$j,++$n) {
      if (($flags{$i,$j} & 0x10) && (($flags{$i,$j} & 0x02)==0)) {
        $x{$i,$j} = $lastx;
      } elsif ($flags{$i,$j} & 0x02) {
        $tmpx = uint8();
	if (($flags{$i,$j} & 0x10)==0) { $tmpx = 0 - $tmpx; }
	$x{$i,$j} = $lastx + $tmpx;
      } else {
        $tmpx = int16();
        $x{$i,$j} = $lastx + $tmpx;
      }
      $lastx = $x{$i,$j};
    }
  }
  for ($i=0,$n=0; $i<$numContours; ++$i) {
    for ($j=0; $j<$contourLen[$i]; ++$j,++$n) {
      if (($flags{$i,$j} & 0x20) && (($flags{$i,$j} & 0x04)==0)) {
        $y{$i,$j} = $lasty;
      } elsif ($flags{$i,$j} & 0x04) {
        $tmpy = uint8();
	if (($flags{$i,$j} & 0x20)==0) { $tmpy = 0 - $tmpy; }
	$y{$i,$j} = $lasty + $tmpy;
      } else {
        $tmpy = int16();
        $y{$i,$j} = $lasty + $tmpy;
      }
      $lasty = $y{$i,$j};
    }
  }
  for ($i=0; $i<$numContours; ++$i) {
    for ($j=0; $j<$contourLen[$i]; ++$j) {
      print "$x{$i,$j}, $y{$i,$j}";
      if ($flags{$i,$j} & 0x01) { print " onCurve"; }
      print "\n";
    }
    print "end\n";
  }


close(TTF);

#
# END OF MAIN
#

sub str32 {
  my($ret);
  read(TTF,$ret,4);
  return($ret);
}

sub str16 {
  my($ret);
  read(TTF,$ret,2);
  return($ret);
}

sub uint32 {
  my($ret);
  read(TTF,$ret,4);
  return(unpack("N",$ret));
}

sub uint16 {
  my($ret);
  read(TTF,$ret,2);
  return(unpack("n",$ret));
}

sub uint8 {
  my($ret);
  read(TTF,$ret,1);
  return(unpack("C",$ret));
}

sub int16 {
  my($ret,$bits);
  read(TTF,$ret,2);
  $bits=unpack("n",$ret);
  if ($bits & 0x8000) {
    return(-65536+$bits);
  } else {
    return($bits);
  }
}

sub skip8 {
  read(TTF,$skip,1);
}

sub skip16 {
  read(TTF,$skip,2);
}

sub skip32 {
  read(TTF,$skip,4);
}

sub skip64 {
  read(TTF,$skip,8);
}


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.