summaryrefslogtreecommitdiff
path: root/bin/pychart/pdfcanvas.py
diff options
context:
space:
mode:
authorpinky <>2006-12-07 13:41:40 +0000
committerpinky <>2006-12-07 13:41:40 +0000
commit004a0b996ff8f269451e07346f71a129a1f3fbaf (patch)
tree48f43c1fc2ca4c1f4d5648e7e73553d3f4ccae06 /bin/pychart/pdfcanvas.py
New trunk
bzr revid: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
Diffstat (limited to 'bin/pychart/pdfcanvas.py')
-rw-r--r--bin/pychart/pdfcanvas.py297
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()