download: http://starship.python.net/crew/jjkunce/
disclaimers: * NO WARRANTIES * USE AT YOUR OWN RISK *
'''
import htmllib, formatter, string
from types import *
import piddle
TRACE=0
class HTMLPiddler:
'''jjk 02/01/00'''
def __init__(self, html='', start=(0,0), xLimits=(0,800), font=None, color=None):
'''instance initializer
jjk 02/01/00'''
self.html = html
self.start = start
self.xLimits = xLimits
if not font: font = piddle.Font()
self.font = font
self.color = color
def renderOn(self, aPiddleCanvas):
'''draw the text with aPiddleCanvas
jjk 02/01/00'''
writer = _HtmlPiddleWriter(self, aPiddleCanvas)
fmt = formatter.AbstractFormatter(writer)
parser = _HtmlParser(fmt)
parser.feed(self.html)
parser.close()
class _HtmlParser(htmllib.HTMLParser):
def anchor_bgn(self, href, name, type):
htmllib.HTMLParser.anchor_bgn(self, href, name, type)
self.formatter.writer.anchor_bgn(href, name, type)
def anchor_end(self):
htmllib.HTMLParser.anchor_end(self)
self.formatter.writer.anchor_end()
class _HtmlPiddleWriter:
FontSizeDict = {"h1":36, "h2":24, "h3":18, "h4":12, "h5":10, "h6":8}
DefaultFontSize = 12
def __init__(self, aHTMLPiddler, aPiddleCanvas):
self.piddler = aHTMLPiddler #view = view
self.pc = aPiddleCanvas
self.anchor = None
self.lineHeight = 0
self.atbreak = 0
self.color = self.piddler.color
self.defaultFont = self.font = self.piddler.font
s = "W" * 20
x = self.pc.stringWidth(s, self.font)
y = self.pc.fontHeight(self.font)
x = (x + 19) / 20 # Largest character size
self.fsizex = x
self.fsizey = self.oldLineHeight = y
self.indentSize = x * 3
self.lmargin, self.rmargin = self.piddler.xLimits
self.x, self.y = self.piddler.start
self.indent = self.lmargin + (x/3)
def anchor_bgn(self, href, name, type):
if href:
self.oldcolor = self.color
self.color = piddle.Color(0.0, 0.0, 200/255.0)
self.anchor = (href, name, type)
def anchor_end(self):
if self.anchor:
self.color = self.oldcolor
self.anchor = None
# Start of methods required by the formatter
def new_font(self, fontParams):
if TRACE: print 'nf',fontParams
# fontParams is None, or the tuple (size, i, b, tt)
if not fontParams:
fontParams = (None, None, None, None)
size = fontParams[0]
try:
points = self.FontSizeDict[size]
except KeyError:
points = self.DefaultFontSize
if fontParams[3]:
face = "courier" #"modern"
elif type(size) is StringType and size[0] == "h":
face = "helvetica" #"swiss"
else:
face = "times" #"roman"
italic = fontParams[1] # Italic indicator
if italic==None:
italic = 0
bold = fontParams[2] # Bold indicator
if bold==None:
bold = 0
self.font = piddle.Font(points, bold, italic, face=face)
x = self.pc.stringWidth('W'*20, self.font)
self.fsizex = (x + 19) / 20 # Largest character size
self.fsizey = self.pc.fontHeight(self.font)
def new_margin(self, margin, level):
self.send_line_break()
self.indent = self.x = self.lmargin + self.indentSize * level
def new_spacing(self, spacing):
self.send_line_break()
t = "new_spacing(%s)" % `spacing`
self.OutputLine(t, 1)
def new_styles(self, styles):
self.send_line_break()
t = "new_styles(%s)" % `styles`
self.OutputLine(t, 1)
def send_label_data(self, data):
if data == "*":
w = self.pc.stringWidth(data, self.font) / 3
h = self.pc.fontHeight(self.font) / 3
x = self.indent - w
y = self.y - w
self.pc.drawRect(x, y, x-w, y-w)
else:
w = self.pc.stringWidth(data, self.font)
h = self.pc.fontHeight(self.font)
x = self.indent - w - self.fsizex / 3
if x < 0:
x = 0
self.pc.drawString(data, x, self.y, self.font, self.color)
def send_paragraph(self, blankline):
self.send_line_break()
self.y = self.y + self.oldLineHeight * blankline
def send_line_break(self):
if self.lineHeight:
self.y = self.y + self.lineHeight
self.oldLineHeight = self.lineHeight
self.lineHeight = 0
self.x = self.indent
self.atbreak = 0
if TRACE: raw_input('lb')
def send_hor_rule(self):
self.send_line_break()
self.y = self.y + self.oldLineHeight
border = self.fsizex
self.pc.drawLine(border, self.y, self.rmargin-border, self.y, piddle.Color(0.0, 0.0, 200/255.0))
self.y = self.y + self.oldLineHeight
def send_literal_data(self, data):
if not data:
return
lines = string.splitfields(data, '\n')
text = string.expandtabs(lines[0])
for l in lines[1:]:
self.OutputLine(text, 1)
text = string.expandtabs(l)
self.OutputLine(text, 0)
self.atbreak = 0
def send_flowing_data(self, data):
if not data:
return
atbreak = self.atbreak or data[0] in string.whitespace
text = ""
pixels = chars = 0
for word in string.split(data):
bword = " " + word # blank + word
length = len(bword)
# The current line is "text" and its size is
# "pixels" pixels plus "chars" characters.
if not atbreak:
text = word
chars = chars + length - 1
elif self.x + pixels + (chars + length) * self.fsizex < self.rmargin:
# Word fits easily on current line.
text = text + bword
chars = chars + length
else:
w = self.pc.stringWidth(text+bword, self.font)
h = self.pc.fontHeight(self.font)
if TRACE: print 'sfd T:', text+bword
if TRACE: print 'sfd',self.x,w,self.x+w,self.rmargin
if self.x + w < self.rmargin:
# Word fits.
text = text + bword
pixels = w
chars = 0
else:
# Word does not fit. Output current line.
self.OutputLine(text, 1)
text = word
chars = length - 1
pixels = 0
atbreak = 1
self.OutputLine(text, 0)
self.atbreak = data[-1] in string.whitespace
def OutputLine(self, text, linebreak = 0):
if text:
if TRACE: print 'olt:',text
if TRACE: print 'olf:',self.font.size, self.font.bold, self.font.italic, self.font.underline, self.font.face
self.pc.drawString(text, self.x, self.y, self.font, self.color)
#if self.anchor:
# o.anchor = self.anchor
self.lineHeight = max(self.lineHeight, self.pc.fontHeight(self.font))
self.x = self.x + self.pc.stringWidth(text, self.font)
if linebreak:
self.send_line_break()
__copyrite_jim__ = '''\
Copyright 1994, 1995 by James C. Ahlstrom, Stirling NJ, USA.
Comments and complaints to jim@interet.com
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation.
JAMES C. AHLSTROM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''
DEMO_HTML = '''Here's some starting text - should be rendered in
default font and color, and should start at specified start coordinates.
HTMLPiddler.py
Rendering HTML with Piddle
The HTMLPiddler class accepts an HTML string and a few layout constraints,
and renders the HTML on a piddle canvas
An Example:
piddler = HTMLPiddler(html=aHtmlString,
start=(startX, startY),
xLimits=(leftMarginX, rightMarginX),
font=aPiddleFontForDefault,
color=aPiddleColorForDefault)
piddler.renderOn(aPiddleCanvas)
Limitations
- only renders a subset of HTML (mostly text-related tags)
- content between unsupported tags may not be rendered at all
HTMLPiddler is derived largely on "demo07.py" from the
WPY distribution
by Jim Ahlstrom
HTMLPiddler.py is mainly a demonstration/proof-of-concept, and
is not really intended for real work.
Jeff Kunce
http://starship.python.net/crew/jjkunce/
'''
def demoPDF(html):
import piddlePDF
pc = piddlePDF.PDFCanvas((750,1000),'HTMLPiddler.pdf')
pc.drawLine(100,100,250,150, color=piddle.green)
pc.drawRect(100,100,650,900, edgeColor=piddle.pink)
ptt = HTMLPiddler(html, (250,150), (100,650))
ptt.renderOn(pc)
pc.save()
def demoPIL(html):
print 'be patient, this is a little slow...'
import piddlePIL
pc = piddlePIL.PILCanvas((800,600), 'HTMLPiddler')
pc.drawLine(0,0,100,80, color=piddle.green)
pc.drawRect(50,50,750,550, edgeColor=piddle.pink)
ptt = HTMLPiddler(html, (100,80), (50,750))
ptt.renderOn(pc)
pc.save(format='tif')
def demoTK(html):
import piddleTK
pc = piddleTK.TKCanvas((800,600))
pc.drawLine(0,0,50,50, color=piddle.green)
pc.drawRect(10,10,590,790, edgeColor=piddle.pink)
ptt = HTMLPiddler(html, (50,50), (10,790))
pc.flush()
ptt.renderOn(pc)
def demoWX(html):
import piddleWX
pc = piddleWX.WXCanvas((800,600))
pc.drawLine(0,0,50,50, color=piddle.green)
pc.drawRect(10,10,590,790, edgeColor=piddle.pink)
ptt = HTMLPiddler(html, (50,50), (10,790))
pc.flush()
ptt.renderOn(pc)
def demo(html=DEMO_HTML):
while 1:
print 'Demo of HTMLPiddler.py'
print ' 1. piddlePDF'
print ' 2. piddlePIL'
#print ' 3. piddleTK'
#print ' 4. piddleWX'
print ' 0. EXIT'
sel = raw_input('Enter Selection Number: ')
try: sel = string.atoi(string.strip(sel))
except: sel = -1
if (sel==0): break
elif (sel==1): demoPDF(html)
elif (sel==2): demoPIL(html)
elif (sel==3): demoTK(html)
elif (sel==4): demoWX(html)
if __name__=='__main__':
import pdb
demo()