Adafruit_CircuitPython_Port.../adafruit_portalbase/graphics.py
2024-03-23 09:13:40 -07:00

163 lines
5.6 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.
"""
def __init__(self, display, *, default_bg=0x000000, scale=1, debug=False): # noqa: PLR0912,PLR0913 Too many branches,Too many arguments in function definition
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.splash.append(self._bg_group)
# set the default background
if default_bg is not None:
self.display.root_group = 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 isinstance(file_or_color, str): # its a filenme:
background = displayio.OnDiskBitmap(file_or_color)
self._bg_sprite = displayio.TileGrid(
background,
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): # noqa: PLR0912,PLR0913 Too many branches,Too many arguments in function definition
"""Display a QR code
:param qr_data: The data for the QR code, None to remove.
: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.
"""
if qr_data is None:
if self._qr_group and self._qr_group in self.splash:
self.splash.remove(self._qr_group)
self._qr_group = None
gc.collect()
return
import adafruit_miniqr
# 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
# 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)