diff options
| author | pinky <> | 2006-12-07 13:41:40 +0000 |
|---|---|---|
| committer | pinky <> | 2006-12-07 13:41:40 +0000 |
| commit | 004a0b996ff8f269451e07346f71a129a1f3fbaf (patch) | |
| tree | 48f43c1fc2ca4c1f4d5648e7e73553d3f4ccae06 /bin/pychart/pdfcanvas.py | |
New trunk
bzr revid: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
Diffstat (limited to 'bin/pychart/pdfcanvas.py')
| -rw-r--r-- | bin/pychart/pdfcanvas.py | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/bin/pychart/pdfcanvas.py b/bin/pychart/pdfcanvas.py new file mode 100644 index 00000000000..0413e551946 --- /dev/null +++ b/bin/pychart/pdfcanvas.py @@ -0,0 +1,297 @@ +# +# Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com) +# +# Jockey is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any +# later version. +# +# Jockey is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +import sys +import pychart_util +import string +import re +import math +import theme +import os +import basecanvas +from scaling import * + +try: + import zlib + _zlib_available_p = 1 +except: + _zlib_available_p = 0 + +class pdf_stream(object): + def __init__(self, fp): + self.fp = fp + self.off = 0 + def write(self, str): + self.fp.write(str) + self.off += len(str) + def tell(self): + return self.off + +def to_radian(deg): + return deg*2*math.pi / 360.0 + +class T(basecanvas.T): + def __init__(self, fname, compress_p_): + basecanvas.T.__init__(self) + self.__out_fname = fname + self.__reset_context() + self.__next_obj_id = 1 + self.__next_font_id = 1 + self.__obj_offsets = {} + self.__registered_fonts = {} + self.__lines = [] + self.__nr_gsave = 0 + + if compress_p_ and not _zlib_available_p: + pychart_util.warn("Zlib not available. Compression request ignored.\n") + compress_p_ = 0 + self.__compress_p = compress_p_ + + def __intern_font(self, name): + "Assign an ID to the font NAME. Return its ID." + if not self.__registered_fonts.has_key(name): + self.__registered_fonts[name] = self.__next_font_id + self.__next_font_id += 1 + return self.__registered_fonts[name] + + def __define_obj(self, fp, str): + obj_id = self.__next_obj_id + self.__next_obj_id += 1 + self.__obj_offsets[obj_id] = fp.tell() + fp.write("%d 0 obj\n%s\nendobj\n" % (obj_id, str)) + return obj_id + + def __define_stream_obj(self, fp, s): + if self.__compress_p: + p = zlib.compress(s) + return self.__define_obj(fp, "<</Length %d/Filter/FlateDecode>>\nstream\n%sendstream" + % (len(p), p)) + else: + return self.__define_obj(fp, "<</Length %d\n>>\nstream\n%s\nendstream" + % (len(s), s)) + + def __define_font_obj(self, fp, name, font_id): + obj_id = self.__define_obj(fp, """<</Type/Font /Subtype/Type1 /Name/F%d /BaseFont/%s /Encoding/MacRomanEncoding>>""" % (font_id, name)) + return obj_id + + def __reset_context(self): + self.__font_name = None + self.__font_size = -1 + self.__line_style = None + self.__fill_color = None + self.__stroke_color = None + self.__mtx_pushed = 0 + + def newpath(self): + pass + def set_fill_color(self, color): + if self.__fill_color == color: + return + if color.r == color.g and color.r == color.b: + self.__write("%f g\n" % (color.r)) + self.__write("%f G\n" % (color.r)) + else: + self.__write("%f %f %f rg\n" % (color.r, color.g, color.b)) + self.__write("%f %f %f RG\n" % (color.r, color.g, color.b)) + self.__fill_color = color + def set_stroke_color(self, color): + self.set_fill_color(color) + return + + def __arcsub(self, x, y, radius, start, theta): + xcos = math.cos(to_radian(theta)) + xsin = math.sin(to_radian(theta)) + x0 = radius * xcos + y0 = radius * xsin + x1 = radius * (4-xcos)/3.0 + y1 = radius * (1-xcos)*(xcos-3)/(3*xsin) + + xx0, xy0 = pychart_util.rotate(x0, y0, start+theta) + xx1, xy1 = pychart_util.rotate(x1, -y1, start+theta) + xx2, xy2 = pychart_util.rotate(x1, y1, start+theta) + self.__write("%f %f %f %f %f %f c\n" % + (x+xx1, y+xy1, x+xx2, y+xy2, x+xx0, y+xy0)) + def path_arc(self, x, y, radius, ratio, start, end): + self.comment("PATHARC %f %f %f %f %f %f\n" + % (x, y, radius, ratio, start, end)) + step = 10 + if radius < 10: + step = 20 + if radius < 5: + step = 30 + if ratio != 1.0: + self.push_transformation((x, y), (1, ratio), None) + deg = start + while deg < end: + theta = min(step, end-deg) + self.__arcsub(x, y, radius, deg, theta/2) + deg += theta + self.pop_transformation() + else: + deg = start + while deg < end: + theta = min(step, end-deg) + self.__arcsub(x, y, radius, deg, theta/2) + deg += theta + self.comment("end PATHARC\n") + + def text_begin(self): + self.__write("BT ") + self.__font_name = None + self.__font_size = None + + def text_end(self): + self.__write("ET\n") + def text_moveto(self, x, y, angle): + if angle != None: + xcos = math.cos(to_radian(angle)) + xsin = math.sin(to_radian(angle)) + self.__write("%f %f %f %f %f %f Tm " % (xcos, xsin, -xsin, xcos, x, y)) + else: + self.__write("1 0 0 1 %f %f Tm " % (x, y)) + + def text_show(self, font_name, font_size, color, str): + if self.__font_name != font_name or self.__font_size != font_size: + font_id = self.__intern_font(font_name) + self.__write("/F%d %d Tf " % (font_id, font_size)) + self.__font_name = font_name + self.__font_size = font_size + self.set_fill_color(color) + self.__write("(%s) Tj " % (str)) + + def push_transformation(self, baseloc, scale, angle, in_text = 0): + if in_text: + op = "Tm" + else: + op = "cm" + self.gsave() + + if baseloc == None: + baseloc = (0,0) + + if angle != None: + radian = to_radian(angle) + self.__write("%f %f %f %f %f %f %s\n" % + (math.cos(radian), math.sin(radian), + -math.sin(radian), math.cos(radian), + baseloc[0], baseloc[1], op)) + if scale != None: + self.__write("%f 0 0 %f %f %f %s\n" % (scale[0], scale[1], + baseloc[0], + baseloc[1], op)) + + def pop_transformation(self, in_text = 0): + if not in_text: + self.grestore() + def closepath(self): + self.__write("h\n") + def clip_sub(self): + self.__write("W n\n") + def fill(self): + self.__write("f n\n") + def gsave(self): + self.__write("q\n") + def grestore(self): + self.__write("Q\n") + self.__reset_context() + + def moveto(self, x, y): + self.__write('%f %f m ' % (x, y)) + def lineto(self, x, y): + self.__write("%f %f l\n" % (x, y)) + def stroke(self): + self.__write("S\n") + + def set_line_style(self, style): + if (self.__line_style == style): + pass + else: + self.set_stroke_color(style.color) + self.__write("%f w " % nscale(style.width)) + if style.dash != None: + self.__write("[%s] 0 d\n" % + " ".join(map(str, nscale_seq(style.dash)))) + else: + self.__write("[] 0 d\n") + self.__write("%d j %d J\n" % (style.cap_style, style.join_style)) + self.__line_style = style + + def comment(self, str): + if not self.__compress_p: + self.__write("%%" + str + "\n") + + def verbatim(self, str): + self.__write(str) + + def __write(self, str): + self.__lines.append(str) + +# def setbb(self, xmin, ymin, xmax, ymax): +# self.__xmin = xmin +# self.__ymin = ymin +# self.__xmax = xmax +# self.__ymax = ymax + + def close(self): + basecanvas.T.close(self) + if self.__lines == []: + return + + _fp, need_close = self.open_output(self.__out_fname) + fp = pdf_stream(_fp) + + fp.write("%PDF-1.2\n") + + stream_obj_id = self.__define_stream_obj(fp, " ".join(self.__lines)) + + fontstr = "" + for font_name, font_id in self.__registered_fonts.items(): + obj_id = self.__define_font_obj(fp, font_name, font_id) + fontstr += "/F%d %d 0 R " % (font_id, obj_id) + + pages_obj_id = self.__define_obj(fp, " <</Type/Pages /Kids [%d 0 R] /Count 1 >>" % (self.__next_obj_id + 1)) + + bbox = theme.adjust_bounding_box([xscale(self.__xmin), yscale(self.__ymin), + xscale(self.__xmax), yscale(self.__ymax)]) + + page_obj_id = self.__define_obj(fp, """ <</Type/Page +\t/Parent %d 0 R +\t/Contents %d 0 R +\t/MediaBox [%d %d %d %d] +\t/Resources << /ProcSet [/PDF /Text] +\t\t/Font << %s >> +>> >>""" % (pages_obj_id, stream_obj_id, + bbox[0], bbox[1], bbox[2], bbox[3], fontstr)) + + info_str = "/Producer (%s)\n/CreationDate (%s)" % (self.creator, self.creation_date) + + if self.title: + info_str += "\n/Title (%s)" % (self.title, ) + if self.author: + info_str += "\n/Author (%s)" % (self.author, ) + + info_obj_id = self.__define_obj(fp, """<<%s>>""" % info_str) + catalog_obj_id = self.__define_obj(fp, """ <</Type/Catalog/Pages %d 0 R>>""" % (pages_obj_id)) + + xref_offset = fp.tell() + fp.write("xref\n0 %d\n" % (len(self.__obj_offsets)+1)) + fp.write("0000000000 65535 f \n") + id = 1 + while id <= len(self.__obj_offsets): + fp.write("%010d 00000 n \n" % (self.__obj_offsets[id])) + id += 1 + fp.write("trailer << /Size %d /Root %d 0 R /Info %d 0 R\n>>\n" % (len(self.__obj_offsets)+1, catalog_obj_id, info_obj_id)) + fp.write("startxref\n%d\n%%%%EOF\n" % xref_offset) + + if need_close: + _fp.close() |
