114 lines
3.3 KiB
Python
114 lines
3.3 KiB
Python
from io import BytesIO, IOBase
|
|
import qrcode
|
|
import cairo
|
|
from gi.repository import PangoCairo as pangocairo
|
|
from gi.repository import Pango as pango
|
|
DPI = 300
|
|
INCH_PER_MM = 0.039
|
|
|
|
|
|
def separate_context(func):
|
|
def inner(self, *args, **kwargs):
|
|
self.context.save()
|
|
ret = func(self, *args, **kwargs)
|
|
self.context.restore()
|
|
return ret
|
|
return inner
|
|
|
|
|
|
class Image:
|
|
_ctx = None
|
|
def __init__(self, width, height, color=None):
|
|
self.width = int(width)
|
|
self.height = int(height)
|
|
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.width, self.height)
|
|
if color:
|
|
self.fill(color)
|
|
|
|
@property
|
|
def context(self):
|
|
if not self._ctx:
|
|
self._ctx = cairo.Context(self.surface)
|
|
return self._ctx
|
|
|
|
@separate_context
|
|
def fill(self, color):
|
|
self.rect(0, 0, self.width, self.height, color)
|
|
|
|
@separate_context
|
|
def rect(self, x, y, width, height, color=(0, 0, 0)):
|
|
self.context.rectangle(x, y, width, height)
|
|
self.context.set_source_rgb(*color)
|
|
self.context.fill()
|
|
|
|
@separate_context
|
|
def draw_text(self, text, x, y, width=None, height=None, size=25, font='arial 25', color=(0,0,0)):
|
|
width = width or self.width-x
|
|
height = height or self.height-y
|
|
self.context.set_source_rgb(*color)
|
|
self.context.rectangle(x, y, self.width, height)
|
|
|
|
font = pango.FontDescription(font)
|
|
|
|
layout = pangocairo.create_layout(self.context)
|
|
layout.set_width(width * pango.SCALE)
|
|
layout.set_text(text, -1)
|
|
layout.set_font_description(font)
|
|
|
|
pangocairo.update_layout(self.context, layout)
|
|
pangocairo.show_layout(self.context, layout)
|
|
|
|
def save(self, name_or_file):
|
|
self.surface.write_to_png(name_or_file)
|
|
if isinstance(name_or_file, IOBase):
|
|
name_or_file.seek(0)
|
|
|
|
def compose(self, image, x=0, y=0, width=None, height=None):
|
|
self.context.scale(width/image.width, height/image.height)
|
|
self.context.set_source_surface(image.surface, x, y)
|
|
self.context.paint()
|
|
|
|
|
|
class QRCairo(qrcode.image.base.BaseImage):
|
|
|
|
@staticmethod
|
|
def _map_color(color):
|
|
return {'white': (1, 1, 1),
|
|
'black': (0, 0, 0)}[color]
|
|
|
|
def new_image(self, **kwargs):
|
|
back_color = self._map_color(kwargs.get("fill_color", "white"))
|
|
fill_color = self._map_color(kwargs.get("back_color", "black"))
|
|
self.fill_color = fill_color
|
|
|
|
return Image(self.pixel_size, self.pixel_size, back_color)
|
|
|
|
def drawrect(self, row, col):
|
|
(x, y), (x2, y2) = self.pixel_box(row, col)
|
|
self._img.rect(x, y, self.box_size, self.box_size, self.fill_color)
|
|
|
|
def save(self, fobj):
|
|
self._img.save(fobj)
|
|
|
|
|
|
def make_qr(url, size=19):
|
|
size = DPI*INCH_PER_MM*size
|
|
q = qrcode.QRCode(version=6, error_correction=qrcode.ERROR_CORRECT_M, border=0)
|
|
q.add_data(url)
|
|
q.make()
|
|
img = q.make_image(image_factory=QRCairo)
|
|
return img
|
|
|
|
|
|
def make_label(text, url, dpi=DPI):
|
|
qr = make_qr(url)
|
|
dpm = dpi*INCH_PER_MM
|
|
img = Image(51*dpm, 19*dpm, (1, 1, 1))
|
|
img.draw_text(text, 19.5*dpm, 0)
|
|
qr_img = qr._img
|
|
img.compose(qr_img, 0, 0, int(19*dpm), int(19*dpm))
|
|
return img
|
|
|
|
io = BytesIO()
|
|
make_label('ebin xD', 'http://www.wykop.pl/').save('output.png')
|
|
|