first import

git-svn-id: https://callirhoe.googlecode.com/svn/trunk@5 81c8bb96-aa45-f2e2-0eef-c4fa4a15c6df
This commit is contained in:
geortz@gmail.com 2012-07-17 20:44:12 +00:00
parent ec2b26784f
commit 21c3f79c9f
15 changed files with 815 additions and 0 deletions

170
callirhoe.py Executable file
View File

@ -0,0 +1,170 @@
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
_version = "0.1"
import calendar
import sys
import time
import os.path
import optparse
import glob
from lib.xcairo import *
from lib.render import *
plugin_path = [ os.path.expanduser("~/.callirhoe"), sys.path[0] if sys.path[0] else "." ]
def available_files(parent, dir, fmatch = ""):
good = False
res = []
pattern = parent + "/" + dir + "/*.py"
# TODO: improve matching with __init__ when lang known
for x in glob.glob(pattern):
basex = os.path.basename(x)
if basex == "__init__.py": good = True
else:
base = os.path.splitext(basex)[0]
if base and ((not fmatch) or (fmatch == base)): res.append((base,parent))
return res if good else []
# cat = lang (category)
# longcat = language
# longcat2 = languages
# listopt = --list-lang
# preset = "EN"
def import_plugin(cat, longcat, longcat2, listopt, preset):
try:
found = available_files(plugin_path[0], cat, preset) + available_files(plugin_path[1], cat, preset)
if len(found) == 0: raise ImportError
old = sys.path[0];
sys.path[0] = found[0][1]
m = __import__("%s.%s" % (cat,preset), globals(), locals(), [ "*" ])
sys.path[0] = old
return m
except ImportError:
print >> sys.stderr, "%s definition `%s' not found, use %s to see available %s" % (longcat,preset,listopt,longcat2)
sys.exit(1)
parser = optparse.OptionParser(usage="usage: %prog [options] FILE",
description="High quality calendar rendering with vector graphics.\n"
"By default, a pdf calendar of the current year will be written to FILE. Program version: " + _version)
parser.add_option("-y", "--year", dest="year", type="int", default=-1,
help="select YEAR instead of current one")
parser.add_option("-l", "--lang", dest="lang", default="EN",
help="choose language [EN]")
parser.add_option("-s", "--style", dest="style", default="default",
help="choose style [default]")
parser.add_option("-g", "--geometry", dest="geom", default="default",
help="choose geometry [default]")
parser.add_option("--landscape", action="store_true", dest="landscape", default=False,
help="landscape mode")
parser.add_option("--list-languages", action="store_true", dest="list_languages", default=False,
help="list available languages")
parser.add_option("--list-styles", action="store_true", dest="list_styles", default=False,
help="list available styles")
parser.add_option("--list-geometries", action="store_true", dest="list_geometries", default=False,
help="list available geometries")
parser.add_option("--lang-var", action="append", dest="lang_assign",
help="modify a language variable")
parser.add_option("--style-var", action="append", dest="style_assign",
help="modify a style variable, e.g. dom.frame_thickness=0")
parser.add_option("--geom-var", action="append", dest="geom_assign",
help="modify a geometry variable")
#for x in sys.argv:
# if x[0] == '-' and not parser.has_option(x):
# print "possibly bad option", x
# ./callirhoe --lang fr year=2010 months=1-6 foo.pdf
(options,args) = parser.parse_args()
def plugin_list(cat):
return available_files(plugin_path[0], cat) + available_files(plugin_path[1], cat)
if options.list_languages:
for x in plugin_list("lang"): print x[0],
print
if options.list_styles:
for x in plugin_list("style"): print x[0],
print
if options.list_geometries:
for x in plugin_list("geom"): print x[0],
print
if options.list_languages or options.list_styles or options.list_geometries: sys.exit(0)
if len(args)==0:
parser.print_help()
sys.exit(0)
cal_lang = import_plugin("lang", "language", "languages", "--list-languages", options.lang)
cal_style = import_plugin("style", "style", "styles", "--list-styles", options.style)
cal_geom = import_plugin("geom", "geometry", "geometries", "--list-geometries", options.geom)
if options.lang_assign:
for x in options.lang_assign: exec "cal_lang.%s" % x
if options.style_assign:
for x in options.style_assign: exec "cal_style.%s" % x
if options.geom_assign:
for x in options.geom_assign: exec "cal_geom.%s" % x
calendar.month_name = cal_lang.month_name
calendar.day_name = cal_lang.day_name
def get_orthodox_easter(y):
y1, y2, y3 = y - y//4 * 4, y - y//7 * 7, y - y//19 * 19
a = 19*y3 + 15
y4 = a - a//30 * 30
b = 2*y1 + 4*y2 + 6*(y4 + 1)
y5 = b - b/7 * 7
r = 1 + 3 + y4 + y5;
return (5, r - 30) if r > 30 else (4,r)
year = options.year if options.year >= 0 else time.localtime()[0]
p = PDFPage(args[0], options.landscape)
R0,R1 = rect_vsplit(p.Text_rect, 0.05)
Rcal,Rc = rect_vsplit(R1,0.97)
if options.landscape:
rows,cols = 3,4
else:
rows,cols = 4,3
foo = GLayout(Rcal, rows, cols, pad = (p.Text_rect[2]*0.02,)*4)
shad = p.Size[0]*0.01 if cal_style.month.box_shadow else 0
for i in range(min(foo.count(),12),0,-1):
draw_month(p.cr, foo.item_seq(i-1), month=i, year=year,
style = cal_style, geom = cal_geom, box_shadow = shad)
# render.draw_box(render.cr,*foo.item_seq(i))
#draw_str(p.cr, str(year), R0, stroke_rgba = (0,0,0,0.3), align=1)
draw_str(p.cr, str(year), R0, stroke_rgba = (0,0,0,0.3), align=2)
#draw_str(p.cr, str(year), R0, stroke_rgba = (0,0,0,0.3), align=3)
draw_str(p.cr, "created by Callirhoe ver.0.1 © 2012 GeoTz", Rc, stroke_rgba = (0,0,0,0.5), stretch=0, align=2, slant=cairo.FONT_SLANT_ITALIC)
#render.cr.move_to(render.Page.Text_pos[0],render.Page.Text_pos[1])
#render.cr.line_to(render.Page.Text_size[0]+render.Page.Text_pos[0], render.Page.Text_size[1]+render.Page.Text_pos[1])
#render.cr.stroke()
#draw_month(cr, *foo.item(2), m=9)
#bw, bh = 40,40
#draw_day_cell(cr, 30, 50, bw, bh, '24', 'Παραμονή Χριστουγ.', 'Ευγενία', default_style)
#draw_day_cell(cr, 30+bw, 50, bw, bh, '25', 'ΧΡΙΣΤΟΥΓΕΝΝΑ', 'Χρήστος, Χριστίνα', weekend_holiday_style)
#draw_day_cell(cr, 30+2*bw, 50, bw, bh, '26', '2η μέρα Χριστουγ.', 'Εμμανουήλ', weekend_style)
#draw_day_cell(cr, 30+3*bw, 50, bw, bh, '27', '', 'Στέφανος', default_style)
#draw_day_page(cr, 30+2*bw, 50, bw, bh, '26', 'Κυριακή', 'Δεκεμβρίου', [1,1,1], [.3,.3,.3])

0
geom/__init__.py Normal file
View File

27
geom/default.py Normal file
View File

@ -0,0 +1,27 @@
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# --- geom.default ---
class dom:
num_size = (0.5,0.5)
header_size = footer_size = (0.8,0.1)
top_margin = bottom_margin = 0.05
class month:
fuzzy_rot = 0
fuzzy_dx = 0
fuzzy_dy = 0

27
geom/fuzzy.py Normal file
View File

@ -0,0 +1,27 @@
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# --- geom.default ---
class dom:
num_size = (0.5,0.5)
header_size = footer_size = (0.8,0.1)
top_margin = bottom_margin = 0.05
class month:
fuzzy_rot = 0.25
fuzzy_dx = 0
fuzzy_dy = 0

29
lang/EL.py Normal file
View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
day_name = [ u'Δευτέρα', u'Τρίτη', u'Τετάρτη',
u'Πέμπτη', u'Παρασκευή', u'Σάββατο', u'Κυριακή' ]
short_day_name = [ u'Δευ', u'Τρι', u'Τετ', u'Πεμ', u'Παρ', u'Σαβ', u'Κυρ' ]
month_name = [ '', u'Ιανουάριος', u'Φεβρουάριος', u'Μάρτιος', u'Απρίλιος',
u'Μάιος', u'Ιούνιος', u'Ιούλιος', u'Αύγουστος',
u'Σεπτέμβριος', u'Οκτώβριος', u'Νοέμβριος', u'Δεκέμβριος' ]
short_month_name = [ '', u'Ιαν', u'Φεβ', u'Μαρ', u'Απρ', u'Μαϊ', u'Ιον', u'Ιολ',
u'Αυγ', u'Σεπ', u'Οκτ', u'Νοε', u'Δεκ' ]

31
lang/EN.py Normal file
View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
day_name = [ u'Monday', u'Tuesday', u'Wednesday',
u'Thursday', u'Friday', u'Saturday', u'Sunday' ]
short_day_name = [ u'Mon', u'Tue', u'Wed', u'Thu', u'Fri', u'Sat', u'Sun' ]
month_name = [ '',
u'January', u'February', u'March', u'April',
u'May', u'June', u'July', u'August',
u'September', u'October', u'November', u'December' ]
short_month_name = [ '',
u'Jan', u'Feb', u'Mar', u'Apr', u'May', u'Jun',
u'Jul', u'Aug', u'Sep', u'Oct', u'Nov', u'Dec' ]

30
lang/FR.py Normal file
View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
day_name = [ u'Lundi', u'Mardi', u'Mercredi',
u'Jeudi', u'Vendredi', u'Samedi', u'Dimanche' ]
short_day_name = [ u'Lun', u'Mar', u'Mer', u'Jeu', u'Ven', u'Sam', u'Dim' ]
month_name = [ '',
u'Janvier', u'Février', u'Mars', u'Avril',
u'Mai', u'Juin', u'Juillet', u'Août',
u'Septembre', u'Octobre', u'Novembre', u'Décembre' ]
short_month_name = [ '', u'Jan', u'Fév', u'Mar', u'Avr', u'Mai', u'Jun', u'Jul',
u'Aoû', u'Sep', u'Oct', u'Nov', u'Déc' ]

0
lang/__init__.py Normal file
View File

0
lib/__init__.py Normal file
View File

158
lib/geom.py Normal file
View File

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# *****************************************
# #
# general-purpose geometry routines #
# #
# *****************************************
def rect_rel_scale(r, fw, fh):
x, y, w, h = r
return (x + w*(1 - fw)/2.0, y + h*(1 - fh)/2.0, w*fw, h*fh)
def rect_to_abs(r):
x, y, w, h = r
return (x, y, x + w, y + h)
def abs_to_rect(a):
x1, y1, x2, y2 = a
return (x1, y1, x2 - x1, y2 - y1)
def rect_hull(r1,r2):
x1, y1, x2, y2 = rect_to_abs(r1)
x3, y3, x4, y4 = rect_to_abs(r2)
return abs_to_rect((min(x1,x3), min(y1,y3), max(x2,x4), max(y2,y4)))
def rect_hsplit(r, f = 0.5):
x, y, w, h = r
r1 = (x, y, w*f, h)
r2 =(x + w*f, y, w*(1 - f), h)
return (r1, r2)
def rect_vsplit(r, f = 0.5):
x, y, w, h = r
r1 = (x, y, w, h*f)
r2 = (x, y + h*f, w, h*(1 - f))
return (r1, r2)
def rect_qsplit(r, fv = 0.5, fh = 0.5):
x, y, w, h = r
rv = rect_vsplit(r, fv)
return rect_hsplit(rv[0], fh) + rect_hsplit(rv[1], fh)
def color_mix(a, b, frac):
k = min(len(a), len(b))
return map(lambda (x,y): x*frac + y*(1 - frac), zip(a,b))
def color_auto_fg(bg, light = (1,1,1), dark = (0,0,0)):
return light if bg[0] + bg[1] + bg[2] < 1.5 else dark
# ********* layout managers ***********
class VLayout:
def __init__(self, rect, nitems = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
self.pos = (rect[0], rect[1])
self.size = (rect[2], rect[3])
self.items = nitems
self.pad = pad
def count(self):
return self.items
def resize(self, k):
self.items = k
def grow(self, delta = 1):
self.items += delta
def move(newpos):
self.pos = newpos;
def item(self, i = 0):
vinter = (self.pad[0] + self.pad[2])/2.0;
vsize = (self.size[1] - vinter)/self.items;
return (self.pos[0] + self.pad[1], self.pos[1] + self.pad[0] + i*vsize,
self.size[0] -self.pad[1] - self.pad[3], vsize - vinter)
def item_span(self, n, k = -1):
if k < 0: k = (self.count() - n) // 2
return rect_hull(self.item(k), self.item(k + n - 1))
class HLayout:
def __init__(self, rect, nitems = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
self.pos = (rect[0],rect[1])
self.rep = VLayout((0.0, 0.0, rect[3], rect[2]), nitems, (pad[1], pad[0], pad[3], pad[2]))
def count(self):
return self.rep.count()
def resize(self, k):
self.rep.resize(k)
def move(newpos):
self.rep.move(newpos)
def item(self, i = 0):
t = self.rep.item(i)
return (t[1] + self.pos[0], t[0] + self.pos[1], t[3], t[2])
def item_span(self, n, k = -1):
if k < 0: k = (self.rep.count() - n) // 2
return rect_hull(self.item(k), self.item(k + n - 1))
class GLayout:
def __init__(self, rect, nrows = 1, ncols = 1, pad = (0.0,0.0,0.0,0.0)): # TLBR
self.vrep = VLayout(rect, nrows, (pad[0], 0.0, pad[2], 0.0))
t = self.vrep.item(0)
self.hrep = HLayout((rect[0], rect[1], t[2], t[3]), ncols, (0.0, pad[1], 0.0, pad[3]))
def row_count(self):
return self.vrep.count()
def col_count(self):
return self.hrep.count()
def count(self):
return self.row_count()*self.col_count()
def resize(self, rows, cols):
self.vrep.resize(rows)
t = self.vrep.item(0)
self.hrep = HLayout(t[0:2], t[2:4], cols, (0.0, pad[1], 0.0, pad[3]))
def move(newpos):
self.vrep.move(newpos)
self.hrep.move(newpos)
def item(self, row, col):
ty = self.vrep.item(row)
tx = self.hrep.item(col)
return (tx[0], ty[1], tx[2], tx[3])
def item_seq(self, k, column_wise = False):
if not column_wise:
row, col = k // self.col_count(), k % self.col_count()
else:
col, row = k // self.row_count(), k % self.row_count()
return self.item(row, col)
def item_span(self, nr, nc, row = -1, col = -1):
if row < 0: row = (self.row_count() - nr) // 2
if col < 0: col = (self.col_count() - nc) // 2
return rect_hull(self.item(row, col), self.item(row + nr - 1, col + nc - 1))

101
lib/render.py Normal file
View File

@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# *****************************************
# #
# calendar drawing routines #
# #
# *****************************************
import math
import calendar
import random
from xcairo import *
from geom import *
# TODO: replace rects with rect_rel_scale()
def draw_day_cell(cr, rect, day_of_month, header, footer, style, G):
x, y, w, h = rect
draw_box(cr, rect, style.frame, style.bg, style.frame_thickness)
R = rect_rel_scale(rect, G.num_size[0], G.num_size[1])
draw_str(cr, day_of_month, R, -1, style.fg, 2,
font = style.font, measure = "55")
if header:
R = (x + (1 - G.header_size[0])*w/2, y + G.top_margin*h,
w*G.header_size[0], h*G.header_size[1])
draw_str(cr, header, R, -1, style.header, 2, font = style.header_font)
if footer:
R = (x + (1 - G.footer_size[0])*w/2, y + (1 - G.bottom_margin - G.footer_size[1])*h,
w*G.footer_size[0], h*G.footer_size[1])
draw_str(cr, footer, R, -1, style.footer, 2, font = style.footer_font)
def draw_day_page(cr, rect, day_of_month, header, footer, fill = (1,1,1), stroke = (0,0,0)):
x, y, w, h = rect
draw_box(cr, rect, (0,0,0), fill)
draw_str(cr, day_of_month, (x + w*.382/2, y + h*.382/2, w*.618, h*.618), 3, stroke)
draw_str(cr, header, (x +0.1*w, y + 0.05*h, w*0.8, 0.1*h), -1, (0,0,0), 2)
draw_str(cr, footer, (x +0.1*w, y + 0.85*h, w*0.8, 0.1*h), -1, (0,0,0), 2)
# TODO: implement GEOMETRY, STYLE, DATA SOURCES...
# TODO: use named options...
def draw_month(cr, rect, month, year, style, geom, box_shadow = 0):
x, y, w, h = rect
cw = w/7.0;
ch = h/7.0;
cr.save()
cr.translate(x,y)
cr.translate(w/2, h/2)
cr.translate(w*(random.random() - 0.5)*geom.month.fuzzy_dx,
h*(random.random() - 0.5)*geom.month.fuzzy_dy)
cr.rotate((random.random() - 0.5)*geom.month.fuzzy_rot)
cr.translate(-w/2.0, -h/2.0)
cal = calendar.monthrange(year, month)
day = cal[0]
dom = -day + 1;
wmeasure = 'A'*max(map(len,calendar.day_name))
mmeasure = 'A'*max(map(len,calendar.month_name))
for col in range(7):
R = (col*cw, ch*3.0/5, cw, ch*2.0/5)
draw_box(cr, R, style.dom.frame,
style.dom.bg if col < 5 else style.dom_weekend.bg, style.dow.frame_thickness)
R = (col*cw, ch*3.0/5 + ch*2.0/5*1.0/4, cw, ch*2.0/5*1/2)
draw_str(cr, calendar.day_name[col], R, -1, style.dow.fg, 2,
font = style.dow.font, measure = wmeasure)
# TODO: use grid layout
for row in range(6):
for col in range(7):
day_style = style.dom_weekend if col >= 5 else style.dom
R = (col*cw, (row + 1)*ch, cw, ch)
if dom > 0 and dom <= cal[1]:
draw_day_cell(cr, R, str(dom), '', '', day_style, geom.dom)
else:
draw_box(cr, R, day_style.frame, day_style.bg, day_style.frame_thickness)
dom += 1
mcolor = style.month.color_map[month]
mcolor_fg = color_auto_fg(mcolor)
draw_box(cr, (0, 0, w, h), style.month.frame, (), 2, box_shadow)
draw_box(cr, (0, 0, w, ch*3.0/5), style.month.frame, mcolor)
R = (0, ch*3.0/5*1/4, w, ch*3.0/5*1/2)
draw_str(cr, calendar.month_name[month], R, -1, mcolor_fg, 2, False,
style.month.font, measure=mmeasure, shadow=style.month.text_shadow)
cr.restore()

120
lib/xcairo.py Normal file
View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# *****************************************
# #
# general-purpose drawing routines #
# higher-level CAIRO routines #
# #
# *****************************************
import cairo
import math
class PDFPage:
def __init__(self, filename, landscape = False, w = 210.0, h = 297.0, dpi = 72.0):
self.DPI = dpi # default dpi
if not landscape:
self.Size_mm = (w, h) # (width, height) in mm
else:
self.Size_mm = (h, w)
self.Size = (self.Size_mm[0]/25.4 * self.DPI, self.Size_mm[1]/25.4 * self.DPI) # size in dots
Mag = 72.0/self.DPI;
self.Margins = (self.Size[1]*0.025, self.Size[0]*0.025,
self.Size[1]*0.025, self.Size[0]*0.025) # top left bottom right
txs = (self.Size[0] - self.Margins[1] - self.Margins[3],
self.Size[1] - self.Margins[0] - self.Margins[2])
self.Text_rect = (self.Margins[1], self.Margins[0], txs[0], txs[1])
if not landscape:
self.Surface = cairo.PDFSurface (filename, self.Size[0]*Mag, self.Size[1]*Mag)
else:
self.Surface = cairo.PDFSurface (filename, self.Size[1]*Mag, self.Size[0]*Mag)
self.cr = cairo.Context (self.Surface)
self.cr.scale (Mag, Mag) # Normalizing the canvas
if landscape:
self.cr.translate(0,self.Size[0])
self.cr.rotate(-math.pi/2)
def default_width(cr, factor = 1.0):
return max(cr.device_to_user_distance(0.1*factor, 0.1*factor))
def set_color(cr, rgba):
if len(rgba) == 3:
cr.set_source_rgb(*rgba)
else:
cr.set_source_rgba(*rgba)
def draw_shadow(cr, rect, thickness, shadow_color = (0,0,0,0.3)):
if thickness <= 0: return
f = thickness
x, y, w, h = rect
cr.move_to(x + f, y + h)
cr.rel_line_to(0, f); cr.rel_line_to(w, 0); cr.rel_line_to(0, -h)
cr.rel_line_to(-f, 0); cr.rel_line_to(0, h - f); cr.rel_line_to(-w + f, 0);
set_color(cr, shadow_color)
cr.close_path(); cr.fill();
def draw_box(cr, rect, stroke_rgba = (), fill_rgba = (), width_scale = 1.0, shadow = 0):
if (width_scale <= 0): return
draw_shadow(cr, rect, shadow)
x, y, w, h = rect
cr.move_to(x, y)
cr.rel_line_to(w, 0)
cr.rel_line_to(0, h)
cr.rel_line_to(-w, 0)
cr.close_path()
if fill_rgba:
set_color(cr, fill_rgba)
cr.fill_preserve()
if stroke_rgba:
set_color(cr, stroke_rgba)
cr.set_line_width(default_width(cr, width_scale))
cr.stroke()
def draw_str(cr, text, rect, stretch = -1, stroke_rgba = (), align = 0, bbox = False,
font = "Times", slant = cairo.FONT_SLANT_NORMAL, weight = cairo.FONT_WEIGHT_NORMAL,
measure = '', shadow = False):
x, y, w, h = rect
cr.save()
cr.select_font_face(font, slant, weight)
if not measure: measure = text
te = cr.text_extents(measure)
tw, th = te[2], te[3]
cr.translate(x, y + h)
ratio, tratio = w*1.0/h, tw*1.0/th;
xratio, yratio = tw*1.0/w, th*1.0/h;
if stretch < 0: stretch = 1 if xratio >= yratio else 2
if stretch == 0: bbw, bbh = w, h;
elif stretch == 1: bbw, bbh = tw, tw/ratio; cr.scale(1.0/xratio, 1.0/xratio)
elif stretch == 2: bbw, bbh = th*ratio, th; cr.scale(1.0/yratio, 1.0/yratio)
elif stretch == 3: bbw, bbh = tw, th; cr.scale(1.0/xratio, 1.0/yratio)
te = cr.text_extents(text)
tw,th = te[2], te[3]
if align == 1: px, py = bbw - tw, 0
elif align == 2: px, py = (bbw-tw)/2.0, 0
else: px, py = 0, 0
cr.set_line_width(default_width(cr))
if shadow:
cr.set_source_rgba(0, 0, 0, 0.5)
cr.move_to(px + default_width(cr, 5), py + default_width(cr, 5))
cr.show_text(text)
cr.move_to(px, py)
if stroke_rgba: set_color(cr, stroke_rgba)
cr.show_text(text)
if bbox: draw_box(cr, (0, 0, bbw, -bbh), stroke_rgba)
cr.restore()

0
style/__init__.py Normal file
View File

58
style/bw.py Normal file
View File

@ -0,0 +1,58 @@
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# --- style.default ---
# day of week
class dow:
fg = (.33,.33,.33)
frame_thickness = 1.0
frame = (0.8,0.8,0.8)
font = "Arial"
# day of month
class dom:
bg = (1,1,1)
frame = (0.8,0.8,0.8)
frame_thickness = 1.0
fg = (0.2,0.2,0.2)
font = "Times New Roman"
header = (0.5,0.5,0.5)
footer = header
header_font = footer_font = "Arial"
class dom_weekend(dom):
bg = (0.95,0.95,0.95)
fg = (0,0,0)
font = "Times New Roman Bold"
class dom_holiday(dom):
fg = (0,0,0)
header = (0,0,0)
font = "Times New Roman Bold"
class dom_weekend_holiday_style(dom_holiday):
bg = (0,0,0)
from lib.render import color_mix
class month:
font = "Times New Roman Bold"
frame = (0,0,0)
bg = (1,1,1)
color_map = ((1,1,1),)*13
box_shadow = False
text_shadow = False

64
style/default.py Normal file
View File

@ -0,0 +1,64 @@
# callirhoe - high quality calendar rendering
# Copyright (C) 2012 George M. Tzoumas
# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/
# --- style.default ---
# day of week
class dow:
fg = (0,0,1)
frame_thickness = 1.0
frame = (0.8,0.8,0.8)
font = "Arial"
# day of month
class dom:
bg = (1,1,1)
frame = (0.8,0.8,0.8)
frame_thickness = 1.0
fg = (0.2,0.2,0.2)
font = "GFS Bodoni"
header = (0.5,0.5,0.5)
footer = header
header_font = footer_font = "Arial"
class dom_weekend(dom):
bg = (0.7,1,1)
fg = (0,0,1)
class dom_holiday(dom):
fg = (1,0,0)
header = (1,0,0)
class dom_weekend_holiday_style(dom_holiday):
bg = (0.7,1,1)
from lib.render import color_mix
class month:
font = "GFS Artemisia Bold"
frame = (0,0,0)
bg = (1,1,1)
winter = (0,0.4,1)
spring = (0.0,0.5,0.0)
summer = (1,0.3,0)
autumn = (0.9,0.9,0)
color_map = ((0,0,0), winter,
color_mix(winter,spring,0.66), color_mix(winter,spring,0.33), spring, # april
color_mix(spring,summer,0.66), color_mix(spring,summer,0.33), summer, # july
color_mix(summer,autumn,0.66), color_mix(summer,autumn,0.33), autumn, # october
color_mix(autumn,winter,0.66), color_mix(autumn,winter,0.33)) # december
text_shadow = True
box_shadow = True