mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
382 lines
13 KiB
Python
Executable File
382 lines
13 KiB
Python
Executable File
'''\
|
|
rendering HTML text with piddle
|
|
HTMLPiddler.py
|
|
jjk 02/02/00 001 first working version
|
|
jjk 02/03/00 002 some enhancements, renamed from piddleTaggedText.py
|
|
jjk 02/04/00 003 more enhancements, renamed from piddleHtmlWriter.py
|
|
|
|
Purpose:
|
|
The HTMLPiddler class accepts an HTML string and a few layout constraints,
|
|
and renders the HTML on a piddle canvas. This code is mainly a demonstration
|
|
and proof-of-concept, and is not really intended for real work.
|
|
|
|
Usage:
|
|
piddler = HTMLPiddler(html=aHtmlString,
|
|
start=(startX, startY),
|
|
xLimits=(leftMarginX, rightMarginX),
|
|
font=aPiddleFontForDefault,
|
|
color=aPiddleColorForDefault)
|
|
piddler.renderOn(aPiddleCanvas)
|
|
|
|
see also demo() functions at end of this file
|
|
|
|
Example:
|
|
Just run this module as a python script (must have piddle installed)
|
|
|
|
Limitations:
|
|
-only renders a subset of HTML (mostly text-related tags)
|
|
-content between unsupported tags may not be rendered at all
|
|
|
|
Implementation:
|
|
-derived largely on "demo07.py" from Jim Ahlstrom's WPY distribution (see credits)
|
|
-uses the parser-formatter-writer model from the python standard library
|
|
|
|
Credits:
|
|
PIDDLE
|
|
author: Joe Strout <joe@strout.net>, et al
|
|
download: http://www.strout.net/python/piddle/
|
|
disclaimers: see __copyrite_jim__ below
|
|
WPY
|
|
author: Jim Ahlstrom <jim@interet.com>
|
|
download: http://www.python.org/ftp/python/wpy/
|
|
disclaimers: see __copyrite_jim__ below
|
|
HTMLPiddler.py
|
|
author: Jeff Kunce <kuncej@mail.conservation.state.mo.us>
|
|
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.
|
|
<BR><BR>
|
|
<H2>HTMLPiddler.py</H2>
|
|
<H3>Rendering HTML with Piddle</H3>
|
|
|
|
<P>The <b>HTMLPiddler</b> class accepts an HTML string and a few layout constraints,
|
|
and renders the HTML on a piddle canvas
|
|
<P>An Example:
|
|
<PRE>
|
|
piddler = HTMLPiddler(html=aHtmlString,
|
|
start=(startX, startY),
|
|
xLimits=(leftMarginX, rightMarginX),
|
|
font=aPiddleFontForDefault,
|
|
color=aPiddleColorForDefault)
|
|
piddler.renderOn(aPiddleCanvas)
|
|
</PRE>
|
|
|
|
<P>Limitations
|
|
<UL>
|
|
<LI>only renders a subset of HTML (mostly text-related tags)
|
|
<LI>content between unsupported tags may not be rendered at all
|
|
</UL>
|
|
|
|
<P><b>HTMLPiddler</b> is derived largely on "demo07.py" from the
|
|
<A HREF="http://www.python.org/ftp/python/wpy/">WPY distribution</A>
|
|
by <A HREF="mailto:jim@interet.com">Jim Ahlstrom</A>
|
|
|
|
<P><i><b>HTMLPiddler.py</b> is mainly a demonstration/proof-of-concept, and
|
|
is not really intended for real work.</i>
|
|
<BR>
|
|
<BR><A HREF="mailto:kuncej@mail.conservation.state.mo.us">Jeff Kunce</A>
|
|
<BR><A HREF="http://starship.python.net/crew/jjkunce/">
|
|
http://starship.python.net/crew/jjkunce/</A>
|
|
'''
|
|
|
|
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()
|