Initial commit

This commit is contained in:
Emilio Mariscal
2016-09-06 16:15:55 -03:00
commit 17ab83fb71
9 changed files with 285 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
ENV
*.DS_Store
*.pyc

BIN
OpenSans-Bold.ttf Executable file

Binary file not shown.

BIN
OpenSans-Regular.ttf Executable file

Binary file not shown.

14
README.md Normal file
View File

@@ -0,0 +1,14 @@
# ESC-POS Server Print
## Simple web server for print using ESC-POS.
## Install and run
* Install pip requirements
* Run 'python server.py'
## License
You may use any Mootor project under the terms of either the MIT License or the GNU General Public License (GPL) Version 3.
(c) 2016 Emilio Mariscal

88
image.py Normal file
View File

@@ -0,0 +1,88 @@
""" Image format handling class
This module contains the image format handler :py:class:`EscposImage`.
:author: `Michael Billington <michael.billington@gmail.com>`_
:organization: `python-escpos <https://github.com/python-escpos>`_
:copyright: Copyright (c) 2016 Michael Billington <michael.billington@gmail.com>
:license: GNU GPL v3
"""
from PIL import Image, ImageOps
class EscposImage(object):
"""
Load images in, and output ESC/POS formats.
The class is designed to efficiently delegate image processing to
PIL, rather than spend CPU cycles looping over pixels.
"""
def __init__(self, img_source):
"""
Load in an image
:param img_source: PIL.Image, or filename to load one from.
"""
if isinstance(img_source, Image.Image):
img_original = img_source
else:
img_original = Image.open(img_source)
# Convert to white RGB background, paste over white background
# to strip alpha.
img_original = img_original.convert('RGBA')
im = Image.new("RGB", img_original.size, (255, 255, 255))
im.paste(img_original, mask=img_original.split()[3])
# Convert down to greyscale
im = im.convert("L")
# Invert: Only works on 'L' images
im = ImageOps.invert(im)
# Pure black and white
self._im = im.convert("1")
@property
def width(self):
"""
Width of image in pixels
"""
width_pixels, _ = self._im.size
return width_pixels
@property
def width_bytes(self):
"""
Width of image if you use 8 pixels per byte and 0-pad at the end.
"""
return (self.width + 7) >> 3
@property
def height(self):
"""
Height of image in pixels
"""
_, height_pixels = self._im.size
return height_pixels
def to_column_format(self, high_density_vertical=True):
"""
Extract slices of an image as equal-sized blobs of column-format data.
:param high_density_vertical: Printed line height in dots
"""
im = self._im.transpose(Image.ROTATE_270).transpose(Image.FLIP_LEFT_RIGHT)
line_height = 24 if high_density_vertical else 8
width_pixels, height_pixels = im.size
top = 0
left = 0
while left < width_pixels:
box = (left, top, left + line_height, top + height_pixels)
im_slice = im.transform((line_height, height_pixels), Image.EXTENT, box)
im_bytes = im_slice.tobytes()
yield(im_bytes)
left += line_height
def to_raster_format(self):
"""
Convert image to raster-format binary
"""
return self._im.tobytes()

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

4
reqs.txt Normal file
View File

@@ -0,0 +1,4 @@
Pillow==3.3.0
pyserial==3.1.1
six==1.10.0
wheel==0.24.0

176
server.py Normal file
View File

@@ -0,0 +1,176 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
ESC-POS Server Print - a web service for print using ESC-POS.
You may use any Server Print project under the terms
of the GNU General Public License (GPL) Version 3.
(c) 2016 Emilio Mariscal (emi420 [at] gmail.com)
Module description:
Server Print
Simple web server for print using ESC-POS.
'''
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
from PIL import Image, ImageDraw, ImageFont
from urlparse import urlparse, parse_qs
import textwrap
import serial
import time
import image
import six
# Set to false if you want to test the image without printing
DEBUG = False
PORT = 8001
SERIAL = '/dev/ttyUSB0'
SPEED = 38400
DENSITY = 3
H1_FONT = ImageFont.truetype("OpenSans-Bold.ttf", 70)
H2_FONT = ImageFont.truetype("OpenSans-Regular.ttf", 30)
P_FONT = ImageFont.truetype("OpenSans-Regular.ttf", 23)
TMP_FILE = "page.png"
LOGO_FILE = "logo.png"
W = 300
GS = b'\x1d'
def _int_low_high(inp_number, out_bytes):
"""
Generate multiple bytes for a number: In lower and higher parts, or more parts as needed.
Function from python-escpos library (https://github.com/python-escpos/python-escpos)
:param inp_number: Input number
:param out_bytes: The number of bytes to output (1 - 4).
"""
max_input = (256 << (out_bytes * 8) - 1)
if not 1 <= out_bytes <= 4:
raise ValueError("Can only output 1-4 bytes")
if not 0 <= inp_number <= max_input:
raise ValueError("Number too large. Can only output up to {0} in {1} bytes".format(max_input, out_bytes))
outp = b''
for _ in range(0, out_bytes):
outp += six.int2byte(inp_number % 256)
inp_number //= 256
return outp
'''
APIServer create a simple web server to generate and print images
'''
class APIServer(BaseHTTPRequestHandler):
def do_GET(self):
mime = "text/html"
self.send_response(200)
self.send_header("Content-type", mime)
self.send_header('Allow', 'GET, OPTIONS')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
height = 150
imgtmp = Image.new("RGBA", (W,100), (255,255,255))
drawtmp = ImageDraw.Draw(imgtmp)
params = parse_qs(urlparse(self.path).query)
if params:
h1 = unicode(params.get("h1")[0],"utf8")
h2 = unicode(params.get("h2")[0],"utf8")
p = unicode(params.get("p")[0],"utf8")
linesh2 = textwrap.wrap(h2, width=20)
lines = textwrap.wrap(p, width=20)
imglogo = Image.open(LOGO_FILE, 'r')
img_w, img_h = imglogo.size
wh1, hh1 = drawtmp.textsize(h1, font=H1_FONT)
wh2, hh2 = drawtmp.textsize(h2, font=H2_FONT)
height += img_h + hh1 + hh2
for line in lines:
w, h = drawtmp.textsize(line, font=P_FONT)
height += h
for line in linesh2:
w, h = drawtmp.textsize(line, font=H2_FONT)
height += h
del drawtmp
img = Image.new("RGBA", (W,height), (255,255,255))
img.paste(imglogo, (((W - img_w) / 2),30))
draw = ImageDraw.Draw(img)
draw.text(((W-wh1)/2, img_h + 50), h1, (0,0,0), font=H1_FONT)
y_text = img_h + hh1 + 80
for line in linesh2:
w, h = draw.textsize(line, font=H2_FONT)
draw.text(((W-w)/2, y_text), line, (0,0,0), font=H2_FONT)
y_text += h
y_text += 25
for line in lines:
w, h = draw.textsize(line, font=P_FONT)
draw.text(((W-w)/2, y_text), line, (0,0,0), font=P_FONT)
y_text += h
del draw
img.save(TMP_FILE, "PNG")
if not DEBUG:
conn = serial.Serial(SERIAL, SPEED, timeout=10)
im = image.EscposImage(TMP_FILE)
out = im.to_raster_format()
header = GS + b"v0" + six.int2byte(DENSITY) + _int_low_high(im.width_bytes, 2) + _int_low_high(im.height, 2)
conn.write(header + out)
conn.write("\x0a\x0a\x0a\x1d\x56\x00\x0a\x0a")
time.sleep(1)
conn.close()
printer_returns = 1
else:
printer_returns = 0
self.wfile.write(printer_returns)
return
def main():
try:
server = HTTPServer(('', PORT), APIServer)
print 'Started httpserver on port ' + str(PORT)
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
if __name__ == '__main__':
main()