Skip to content

Instantly share code, notes, and snippets.

@kived
Created July 2, 2015 20:30
Show Gist options
  • Save kived/1ece269b7ddac5956ee8 to your computer and use it in GitHub Desktop.
Save kived/1ece269b7ddac5956ee8 to your computer and use it in GitHub Desktop.
Kivy: HTML to Label markup
class HTML2Markup(object):
html_bool = {
'true': True,
't': True,
'1': True,
'yes': True,
'y': True,
'false': False,
'f': False,
'0': False,
'no': False,
'n': False
}
_join = ''.join
def parse_bool(self, value):
'''Parse a string or integer to determine truthiness.
Defaults to True (for the case of valueless attributes, i.e. <span narrow></span>'''
value = unicode(value).lower()
return self.html_bool.get(value, True)
def handle_tag(self, data, tag, attrs):
if tag == 'hr':
data += '-' * 40 + '\r\n'
return data, attrs
def handle_tag_close(self, data, tag, attrs):
return data, attrs
def handle_attrs(self, attrs, current_attrs):
data = []
for name, value in attrs.iteritems():
if name == 'align':
pass
elif name == 'narrow':
if value:
data.append('[size=12]')
else:
data.append('[/size]')
elif name == 'bold':
if value:
data.append('[b]')
else:
data.append('[/b]')
elif name == 'double-height':
if value:
data.append('[size=20]')
else:
data.append('[/size]')
elif name == 'double-width':
if value:
data.append('[size=20][b]')
else:
data.append('[/b][/size]')
elif name == 'underline':
pass
elif name == 'rotate':
pass
elif name == 'flip':
pass
elif name == 'invert':
pass
elif name == 'smooth':
pass
if data:
return self._join(data)
return ''
def htmlout(self, text):
return text.replace('\r', '')
@staticmethod
def finish(text):
while text[:2] == '[/':
_, _, text = text.partition(']')
return text
def convert_to_bytes(self, unihtml):
return unihtml.encode('utf-8')
from HTMLParser import HTMLParser
from htmlentitydefs import name2codepoint
'''
<!DOCTYPE aerisprint>
COMMANDS
initialize
cashdrawer
cut
feed
output
raw
test print
LAYOUT
endline <br />
tab <tab />
image <img src="..." double-width="<True, False>" double-height="<True, False>" />
barcode <barcode code="..." type="<UPC-A, UPC-E, EAN, CODE128>" mode="<A, B, C>" />
qrcode <qrcode code="..." double-width="<True, False>" double-height="<True, False>" />
set horizontal <position absolute="..." />
move horizontal <position relative="..." />
SETUP <?print attr=value ... />
tab stops tabstops = 1, 2, 3, ...
char spacing char-spacing = n
line spacing line-spacing = n
unit of measurement unit = n
left margin margin = n
STYLES
alignment align = <left, center, right>
narrow narrow = <True, False>
bold bold = <True, False> <b></b>
double height double-height = <True, False> <h3></h3>
double width double-width = <True, False> <h2></h2>
underline underline = <True, False, double> <u></u> <u double="True"></u>
rotation rotate = <True, False>
flip flip = <True, False>
inverted invert = <True, False>
smoothing smooth = <True, False>
'''
class HTML2Print(HTMLParser):
_join = ''.join
tag_stack_default = {}
attr_stack_default = {
'align': 'left',
'narrow': False,
'bold': False,
'double-height': False,
'double-width': False,
'underline': False,
'rotate': False,
'flip': False,
'invert': False,
'smooth': True,
'color': 'black'
}
def __init__(self, target, *args, **kwargs):
HTMLParser.__init__(self, *args, **kwargs)
self.target = target
def __call__(self, html):
if isinstance(html, unicode):
html = self.target.convert_to_bytes(html)
return self.handle(html)
@property
def data(self):
data = self._join(self._data)
if isinstance(data, unicode):
data = data.encode('utf8')
return data
@property
def current_attrs(self):
return {k:v[-1] for k, v in self._attr_stack.iteritems()}
def handle(self, html):
self.reset()
self.feed(html)
return self.close()
def reset(self):
HTMLParser.reset(self)
self._doctype = None
self._data = []
self._tag_stack = self.tag_stack_default.copy()
self._attr_stack = {k:[v, ] for k, v in self.attr_stack_default.iteritems()}
def close(self):
if hasattr(self.target, 'finish'):
return self.target.finish(self.data)
return self.data
def out(self, text, attrs=None):
self._data.append(self.target.htmlout(text))
def endline(self):
if hasattr(self.target, 'endline'):
return self.target.endline()
return '\r\n'
def tab(self):
if hasattr(self.target, 'tab'):
return self.target.tab()
return '\t'
def handle_tag(self, tag, attrs):
data = ''
if tag == 'br':
data = self.endline()
elif tag == 'tab':
data = self.tab()
elif tag == 'h1':
attrs['double-width'] = True
attrs['double-height'] = True
elif tag == 'h2':
attrs['double-width'] = True
elif tag == 'h3':
attrs['double-height'] = True
elif tag == 'b':
attrs['bold'] = True
elif tag == 'u':
attrs['underline'] = True
if 'double' in attrs:
attrs['underline'] = 'double'
del attrs['double']
return self.target.handle_tag(data, tag, attrs)
def handle_tag_close(self, tag, attrs):
data = ''
line_tags = ('h1', 'h2', 'h3', 'p')
if tag in line_tags:
data = self.endline()
# if tag == 'p' and 'align' in attrs:
if 'align' in attrs:
data += self.handle_attrs({'align': ('left', attrs['align'])}, False)
return self.target.handle_tag_close(data, tag, attrs)
def open_tag(self, tag, attrs):
data, attrs = self.handle_tag(tag, attrs)
if not tag in self._tag_stack:
self._tag_stack[tag] = [attrs, ]
else:
self._tag_stack[tag].append(attrs)
self.open_attrs(attrs)
if data:
self.out(data)
def close_tag(self, tag):
# del self._tag_stack[tag][-1]
# attrs = self._tag_stack[tag] and self._tag_stack[tag][-1] or {}
attrs = self._tag_stack[tag].pop()
data, attrs = self.handle_tag_close(tag, attrs)
if data:
self.out(data, attrs)
self.close_attrs(attrs)
def open_attrs(self, attrs):
h_attrs = {}
for name, value in attrs.iteritems():
oldvalue = self._attr_stack[name][-1] if name in self._attr_stack else None
self._attr_stack[name].append(value)
h_attrs[name] = (value, oldvalue)
self.handle_attrs(h_attrs)
def close_attrs(self, attrs):
h_attrs = {}
for name, value in attrs.iteritems():
del self._attr_stack[name][-1]
oldvalue = self._attr_stack[name][-1]
h_attrs[name] = (oldvalue, value)
self.handle_attrs(h_attrs)
def handle_attrs(self, attrs, output=True):
data = self.target.handle_attrs({k:v[0] for k, v in attrs.iteritems() if v[0] != v[1]}, self.current_attrs)
if output and data:
self.out(data)
return data
def handle_params(self, params):
data = []
for name, value in params.iteritems():
data.append(self.target.handle_param(name, value))
if data:
self.out(self._join(data))
def handle_starttag(self, tag, attrs):
self.open_tag(tag, dict(attrs))
def handle_endtag(self, tag):
self.close_tag(tag)
def handle_data(self, data):
self.out(data.replace('\n', '').replace('\r', ''))
def handle_entityref(self, name):
self.out(unichr(name2codepoint[name]))
def handle_charref(self, name):
if name[0] == 'x':
name = name[1:]
char = unichr(int(name, 16))
else:
char = unichr(int(name))
self.out(char)
def handle_comment(self, data):
'''Ignore comments.'''
pass
def handle_decl(self, data):
'''Handle declarations.'''
if data.strip().lower() == 'doctype aerisprint':
self._doctype = 'aerisprint'
self.out(self.target.handle_attrs(self.current_attrs, self.current_attrs))
else:
raise GryphusError('invalid template declaration: {}'.format(data))
def handle_pi(self, data):
'''Handle processing instructions.'''
tag, _, paramlist = data.partition(' ')
if tag == 'print':
params = {k:v.strip('"') for k, v in re.findall(r'(\S+)\s*=\s*(".*?"|\S+)', paramlist)}
self.handle_params(params)
def unknown_decl(self, data):
'''Ignore unknown declarations.'''
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment