Skip to content

Commit

Permalink
Add util functions to generate qr codes for urls
Browse files Browse the repository at this point in the history
  • Loading branch information
johannaengland committed May 6, 2024
1 parent 35f1a9b commit 3257306
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.d/2887.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add functionality to create QR codes to a given url
66 changes: 64 additions & 2 deletions python/nav/web/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
# along with NAV. If not, see <http://www.gnu.org/licenses/>.
#
"""Utils for views"""
import base64
import io
import os

from django.http import HttpResponse


from django.views.generic.list import ListView

import qrcode
from PIL import ImageDraw, ImageFont
import qrcode.image.pil


def get_navpath_root():
"""Returns the default navpath root
Expand Down Expand Up @@ -51,6 +56,7 @@ def require_param(parameter):
Will check both GET and POST querydict for the parameter.
"""

# pylint: disable=missing-docstring
def wrap(func):
def wrapper(request, *args, **kwargs):
Expand All @@ -64,3 +70,59 @@ def wrapper(request, *args, **kwargs):
return wrapper

return wrap


def generate_qr_code(url: str, name: str = "") -> io.BytesIO:
"""
Generate a QR code from a given url, and, if given, adds the name below as a
caption
Returns the generated image as a bytes buffer
"""
# Creating QR code
qr = qrcode.QRCode(box_size=10)
qr.add_data(url)
img = qr.make_image()
draw = ImageDraw.Draw(img)

# Adding the name as caption
if name:
img_width, img_height = img.size
font_path = os.path.join(os.path.dirname(__file__), "static/fonts/OS600.woff")
if len(name) < 25:
font = ImageFont.truetype(font_path, 25)
elif len(name) < 50:
font = ImageFont.truetype(font_path, 15)
else:
font = ImageFont.truetype(font_path, 10)
caption_width = font.getlength(name)
draw.text(
((img_width - caption_width) / 2, img_height - 40),
text=name,
font=font,
fill="black",
)

file_object = io.BytesIO()
img.save(file_object, "PNG")
img.close()

return file_object


def convert_bytes_buffer_to_bytes_string(bytes_buffer: io.BytesIO) -> str:
return base64.b64encode(bytes_buffer.getvalue()).decode('utf-8')


def generate_qr_codes_as_byte_strings(url_dict: dict[str, str]) -> list[str]:
"""
Takes a dict of the form {name:url} and returns a list of generated QR codes as
byte strings
"""
qr_code_byte_strings = []
for name, url in url_dict.items():
qr_code_byte_buffer = generate_qr_code(url=url, name=name)
qr_code_byte_strings.append(
convert_bytes_buffer_to_bytes_string(bytes_buffer=qr_code_byte_buffer)
)
return qr_code_byte_strings
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ pyaml
twisted~=23.8.0 # last version that still supports Python 3.7

networkx==2.6.3
# Cannot be removed as long as qrcode is included
Pillow>3.3.2
qrcode>7.4
pyrad==2.1
sphinx==5.3.0
sphinxcontrib-programoutput==0.17
Expand Down
16 changes: 16 additions & 0 deletions tests/unittests/web/qrcode_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import io

from nav.web.utils import generate_qr_code, generate_qr_codes_as_byte_strings


def test_generate_qr_code_returns_byte_buffer():
qr_code = generate_qr_code(url="www.example.com", name="buick.lab.uninett.no")
assert isinstance(qr_code, io.BytesIO)


def test_generate_qr_codes_as_byte_strings_returns_list_of_byte_strings():
qr_codes = generate_qr_codes_as_byte_strings(
{"buick.lab.uninett.no": "www.example.com"}
)
assert isinstance(qr_codes, list)
assert isinstance(qr_codes[0], str)

0 comments on commit 3257306

Please sign in to comment.