1 from pyx
import bbox
, canvasitem
, font
, pykpathsea
3 from pyx
.font
import t1file
7 def __init__(self
, name
, c
, q
, d
, tfmconv
, pyxconv
, debug
=0):
9 self
.q
= q
# desired size of font (fix_word) in TeX points
10 self
.d
= d
# design size of font (fix_word) in TeX points
11 self
.tfmconv
= tfmconv
# conversion factor from tfm units to dvi units
12 self
.pyxconv
= pyxconv
# conversion factor from dvi units to PostScript points
13 tfmpath
= pykpathsea
.find_file("%s.tfm" % self
.name
, pykpathsea
.kpse_tfm_format
)
15 raise TFMError("cannot find %s.tfm" % self
.name
)
16 self
.TFMfile
= tfmfile
.TFMfile(tfmpath
, debug
)
18 # We only check for equality of font checksums if none of them
19 # is zero. The case c == 0 happend in some VF files and
20 # according to the VFtoVP documentation, paragraph 40, a check
21 # is only performed if TFMfile.checksum > 0. Anyhow, being
22 # more generous here seems to be reasonable
23 if self
.TFMfile
.checksum
!= c
and self
.TFMfile
.checksum
!= 0 and c
!= 0:
24 raise DVIError("check sums do not agree: %d vs. %d" %
25 (self
.TFMfile
.checksum
, c
))
27 # Check whether the given design size matches the one defined in the tfm file
28 if abs(self
.TFMfile
.designsize
- d
) > 2:
29 raise DVIError("design sizes do not agree: %d vs. %d" % (self
.TFMfile
.designsize
, d
))
30 #if q < 0 or q > 134217728:
31 # raise DVIError("font '%s' not loaded: bad scale" % self.name)
32 if d
< 0 or d
> 134217728:
33 raise DVIError("font '%s' not loaded: bad design size" % self
.name
)
41 # The following code is a very crude way to obtain the information
42 # required for the PDF font descritor. (TODO: The correct way would
43 # be to read the information from the AFM file.)
46 fontinfo
.fontbbox
= (0,
47 -self
.getdepth_ds(ord("y")),
48 self
.getwidth_ds(ord("W")),
49 self
.getheight_ds(ord("H")))
51 fontinfo
.fontbbox
= (0, -10, 100, 100)
53 fontinfo
.italicangle
= -180/math
.pi
*math
.atan(self
.TFMfile
.param
[0]/65536.0)
55 fontinfo
.italicangle
= 0
56 fontinfo
.ascent
= fontinfo
.fontbbox
[3]
57 fontinfo
.descent
= fontinfo
.fontbbox
[1]
59 fontinfo
.capheight
= self
.getheight_ds(ord("h"))
61 fontinfo
.capheight
= 100
63 fontinfo
.vstem
= self
.getwidth_ds(ord("."))/3
69 return "font %s designed at %g TeX pts used at %g TeX pts" % (self
.name
,
70 16.0*self
.d
/16777216L,
71 16.0*self
.q
/16777216L)
74 """ return size of font in (PS) points """
75 # The factor 16L/16777216L=2**(-20) converts a fix_word (here self.q)
76 # to the corresponding float. Furthermore, we have to convert from TeX
77 # points to points, hence the factor 72/72.27.
78 return 16L*self
.q
/16777216L*72/72.27
80 def _convert_tfm_to_dvi(self
, length
):
81 # doing the integer math with long integers will lead to different roundings
82 # return 16*length*int(round(self.q*self.tfmconv))/16777216
84 # Knuth instead suggests the following algorithm based on 4 byte integer logic only
85 # z = int(round(self.q*self.tfmconv))
86 # b0, b1, b2, b3 = [ord(c) for c in struct.pack(">L", length)]
87 # assert b0 == 0 or b0 == 255
93 # result = ( ( ( ( ( b3 * z ) >> 8 ) + ( b2 * z ) ) >> 8 ) + ( b1 * z ) ) >> shift
95 # result = result - (z << (8-shift))
97 # however, we can simplify this using a single long integer multiplication,
98 # but take into account the transformation of z
99 z
= int(round(self
.q
*self
.tfmconv
))
100 assert -16777216 <= length
< 16777216 # -(1 << 24) <= length < (1 << 24)
101 assert z
< 134217728 # 1 << 27
103 while z
>= 8388608: # 1 << 23
106 # length*z is a long integer, but the result will be a regular integer
107 return int(length
*long(z
) >> shift
)
109 def _convert_tfm_to_ds(self
, length
):
110 return (16*long(round(length
*float(self
.q
)*self
.tfmconv
))/16777216) * self
.pyxconv
* 1000 / self
.getsize_pt()
112 def _convert_tfm_to_pt(self
, length
):
113 return (16*long(round(length
*float(self
.q
)*self
.tfmconv
))/16777216) * self
.pyxconv
115 # routines returning lengths as integers in dvi units
117 def getwidth_dvi(self
, charcode
):
118 return self
._convert
_tfm
_to
_dvi
(self
.TFMfile
.width
[self
.TFMfile
.char_info
[charcode
].width_index
])
120 def getheight_dvi(self
, charcode
):
121 return self
._convert
_tfm
_to
_dvi
(self
.TFMfile
.height
[self
.TFMfile
.char_info
[charcode
].height_index
])
123 def getdepth_dvi(self
, charcode
):
124 return self
._convert
_tfm
_to
_dvi
(self
.TFMfile
.depth
[self
.TFMfile
.char_info
[charcode
].depth_index
])
126 def getitalic_dvi(self
, charcode
):
127 return self
._convert
_tfm
_to
_dvi
(self
.TFMfile
.italic
[self
.TFMfile
.char_info
[charcode
].italic_index
])
129 # routines returning lengths as integers in design size (AFM) units
131 def getwidth_ds(self
, charcode
):
132 return self
._convert
_tfm
_to
_ds
(self
.TFMfile
.width
[self
.TFMfile
.char_info
[charcode
].width_index
])
134 def getheight_ds(self
, charcode
):
135 return self
._convert
_tfm
_to
_ds
(self
.TFMfile
.height
[self
.TFMfile
.char_info
[charcode
].height_index
])
137 def getdepth_ds(self
, charcode
):
138 return self
._convert
_tfm
_to
_ds
(self
.TFMfile
.depth
[self
.TFMfile
.char_info
[charcode
].depth_index
])
140 def getitalic_ds(self
, charcode
):
141 return self
._convert
_tfm
_to
_ds
(self
.TFMfile
.italic
[self
.TFMfile
.char_info
[charcode
].italic_index
])
143 # routines returning lengths as floats in PostScript points
145 def getwidth_pt(self
, charcode
):
146 return self
._convert
_tfm
_to
_pt
(self
.TFMfile
.width
[self
.TFMfile
.char_info
[charcode
].width_index
])
148 def getheight_pt(self
, charcode
):
149 return self
._convert
_tfm
_to
_pt
(self
.TFMfile
.height
[self
.TFMfile
.char_info
[charcode
].height_index
])
151 def getdepth_pt(self
, charcode
):
152 return self
._convert
_tfm
_to
_pt
(self
.TFMfile
.depth
[self
.TFMfile
.char_info
[charcode
].depth_index
])
154 def getitalic_pt(self
, charcode
):
155 return self
._convert
_tfm
_to
_pt
(self
.TFMfile
.italic
[self
.TFMfile
.char_info
[charcode
].italic_index
])
157 def text_pt(self
, x_pt
, y_pt
, charcodes
):
158 return TeXtext_pt(self
, x_pt
, y_pt
, charcodes
, self
.getsize_pt())
160 def getMAPline(self
, fontmap
):
161 if self
.name
not in fontmap
:
162 raise RuntimeError("missing font information for '%s'; check fontmapping file(s)" % self
.name
)
163 return fontmap
[self
.name
]
166 class virtualfont(TeXfont
):
168 def __init__(self
, name
, path
, c
, q
, d
, tfmconv
, pyxconv
, debug
=0):
169 TeXfont
.__init
__(self
, name
, c
, q
, d
, tfmconv
, pyxconv
, debug
)
170 self
.vffile
= vffile
.vffile(path
, self
.scale
, tfmconv
, pyxconv
, debug
> 1)
173 """ return fonts used in virtual font itself """
174 return self
.vffile
.getfonts()
176 def getchar(self
, cc
):
177 """ return dvi chunk corresponding to char code cc """
178 return self
.vffile
.getchar(cc
)
180 def text_pt(self
, x_pt
, y_pt
, charcodes
):
181 raise RuntimeError("you don't know what you're doing")
184 class TeXtext_pt(canvasitem
.canvasitem
):
186 def __init__(self
, font
, x_pt
, y_pt
, charcodes
, size_pt
):
190 self
.charcodes
= charcodes
191 self
.size_pt
= size_pt
193 self
.width_pt
= sum([self
.font
.getwidth_pt(charcode
) for charcode
in charcodes
])
194 self
.height_pt
= max([self
.font
.getheight_pt(charcode
) for charcode
in charcodes
])
195 self
.depth_pt
= max([self
.font
.getdepth_pt(charcode
) for charcode
in charcodes
])
197 self
._bbox
= bbox
.bbox_pt(self
.x_pt
, self
.y_pt
-self
.depth_pt
, self
.x_pt
+self
.width_pt
, self
.y_pt
+self
.height_pt
)
202 def processPS(self
, file, writer
, context
, registry
, bbox
):
204 mapline
= self
.font
.getMAPline(writer
.getfontmap())
205 font
= mapline
.getfont()
206 text
= font
.text_pt(self
.x_pt
, self
.y_pt
, self
.charcodes
, self
.size_pt
, decoding
=mapline
.getencoding(), slant
=mapline
.slant
, ignorebbox
=True)
207 text
.processPS(file, writer
, context
, registry
, bbox
)
209 def processPDF(self
, file, writer
, context
, registry
, bbox
):