Adafruit_CircuitPython_Port.../adafruit_portalbase/graphics.py
Melissa LeBlanc-Williams 07c40f1f51 Increase QR Code size range
2021-09-15 13:55:39 -07:00

168 lines
5.7 KiB
Python

# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2020 Melissa LeBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`adafruit_portalbase.graphics`
================================================================================
Base Library for the Portal-style libraries.
* Author(s): Melissa LeBlanc-Williams
Implementation Notes
--------------------
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
"""
import gc
import displayio
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PortalBase.git"
class GraphicsBase:
"""Graphics Base Class for the Portal-style libraries.
:param display: An initialized display.
:param default_bg: The path to your default background image file or a hex color.
Defaults to 0x000000.
:param bool auto_refresh: Automatically refresh the eInk after writing to displayio.
Defaults to True.
:param debug: Turn on debug print outs. Defaults to False.
"""
# pylint: disable=too-many-instance-attributes, too-many-locals, too-many-branches, too-many-statements
def __init__(self, display, *, default_bg=0x000000, scale=1, debug=False):
self._debug = debug
self.display = display
if self._debug:
print("Init display")
self.splash = displayio.Group(scale=scale)
self._qr_group = None
if self._debug:
print("Init background")
self._bg_group = displayio.Group()
self._bg_file = None
self.splash.append(self._bg_group)
# set the default background
if default_bg is not None:
self.display.show(self.splash)
self.set_background(default_bg)
gc.collect()
def set_background(self, file_or_color, position=None):
"""The background image to a bitmap file.
:param file_or_color: The filename of the chosen background image, or a hex color.
:param tuple position: Optional x and y coordinates to place the background at.
"""
while self._bg_group:
self._bg_group.pop()
if not position:
position = (0, 0) # default in top corner
if not file_or_color:
return # we're done, no background desired
if self._bg_file:
self._bg_file.close()
if isinstance(file_or_color, str): # its a filenme:
self._bg_file = open(file_or_color, "rb")
background = displayio.OnDiskBitmap(self._bg_file)
self._bg_sprite = displayio.TileGrid(
background,
pixel_shader=getattr(
background, "pixel_shader", displayio.ColorConverter()
),
# TODO: Once CP6 is no longer supported, replace the above line with below
# pixel_shader=background.pixel_shader,
x=position[0],
y=position[1],
)
elif isinstance(file_or_color, int):
# Make a background color fill
color_bitmap = displayio.Bitmap(self.display.width, self.display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = file_or_color
self._bg_sprite = displayio.TileGrid(
color_bitmap,
pixel_shader=color_palette,
x=position[0],
y=position[1],
)
else:
raise RuntimeError("Unknown type of background")
self._bg_group.append(self._bg_sprite)
gc.collect()
def qrcode(
self, qr_data, *, qr_size=1, x=0, y=0, qr_color=0x000000
): # pylint: disable=invalid-name
"""Display a QR code
:param qr_data: The data for the QR code.
:param int qr_size: The scale of the QR code.
:param x: The x position of upper left corner of the QR code on the display.
:param y: The y position of upper left corner of the QR code on the display.
"""
import adafruit_miniqr # pylint: disable=import-outside-toplevel
# generate the QR code
for qrtype in range(1, 6):
try:
qrcode = adafruit_miniqr.QRCode(qr_type=qrtype)
qrcode.add_data(qr_data)
qrcode.make()
break
except RuntimeError:
pass
# print("Trying with larger code")
else:
raise RuntimeError("Could not make QR code")
# monochrome (2 color) palette
palette = displayio.Palette(2)
palette[0] = 0xFFFFFF
palette[1] = qr_color
# pylint: disable=invalid-name
# bitmap the size of the matrix, plus border, monochrome (2 colors)
qr_bitmap = displayio.Bitmap(
qrcode.matrix.width + 2, qrcode.matrix.height + 2, 2
)
for i in range(qr_bitmap.width * qr_bitmap.height):
qr_bitmap[i] = 0
# transcribe QR code into bitmap
for xx in range(qrcode.matrix.width):
for yy in range(qrcode.matrix.height):
qr_bitmap[xx + 1, yy + 1] = 1 if qrcode.matrix[xx, yy] else 0
# display the QR code
qr_sprite = displayio.TileGrid(qr_bitmap, pixel_shader=palette)
if self._qr_group:
try:
self._qr_group.pop()
except IndexError: # later test if empty
pass
else:
self._qr_group = displayio.Group()
self.splash.append(self._qr_group)
self._qr_group.scale = qr_size
self._qr_group.x = x
self._qr_group.y = y
self._qr_group.append(qr_sprite)