Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/net/qrcode.py : 42%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2020 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7import gi
8gi.require_version("Gtk", "3.0")
9from gi.repository import Gtk, GLib, GdkPixbuf
11from xpra.gtk_common.gtk_util import add_close_accel
12from xpra.util import first_time
13from xpra.log import Logger
15log = Logger("menu")
18_qrencode_fn = None
19def get_qrencode_fn():
20 global _qrencode_fn
21 if _qrencode_fn is None:
22 _qrencode_fn = _get_qrencode_fn() or False
23 log("get_qrencode_fn()=%s", _qrencode_fn)
24 return _qrencode_fn
26def _get_qrencode_fn():
27 try:
28 from PIL import Image
29 from qrencode import encode
30 def qrencode_fn(s):
31 return encode(s)[2]
32 return qrencode_fn
33 except ImportError:
34 try:
35 from PIL import Image
36 from ctypes import (
37 Structure, POINTER,
38 cdll, create_string_buffer, c_int, c_char_p,
39 )
40 from ctypes.util import find_library
41 class QRCode(Structure):
42 _fields_ = (
43 ("version", c_int),
44 ("width", c_int),
45 ("data", c_char_p),
46 )
47 PQRCode = POINTER(QRCode)
48 lib_file = None
49 for lib_name in ("libqrencode", "qrencode"):
50 lib_file = find_library(lib_name)
51 if lib_file:
52 break
53 if not lib_file:
54 if first_time("libqrencode"):
55 log.warn("Warning: libqrencode not found")
56 return None
57 libqrencode = cdll.LoadLibrary(lib_file)
58 encodeString8bit = libqrencode.QRcode_encodeString8bit
59 encodeString8bit.argtypes = (c_char_p, c_int, c_int)
60 encodeString8bit.restype = PQRCode
61 QRcode_free = libqrencode.QRcode_free
62 QRcode_free.argtypes = (PQRCode,)
63 def qrencode_ctypes_fn(s):
64 data = create_string_buffer(s.encode("latin1"))
65 qrcode = encodeString8bit(data, 0, 0).contents
66 try:
67 size = qrcode.width
68 pixels = bytearray(size*size)
69 pdata = qrcode.data
70 for i in range(size*size):
71 pixels[i] = 0 if (pdata[i] & 0x1) else 255
72 return Image.frombytes('L', (size, size), bytes(pixels))
73 finally:
74 QRcode_free(qrcode)
75 return qrencode_ctypes_fn
76 except Exception:
77 log.error("failed to load qrencode via ctypes", exc_info=True)
78 return None
81def qrencode(s):
82 fn = get_qrencode_fn()
83 if fn:
84 return fn(s)
85 return None
87def show_qr(uri, width=640, height=640):
88 #support old-style URIs, ie: tcp:host:port
89 if uri.find(":")!=uri.find("://"):
90 uri = uri.replace(":", "://", 1)
91 parts = uri.split(":", 1)
92 if parts[0] in ("tcp", "ws"):
93 uri = "http:"+parts[1]
94 else:
95 uri = "https:"+parts[1]
96 pixbuf = qr_pixbuf(uri, width, height)
97 if not pixbuf:
98 return
99 image = Gtk.Image().new_from_pixbuf(pixbuf)
100 window = Gtk.Window(modal=True, title="QR Code")
101 window.set_position(Gtk.WindowPosition.CENTER)
102 window.add(image)
103 window.set_size_request(width, height)
104 window.set_resizable(False)
105 def close(*_args):
106 window.destroy()
107 add_close_accel(window, close)
108 window.show_all()
110def qr_pixbuf(uri, width=640, height=640):
111 img = qrencode(uri)
112 if not img:
113 return None
114 from PIL import Image
115 img = img.convert("RGB")
116 img = img.resize((width, height), Image.NEAREST)
117 data = img.tobytes()
118 w, h = img.size
119 data = GLib.Bytes.new(data)
120 pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(data, GdkPixbuf.Colorspace.RGB,
121 False, 8, w, h, w * 3)
122 return pixbuf
125def main():
126 if "-v" in sys.argv or "--verbose" in sys.argv:
127 log.enable_debug()
128 fn = get_qrencode_fn()
129 log.info("qrencode_fn=%s" % (fn,))
132if __name__ == "__main__":
133 import sys
134 main()
135 sys.exit(0)