From 434b27574a12fdca34a0080693efdd4619dcf1f3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Wobst?= Date: Fri, 26 Oct 2007 11:43:38 +0000 Subject: [PATCH] fontstripping and textaspath writer options; psfontmaps and pdffontmaps config options git-svn-id: https://pyx.svn.sourceforge.net/svnroot/pyx/trunk/pyx@2951 069f4177-920e-0410-937b-c2a4a81bcd90 --- CHANGES | 2 + pyx/canvas.py | 19 ++-- pyx/document.py | 4 +- pyx/font/font.py | 256 +++++++++++++++++++++++++++++++---------------------- pyx/font/t1file.py | 10 ++- pyx/pdfwriter.py | 13 +-- pyx/pswriter.py | 81 ++++++++--------- 7 files changed, 216 insertions(+), 169 deletions(-) diff --git a/CHANGES b/CHANGES index fc7595b4..335b4460 100644 --- a/CHANGES +++ b/CHANGES @@ -103,9 +103,11 @@ TODO: (using fonts without a metrics is still supported, but properly issues a warning now) - interface for basic TeX-less text output + - new PS and PDF writer options: fontstripping and textaspath (TODO: documentation) - canvas and document modules: - auto-guess output filename from the script filename - config module: + - psfontmaps and pdffontmaps config options (TODO: documentation) - config option for format warnings diff --git a/pyx/canvas.py b/pyx/canvas.py index 0d6dbee6..26de917e 100644 --- a/pyx/canvas.py +++ b/pyx/canvas.py @@ -158,15 +158,16 @@ class _canvas(canvasitem.canvasitem): file.write("q\n") # gsave nbbox = bboxmodule.empty() for item in self.items: - if isinstance(item, font.text_pt): - if not context.textregion: - file.write("BT\n") - context.textregion = 1 - else: - if context.textregion: - file.write("ET\n") - context.textregion = 0 - context.selectedfont = None + if not writer.textaspath: + if isinstance(item, font.text_pt): + if not context.textregion: + file.write("BT\n") + context.textregion = 1 + else: + if context.textregion: + file.write("ET\n") + context.textregion = 0 + context.selectedfont = None item.processPDF(file, writer, context, registry, nbbox) if context.textregion: file.write("ET\n") diff --git a/pyx/document.py b/pyx/document.py index 6a28b83d..6a68c91e 100644 --- a/pyx/document.py +++ b/pyx/document.py @@ -169,10 +169,10 @@ class document: self.pages.append(page) def writeEPSfile(self, file=None, **kwargs): - pswriter.epswriter(self, _outputstream(file, "eps"), **kwargs) + pswriter.EPSwriter(self, _outputstream(file, "eps"), **kwargs) def writePSfile(self, file=None, **kwargs): - pswriter.pswriter(self, _outputstream(file, "ps"), **kwargs) + pswriter.PSwriter(self, _outputstream(file, "ps"), **kwargs) def writePDFfile(self, file=None, **kwargs): pdfwriter.PDFwriter(self, _outputstream(file, "pdf"), **kwargs) diff --git a/pyx/font/font.py b/pyx/font/font.py index 7dc7ffe2..e8d6be3b 100644 --- a/pyx/font/font.py +++ b/pyx/font/font.py @@ -20,7 +20,7 @@ # along with PyX; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from pyx import bbox, canvasitem, pswriter, pdfwriter, trafo, unit +from pyx import bbox, canvasitem, deco, path, pswriter, pdfwriter, trafo, unit import t1file try: @@ -45,7 +45,6 @@ class PST1file(pswriter.PSresource): self.id = t1file.name self.glyphnames = set(glyphnames) self.charcodes = set(charcodes) - self.strip = 1 def merge(self, other): self.glyphnames.update(other.glyphnames) @@ -53,7 +52,7 @@ class PST1file(pswriter.PSresource): def output(self, file, writer, registry): file.write("%%%%BeginFont: %s\n" % self.t1file.name) - if self.strip: + if writer.stripfonts: if self.glyphnames: file.write("%%Included glyphs: %s\n" % " ".join(self.glyphnames)) if self.charcodes: @@ -236,14 +235,13 @@ class PDFfontfile(pdfwriter.PDFobject): self.t1file = t1file self.glyphnames = set(glyphnames) self.charcodes = set(charcodes) - self.strip = 1 def merge(self, other): self.glyphnames.update(other.glyphnames) self.charcodes.update(other.charcodes) def write(self, file, writer, registry): - if self.strip: + if writer.stripfonts: self.t1file.getstrippedfont(self.glyphnames, self.charcodes).outputPDF(file, writer) else: self.t1file.outputPDF(file, writer) @@ -391,123 +389,169 @@ class T1text_pt(text_pt): if not self.ignorebbox: bbox += self.bbox() - # register resources - if self.font.t1file is not None: + if writer.textaspath: if self.decode: - registry.add(PST1file(self.font.t1file, self.glyphnames, [])) - else: - registry.add(PST1file(self.font.t1file, [], self.charcodes)) - - fontname = self.font.name - if self.decode: - encodingname = self.getencodingname(context.encodings.setdefault(self.font.name, {})) - encoding = context.encodings[self.font.name][encodingname] - newfontname = "%s-%s" % (fontname, encodingname) - registry.add(_ReEncodeFont) - registry.add(PSreencodefont(fontname, newfontname, encoding)) - fontname = newfontname - - if self.slant: - newfontmatrix = trafo.trafo_pt(matrix=((1, self.slant), (0, 1))) * self.font.t1file.fontmatrix - newfontname = "%s-slant%f" % (fontname, self.slant) - registry.add(_ChangeFontMatrix) - registry.add(PSchangefontmatrix(fontname, newfontname, newfontmatrix)) - fontname = newfontname - - # select font if necessary - sf = selectedfont(fontname, self.size_pt) - if context.selectedfont is None or sf != context.selectedfont: - context.selectedfont = sf - sf.outputPS(file, writer) - - file.write("%f %f moveto (" % (self.x_pt, self.y_pt)) - if self.decode: - if self.kerning: - data = self.font.metric.resolvekernings(self.glyphnames, self.size_pt) + if self.kerning: + data = self.font.metric.resolvekernings(self.glyphnames, self.size_pt) + else: + data = self.glyphnames else: - data = self.glyphnames + data = self.charcodes + textpath = path.path() + for i, value in enumerate(data): + if self.kerning and i % 2: + if value is not None: + self.x_pt += value + else: + glyphpath, wx_pt, wy_pt = self.font.t1file.getglyphpathwxwy_pt(value, self.size_pt, convertcharcode=not self.decode) + textpath += glyphpath.transformed(trafo.translate_pt(self.x_pt, self.y_pt)) + self.x_pt += wx_pt + self.y_pt += wy_pt + deco.decoratedpath(textpath, fillstyles=[]).processPS(file, writer, context, registry, bbox) else: - data = self.charcodes - for i, value in enumerate(data): - if self.kerning and i % 2: - if value is not None: - file.write(") show\n%f 0 rmoveto (" % value) - else: + # register resources + if self.font.t1file is not None: if self.decode: - value = encoding[value] - if 32 < value < 127 and chr(value) not in "()[]<>\\": - file.write("%s" % chr(value)) + registry.add(PST1file(self.font.t1file, self.glyphnames, [])) + else: + registry.add(PST1file(self.font.t1file, [], self.charcodes)) + + fontname = self.font.name + if self.decode: + encodingname = self.getencodingname(context.encodings.setdefault(self.font.name, {})) + encoding = context.encodings[self.font.name][encodingname] + newfontname = "%s-%s" % (fontname, encodingname) + registry.add(_ReEncodeFont) + registry.add(PSreencodefont(fontname, newfontname, encoding)) + fontname = newfontname + + if self.slant: + newfontmatrix = trafo.trafo_pt(matrix=((1, self.slant), (0, 1))) * self.font.t1file.fontmatrix + newfontname = "%s-slant%f" % (fontname, self.slant) + registry.add(_ChangeFontMatrix) + registry.add(PSchangefontmatrix(fontname, newfontname, newfontmatrix)) + fontname = newfontname + + # select font if necessary + sf = selectedfont(fontname, self.size_pt) + if context.selectedfont is None or sf != context.selectedfont: + context.selectedfont = sf + sf.outputPS(file, writer) + + file.write("%f %f moveto (" % (self.x_pt, self.y_pt)) + if self.decode: + if self.kerning: + data = self.font.metric.resolvekernings(self.glyphnames, self.size_pt) + else: + data = self.glyphnames + else: + data = self.charcodes + for i, value in enumerate(data): + if self.kerning and i % 2: + if value is not None: + file.write(") show\n%f 0 rmoveto (" % value) else: - file.write("\\%03o" % value) - file.write(") show\n") + if self.decode: + value = encoding[value] + if 32 < value < 127 and chr(value) not in "()[]<>\\": + file.write("%s" % chr(value)) + else: + file.write("\\%03o" % value) + file.write(") show\n") def processPDF(self, file, writer, context, registry, bbox): if not self.ignorebbox: bbox += self.bbox() - if self.decode: - encodingname = self.getencodingname(context.encodings.setdefault(self.font.name, {})) - encoding = context.encodings[self.font.name][encodingname] - charcodes = [encoding[glyphname] for glyphname in self.glyphnames] - else: - charcodes = self.charcodes - - # create resources - fontname = self.font.name - if self.decode: - newfontname = "%s-%s" % (fontname, encodingname) - _encoding = PDFencoding(encoding, newfontname) - fontname = newfontname - else: - _encoding = None - if self.font.t1file is not None: + if writer.textaspath: if self.decode: - fontfile = PDFfontfile(self.font.t1file, self.glyphnames, []) + if self.kerning: + data = self.font.metric.resolvekernings(self.glyphnames, self.size_pt) + else: + data = self.glyphnames else: - fontfile = PDFfontfile(self.font.t1file, [], self.charcodes) - else: - fontfile = None - fontdescriptor = PDFfontdescriptor(self.font.name, fontfile, self.font.metric) - font = PDFfont(fontname, self.font.name, charcodes, fontdescriptor, _encoding, self.font.metric) - - # register resources - if fontfile is not None: - registry.add(fontfile) - registry.add(fontdescriptor) - if _encoding is not None: - registry.add(_encoding) - registry.add(font) - - registry.addresource("Font", fontname, font, procset="Text") - - if self.slant is None: - slantvalue = 0 + data = self.charcodes + textpath = path.path() + for i, value in enumerate(data): + if self.kerning and i % 2: + if value is not None: + self.x_pt += value + else: + glyphpath, wx_pt, wy_pt = self.font.t1file.getglyphpathwxwy_pt(value, self.size_pt, convertcharcode=not self.decode) + textpath += glyphpath.transformed(trafo.translate_pt(self.x_pt, self.y_pt)) + self.x_pt += wx_pt + self.y_pt += wy_pt + deco.decoratedpath(textpath, fillstyles=[]).processPDF(file, writer, context, registry, bbox) else: - slantvalue = self.slant + if self.decode: + encodingname = self.getencodingname(context.encodings.setdefault(self.font.name, {})) + encoding = context.encodings[self.font.name][encodingname] + charcodes = [encoding[glyphname] for glyphname in self.glyphnames] + else: + charcodes = self.charcodes - # select font if necessary - sf = selectedfont(fontname, self.size_pt) - if context.selectedfont is None or sf != context.selectedfont: - context.selectedfont = sf - sf.outputPDF(file, writer) + # create resources + fontname = self.font.name + if self.decode: + newfontname = "%s-%s" % (fontname, encodingname) + _encoding = PDFencoding(encoding, newfontname) + fontname = newfontname + else: + _encoding = None + if self.font.t1file is not None: + if self.decode: + fontfile = PDFfontfile(self.font.t1file, self.glyphnames, []) + else: + fontfile = PDFfontfile(self.font.t1file, [], self.charcodes) + else: + fontfile = None + fontdescriptor = PDFfontdescriptor(self.font.name, fontfile, self.font.metric) + font = PDFfont(fontname, self.font.name, charcodes, fontdescriptor, _encoding, self.font.metric) + + # register resources + if fontfile is not None: + registry.add(fontfile) + registry.add(fontdescriptor) + if _encoding is not None: + registry.add(_encoding) + registry.add(font) + + registry.addresource("Font", fontname, font, procset="Text") + + if self.slant is None: + slantvalue = 0 + else: + slantvalue = self.slant + + # select font if necessary + sf = selectedfont(fontname, self.size_pt) + if context.selectedfont is None or sf != context.selectedfont: + context.selectedfont = sf + sf.outputPDF(file, writer) - file.write("1 0 %f 1 %f %f Tm [(" % (slantvalue, self.x_pt, self.y_pt)) - if self.decode: if self.kerning: - data = self.font.metric.resolvekernings(self.glyphnames) + file.write("1 0 %f 1 %f %f Tm [(" % (slantvalue, self.x_pt, self.y_pt)) else: - data = self.glyphnames - else: - data = self.charcodes - for i, value in enumerate(data): - if self.kerning and i % 2: - if value is not None: - file.write(")%f(" % (-value)) + file.write("1 0 %f 1 %f %f Tm (" % (slantvalue, self.x_pt, self.y_pt)) + if self.decode: + if self.kerning: + data = self.font.metric.resolvekernings(self.glyphnames) + else: + data = self.glyphnames else: - if self.decode: - value = encoding[value] - if 32 <= value <= 127 and chr(value) not in "()[]<>\\": - file.write("%s" % chr(value)) + data = self.charcodes + for i, value in enumerate(data): + if self.kerning and i % 2: + if value is not None: + file.write(")%f(" % (-value)) else: - file.write("\\%03o" % value) - file.write(")] TJ\n") + if self.decode: + value = encoding[value] + if 32 <= value <= 127 and chr(value) not in "()[]<>\\": + file.write("%s" % chr(value)) + else: + file.write("\\%03o" % value) + if self.kerning: + file.write(")] TJ\n") + else: + file.write(") Tj\n") diff --git a/pyx/font/t1file.py b/pyx/font/t1file.py index 351aeb8b..b7cf8041 100644 --- a/pyx/font/t1file.py +++ b/pyx/font/t1file.py @@ -882,7 +882,11 @@ class T1file: def gatherglyphcalls(self, glyph, seacglyphs, subrs, othersubrs, context): self.gathercalls(self.getglyphcmds(glyph), seacglyphs, subrs, othersubrs, context) - def getglyphpathwxwy_pt(self, glyph, size): + def getglyphpathwxwy_pt(self, glyph, size, convertcharcode=False): + if convertcharcode: + if not self.encoding: + self._encoding() + glyph = self.encoding[glyph] t = self.fontmatrix.scaled(size) context = T1context(self) p = path() @@ -890,11 +894,11 @@ class T1file: wx, wy = t.apply_pt(context.wx, context.wy) return p, wx, wy - def getglyphpath(self, glyph, size): + def getglyphpath(self, glyph, size, convertcharcode=False): """return a PyX path for glyph named glyph""" return self.getglyphpathwxwy_pt(glyph, size)[0] - def getglyphwxwy_pt(self, glyph, size): + def getglyphwxwy_pt(self, glyph, size, convertcharcode=False): return self.getglyphpathwxwy_pt(glyph, size)[1:] def getdata2(self, subrs=None, glyphs=None): diff --git a/pyx/pdfwriter.py b/pyx/pdfwriter.py index fa34cbf6..d9bc8a5c 100644 --- a/pyx/pdfwriter.py +++ b/pyx/pdfwriter.py @@ -27,7 +27,7 @@ try: except: haszlib = 0 -import bbox, style, unit, version +import bbox, config, style, unit, version @@ -271,7 +271,8 @@ class PDFwriter: def __init__(self, document, file, title=None, author=None, subject=None, keywords=None, - fullscreen=0, writebbox=0, compress=1, compresslevel=6): + fullscreen=0, writebbox=0, compress=1, compresslevel=6, + stripfonts=True, textaspath=False): self._fontmap = None self.title = title @@ -285,6 +286,8 @@ class PDFwriter: warnings.warn("compression disabled due to missing zlib module") self.compress = compress self.compresslevel = compresslevel + self.stripfonts = stripfonts + self.textaspath = textaspath # the PDFcatalog class automatically builds up the pdfobjects from a document registry = PDFregistry() @@ -299,9 +302,9 @@ class PDFwriter: if self._fontmap is None: # late import due to cyclic dependency from pyx.dvi import mapfile - self._fontmap = mapfile.readfontmap(["pdftex.map"]) - # config.get("text", "fontmaps", "psfonts.map") - # self.fontmap = dvifile.readfontmap(self.fontmaps.split()) + fontmapfiles = config.get("text", "pdffontmaps", "pdftex.map") + separator = config.get("general", "separator", "|") + self._fontmap = mapfile.readfontmap(fontmapfiles.split(separator)) return self._fontmap diff --git a/pyx/pswriter.py b/pyx/pswriter.py index ba1ec0c1..13e75b53 100644 --- a/pyx/pswriter.py +++ b/pyx/pswriter.py @@ -21,24 +21,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import cStringIO, copy, time, math -import bbox, style, version, unit, trafo - -try: - enumerate([]) -except NameError: - # fallback implementation for Python 2.2 and below - def enumerate(list): - return zip(xrange(len(list)), list) - -try: - dict([]) -except NameError: - # fallback implementation for Python 2.1 - def dict(list): - result = {} - for key, value in list: - result[key] = value - return result +import bbox, config, style, version, unit, trafo class PSregistry: @@ -91,10 +74,6 @@ class PSresource: def output(self, file, writer, registry): raise NotImplementedError("output not implemented for %s" % repr(self)) -# -# Different variants of prolog items -# - class PSdefinition(PSresource): """ PostScript function definition included in the prolog """ @@ -109,11 +88,39 @@ class PSdefinition(PSresource): file.write("%(body)s /%(id)s exch def\n" % self.__dict__) file.write("%%EndRessource\n") +# +# Writers +# -class epswriter: +class _PSwriter: - def __init__(self, document, file, title=None): + def __init__(self, title=None, stripfonts=True, textaspath=False): self._fontmap = None + self.title = title + self.stripfonts = stripfonts + self.textaspath = textaspath + + def writeinfo(self, file): + file.write("%%%%Creator: PyX %s\n" % version.version) + if self.title is not None: + file.write("%%%%Title: %s\n" % self.title) + file.write("%%%%CreationDate: %s\n" % + time.asctime(time.localtime(time.time()))) + + def getfontmap(self): + if self._fontmap is None: + # late import due to cyclic dependency + from pyx.dvi import mapfile + fontmapfiles = config.get("text", "psfontmaps", "psfonts.map") + separator = config.get("general", "separator", "|") + self._fontmap = mapfile.readfontmap(fontmapfiles.split(separator)) + return self._fontmap + + +class EPSwriter(_PSwriter): + + def __init__(self, document, file, **kwargs): + _PSwriter.__init__(self, **kwargs) if len(document.pages) != 1: raise ValueError("EPS file can be constructed out of a single page document only") @@ -131,11 +138,7 @@ class epswriter: if pagebbox: file.write("%%%%BoundingBox: %d %d %d %d\n" % pagebbox.lowrestuple_pt()) file.write("%%%%HiResBoundingBox: %g %g %g %g\n" % pagebbox.highrestuple_pt()) - file.write("%%%%Creator: PyX %s\n" % version.version) - if title is not None: - file.write("%%%%Title: %s\n" % title) - file.write("%%%%CreationDate: %s\n" % - time.asctime(time.localtime(time.time()))) + self.writeinfo(file) file.write("%%EndComments\n") file.write("%%BeginProlog\n") @@ -149,19 +152,12 @@ class epswriter: file.write("%%Trailer\n") file.write("%%EOF\n") - def getfontmap(self): - if self._fontmap is None: - # late import due to cyclic dependency - from pyx.dvi import mapfile - self._fontmap = mapfile.readfontmap(["psfonts.map"]) - # config.get("text", "fontmaps", "psfonts.map") - # self.fontmap = dvifile.readfontmap(self.fontmaps.split()) - return self._fontmap +class PSwriter(_PSwriter): -class pswriter: + def __init__(self, document, file, writebbox=0, **kwargs): + _PSwriter.__init__(self, **kwargs) - def __init__(self, document, file, writebbox=0, title=None): # We first have to process the content of the pages, writing them into the stream pagesfile # Doing so, we fill the registry and also calculate the page bounding boxes, which are # stored in page._bbox for every page @@ -202,11 +198,7 @@ class pswriter: if documentbbox and writebbox: file.write("%%%%BoundingBox: %d %d %d %d\n" % documentbbox.lowrestuple_pt()) file.write("%%%%HiResBoundingBox: %g %g %g %g\n" % documentbbox.highrestuple_pt()) - file.write("%%%%Creator: PyX %s\n" % version.version) - if title is not None: - file.write("%%%%Title: %s\n" % title) - file.write("%%%%CreationDate: %s\n" % - time.asctime(time.localtime(time.time()))) + self.writeinfo(file) # required paper formats paperformats = {} @@ -250,6 +242,7 @@ class pswriter: file.write("%%Trailer\n") file.write("%%EOF\n") + class context: def __init__(self): -- 2.11.4.GIT