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