1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (C) 2012 David Planella <david.planella@ubuntu.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
import qrencode
import Image
import ImageOps
import cairo
import array
class QRCodeSize(object):
SMALL = 120
MEDIUM = 230
LARGE = 350
class QRCodeOutput(object):
PIL_IMAGE = 0
CAIRO_SURFACE = 1
class QRCode(object):
def __init__(self, output_size=QRCodeSize.MEDIUM):
self.output_size = output_size
self.qrcode_size = 0
self.pixel_size = 1
self.image = None
self.cr_surface = None
def encode(self, text, output_type=QRCodeOutput.PIL_IMAGE):
'''Encodes the given text and returns a QR code in the given format'''
if output_type == QRCodeOutput.PIL_IMAGE:
qr_code = self._encode_to_pil(text)
elif output_type == QRCodeOutput.CAIRO_SURFACE:
qr_code = self._encode_to_cairo(text)
return qr_code
def _encode_to_cairo(self, text):
'''Encodes the given text and returns a Cairo surface'''
self._encode_to_pil(text)
# Convert the Python PIL image to a Cairo surface.
# Notice the conversion to BGRA that Cairo expects
# See http://cairographics.org/pythoncairopil/ and
# http://mail.gnome.org/archives/gtkmm-list/2007-May/msg00111.html
bytearr = array.array('B', self.image.tostring("raw", "BGRA", 0, 1))
height, width = self.image.size
#print self.image.size
self.cr_surface = cairo.ImageSurface.create_for_data(bytearr,
cairo.FORMAT_ARGB32,
width, height,
width * 4)
return self.cr_surface
def _encode_to_pil(self, text):
'''Encodes the given text and returns a Python PIL Image'''
version, self.qrcode_size, self.image = qrencode.encode(text)
self.image = self.image.convert('RGBA')
self._resize()
self._add_border()
return self.image
def _resize(self):
self._set_pixel_size(self.qrcode_size)
#print self.pixel_size, self.qrcode_size
self.image = self.image.resize((self.pixel_size * self.qrcode_size,
self.pixel_size * self.qrcode_size),
Image.NEAREST)
def _set_pixel_size(self, barcode_orig_size):
pixel_size = 1
#print pixel_size * barcode_orig_size, self.output_size
while (pixel_size * barcode_orig_size < self.output_size):
pixel_size += 1
while ((pixel_size * barcode_orig_size > self.output_size) or \
((pixel_size * barcode_orig_size) % 2 != 0) or \
(pixel_size * barcode_orig_size + 2 * pixel_size > \
self.output_size)):
pixel_size -= 1
# FIXME: it needs to automatically go up to the next size,
# rather than hardcoding it as now
if pixel_size == 0:
self.output_size = QRCodeSize.MEDIUM
self.pixel_size = pixel_size
def _add_border(self):
'''Adds a border to the QR code'''
# Add a border
border_size = (self.output_size - self.image.size[0]) / 2
self.image = ImageOps.expand(self.image, border=border_size,
fill='white')
|