1
0
Fork 0

Initial commit.

master
q3k 2015-08-30 00:46:51 +02:00
commit 9f17cf2b52
4 changed files with 207 additions and 0 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
Use the source, luke :^)

109
render.py Normal file
View File

@ -0,0 +1,109 @@
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
app = App(__name__)
class Renderer(object):
INCH_PER_MM = 0.039
DPI = 300
def __init__(self, size=(19,51)):
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):
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)
font = pango.FontDescription(fontname)
layout.set_font_description(font)
layout.set_text(text)
layout.set_alignment(pango.ALIGN_CENTER)
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')
@app.route('/stuff/preview/<int:size>/')
def stuff_preview(size):
text = flask.request.args.get('text')
r = Renderer()
r.render_text(text, 'Sans {}'.format(size), 0, -1)
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):
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')
r = Renderer()
r.render_text(text, 'Sans {}'.format(size), 0, -1)
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)

BIN
templates/.index.html.swp Normal file

Binary file not shown.

97
templates/index.html Normal file
View File

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hackerspace Printing System For Printing</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Are you sure you want to print this?</h4>
</div>
<div class="modal-body">
<p>These labels cost money. Don't be an asshole, and only print stuff that is really needed.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Nevermind</button>
<button type="button" id="btnconfirm" class="btn btn-primary">Yes please</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="page-header">
<h1>Hackerspace Printing System For Printing Labels</h1>
</div>
<h3>Box 'o Stuff Label <small>For SAMLA boxes with common equipment</small></h3>
<div class="row">
<div class="col-md-2">
<h4>Preview</h4>
<img id="preview" src="/stuff/preview/70/?text=dupa" style="border-width: 1px; border-style: solid; height: 300px;"/><br/>
</div>
<div class="col-md-3">
<h4>Settings</h4>
<div class="form-group">
<label for="fontsize">Font Size</label>
<input id="fontsize" value="60" style="width: 100px;" class="form-control" />
</div>
<div class="form-group">
<label for="labeltext">Label Text</label>
<input id="labeltext" value="Sample Text" style="width: 200px;" class="form-control" />
</div>
<button type="button" id="btnpreview" class="btn btn-default btn-lg"><span class="glyphicon glyphicon-picture" aria-hidden="true"></span> Preview</button>
<button type="button" id="btnprint" class="btn btn-warning btn-lg"><span class="glyphicon glyphicon-print" aria-hidden="true"></span> Print!</button>
</div>
<div class="col-md-7">
<h4>API</h4>
<pre>$ # To get a label preview
$ curl http://label.waw.hackerspace.pl/stuff/preview/60/?text=foobar | feh -
$ # To print the label
$ curl -d "" http://label.waw.hackerspace.pl/stuff/print/60/?text=foobar</pre>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-growl/1.0.0/jquery.bootstrap-growl.min.js"></script>
<script>
$(document).ready(function() {
var generatePreview = function() {
var fontsize = parseInt($("#fontsize").val());
var text = encodeURIComponent($("#labeltext").val());
$("#preview").attr("src", "/stuff/preview/" + fontsize + "/?text=" + text);
};
$("#btnpreview").click(generatePreview);
var asked = false;
var print = function() {
var fontsize = parseInt($("#fontsize").val());
var text = encodeURIComponent($("#labeltext").val());
$.post("/stuff/print/" + fontsize + "/?text=" + text, function(data) {
if (data == "ok") {
$.bootstrapGrowl('Printed succesfully!', {'type': 'success'});
} else {
$.bootstrapGrowl('An error ocurred: ' + data, {'type': 'warning'});
}
});
};
$("#btnprint").click(function() {
if (!asked) {
$("#myModal").modal('show');
} else {
print();
}
});
$("#btnconfirm").click(function() {
asked = true;
$("#myModal").modal('hide');
print();
});
generatePreview();
});
</script>
</body>
</html>