|
|
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
|
|
|
|
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
|
|