Created
July 2, 2015 20:30
-
-
Save kived/1ece269b7ddac5956ee8 to your computer and use it in GitHub Desktop.
Kivy: HTML to Label markup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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