1
0
Fork 0
labelmaker/render.py

148 lines
4.2 KiB
Python

import json
import math
import os
import StringIO
import subprocess
import tempfile
import time
import cairo
import flask
import pango
import pangocairo
class App(flask.Flask):
def __init__(self, *args, **kwargs):
super(App, self).__init__(*args, **kwargs)
self.last = 0
self.health = (0, False, "unknown")
app = App(__name__)
class Renderer(object):
INCH_PER_MM = 0.039
DPI = 300
def __init__(self, size=(36,89)):
width, height = [int(s * self.INCH_PER_MM * self.DPI) for s in size]
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
context = cairo.Context(surface)
# fill it white, while we're at it
context.rectangle(0, 0, width, height)
context.set_source_rgb(1, 1, 1)
context.fill()
context.translate(width, 0)
context.rotate(math.pi/2)
# yolo
self.width, self.height = height, width
self.context = context
self.surface = surface
def export_png(self, name):
with open(name, 'w') as f:
self.surface.write_to_png(f)
def render_text(self, text, fontname, x, y, html=False):
self.context.save()
if y != -1:
self.context.translate(x, y)
pangocairo_context = pangocairo.CairoContext(self.context)
pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
layout = pangocairo_context.create_layout()
layout.set_width(self.width*pango.SCALE)
layout.set_alignment(pango.ALIGN_CENTER)
if html:
# Absolutely horrifying hack to fix broken text wrapping
layout.set_markup('<span font_desc="%s">%s</span>' % (fontname, text))
else:
font = pango.FontDescription(fontname)
layout.set_font_description(font)
layout.set_text(text)
if y == -1:
self.context.translate(0, (self.height - layout.get_size()[1]/pango.SCALE)/2)
self.context.set_source_rgb(0, 0, 0)
pangocairo_context.update_layout(layout)
pangocairo_context.show_layout(layout)
self.context.restore()
@app.route('/')
def index():
return flask.render_template('index.html')
def healthcheck():
last_checked, last_status, last_details = app.health
if time.time() - last_checked < 1:
return last_status, last_details
output = subprocess.check_output(['lpstat', '-p', '-d'])
mark = False
for line in output.split('\n'):
line = line.strip()
if line.startswith('printer DYMO_LabelWriter_450'):
if 'is idle.' in line:
return True, 'Idle'
mark = True
continue
if mark:
if line.startswith('Ready to print'):
app.health = (time.time(), True, line)
return True, line
else:
app.health = (time.time(), False, line)
return False, line
mark = False
@app.route('/health')
def health():
ok, details = healthcheck()
return json.dumps({'ok': ok, 'details': details})
@app.route('/stuff/preview/<int:size>/')
def stuff_preview(size):
text = flask.request.args.get('text')
html = flask.request.args.get('html') == '1'
r = Renderer()
r.render_text(text, 'Sans {}'.format(size), 0, -1, html)
sio = StringIO.StringIO()
r.surface.write_to_png(sio)
sio.seek(0)
return flask.send_file(sio, mimetype='image/png')
DELAY = 5
@app.route('/stuff/print/<int:size>/', methods=['POST'])
def stuff_print(size):
if not healthcheck()[0]:
return 'Printer is down.'
last = app.last
print last, time.time() - last
if time.time() - last < DELAY:
return 'Please wait {} more seconds before next print.'.format(int(DELAY - (time.time() - last)))
text = flask.request.args.get('text')
html = flask.request.args.get('html') == '1'
r = Renderer()
r.render_text(text, 'Sans {}'.format(size), 0, -1, html)
path = '/tmp/hslabel'
f = open(path, 'w')
r.surface.write_to_png(f)
f.flush()
f.close()
time.sleep(1)
ex = 'lpr -P DYMO_LabelWriter_450 {}'.format(path)
os.system(ex)
f.close()
app.last = time.time()
return 'ok'
if __name__ == '__main__':
app.run(debug=True)