removed unwanted trailing spaces from fpdf
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.00.0 (2012-08-23 08:35:38) dev
|
Version 2.00.0 (2012-08-23 08:36:47) dev
|
||||||
|
|||||||
@@ -14,3 +14,5 @@ except ImportError:
|
|||||||
warnings.warn("web2py gluon package not installed, required for html2pdf")
|
warnings.warn("web2py gluon package not installed, required for html2pdf")
|
||||||
|
|
||||||
from template import Template
|
from template import Template
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ fpdf_charwidths['symbol']={
|
|||||||
'\xc6':823,'\xc7':768,'\xc8':768,'\xc9':713,'\xca':713,'\xcb':713,'\xcc':713,'\xcd':713,'\xce':713,'\xcf':713,'\xd0':768,'\xd1':713,'\xd2':790,'\xd3':790,'\xd4':890,'\xd5':823,'\xd6':549,'\xd7':250,'\xd8':713,'\xd9':603,'\xda':603,'\xdb':1042,
|
'\xc6':823,'\xc7':768,'\xc8':768,'\xc9':713,'\xca':713,'\xcb':713,'\xcc':713,'\xcd':713,'\xce':713,'\xcf':713,'\xd0':768,'\xd1':713,'\xd2':790,'\xd3':790,'\xd4':890,'\xd5':823,'\xd6':549,'\xd7':250,'\xd8':713,'\xd9':603,'\xda':603,'\xdb':1042,
|
||||||
'\xdc':987,'\xdd':603,'\xde':987,'\xdf':603,'\xe0':494,'\xe1':329,'\xe2':790,'\xe3':790,'\xe4':786,'\xe5':713,'\xe6':384,'\xe7':384,'\xe8':384,'\xe9':384,'\xea':384,'\xeb':384,'\xec':494,'\xed':494,'\xee':494,'\xef':494,'\xf0':0,'\xf1':329,
|
'\xdc':987,'\xdd':603,'\xde':987,'\xdf':603,'\xe0':494,'\xe1':329,'\xe2':790,'\xe3':790,'\xe4':786,'\xe5':713,'\xe6':384,'\xe7':384,'\xe8':384,'\xe9':384,'\xea':384,'\xeb':384,'\xec':494,'\xed':494,'\xee':494,'\xef':494,'\xf0':0,'\xf1':329,
|
||||||
'\xf2':274,'\xf3':686,'\xf4':686,'\xf5':686,'\xf6':384,'\xf7':384,'\xf8':384,'\xf9':384,'\xfa':384,'\xfb':384,'\xfc':494,'\xfd':494,'\xfe':494,'\xff':0}
|
'\xf2':274,'\xf3':686,'\xf4':686,'\xf5':686,'\xf6':384,'\xf7':384,'\xf8':384,'\xf9':384,'\xfa':384,'\xfb':384,'\xfc':494,'\xfd':494,'\xfe':494,'\xff':0}
|
||||||
|
|
||||||
fpdf_charwidths['times']={
|
fpdf_charwidths['times']={
|
||||||
'\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250,
|
'\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250,
|
||||||
'\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':408,'#':500,'$':500,'%':833,'&':778,'\'':180,'(':333,')':333,'*':500,'+':564,
|
'\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':408,'#':500,'$':500,'%':833,'&':778,'\'':180,'(':333,')':333,'*':500,'+':564,
|
||||||
@@ -111,7 +111,7 @@ fpdf_charwidths['timesB']={
|
|||||||
'\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':389,'\xcd':389,'\xce':389,'\xcf':389,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':570,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722,
|
'\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':389,'\xcd':389,'\xce':389,'\xcf':389,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':570,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722,
|
||||||
'\xdc':722,'\xdd':722,'\xde':611,'\xdf':556,'\xe0':500,'\xe1':500,'\xe2':500,'\xe3':500,'\xe4':500,'\xe5':500,'\xe6':722,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':556,
|
'\xdc':722,'\xdd':722,'\xde':611,'\xdf':556,'\xe0':500,'\xe1':500,'\xe2':500,'\xe3':500,'\xe4':500,'\xe5':500,'\xe6':722,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':556,
|
||||||
'\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':570,'\xf8':500,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':500,'\xfe':556,'\xff':500}
|
'\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':570,'\xf8':500,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':500,'\xfe':556,'\xff':500}
|
||||||
|
|
||||||
fpdf_charwidths['timesBI']={
|
fpdf_charwidths['timesBI']={
|
||||||
'\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250,
|
'\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250,
|
||||||
'\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':389,'"':555,'#':500,'$':500,'%':833,'&':778,'\'':278,'(':333,')':333,'*':500,'+':570,
|
'\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':389,'"':555,'#':500,'$':500,'%':833,'&':778,'\'':278,'(':333,')':333,'*':500,'+':570,
|
||||||
@@ -154,3 +154,4 @@ fpdf_charwidths['zapfdingbats']={
|
|||||||
'\xdc':927,'\xdd':928,'\xde':928,'\xdf':834,'\xe0':873,'\xe1':828,'\xe2':924,'\xe3':924,'\xe4':917,'\xe5':930,'\xe6':931,'\xe7':463,'\xe8':883,'\xe9':836,'\xea':836,'\xeb':867,'\xec':867,'\xed':696,'\xee':696,'\xef':874,'\xf0':0,'\xf1':874,
|
'\xdc':927,'\xdd':928,'\xde':928,'\xdf':834,'\xe0':873,'\xe1':828,'\xe2':924,'\xe3':924,'\xe4':917,'\xe5':930,'\xe6':931,'\xe7':463,'\xe8':883,'\xe9':836,'\xea':836,'\xeb':867,'\xec':867,'\xed':696,'\xee':696,'\xef':874,'\xf0':0,'\xf1':874,
|
||||||
'\xf2':760,'\xf3':946,'\xf4':771,'\xf5':865,'\xf6':771,'\xf7':888,'\xf8':967,'\xf9':888,'\xfa':831,'\xfb':873,'\xfc':927,'\xfd':970,'\xfe':918,'\xff':0}
|
'\xf2':760,'\xf3':946,'\xf4':771,'\xf5':865,'\xf6':771,'\xf7':888,'\xf8':967,'\xf9':888,'\xfa':831,'\xfb':873,'\xfc':927,'\xfd':970,'\xfe':918,'\xff':0}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+30
-29
@@ -48,7 +48,7 @@ def set_global(var, val):
|
|||||||
|
|
||||||
class FPDF(object):
|
class FPDF(object):
|
||||||
"PDF Generation class"
|
"PDF Generation class"
|
||||||
|
|
||||||
def __init__(self, orientation='P',unit='mm',format='A4'):
|
def __init__(self, orientation='P',unit='mm',format='A4'):
|
||||||
# Some checks
|
# Some checks
|
||||||
self._dochecks()
|
self._dochecks()
|
||||||
@@ -352,7 +352,7 @@ class FPDF(object):
|
|||||||
elif (self.current_font['desc']['MissingWidth']) :
|
elif (self.current_font['desc']['MissingWidth']) :
|
||||||
w += self.current_font['desc']['MissingWidth']
|
w += self.current_font['desc']['MissingWidth']
|
||||||
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
||||||
else:
|
else:
|
||||||
w += 500
|
w += 500
|
||||||
else:
|
else:
|
||||||
for i in xrange(0, l):
|
for i in xrange(0, l):
|
||||||
@@ -397,10 +397,10 @@ class FPDF(object):
|
|||||||
global SYSTEM_TTFONTS
|
global SYSTEM_TTFONTS
|
||||||
if os.path.exists(fname):
|
if os.path.exists(fname):
|
||||||
ttffilename = fname
|
ttffilename = fname
|
||||||
elif (FPDF_FONT_DIR and
|
elif (FPDF_FONT_DIR and
|
||||||
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
||||||
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
||||||
elif (SYSTEM_TTFONTS and
|
elif (SYSTEM_TTFONTS and
|
||||||
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
||||||
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
||||||
else:
|
else:
|
||||||
@@ -455,11 +455,11 @@ class FPDF(object):
|
|||||||
else:
|
else:
|
||||||
sbarr = range(0,32)
|
sbarr = range(0,32)
|
||||||
self.fonts[fontkey] = {
|
self.fonts[fontkey] = {
|
||||||
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
||||||
'name': font_dict['name'], 'desc': font_dict['desc'],
|
'name': font_dict['name'], 'desc': font_dict['desc'],
|
||||||
'up': font_dict['up'], 'ut': font_dict['ut'],
|
'up': font_dict['up'], 'ut': font_dict['ut'],
|
||||||
'cw': font_dict['cw'],
|
'cw': font_dict['cw'],
|
||||||
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
||||||
'subset': sbarr, 'unifilename': unifilename,
|
'subset': sbarr, 'unifilename': unifilename,
|
||||||
}
|
}
|
||||||
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
||||||
@@ -490,7 +490,7 @@ class FPDF(object):
|
|||||||
if (type == 'TrueType'):
|
if (type == 'TrueType'):
|
||||||
self.font_files[filename]={'length1': originalsize}
|
self.font_files[filename]={'length1': originalsize}
|
||||||
else:
|
else:
|
||||||
self.font_files[filename]={'length1': size1,
|
self.font_files[filename]={'length1': size1,
|
||||||
'length2': size2}
|
'length2': size2}
|
||||||
|
|
||||||
def set_font(self, family,style='',size=0):
|
def set_font(self, family,style='',size=0):
|
||||||
@@ -656,7 +656,7 @@ class FPDF(object):
|
|||||||
dx=self.c_margin
|
dx=self.c_margin
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
s+='q '+self.text_color+' '
|
s+='q '+self.text_color+' '
|
||||||
|
|
||||||
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
||||||
if (self.ws and self.unifontsubset):
|
if (self.ws and self.unifontsubset):
|
||||||
for uni in UTF8StringToArray(txt):
|
for uni in UTF8StringToArray(txt):
|
||||||
@@ -680,9 +680,9 @@ class FPDF(object):
|
|||||||
for uni in UTF8StringToArray(txt):
|
for uni in UTF8StringToArray(txt):
|
||||||
self.current_font['subset'].append(uni)
|
self.current_font['subset'].append(uni)
|
||||||
else:
|
else:
|
||||||
txt2 = txt.replace('\\','\\\\').replace(')','\\)').replace('(','\\(')
|
txt2 = txt.replace('\\','\\\\').replace(')','\\)').replace('(','\\(')
|
||||||
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
||||||
|
|
||||||
if(self.underline):
|
if(self.underline):
|
||||||
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
@@ -760,7 +760,7 @@ class FPDF(object):
|
|||||||
sep=i
|
sep=i
|
||||||
ls=l
|
ls=l
|
||||||
ns+=1
|
ns+=1
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -844,7 +844,7 @@ class FPDF(object):
|
|||||||
continue
|
continue
|
||||||
if(c==' '):
|
if(c==' '):
|
||||||
sep=i
|
sep=i
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -1198,7 +1198,7 @@ class FPDF(object):
|
|||||||
self._out('<</Type /Font');
|
self._out('<</Type /Font');
|
||||||
self._out('/Subtype /Type0');
|
self._out('/Subtype /Type0');
|
||||||
self._out('/BaseFont /' + fontname + '');
|
self._out('/BaseFont /' + fontname + '');
|
||||||
self._out('/Encoding /Identity-H');
|
self._out('/Encoding /Identity-H');
|
||||||
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
||||||
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
||||||
self._out('>>')
|
self._out('>>')
|
||||||
@@ -1260,7 +1260,7 @@ class FPDF(object):
|
|||||||
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
||||||
v = font['desc'][kd]
|
v = font['desc'][kd]
|
||||||
if (kd == 'Flags'):
|
if (kd == 'Flags'):
|
||||||
v = v | 4;
|
v = v | 4;
|
||||||
v = v & ~32; # SYMBOLIC font flag
|
v = v & ~32; # SYMBOLIC font flag
|
||||||
self._out(' /%s %s' % (kd, v))
|
self._out(' /%s %s' % (kd, v))
|
||||||
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
||||||
@@ -1282,7 +1282,7 @@ class FPDF(object):
|
|||||||
self._putstream(cidtogidmap)
|
self._putstream(cidtogidmap)
|
||||||
self._out('endobj')
|
self._out('endobj')
|
||||||
|
|
||||||
#Font file
|
#Font file
|
||||||
self._newobj()
|
self._newobj()
|
||||||
self._out('<</Length ' + str(len(fontstream)))
|
self._out('<</Length ' + str(len(fontstream)))
|
||||||
self._out('/Filter /FlateDecode')
|
self._out('/Filter /FlateDecode')
|
||||||
@@ -1344,7 +1344,7 @@ class FPDF(object):
|
|||||||
continue
|
continue
|
||||||
width = font['cw'][cid]
|
width = font['cw'][cid]
|
||||||
if (width == 65535): width = 0
|
if (width == 65535): width = 0
|
||||||
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
||||||
continue
|
continue
|
||||||
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
||||||
if (cid == (prevcid + 1)):
|
if (cid == (prevcid + 1)):
|
||||||
@@ -1396,7 +1396,7 @@ class FPDF(object):
|
|||||||
if (len(set(ws)) == 1):
|
if (len(set(ws)) == 1):
|
||||||
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
||||||
else:
|
else:
|
||||||
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
||||||
self._out('/W [%s]' % ''.join(w))
|
self._out('/W [%s]' % ''.join(w))
|
||||||
|
|
||||||
def _putimages(self):
|
def _putimages(self):
|
||||||
@@ -1408,7 +1408,7 @@ class FPDF(object):
|
|||||||
del info['data']
|
del info['data']
|
||||||
if 'smask' in info:
|
if 'smask' in info:
|
||||||
del info['smask']
|
del info['smask']
|
||||||
|
|
||||||
def _putimage(self, info):
|
def _putimage(self, info):
|
||||||
if 'data' in info:
|
if 'data' in info:
|
||||||
self._newobj()
|
self._newobj()
|
||||||
@@ -1785,20 +1785,20 @@ class FPDF(object):
|
|||||||
|
|
||||||
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
||||||
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
wide = w
|
wide = w
|
||||||
|
|
||||||
# wide/narrow codes for the digits
|
# wide/narrow codes for the digits
|
||||||
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
||||||
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
||||||
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
# add leading zero if code-length is odd
|
# add leading zero if code-length is odd
|
||||||
if len(code) % 2 != 0:
|
if len(code) % 2 != 0:
|
||||||
code = '0' + code
|
code = '0' + code
|
||||||
|
|
||||||
# add start and stop codes
|
# add start and stop codes
|
||||||
code = 'AA' + code.lower() + 'ZA'
|
code = 'AA' + code.lower() + 'ZA'
|
||||||
|
|
||||||
@@ -1837,7 +1837,7 @@ class FPDF(object):
|
|||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
gap = narrow
|
gap = narrow
|
||||||
|
|
||||||
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
||||||
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
||||||
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
||||||
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
||||||
@@ -1854,8 +1854,8 @@ class FPDF(object):
|
|||||||
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
|
|
||||||
code = code.upper()
|
code = code.upper()
|
||||||
for i in xrange (0, len(code), 2):
|
for i in xrange (0, len(code), 2):
|
||||||
char_bar = code[i]
|
char_bar = code[i]
|
||||||
@@ -1865,7 +1865,7 @@ class FPDF(object):
|
|||||||
|
|
||||||
seq= ''
|
seq= ''
|
||||||
for s in xrange(0, len(bar_char[char_bar])):
|
for s in xrange(0, len(bar_char[char_bar])):
|
||||||
seq += bar_char[char_bar][s]
|
seq += bar_char[char_bar][s]
|
||||||
|
|
||||||
for bar in xrange(0, len(seq)):
|
for bar in xrange(0, len(seq)):
|
||||||
if seq[bar] == 'n':
|
if seq[bar] == 'n':
|
||||||
@@ -1879,3 +1879,4 @@ class FPDF(object):
|
|||||||
x += gap
|
x += gap
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.page_links = {}
|
self.page_links = {}
|
||||||
self.font_list = ("times","courier", "helvetica")
|
self.font_list = ("times","courier", "helvetica")
|
||||||
self.font = None
|
self.font = None
|
||||||
self.font_stack = []
|
self.font_stack = []
|
||||||
self.pdf = pdf
|
self.pdf = pdf
|
||||||
self.r = self.g = self.b = 0
|
self.r = self.g = self.b = 0
|
||||||
self.indent = 0
|
self.indent = 0
|
||||||
@@ -54,7 +54,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.thead = None
|
self.thead = None
|
||||||
self.tfoot = None
|
self.tfoot = None
|
||||||
self.theader_out = self.tfooter_out = False
|
self.theader_out = self.tfooter_out = False
|
||||||
|
|
||||||
def width2mm(self, length):
|
def width2mm(self, length):
|
||||||
if length[-1]=='%':
|
if length[-1]=='%':
|
||||||
total = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin
|
total = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin
|
||||||
@@ -101,13 +101,13 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.pdf.add_page()
|
self.pdf.add_page()
|
||||||
self.theader_out = self.tfooter_out = False
|
self.theader_out = self.tfooter_out = False
|
||||||
if self.tfoot is None and self.thead is None:
|
if self.tfoot is None and self.thead is None:
|
||||||
if not self.theader_out:
|
if not self.theader_out:
|
||||||
self.output_table_header()
|
self.output_table_header()
|
||||||
self.box_shadow(w, h, bgcolor)
|
self.box_shadow(w, h, bgcolor)
|
||||||
if DEBUG: print "td cell", self.pdf.x, w, txt, "*"
|
if DEBUG: print "td cell", self.pdf.x, w, txt, "*"
|
||||||
self.pdf.cell(w,h,txt,border,0,align)
|
self.pdf.cell(w,h,txt,border,0,align)
|
||||||
elif self.table is not None:
|
elif self.table is not None:
|
||||||
# ignore anything else than td inside a table
|
# ignore anything else than td inside a table
|
||||||
pass
|
pass
|
||||||
elif self.align:
|
elif self.align:
|
||||||
if DEBUG: print "cell", txt, "*"
|
if DEBUG: print "cell", txt, "*"
|
||||||
@@ -142,7 +142,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.pdf.set_x(self.table_offset)
|
self.pdf.set_x(self.table_offset)
|
||||||
#self.pdf.set_x(x)
|
#self.pdf.set_x(x)
|
||||||
self.theader_out = True
|
self.theader_out = True
|
||||||
|
|
||||||
def output_table_footer(self):
|
def output_table_footer(self):
|
||||||
if self.tfooter:
|
if self.tfooter:
|
||||||
x = self.pdf.x
|
x = self.pdf.x
|
||||||
@@ -156,7 +156,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
if int(self.table.get('border', 0)):
|
if int(self.table.get('border', 0)):
|
||||||
self.output_table_sep()
|
self.output_table_sep()
|
||||||
self.tfooter_out = True
|
self.tfooter_out = True
|
||||||
|
|
||||||
def output_table_sep(self):
|
def output_table_sep(self):
|
||||||
self.pdf.set_x(self.table_offset)
|
self.pdf.set_x(self.table_offset)
|
||||||
x1 = self.pdf.x
|
x1 = self.pdf.x
|
||||||
@@ -335,7 +335,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
if face:
|
if face:
|
||||||
self.pdf.set_text_color(0,0,0)
|
self.pdf.set_text_color(0,0,0)
|
||||||
self.color = None
|
self.color = None
|
||||||
self.set_font(face, size)
|
self.set_font(face, size)
|
||||||
self.font = None
|
self.font = None
|
||||||
if tag=='center':
|
if tag=='center':
|
||||||
self.align = None
|
self.align = None
|
||||||
@@ -352,7 +352,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.set_style('u', False)
|
self.set_style('u', False)
|
||||||
self.set_style('b', False)
|
self.set_style('b', False)
|
||||||
self.set_style('i', False)
|
self.set_style('i', False)
|
||||||
self.set_text_color()
|
self.set_text_color()
|
||||||
|
|
||||||
def set_style(self, tag=None, enable=None):
|
def set_style(self, tag=None, enable=None):
|
||||||
#Modify style and select corresponding font
|
#Modify style and select corresponding font
|
||||||
@@ -374,7 +374,7 @@ class HTML2FPDF(HTMLParser):
|
|||||||
self.r = r
|
self.r = r
|
||||||
self.g = g
|
self.g = g
|
||||||
self.b = b
|
self.b = b
|
||||||
|
|
||||||
def put_link(self, url, txt):
|
def put_link(self, url, txt):
|
||||||
#Put a hyperlink
|
#Put a hyperlink
|
||||||
self.set_text_color(0,0,255)
|
self.set_text_color(0,0,255)
|
||||||
@@ -394,3 +394,4 @@ class HTMLMixin(object):
|
|||||||
h2p = HTML2FPDF(self)
|
h2p = HTML2FPDF(self)
|
||||||
h2p.feed(text)
|
h2p.feed(text)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ def print_r(array):
|
|||||||
array = dict([(k, k) for k in array])
|
array = dict([(k, k) for k in array])
|
||||||
for k, v in array.items():
|
for k, v in array.items():
|
||||||
print "[%s] => %s" % (k, v),
|
print "[%s] => %s" % (k, v),
|
||||||
|
|
||||||
def UTF8ToUTF16BE(instr, setbom=True):
|
def UTF8ToUTF16BE(instr, setbom=True):
|
||||||
"Converts UTF-8 strings to UTF16-BE."
|
"Converts UTF-8 strings to UTF16-BE."
|
||||||
outstr = ""
|
outstr = ""
|
||||||
if (setbom):
|
if (setbom):
|
||||||
outstr += "\xFE\xFF";
|
outstr += "\xFE\xFF";
|
||||||
if not isinstance(instr, unicode):
|
if not isinstance(instr, unicode):
|
||||||
instr = instr.decode('UTF-8')
|
instr = instr.decode('UTF-8')
|
||||||
outstr += instr.encode('UTF-16BE')
|
outstr += instr.encode('UTF-16BE')
|
||||||
@@ -30,14 +30,14 @@ def UTF8StringToArray(instr):
|
|||||||
"Converts UTF-8 strings to codepoints array"
|
"Converts UTF-8 strings to codepoints array"
|
||||||
return [ord(c) for c in instr]
|
return [ord(c) for c in instr]
|
||||||
|
|
||||||
# ttfints php helpers:
|
# ttfints php helpers:
|
||||||
|
|
||||||
def die(msg):
|
def die(msg):
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
def str_repeat(s, count):
|
def str_repeat(s, count):
|
||||||
return s * count
|
return s * count
|
||||||
|
|
||||||
def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ):
|
def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ):
|
||||||
if pad_type<0: # pad left
|
if pad_type<0: # pad left
|
||||||
return s.rjust(pad_length, pad_char)
|
return s.rjust(pad_length, pad_char)
|
||||||
@@ -46,4 +46,4 @@ def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ):
|
|||||||
else: # pad both
|
else: # pad both
|
||||||
return s.center(pad_length, pad_char)
|
return s.center(pad_length, pad_char)
|
||||||
|
|
||||||
strlen = count = lambda s: len(s)
|
strlen = count = lambda s: len(s)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Template:
|
|||||||
if elements:
|
if elements:
|
||||||
self.elements = elements
|
self.elements = elements
|
||||||
self.keys = [v['name'].lower() for v in self.elements]
|
self.keys = [v['name'].lower() for v in self.elements]
|
||||||
self.handlers = {'T': self.text, 'L': self.line, 'I': self.image,
|
self.handlers = {'T': self.text, 'L': self.line, 'I': self.image,
|
||||||
'B': self.rect, 'BC': self.barcode, }
|
'B': self.rect, 'BC': self.barcode, }
|
||||||
self.pg_no = 0
|
self.pg_no = 0
|
||||||
self.texts = {}
|
self.texts = {}
|
||||||
@@ -38,7 +38,7 @@ class Template:
|
|||||||
for row in csv.reader(open(infile, 'rb'), delimiter=delimiter):
|
for row in csv.reader(open(infile, 'rb'), delimiter=delimiter):
|
||||||
kargs = {}
|
kargs = {}
|
||||||
for i,v in enumerate(row):
|
for i,v in enumerate(row):
|
||||||
if not v.startswith("'") and decimal_sep!=".":
|
if not v.startswith("'") and decimal_sep!=".":
|
||||||
v = v.replace(decimal_sep,".")
|
v = v.replace(decimal_sep,".")
|
||||||
else:
|
else:
|
||||||
v = v
|
v = v
|
||||||
@@ -53,7 +53,7 @@ class Template:
|
|||||||
def add_page(self):
|
def add_page(self):
|
||||||
self.pg_no += 1
|
self.pg_no += 1
|
||||||
self.texts[self.pg_no] = {}
|
self.texts[self.pg_no] = {}
|
||||||
|
|
||||||
def __setitem__(self, name, value):
|
def __setitem__(self, name, value):
|
||||||
if self.has_key(name):
|
if self.has_key(name):
|
||||||
if isinstance(value,unicode):
|
if isinstance(value,unicode):
|
||||||
@@ -69,7 +69,7 @@ class Template:
|
|||||||
|
|
||||||
def has_key(self, name):
|
def has_key(self, name):
|
||||||
return name.lower() in self.keys
|
return name.lower() in self.keys
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
if self.has_key(name):
|
if self.has_key(name):
|
||||||
key = name.lower()
|
key = name.lower()
|
||||||
@@ -101,7 +101,7 @@ class Template:
|
|||||||
return pdf.multi_cell(w=element['x2']-element['x1'],
|
return pdf.multi_cell(w=element['x2']-element['x1'],
|
||||||
h=element['y2']-element['y1'],
|
h=element['y2']-element['y1'],
|
||||||
txt=text,align=align,split_only=True)
|
txt=text,align=align,split_only=True)
|
||||||
|
|
||||||
def render(self, outfile, dest="F"):
|
def render(self, outfile, dest="F"):
|
||||||
pdf = self.pdf
|
pdf = self.pdf
|
||||||
for pg in range(1, self.pg_no+1):
|
for pg in range(1, self.pg_no+1):
|
||||||
@@ -118,11 +118,11 @@ class Template:
|
|||||||
self.handlers[element['type'].upper()](pdf, **element)
|
self.handlers[element['type'].upper()](pdf, **element)
|
||||||
if 'rotate' in element:
|
if 'rotate' in element:
|
||||||
pdf.rotate(0)
|
pdf.rotate(0)
|
||||||
|
|
||||||
return pdf.output(outfile, dest)
|
return pdf.output(outfile, dest)
|
||||||
|
|
||||||
def text(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=10,
|
def text(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=10,
|
||||||
bold=False, italic=False, underline=False, align="",
|
bold=False, italic=False, underline=False, align="",
|
||||||
foreground=0, backgroud=65535, multiline=None,
|
foreground=0, backgroud=65535, multiline=None,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
if text:
|
if text:
|
||||||
@@ -201,7 +201,7 @@ if __name__ == "__main__":
|
|||||||
title="Sample Invoice", author="Sample Company",
|
title="Sample Invoice", author="Sample Company",
|
||||||
subject="Sample Customer", keywords="Electronic TAX Invoice")
|
subject="Sample Customer", keywords="Electronic TAX Invoice")
|
||||||
f.parse_csv(infile="invoice.csv", delimiter=";", decimal_sep=",")
|
f.parse_csv(infile="invoice.csv", delimiter=";", decimal_sep=",")
|
||||||
|
|
||||||
detail = "Lorem ipsum dolor sit amet, consectetur. " * 30
|
detail = "Lorem ipsum dolor sit amet, consectetur. " * 30
|
||||||
items = []
|
items = []
|
||||||
for i in range(1, 30):
|
for i in range(1, 30):
|
||||||
@@ -210,7 +210,7 @@ if __name__ == "__main__":
|
|||||||
price = round(random.random()*100,3)
|
price = round(random.random()*100,3)
|
||||||
code = "%s%s%02d" % (chr(random.randint(65,90)), chr(random.randint(65,90)),i)
|
code = "%s%s%02d" % (chr(random.randint(65,90)), chr(random.randint(65,90)),i)
|
||||||
items.append(dict(code=code, unit='u',
|
items.append(dict(code=code, unit='u',
|
||||||
qty=qty, price=price,
|
qty=qty, price=price,
|
||||||
amount=qty*price,
|
amount=qty*price,
|
||||||
ds="%s: %s" % (i,ds)))
|
ds="%s: %s" % (i,ds)))
|
||||||
|
|
||||||
@@ -253,7 +253,7 @@ if __name__ == "__main__":
|
|||||||
f["company_name"] = "Sample Company"
|
f["company_name"] = "Sample Company"
|
||||||
f["company_logo"] = "tutorial/logo.png"
|
f["company_logo"] = "tutorial/logo.png"
|
||||||
f["company_header1"] = "Some Address - somewhere -"
|
f["company_header1"] = "Some Address - somewhere -"
|
||||||
f["company_header2"] = "http://www.example.com"
|
f["company_header2"] = "http://www.example.com"
|
||||||
f["company_footer1"] = "Tax Code ..."
|
f["company_footer1"] = "Tax Code ..."
|
||||||
f["company_footer2"] = "Tax/VAT ID ..."
|
f["company_footer2"] = "Tax/VAT ID ..."
|
||||||
f['number'] = '0001-00001234'
|
f['number'] = '0001-00001234'
|
||||||
@@ -261,9 +261,9 @@ if __name__ == "__main__":
|
|||||||
f['due_date'] = '2099-09-10'
|
f['due_date'] = '2099-09-10'
|
||||||
f['customer_name'] = "Sample Client"
|
f['customer_name'] = "Sample Client"
|
||||||
f['customer_address'] = "Siempreviva 1234"
|
f['customer_address'] = "Siempreviva 1234"
|
||||||
|
|
||||||
# print line item...
|
# print line item...
|
||||||
li = 0
|
li = 0
|
||||||
k = 0
|
k = 0
|
||||||
total = Decimal("0.00")
|
total = Decimal("0.00")
|
||||||
for it in li_items:
|
for it in li_items:
|
||||||
@@ -293,9 +293,10 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
f['total_label'] = 'SubTotal:'
|
f['total_label'] = 'SubTotal:'
|
||||||
f['total'] = "%0.2f" % total
|
f['total'] = "%0.2f" % total
|
||||||
|
|
||||||
f.render("./invoice.pdf")
|
f.render("./invoice.pdf")
|
||||||
if sys.platform.startswith("linux"):
|
if sys.platform.startswith("linux"):
|
||||||
os.system("evince ./invoice.pdf")
|
os.system("evince ./invoice.pdf")
|
||||||
else:
|
else:
|
||||||
os.system("./invoice.pdf")
|
os.system("./invoice.pdf")
|
||||||
|
|
||||||
|
|||||||
+177
-177
@@ -1,19 +1,19 @@
|
|||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# TTFontFile class
|
# TTFontFile class
|
||||||
#
|
#
|
||||||
# This class is based on The ReportLab Open Source PDF library
|
# This class is based on The ReportLab Open Source PDF library
|
||||||
# written in Python - http://www.reportlab.com/software/opensource/
|
# written in Python - http://www.reportlab.com/software/opensource/
|
||||||
# together with ideas from the OpenOffice source code and others.
|
# together with ideas from the OpenOffice source code and others.
|
||||||
#
|
#
|
||||||
# Version: 1.04
|
# Version: 1.04
|
||||||
# Date: 2011-09-18
|
# Date: 2011-09-18
|
||||||
# Author: Ian Back <ianb@bpm1.com>
|
# Author: Ian Back <ianb@bpm1.com>
|
||||||
# License: LGPL
|
# License: LGPL
|
||||||
# Copyright (c) Ian Back, 2010
|
# Copyright (c) Ian Back, 2010
|
||||||
# Ported to Python 2.7 by Mariano Reingart (reingart@gmail.com) on 2012
|
# Ported to Python 2.7 by Mariano Reingart (reingart@gmail.com) on 2012
|
||||||
# This header must be retained in any redistribution or
|
# This header must be retained in any redistribution or
|
||||||
# modification of the file.
|
# modification of the file.
|
||||||
#
|
#
|
||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
|
|
||||||
from struct import pack, unpack, unpack_from
|
from struct import pack, unpack, unpack_from
|
||||||
@@ -43,22 +43,22 @@ def sub32(x, y):
|
|||||||
xhi = x[0]
|
xhi = x[0]
|
||||||
ylo = y[1]
|
ylo = y[1]
|
||||||
yhi = y[0]
|
yhi = y[0]
|
||||||
if (ylo > xlo):
|
if (ylo > xlo):
|
||||||
xlo += 1 << 16
|
xlo += 1 << 16
|
||||||
yhi += 1
|
yhi += 1
|
||||||
reslo = xlo-ylo
|
reslo = xlo-ylo
|
||||||
if (yhi > xhi):
|
if (yhi > xhi):
|
||||||
xhi += 1 << 16
|
xhi += 1 << 16
|
||||||
reshi = xhi-yhi
|
reshi = xhi-yhi
|
||||||
reshi = reshi & 0xFFFF
|
reshi = reshi & 0xFFFF
|
||||||
return (reshi, reslo)
|
return (reshi, reslo)
|
||||||
|
|
||||||
def calcChecksum(data):
|
def calcChecksum(data):
|
||||||
if (strlen(data) % 4):
|
if (strlen(data) % 4):
|
||||||
data += str_repeat("\0", (4-(len(data) % 4)))
|
data += str_repeat("\0", (4-(len(data) % 4)))
|
||||||
hi=0x0000
|
hi=0x0000
|
||||||
lo=0x0000
|
lo=0x0000
|
||||||
for i in range(0, len(data), 4):
|
for i in range(0, len(data), 4):
|
||||||
hi += (ord(data[i])<<8) + ord(data[i+1])
|
hi += (ord(data[i])<<8) + ord(data[i+1])
|
||||||
lo += (ord(data[i+2])<<8) + ord(data[i+3])
|
lo += (ord(data[i+2])<<8) + ord(data[i+3])
|
||||||
hi += lo >> 16
|
hi += lo >> 16
|
||||||
@@ -94,34 +94,34 @@ class TTFontFile:
|
|||||||
self.readTableDirectory()
|
self.readTableDirectory()
|
||||||
self.extractInfo()
|
self.extractInfo()
|
||||||
self.fh.close()
|
self.fh.close()
|
||||||
|
|
||||||
def readTableDirectory(self, ):
|
def readTableDirectory(self, ):
|
||||||
self.numTables = self.read_ushort()
|
self.numTables = self.read_ushort()
|
||||||
self.searchRange = self.read_ushort()
|
self.searchRange = self.read_ushort()
|
||||||
self.entrySelector = self.read_ushort()
|
self.entrySelector = self.read_ushort()
|
||||||
self.rangeShift = self.read_ushort()
|
self.rangeShift = self.read_ushort()
|
||||||
self.tables = {}
|
self.tables = {}
|
||||||
for i in range(self.numTables):
|
for i in range(self.numTables):
|
||||||
record = {}
|
record = {}
|
||||||
record['tag'] = self.read_tag()
|
record['tag'] = self.read_tag()
|
||||||
record['checksum'] = (self.read_ushort(),self.read_ushort())
|
record['checksum'] = (self.read_ushort(),self.read_ushort())
|
||||||
record['offset'] = self.read_ulong()
|
record['offset'] = self.read_ulong()
|
||||||
record['length'] = self.read_ulong()
|
record['length'] = self.read_ulong()
|
||||||
self.tables[record['tag']] = record
|
self.tables[record['tag']] = record
|
||||||
|
|
||||||
def get_table_pos(self, tag):
|
def get_table_pos(self, tag):
|
||||||
offset = self.tables[tag]['offset']
|
offset = self.tables[tag]['offset']
|
||||||
length = self.tables[tag]['length']
|
length = self.tables[tag]['length']
|
||||||
return (offset, length)
|
return (offset, length)
|
||||||
|
|
||||||
def seek(self, pos):
|
def seek(self, pos):
|
||||||
self._pos = pos
|
self._pos = pos
|
||||||
self.fh.seek(self._pos)
|
self.fh.seek(self._pos)
|
||||||
|
|
||||||
def skip(self, delta):
|
def skip(self, delta):
|
||||||
self._pos = self._pos + delta
|
self._pos = self._pos + delta
|
||||||
self.fh.seek(self._pos)
|
self.fh.seek(self._pos)
|
||||||
|
|
||||||
def seek_table(self, tag, offset_in_table = 0):
|
def seek_table(self, tag, offset_in_table = 0):
|
||||||
tpos = self.get_table_pos(tag)
|
tpos = self.get_table_pos(tag)
|
||||||
self._pos = tpos[0] + offset_in_table
|
self._pos = tpos[0] + offset_in_table
|
||||||
@@ -132,32 +132,32 @@ class TTFontFile:
|
|||||||
self._pos += 4
|
self._pos += 4
|
||||||
return self.fh.read(4)
|
return self.fh.read(4)
|
||||||
|
|
||||||
def read_short(self):
|
def read_short(self):
|
||||||
self._pos += 2
|
self._pos += 2
|
||||||
s = self.fh.read(2)
|
s = self.fh.read(2)
|
||||||
a = (ord(s[0])<<8) + ord(s[1])
|
a = (ord(s[0])<<8) + ord(s[1])
|
||||||
if (a & (1 << 15) ):
|
if (a & (1 << 15) ):
|
||||||
a = (a - (1 << 16))
|
a = (a - (1 << 16))
|
||||||
return a
|
return a
|
||||||
|
|
||||||
def unpack_short(self, s):
|
def unpack_short(self, s):
|
||||||
a = (ord(s[0])<<8) + ord(s[1])
|
a = (ord(s[0])<<8) + ord(s[1])
|
||||||
if (a & (1 << 15) ):
|
if (a & (1 << 15) ):
|
||||||
a = (a - (1 << 16))
|
a = (a - (1 << 16))
|
||||||
return a
|
return a
|
||||||
|
|
||||||
def read_ushort(self):
|
def read_ushort(self):
|
||||||
self._pos += 2
|
self._pos += 2
|
||||||
s = self.fh.read(2)
|
s = self.fh.read(2)
|
||||||
return (ord(s[0])<<8) + ord(s[1])
|
return (ord(s[0])<<8) + ord(s[1])
|
||||||
|
|
||||||
def read_ulong(self):
|
def read_ulong(self):
|
||||||
self._pos += 4
|
self._pos += 4
|
||||||
s = self.fh.read(4)
|
s = self.fh.read(4)
|
||||||
# if large uInt32 as an integer, PHP converts it to -ve
|
# if large uInt32 as an integer, PHP converts it to -ve
|
||||||
return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24
|
return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24
|
||||||
|
|
||||||
def get_ushort(self, pos):
|
def get_ushort(self, pos):
|
||||||
self.fh.seek(pos)
|
self.fh.seek(pos)
|
||||||
s = self.fh.read(2)
|
s = self.fh.read(2)
|
||||||
return (ord(s[0])<<8) + ord(s[1])
|
return (ord(s[0])<<8) + ord(s[1])
|
||||||
@@ -166,45 +166,45 @@ class TTFontFile:
|
|||||||
self.fh.seek(pos)
|
self.fh.seek(pos)
|
||||||
s = self.fh.read(4)
|
s = self.fh.read(4)
|
||||||
# iF large uInt32 as an integer, PHP converts it to -ve
|
# iF large uInt32 as an integer, PHP converts it to -ve
|
||||||
return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24
|
return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24
|
||||||
|
|
||||||
def pack_short(self, val):
|
def pack_short(self, val):
|
||||||
if (val<0):
|
if (val<0):
|
||||||
val = abs(val)
|
val = abs(val)
|
||||||
val = ~val
|
val = ~val
|
||||||
val += 1
|
val += 1
|
||||||
return pack(">H",val)
|
return pack(">H",val)
|
||||||
|
|
||||||
def splice(self, stream, offset, value):
|
def splice(self, stream, offset, value):
|
||||||
return substr(stream,0,offset) + value + substr(stream,offset+strlen(value))
|
return substr(stream,0,offset) + value + substr(stream,offset+strlen(value))
|
||||||
|
|
||||||
def _set_ushort(self, stream, offset, value):
|
def _set_ushort(self, stream, offset, value):
|
||||||
up = pack(">H", value)
|
up = pack(">H", value)
|
||||||
return self.splice(stream, offset, up)
|
return self.splice(stream, offset, up)
|
||||||
|
|
||||||
def _set_short(self, stream, offset, val):
|
def _set_short(self, stream, offset, val):
|
||||||
if (val<0):
|
if (val<0):
|
||||||
val = abs(val)
|
val = abs(val)
|
||||||
val = ~val
|
val = ~val
|
||||||
val += 1
|
val += 1
|
||||||
up = pack(">H",val)
|
up = pack(">H",val)
|
||||||
return self.splice(stream, offset, up)
|
return self.splice(stream, offset, up)
|
||||||
|
|
||||||
def get_chunk(self, pos, length):
|
def get_chunk(self, pos, length):
|
||||||
self.fh.seek(pos)
|
self.fh.seek(pos)
|
||||||
if (length <1): return ''
|
if (length <1): return ''
|
||||||
return (self.fh.read(length))
|
return (self.fh.read(length))
|
||||||
|
|
||||||
def get_table(self, tag):
|
def get_table(self, tag):
|
||||||
(pos, length) = self.get_table_pos(tag)
|
(pos, length) = self.get_table_pos(tag)
|
||||||
if (length == 0):
|
if (length == 0):
|
||||||
die('Truetype font (' + self.filename + '): error reading table: ' + tag)
|
die('Truetype font (' + self.filename + '): error reading table: ' + tag)
|
||||||
self.fh.seek(pos)
|
self.fh.seek(pos)
|
||||||
return (self.fh.read(length))
|
return (self.fh.read(length))
|
||||||
|
|
||||||
def add(self, tag, data):
|
def add(self, tag, data):
|
||||||
if (tag == 'head') :
|
if (tag == 'head') :
|
||||||
data = self.splice(data, 8, "\0\0\0\0")
|
data = self.splice(data, 8, "\0\0\0\0")
|
||||||
self.otables[tag] = data
|
self.otables[tag] = data
|
||||||
|
|
||||||
############################################/
|
############################################/
|
||||||
@@ -212,7 +212,7 @@ class TTFontFile:
|
|||||||
|
|
||||||
############################################/
|
############################################/
|
||||||
|
|
||||||
def extractInfo(self):
|
def extractInfo(self):
|
||||||
#################/
|
#################/
|
||||||
# name - Naming table
|
# name - Naming table
|
||||||
#################/
|
#################/
|
||||||
@@ -228,7 +228,7 @@ class TTFontFile:
|
|||||||
names = {1:'',2:'',3:'',4:'',6:''}
|
names = {1:'',2:'',3:'',4:'',6:''}
|
||||||
K = names.keys()
|
K = names.keys()
|
||||||
nameCount = len(names)
|
nameCount = len(names)
|
||||||
for i in range(numRecords):
|
for i in range(numRecords):
|
||||||
platformId = self.read_ushort()
|
platformId = self.read_ushort()
|
||||||
encodingId = self.read_ushort()
|
encodingId = self.read_ushort()
|
||||||
languageId = self.read_ushort()
|
languageId = self.read_ushort()
|
||||||
@@ -250,19 +250,19 @@ class TTFontFile:
|
|||||||
length -= 1
|
length -= 1
|
||||||
self._pos = opos
|
self._pos = opos
|
||||||
self.seek(opos)
|
self.seek(opos)
|
||||||
|
|
||||||
elif (platformId == 1 and encodingId == 0 and languageId == 0): # Macintosh, Roman, English, PS Name
|
elif (platformId == 1 and encodingId == 0 and languageId == 0): # Macintosh, Roman, English, PS Name
|
||||||
opos = self._pos
|
opos = self._pos
|
||||||
N = self.get_chunk(string_data_offset + offset, length)
|
N = self.get_chunk(string_data_offset + offset, length)
|
||||||
self._pos = opos
|
self._pos = opos
|
||||||
self.seek(opos)
|
self.seek(opos)
|
||||||
|
|
||||||
if (N and names[nameId]==''):
|
if (N and names[nameId]==''):
|
||||||
names[nameId] = N
|
names[nameId] = N
|
||||||
nameCount -= 1
|
nameCount -= 1
|
||||||
if (nameCount==0): break
|
if (nameCount==0): break
|
||||||
|
|
||||||
|
|
||||||
if (names[6]):
|
if (names[6]):
|
||||||
psName = names[6]
|
psName = names[6]
|
||||||
elif (names[4]):
|
elif (names[4]):
|
||||||
@@ -275,29 +275,29 @@ class TTFontFile:
|
|||||||
die("Could not find PostScript font name")
|
die("Could not find PostScript font name")
|
||||||
self.name = psName
|
self.name = psName
|
||||||
if (names[1]):
|
if (names[1]):
|
||||||
self.familyName = names[1]
|
self.familyName = names[1]
|
||||||
else:
|
else:
|
||||||
self.familyName = psName
|
self.familyName = psName
|
||||||
if (names[2]):
|
if (names[2]):
|
||||||
self.styleName = names[2]
|
self.styleName = names[2]
|
||||||
else:
|
else:
|
||||||
self.styleName = 'Regular'
|
self.styleName = 'Regular'
|
||||||
if (names[4]):
|
if (names[4]):
|
||||||
self.fullName = names[4]
|
self.fullName = names[4]
|
||||||
else:
|
else:
|
||||||
self.fullName = psName
|
self.fullName = psName
|
||||||
if (names[3]):
|
if (names[3]):
|
||||||
self.uniqueFontID = names[3]
|
self.uniqueFontID = names[3]
|
||||||
else:
|
else:
|
||||||
self.uniqueFontID = psName
|
self.uniqueFontID = psName
|
||||||
if (names[6]):
|
if (names[6]):
|
||||||
self.fullName = names[6]
|
self.fullName = names[6]
|
||||||
|
|
||||||
#################/
|
#################/
|
||||||
# head - Font header table
|
# head - Font header table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("head")
|
self.seek_table("head")
|
||||||
self.skip(18)
|
self.skip(18)
|
||||||
self.unitsPerEm = unitsPerEm = self.read_ushort()
|
self.unitsPerEm = unitsPerEm = self.read_ushort()
|
||||||
scale = 1000 / float(unitsPerEm)
|
scale = 1000 / float(unitsPerEm)
|
||||||
self.skip(16)
|
self.skip(16)
|
||||||
@@ -323,22 +323,22 @@ class TTFontFile:
|
|||||||
hheaDescender = self.read_short()
|
hheaDescender = self.read_short()
|
||||||
self.ascent = (hheaAscender *scale)
|
self.ascent = (hheaAscender *scale)
|
||||||
self.descent = (hheaDescender *scale)
|
self.descent = (hheaDescender *scale)
|
||||||
|
|
||||||
|
|
||||||
#################/
|
#################/
|
||||||
# OS/2 - OS/2 and Windows metrics table
|
# OS/2 - OS/2 and Windows metrics table
|
||||||
#################/
|
#################/
|
||||||
if ("OS/2" in self.tables):
|
if ("OS/2" in self.tables):
|
||||||
self.seek_table("OS/2")
|
self.seek_table("OS/2")
|
||||||
version = self.read_ushort()
|
version = self.read_ushort()
|
||||||
self.skip(2)
|
self.skip(2)
|
||||||
usWeightClass = self.read_ushort()
|
usWeightClass = self.read_ushort()
|
||||||
self.skip(2)
|
self.skip(2)
|
||||||
fsType = self.read_ushort()
|
fsType = self.read_ushort()
|
||||||
if (fsType == 0x0002 or (fsType & 0x0300) != 0):
|
if (fsType == 0x0002 or (fsType & 0x0300) != 0):
|
||||||
die('ERROR - Font file ' + self.filename + ' cannot be embedded due to copyright restrictions.')
|
die('ERROR - Font file ' + self.filename + ' cannot be embedded due to copyright restrictions.')
|
||||||
self.restrictedUse = True
|
self.restrictedUse = True
|
||||||
|
|
||||||
self.skip(20)
|
self.skip(20)
|
||||||
sF = self.read_short()
|
sF = self.read_short()
|
||||||
self.sFamilyClass = (sF >> 8)
|
self.sFamilyClass = (sF >> 8)
|
||||||
@@ -348,30 +348,30 @@ class TTFontFile:
|
|||||||
self.skip(26)
|
self.skip(26)
|
||||||
sTypoAscender = self.read_short()
|
sTypoAscender = self.read_short()
|
||||||
sTypoDescender = self.read_short()
|
sTypoDescender = self.read_short()
|
||||||
if (not self.ascent):
|
if (not self.ascent):
|
||||||
self.ascent = (sTypoAscender*scale)
|
self.ascent = (sTypoAscender*scale)
|
||||||
if (not self.descent):
|
if (not self.descent):
|
||||||
self.descent = (sTypoDescender*scale)
|
self.descent = (sTypoDescender*scale)
|
||||||
if (version > 1):
|
if (version > 1):
|
||||||
self.skip(16)
|
self.skip(16)
|
||||||
sCapHeight = self.read_short()
|
sCapHeight = self.read_short()
|
||||||
self.capHeight = (sCapHeight*scale)
|
self.capHeight = (sCapHeight*scale)
|
||||||
else:
|
else:
|
||||||
self.capHeight = self.ascent
|
self.capHeight = self.ascent
|
||||||
|
|
||||||
else:
|
else:
|
||||||
usWeightClass = 500
|
usWeightClass = 500
|
||||||
if (not self.ascent): self.ascent = (yMax*scale)
|
if (not self.ascent): self.ascent = (yMax*scale)
|
||||||
if (not self.descent): self.descent = (yMin*scale)
|
if (not self.descent): self.descent = (yMin*scale)
|
||||||
self.capHeight = self.ascent
|
self.capHeight = self.ascent
|
||||||
|
|
||||||
self.stemV = 50 + int(pow((usWeightClass / 65.0),2))
|
self.stemV = 50 + int(pow((usWeightClass / 65.0),2))
|
||||||
|
|
||||||
#################/
|
#################/
|
||||||
# post - PostScript table
|
# post - PostScript table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("post")
|
self.seek_table("post")
|
||||||
self.skip(4)
|
self.skip(4)
|
||||||
self.italicAngle = self.read_short() + self.read_ushort() / 65536.0
|
self.italicAngle = self.read_short() + self.read_ushort() / 65536.0
|
||||||
self.underlinePosition = self.read_short() * scale
|
self.underlinePosition = self.read_short() * scale
|
||||||
self.underlineThickness = self.read_short() * scale
|
self.underlineThickness = self.read_short() * scale
|
||||||
@@ -390,7 +390,7 @@ class TTFontFile:
|
|||||||
# hhea - Horizontal header table
|
# hhea - Horizontal header table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("hhea")
|
self.seek_table("hhea")
|
||||||
self.skip(32)
|
self.skip(32)
|
||||||
metricDataFormat = self.read_ushort()
|
metricDataFormat = self.read_ushort()
|
||||||
if (metricDataFormat != 0):
|
if (metricDataFormat != 0):
|
||||||
die('Unknown horizontal metric data format '.metricDataFormat)
|
die('Unknown horizontal metric data format '.metricDataFormat)
|
||||||
@@ -402,7 +402,7 @@ class TTFontFile:
|
|||||||
# maxp - Maximum profile table
|
# maxp - Maximum profile table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("maxp")
|
self.seek_table("maxp")
|
||||||
self.skip(4)
|
self.skip(4)
|
||||||
numGlyphs = self.read_ushort()
|
numGlyphs = self.read_ushort()
|
||||||
|
|
||||||
#################/
|
#################/
|
||||||
@@ -424,7 +424,7 @@ class TTFontFile:
|
|||||||
unicode_cmap_offset = cmap_offset + offset
|
unicode_cmap_offset = cmap_offset + offset
|
||||||
break
|
break
|
||||||
self.seek(save_pos )
|
self.seek(save_pos )
|
||||||
|
|
||||||
if (not unicode_cmap_offset):
|
if (not unicode_cmap_offset):
|
||||||
die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)')
|
die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)')
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ class TTFontFile:
|
|||||||
# head - Font header table
|
# head - Font header table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("head")
|
self.seek_table("head")
|
||||||
self.skip(50)
|
self.skip(50)
|
||||||
indexToLocFormat = self.read_ushort()
|
indexToLocFormat = self.read_ushort()
|
||||||
glyphDataFormat = self.read_ushort()
|
glyphDataFormat = self.read_ushort()
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@ class TTFontFile:
|
|||||||
# hhea - Horizontal header table
|
# hhea - Horizontal header table
|
||||||
#################/
|
#################/
|
||||||
self.seek_table("hhea")
|
self.seek_table("hhea")
|
||||||
self.skip(32)
|
self.skip(32)
|
||||||
metricDataFormat = self.read_ushort()
|
metricDataFormat = self.read_ushort()
|
||||||
orignHmetrics = numberOfHMetrics = self.read_ushort()
|
orignHmetrics = numberOfHMetrics = self.read_ushort()
|
||||||
|
|
||||||
@@ -496,9 +496,9 @@ class TTFontFile:
|
|||||||
if (format == 4):
|
if (format == 4):
|
||||||
unicode_cmap_offset = cmap_offset + offset
|
unicode_cmap_offset = cmap_offset + offset
|
||||||
break
|
break
|
||||||
|
|
||||||
self.seek(save_pos )
|
self.seek(save_pos )
|
||||||
|
|
||||||
if (not unicode_cmap_offset):
|
if (not unicode_cmap_offset):
|
||||||
die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)')
|
die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)')
|
||||||
|
|
||||||
@@ -521,7 +521,7 @@ class TTFontFile:
|
|||||||
|
|
||||||
subsetglyphs = [(0, 0)] # special "sorted dict"!
|
subsetglyphs = [(0, 0)] # special "sorted dict"!
|
||||||
subsetCharToGlyph = {}
|
subsetCharToGlyph = {}
|
||||||
for code in subset:
|
for code in subset:
|
||||||
if (code in self.charToGlyph):
|
if (code in self.charToGlyph):
|
||||||
if (self.charToGlyph[code], code) not in subsetglyphs:
|
if (self.charToGlyph[code], code) not in subsetglyphs:
|
||||||
subsetglyphs.append((self.charToGlyph[code], code)) # Old Glyph ID => Unicode
|
subsetglyphs.append((self.charToGlyph[code], code)) # Old Glyph ID => Unicode
|
||||||
@@ -540,12 +540,12 @@ class TTFontFile:
|
|||||||
|
|
||||||
codeToGlyph = {}
|
codeToGlyph = {}
|
||||||
for uni, originalGlyphIdx in sorted(subsetCharToGlyph.items()):
|
for uni, originalGlyphIdx in sorted(subsetCharToGlyph.items()):
|
||||||
codeToGlyph[uni] = glyphSet[originalGlyphIdx]
|
codeToGlyph[uni] = glyphSet[originalGlyphIdx]
|
||||||
|
|
||||||
self.codeToGlyph = codeToGlyph
|
self.codeToGlyph = codeToGlyph
|
||||||
|
|
||||||
for originalGlyphIdx, uni in subsetglyphs:
|
for originalGlyphIdx, uni in subsetglyphs:
|
||||||
nonlocals = {'start': start, 'glyphSet': glyphSet,
|
nonlocals = {'start': start, 'glyphSet': glyphSet,
|
||||||
'subsetglyphs': subsetglyphs}
|
'subsetglyphs': subsetglyphs}
|
||||||
self.getGlyphs(originalGlyphIdx, nonlocals)
|
self.getGlyphs(originalGlyphIdx, nonlocals)
|
||||||
|
|
||||||
@@ -553,12 +553,12 @@ class TTFontFile:
|
|||||||
|
|
||||||
#tables copied from the original
|
#tables copied from the original
|
||||||
tags = ['name']
|
tags = ['name']
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
self.add(tag, self.get_table(tag))
|
self.add(tag, self.get_table(tag))
|
||||||
tags = ['cvt ', 'fpgm', 'prep', 'gasp']
|
tags = ['cvt ', 'fpgm', 'prep', 'gasp']
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if (tag in self.tables):
|
if (tag in self.tables):
|
||||||
self.add(tag, self.get_table(tag))
|
self.add(tag, self.get_table(tag))
|
||||||
|
|
||||||
# post - PostScript
|
# post - PostScript
|
||||||
opost = self.get_table('post')
|
opost = self.get_table('post')
|
||||||
@@ -592,7 +592,7 @@ class TTFontFile:
|
|||||||
while (searchRange * 2 <= segCount ):
|
while (searchRange * 2 <= segCount ):
|
||||||
searchRange = searchRange * 2
|
searchRange = searchRange * 2
|
||||||
entrySelector = entrySelector + 1
|
entrySelector = entrySelector + 1
|
||||||
|
|
||||||
searchRange = searchRange * 2
|
searchRange = searchRange * 2
|
||||||
rangeShift = segCount * 2 - searchRange
|
rangeShift = segCount * 2 - searchRange
|
||||||
length = 16 + (8*segCount ) + (numGlyphs+1)
|
length = 16 + (8*segCount ) + (numGlyphs+1)
|
||||||
@@ -606,46 +606,46 @@ class TTFontFile:
|
|||||||
rangeShift]
|
rangeShift]
|
||||||
|
|
||||||
range_ = sorted(range_.items())
|
range_ = sorted(range_.items())
|
||||||
|
|
||||||
# endCode(s)
|
# endCode(s)
|
||||||
for start, subrange in range_:
|
for start, subrange in range_:
|
||||||
endCode = start + (len(subrange)-1)
|
endCode = start + (len(subrange)-1)
|
||||||
cmap.append(endCode) # endCode(s)
|
cmap.append(endCode) # endCode(s)
|
||||||
|
|
||||||
cmap.append(0xFFFF) # endCode of last Segment
|
cmap.append(0xFFFF) # endCode of last Segment
|
||||||
cmap.append(0) # reservedPad
|
cmap.append(0) # reservedPad
|
||||||
|
|
||||||
# startCode(s)
|
# startCode(s)
|
||||||
for start, subrange in range_:
|
for start, subrange in range_:
|
||||||
cmap.append(start) # startCode(s)
|
cmap.append(start) # startCode(s)
|
||||||
|
|
||||||
cmap.append(0xFFFF) # startCode of last Segment
|
cmap.append(0xFFFF) # startCode of last Segment
|
||||||
# idDelta(s)
|
# idDelta(s)
|
||||||
for start, subrange in range_:
|
for start, subrange in range_:
|
||||||
idDelta = -(start-subrange[0])
|
idDelta = -(start-subrange[0])
|
||||||
n += count(subrange)
|
n += count(subrange)
|
||||||
cmap.append(idDelta) # idDelta(s)
|
cmap.append(idDelta) # idDelta(s)
|
||||||
|
|
||||||
cmap.append(1) # idDelta of last Segment
|
cmap.append(1) # idDelta of last Segment
|
||||||
# idRangeOffset(s)
|
# idRangeOffset(s)
|
||||||
for subrange in range_:
|
for subrange in range_:
|
||||||
cmap.append(0) # idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0
|
cmap.append(0) # idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0
|
||||||
|
|
||||||
cmap.append(0) # idRangeOffset of last Segment
|
cmap.append(0) # idRangeOffset of last Segment
|
||||||
for subrange, glidx in range_:
|
for subrange, glidx in range_:
|
||||||
cmap.extend(glidx)
|
cmap.extend(glidx)
|
||||||
|
|
||||||
cmap.append(0) # Mapping for last character
|
cmap.append(0) # Mapping for last character
|
||||||
cmapstr = ''
|
cmapstr = ''
|
||||||
for cm in cmap:
|
for cm in cmap:
|
||||||
if cm >= 0:
|
if cm >= 0:
|
||||||
cmapstr += pack(">H", cm)
|
cmapstr += pack(">H", cm)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
cmapstr += pack(">h", cm)
|
cmapstr += pack(">h", cm)
|
||||||
except:
|
except:
|
||||||
warnings.warn("cmap value too big/small: %s" % cm)
|
warnings.warn("cmap value too big/small: %s" % cm)
|
||||||
cmapstr += pack(">H", -cm)
|
cmapstr += pack(">H", -cm)
|
||||||
self.add('cmap', cmapstr)
|
self.add('cmap', cmapstr)
|
||||||
|
|
||||||
# glyf - Glyph data
|
# glyf - Glyph data
|
||||||
@@ -674,9 +674,9 @@ class TTFontFile:
|
|||||||
maxComponentDepth = 0 # levels of recursion, set to 0 if font has only simple glyphs
|
maxComponentDepth = 0 # levels of recursion, set to 0 if font has only simple glyphs
|
||||||
self.glyphdata = {}
|
self.glyphdata = {}
|
||||||
|
|
||||||
for originalGlyphIdx, uni in subsetglyphs:
|
for originalGlyphIdx, uni in subsetglyphs:
|
||||||
# hmtx - Horizontal Metrics
|
# hmtx - Horizontal Metrics
|
||||||
hm = self.getHMetric(orignHmetrics, originalGlyphIdx)
|
hm = self.getHMetric(orignHmetrics, originalGlyphIdx)
|
||||||
hmtxstr += hm
|
hmtxstr += hm
|
||||||
|
|
||||||
offsets.append(pos)
|
offsets.append(pos)
|
||||||
@@ -694,7 +694,7 @@ class TTFontFile:
|
|||||||
data = self.get_chunk(glyfOffset+glyphPos,glyphLen)
|
data = self.get_chunk(glyfOffset+glyphPos,glyphLen)
|
||||||
else:
|
else:
|
||||||
data = ''
|
data = ''
|
||||||
|
|
||||||
if (glyphLen > 0):
|
if (glyphLen > 0):
|
||||||
up = unpack(">H", substr(data,0,2))[0]
|
up = unpack(">H", substr(data,0,2))[0]
|
||||||
if (glyphLen > 2 and (up & (1 << 15)) ): # If number of contours <= -1 i.e. composiste glyph
|
if (glyphLen > 2 and (up & (1 << 15)) ): # If number of contours <= -1 i.e. composiste glyph
|
||||||
@@ -714,22 +714,22 @@ class TTFontFile:
|
|||||||
data = 0
|
data = 0
|
||||||
warnings.warn("missing glyph data %s" % glyphIdx)
|
warnings.warn("missing glyph data %s" % glyphIdx)
|
||||||
pos_in_glyph += 4
|
pos_in_glyph += 4
|
||||||
if (flags & GF_WORDS):
|
if (flags & GF_WORDS):
|
||||||
pos_in_glyph += 4
|
pos_in_glyph += 4
|
||||||
else:
|
else:
|
||||||
pos_in_glyph += 2
|
pos_in_glyph += 2
|
||||||
if (flags & GF_SCALE):
|
if (flags & GF_SCALE):
|
||||||
pos_in_glyph += 2
|
pos_in_glyph += 2
|
||||||
elif (flags & GF_XYSCALE):
|
elif (flags & GF_XYSCALE):
|
||||||
pos_in_glyph += 4
|
pos_in_glyph += 4
|
||||||
elif (flags & GF_TWOBYTWO):
|
elif (flags & GF_TWOBYTWO):
|
||||||
pos_in_glyph += 8
|
pos_in_glyph += 8
|
||||||
|
|
||||||
maxComponentElements = max(maxComponentElements, nComponentElements)
|
maxComponentElements = max(maxComponentElements, nComponentElements)
|
||||||
|
|
||||||
glyf += data
|
glyf += data
|
||||||
pos += glyphLen
|
pos += glyphLen
|
||||||
if (pos % 4 != 0):
|
if (pos % 4 != 0):
|
||||||
padding = 4 - (pos % 4)
|
padding = 4 - (pos % 4)
|
||||||
glyf += str_repeat("\0",padding)
|
glyf += str_repeat("\0",padding)
|
||||||
pos += padding
|
pos += padding
|
||||||
@@ -742,15 +742,15 @@ class TTFontFile:
|
|||||||
|
|
||||||
# loca - Index to location
|
# loca - Index to location
|
||||||
locastr = ''
|
locastr = ''
|
||||||
if (((pos + 1) >> 1) > 0xFFFF):
|
if (((pos + 1) >> 1) > 0xFFFF):
|
||||||
indexToLocFormat = 1 # long format
|
indexToLocFormat = 1 # long format
|
||||||
for offset in offsets:
|
for offset in offsets:
|
||||||
locastr += pack(">L",offset)
|
locastr += pack(">L",offset)
|
||||||
else:
|
else:
|
||||||
indexToLocFormat = 0 # short format
|
indexToLocFormat = 0 # short format
|
||||||
for offset in offsets:
|
for offset in offsets:
|
||||||
locastr += pack(">H",(offset/2))
|
locastr += pack(">H",(offset/2))
|
||||||
|
|
||||||
self.add('loca', locastr)
|
self.add('loca', locastr)
|
||||||
|
|
||||||
# head - Font header
|
# head - Font header
|
||||||
@@ -776,8 +776,8 @@ class TTFontFile:
|
|||||||
|
|
||||||
# Put the TTF file together
|
# Put the TTF file together
|
||||||
stm = self.endTTFile('')
|
stm = self.endTTFile('')
|
||||||
return stm
|
return stm
|
||||||
|
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# Recursively get composite glyph data
|
# Recursively get composite glyph data
|
||||||
@@ -786,21 +786,21 @@ class TTFontFile:
|
|||||||
nonlocals['depth'] += 1
|
nonlocals['depth'] += 1
|
||||||
nonlocals['maxdepth'] = max(nonlocals['maxdepth'], nonlocals['depth'])
|
nonlocals['maxdepth'] = max(nonlocals['maxdepth'], nonlocals['depth'])
|
||||||
if (len(self.glyphdata[originalGlyphIdx]['compGlyphs'])):
|
if (len(self.glyphdata[originalGlyphIdx]['compGlyphs'])):
|
||||||
for glyphIdx in self.glyphdata[originalGlyphIdx]['compGlyphs']:
|
for glyphIdx in self.glyphdata[originalGlyphIdx]['compGlyphs']:
|
||||||
self.getGlyphData(glyphIdx, nonlocals)
|
self.getGlyphData(glyphIdx, nonlocals)
|
||||||
|
|
||||||
elif ((self.glyphdata[originalGlyphIdx]['nContours'] > 0) and nonlocals['depth'] > 0): # simple
|
elif ((self.glyphdata[originalGlyphIdx]['nContours'] > 0) and nonlocals['depth'] > 0): # simple
|
||||||
contours += self.glyphdata[originalGlyphIdx]['nContours']
|
contours += self.glyphdata[originalGlyphIdx]['nContours']
|
||||||
points += self.glyphdata[originalGlyphIdx]['nPoints']
|
points += self.glyphdata[originalGlyphIdx]['nPoints']
|
||||||
|
|
||||||
nonlocals['depth'] -= 1
|
nonlocals['depth'] -= 1
|
||||||
|
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# Recursively get composite glyphs
|
# Recursively get composite glyphs
|
||||||
def getGlyphs(self, originalGlyphIdx, nonlocals):
|
def getGlyphs(self, originalGlyphIdx, nonlocals):
|
||||||
# &start, &glyphSet, &subsetglyphs)
|
# &start, &glyphSet, &subsetglyphs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
glyphPos = self.glyphPos[originalGlyphIdx]
|
glyphPos = self.glyphPos[originalGlyphIdx]
|
||||||
glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos
|
glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos
|
||||||
@@ -808,21 +808,21 @@ class TTFontFile:
|
|||||||
warnings.warn("missing glyph %s" % (originalGlyphIdx))
|
warnings.warn("missing glyph %s" % (originalGlyphIdx))
|
||||||
return
|
return
|
||||||
|
|
||||||
if (not glyphLen):
|
if (not glyphLen):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.seek(nonlocals['start'] + glyphPos)
|
self.seek(nonlocals['start'] + glyphPos)
|
||||||
numberOfContours = self.read_short()
|
numberOfContours = self.read_short()
|
||||||
if (numberOfContours < 0):
|
if (numberOfContours < 0):
|
||||||
self.skip(8)
|
self.skip(8)
|
||||||
flags = GF_MORE
|
flags = GF_MORE
|
||||||
while (flags & GF_MORE):
|
while (flags & GF_MORE):
|
||||||
flags = self.read_ushort()
|
flags = self.read_ushort()
|
||||||
glyphIdx = self.read_ushort()
|
glyphIdx = self.read_ushort()
|
||||||
if (glyphIdx not in nonlocals['glyphSet']):
|
if (glyphIdx not in nonlocals['glyphSet']):
|
||||||
nonlocals['glyphSet'][glyphIdx] = len(nonlocals['subsetglyphs']) # old glyphID to new glyphID
|
nonlocals['glyphSet'][glyphIdx] = len(nonlocals['subsetglyphs']) # old glyphID to new glyphID
|
||||||
nonlocals['subsetglyphs'].append((glyphIdx, 1))
|
nonlocals['subsetglyphs'].append((glyphIdx, 1))
|
||||||
|
|
||||||
savepos = self.fh.tell()
|
savepos = self.fh.tell()
|
||||||
self.getGlyphs(glyphIdx, nonlocals)
|
self.getGlyphs(glyphIdx, nonlocals)
|
||||||
self.seek(savepos)
|
self.seek(savepos)
|
||||||
@@ -844,56 +844,56 @@ class TTFontFile:
|
|||||||
aw = 0
|
aw = 0
|
||||||
self.charWidths = [0] * 256*256*2
|
self.charWidths = [0] * 256*256*2
|
||||||
nCharWidths = 0
|
nCharWidths = 0
|
||||||
if ((numberOfHMetrics*4) < self.maxStrLenRead):
|
if ((numberOfHMetrics*4) < self.maxStrLenRead):
|
||||||
data = self.get_chunk(start,(numberOfHMetrics*4))
|
data = self.get_chunk(start,(numberOfHMetrics*4))
|
||||||
arr = unpack(">" + "H" * (len(data)/2), data)
|
arr = unpack(">" + "H" * (len(data)/2), data)
|
||||||
else:
|
else:
|
||||||
self.seek(start)
|
self.seek(start)
|
||||||
for glyph in range(numberOfHMetrics):
|
for glyph in range(numberOfHMetrics):
|
||||||
if ((numberOfHMetrics*4) < self.maxStrLenRead):
|
if ((numberOfHMetrics*4) < self.maxStrLenRead):
|
||||||
aw = arr[(glyph*2)] # PHP starts arrays from index 0!? +1
|
aw = arr[(glyph*2)] # PHP starts arrays from index 0!? +1
|
||||||
else:
|
else:
|
||||||
aw = self.read_ushort()
|
aw = self.read_ushort()
|
||||||
lsb = self.read_ushort()
|
lsb = self.read_ushort()
|
||||||
|
|
||||||
if (glyph in glyphToChar or glyph == 0):
|
if (glyph in glyphToChar or glyph == 0):
|
||||||
if (aw >= (1 << 15) ):
|
if (aw >= (1 << 15) ):
|
||||||
aw = 0 # 1.03 Some (arabic) fonts have -ve values for width
|
aw = 0 # 1.03 Some (arabic) fonts have -ve values for width
|
||||||
# although should be unsigned value - comes out as e.g. 65108 (intended -50)
|
# although should be unsigned value - comes out as e.g. 65108 (intended -50)
|
||||||
if (glyph == 0):
|
if (glyph == 0):
|
||||||
self.defaultWidth = scale*aw
|
self.defaultWidth = scale*aw
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for char in glyphToChar[glyph]:
|
for char in glyphToChar[glyph]:
|
||||||
if (char != 0 and char != 65535):
|
if (char != 0 and char != 65535):
|
||||||
w = int(round(scale*aw))
|
w = int(round(scale*aw))
|
||||||
if (w == 0): w = 65535
|
if (w == 0): w = 65535
|
||||||
if (char < 196608):
|
if (char < 196608):
|
||||||
self.charWidths[char] = w
|
self.charWidths[char] = w
|
||||||
nCharWidths += 1
|
nCharWidths += 1
|
||||||
|
|
||||||
|
|
||||||
data = self.get_chunk((start+numberOfHMetrics*4),(numGlyphs*2))
|
data = self.get_chunk((start+numberOfHMetrics*4),(numGlyphs*2))
|
||||||
arr = unpack(">" + "H" * (len(data)/2), data)
|
arr = unpack(">" + "H" * (len(data)/2), data)
|
||||||
diff = numGlyphs-numberOfHMetrics
|
diff = numGlyphs-numberOfHMetrics
|
||||||
for pos in range(diff):
|
for pos in range(diff):
|
||||||
glyph = pos + numberOfHMetrics
|
glyph = pos + numberOfHMetrics
|
||||||
if (glyph in glyphToChar):
|
if (glyph in glyphToChar):
|
||||||
for char in glyphToChar[glyph]:
|
for char in glyphToChar[glyph]:
|
||||||
if (char != 0 and char != 65535):
|
if (char != 0 and char != 65535):
|
||||||
w = int(round(scale*aw))
|
w = int(round(scale*aw))
|
||||||
if (w == 0): w = 65535
|
if (w == 0): w = 65535
|
||||||
if (char < 196608):
|
if (char < 196608):
|
||||||
self.charWidths[char] = w
|
self.charWidths[char] = w
|
||||||
nCharWidths += 1
|
nCharWidths += 1
|
||||||
|
|
||||||
|
|
||||||
# NB 65535 is a set width of 0
|
# NB 65535 is a set width of 0
|
||||||
# First bytes define number of chars in font
|
# First bytes define number of chars in font
|
||||||
self.charWidths[0] = nCharWidths
|
self.charWidths[0] = nCharWidths
|
||||||
|
|
||||||
|
|
||||||
def getHMetric(self, numberOfHMetrics, gid):
|
|
||||||
|
def getHMetric(self, numberOfHMetrics, gid):
|
||||||
start = self.seek_table("hmtx")
|
start = self.seek_table("hmtx")
|
||||||
if (gid < numberOfHMetrics):
|
if (gid < numberOfHMetrics):
|
||||||
self.seek(start+(gid*4))
|
self.seek(start+(gid*4))
|
||||||
@@ -904,15 +904,15 @@ class TTFontFile:
|
|||||||
self.seek(start+(numberOfHMetrics*2)+(gid*2))
|
self.seek(start+(numberOfHMetrics*2)+(gid*2))
|
||||||
hm += self.fh.read(2)
|
hm += self.fh.read(2)
|
||||||
return hm
|
return hm
|
||||||
|
|
||||||
|
|
||||||
def getLOCA(self, indexToLocFormat, numGlyphs):
|
|
||||||
|
def getLOCA(self, indexToLocFormat, numGlyphs):
|
||||||
start = self.seek_table('loca')
|
start = self.seek_table('loca')
|
||||||
self.glyphPos = []
|
self.glyphPos = []
|
||||||
if (indexToLocFormat == 0):
|
if (indexToLocFormat == 0):
|
||||||
data = self.get_chunk(start,(numGlyphs*2)+2)
|
data = self.get_chunk(start,(numGlyphs*2)+2)
|
||||||
arr = unpack(">" + "H" * (len(data)/2), data)
|
arr = unpack(">" + "H" * (len(data)/2), data)
|
||||||
for n in range(numGlyphs):
|
for n in range(numGlyphs):
|
||||||
self.glyphPos.append((arr[n] * 2)) # n+1 !?
|
self.glyphPos.append((arr[n] * 2)) # n+1 !?
|
||||||
elif (indexToLocFormat == 1):
|
elif (indexToLocFormat == 1):
|
||||||
data = self.get_chunk(start,(numGlyphs*4)+4)
|
data = self.get_chunk(start,(numGlyphs*4)+4)
|
||||||
@@ -938,18 +938,18 @@ class TTFontFile:
|
|||||||
self.skip(2)
|
self.skip(2)
|
||||||
startCount = []
|
startCount = []
|
||||||
for i in range(segCount):
|
for i in range(segCount):
|
||||||
startCount.append(self.read_ushort())
|
startCount.append(self.read_ushort())
|
||||||
idDelta = []
|
idDelta = []
|
||||||
for i in range(segCount):
|
for i in range(segCount):
|
||||||
idDelta.append(self.read_short()) # ???? was unsigned short
|
idDelta.append(self.read_short()) # ???? was unsigned short
|
||||||
idRangeOffset_start = self._pos
|
idRangeOffset_start = self._pos
|
||||||
idRangeOffset = []
|
idRangeOffset = []
|
||||||
for i in range(segCount):
|
for i in range(segCount):
|
||||||
idRangeOffset.append(self.read_ushort())
|
idRangeOffset.append(self.read_ushort())
|
||||||
|
|
||||||
for n in range(segCount):
|
for n in range(segCount):
|
||||||
endpoint = (endCount[n] + 1)
|
endpoint = (endCount[n] + 1)
|
||||||
for unichar in range(startCount[n], endpoint, 1):
|
for unichar in range(startCount[n], endpoint, 1):
|
||||||
if (idRangeOffset[n] == 0):
|
if (idRangeOffset[n] == 0):
|
||||||
glyph = (unichar + idDelta[n]) & 0xFFFF
|
glyph = (unichar + idDelta[n]) & 0xFFFF
|
||||||
else:
|
else:
|
||||||
@@ -961,33 +961,33 @@ class TTFontFile:
|
|||||||
glyph = self.get_ushort(offset)
|
glyph = self.get_ushort(offset)
|
||||||
if (glyph != 0):
|
if (glyph != 0):
|
||||||
glyph = (glyph + idDelta[n]) & 0xFFFF
|
glyph = (glyph + idDelta[n]) & 0xFFFF
|
||||||
|
|
||||||
charToGlyph[unichar] = glyph
|
charToGlyph[unichar] = glyph
|
||||||
if (unichar < 196608):
|
if (unichar < 196608):
|
||||||
self.maxUniChar = max(unichar,self.maxUniChar)
|
self.maxUniChar = max(unichar,self.maxUniChar)
|
||||||
glyphToChar.setdefault(glyph, []).append(unichar)
|
glyphToChar.setdefault(glyph, []).append(unichar)
|
||||||
|
|
||||||
|
|
||||||
# Put the TTF file together
|
# Put the TTF file together
|
||||||
def endTTFile(self, stm):
|
def endTTFile(self, stm):
|
||||||
stm = ''
|
stm = ''
|
||||||
numTables = count(self.otables)
|
numTables = count(self.otables)
|
||||||
searchRange = 1
|
searchRange = 1
|
||||||
entrySelector = 0
|
entrySelector = 0
|
||||||
while (searchRange * 2 <= numTables):
|
while (searchRange * 2 <= numTables):
|
||||||
searchRange = searchRange * 2
|
searchRange = searchRange * 2
|
||||||
entrySelector = entrySelector + 1
|
entrySelector = entrySelector + 1
|
||||||
|
|
||||||
searchRange = searchRange * 16
|
searchRange = searchRange * 16
|
||||||
rangeShift = numTables * 16 - searchRange
|
rangeShift = numTables * 16 - searchRange
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
if (_TTF_MAC_HEADER):
|
if (_TTF_MAC_HEADER):
|
||||||
stm += (pack(">LHHHH", 0x74727565, numTables, searchRange, entrySelector, rangeShift)) # Mac
|
stm += (pack(">LHHHH", 0x74727565, numTables, searchRange, entrySelector, rangeShift)) # Mac
|
||||||
else:
|
else:
|
||||||
stm += (pack(">LHHHH", 0x00010000 , numTables, searchRange, entrySelector, rangeShift)) # Windows
|
stm += (pack(">LHHHH", 0x00010000 , numTables, searchRange, entrySelector, rangeShift)) # Windows
|
||||||
|
|
||||||
|
|
||||||
# Table directory
|
# Table directory
|
||||||
tables = self.otables
|
tables = self.otables
|
||||||
|
|
||||||
@@ -995,7 +995,7 @@ class TTFontFile:
|
|||||||
sorted_tables = sorted(tables.items())
|
sorted_tables = sorted(tables.items())
|
||||||
for tag, data in sorted_tables:
|
for tag, data in sorted_tables:
|
||||||
if (tag == 'head'):
|
if (tag == 'head'):
|
||||||
head_start = offset
|
head_start = offset
|
||||||
stm += tag
|
stm += tag
|
||||||
checksum = calcChecksum(data)
|
checksum = calcChecksum(data)
|
||||||
stm += pack(">HH", checksum[0],checksum[1])
|
stm += pack(">HH", checksum[0],checksum[1])
|
||||||
@@ -1004,7 +1004,7 @@ class TTFontFile:
|
|||||||
offset = offset + paddedLength
|
offset = offset + paddedLength
|
||||||
|
|
||||||
# Table data
|
# Table data
|
||||||
for tag, data in sorted_tables:
|
for tag, data in sorted_tables:
|
||||||
data += "\0\0\0"
|
data += "\0\0\0"
|
||||||
stm += substr(data,0,(strlen(data)&~3))
|
stm += substr(data,0,(strlen(data)&~3))
|
||||||
|
|
||||||
@@ -1012,8 +1012,8 @@ class TTFontFile:
|
|||||||
checksum = sub32((0xB1B0,0xAFBA), checksum)
|
checksum = sub32((0xB1B0,0xAFBA), checksum)
|
||||||
chk = pack(">HH", checksum[0],checksum[1])
|
chk = pack(">HH", checksum[0],checksum[1])
|
||||||
stm = self.splice(stm,(head_start + 8),chk)
|
stm = self.splice(stm,(head_start + 8),chk)
|
||||||
return stm
|
return stm
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ttf = TTFontFile()
|
ttf = TTFontFile()
|
||||||
ttffile = 'DejaVuSansCondensed.ttf';
|
ttffile = 'DejaVuSansCondensed.ttf';
|
||||||
@@ -1030,4 +1030,4 @@ if __name__ == '__main__':
|
|||||||
assert round(ttf.underlineThickness, 0) == 44
|
assert round(ttf.underlineThickness, 0) == 44
|
||||||
# test char widths 8(against binary file generated by tfpdf.php):
|
# test char widths 8(against binary file generated by tfpdf.php):
|
||||||
assert ''.join(ttf.charWidths) == open("dejavusanscondensed.cw.dat").read()
|
assert ''.join(ttf.charWidths) == open("dejavusanscondensed.cw.dat").read()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user