From ef436d2b2e1875a0591d18b5e12041ae432a6d5c Mon Sep 17 00:00:00 2001 From: Neradoc Date: Wed, 2 Apr 2025 05:13:37 +0200 Subject: [PATCH 1/3] update to CP 10 with busdisplay --- adafruit_bitmapsaver.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/adafruit_bitmapsaver.py b/adafruit_bitmapsaver.py index 4b7d892..d8b5f19 100644 --- a/adafruit_bitmapsaver.py +++ b/adafruit_bitmapsaver.py @@ -8,7 +8,7 @@ ================================================================================ Save a displayio.Bitmap (and associated displayio.Palette) in a BMP file. -Make a screenshot (the contents of a displayio.Display) and save in a BMP file. +Make a screenshot (the contents of a busdisplay.BusDisplay) and save in a BMP file. * Author(s): Dave Astels, Matt Land @@ -26,12 +26,17 @@ """ -# imports +# pylint: disable=ungrouped-imports import gc import struct import board -from displayio import Bitmap, Palette, Display, ColorConverter +from displayio import Bitmap, Palette, ColorConverter + +try: + from busdisplay import BusDisplay +except ImportError: + from displayio import Display as BusDisplay try: from typing import Tuple, Optional, Union @@ -67,9 +72,11 @@ def _bytes_per_row(source_width: int) -> int: return pixel_bytes + padding_bytes -def _rotated_height_and_width(pixel_source: Union[Bitmap, Display]) -> Tuple[int, int]: +def _rotated_height_and_width( + pixel_source: Union[Bitmap, BusDisplay] +) -> Tuple[int, int]: # flip axis if the display is rotated - if isinstance(pixel_source, Display) and (pixel_source.rotation % 180 != 0): + if isinstance(pixel_source, BusDisplay) and (pixel_source.rotation % 180 != 0): return pixel_source.height, pixel_source.width return pixel_source.width, pixel_source.height @@ -111,7 +118,7 @@ def rgb565_to_rgb888(rgb565): # pylint:disable=too-many-locals def _write_pixels( output_file: BufferedWriter, - pixel_source: Union[Bitmap, Display], + pixel_source: Union[Bitmap, BusDisplay], palette: Optional[Union[Palette, ColorConverter]], ) -> None: saving_bitmap = isinstance(pixel_source, Bitmap) @@ -156,7 +163,7 @@ def _write_pixels( def save_pixels( file_or_filename: Union[str, BufferedWriter], - pixel_source: Union[Display, Bitmap] = None, + pixel_source: Union[BusDisplay, Bitmap] = None, palette: Optional[Union[Palette, ColorConverter]] = None, ) -> None: """Save pixels to a 24 bit per pixel BMP file. @@ -177,7 +184,7 @@ def save_pixels( raise ValueError( "Third argument must be a Palette or ColorConverter for a Bitmap save" ) - elif not isinstance(pixel_source, Display): + elif not isinstance(pixel_source, BusDisplay): raise ValueError("Second argument must be a Bitmap or Display") try: if isinstance(file_or_filename, str): From b75aac874d6d860d4e7689587e1aee62213da54a Mon Sep 17 00:00:00 2001 From: Neradoc Date: Wed, 2 Apr 2025 05:15:59 +0200 Subject: [PATCH 2/3] no need to keep compatibility with 8.x --- adafruit_bitmapsaver.py | 8 ++------ docs/api.rst | 6 ++---- docs/conf.py | 9 ++++++++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/adafruit_bitmapsaver.py b/adafruit_bitmapsaver.py index d8b5f19..f59d319 100644 --- a/adafruit_bitmapsaver.py +++ b/adafruit_bitmapsaver.py @@ -26,17 +26,13 @@ """ -# pylint: disable=ungrouped-imports +# imports import gc import struct import board from displayio import Bitmap, Palette, ColorConverter - -try: - from busdisplay import BusDisplay -except ImportError: - from displayio import Display as BusDisplay +from busdisplay import BusDisplay try: from typing import Tuple, Optional, Union diff --git a/docs/api.rst b/docs/api.rst index 1819110..92e264a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,8 +1,6 @@ -.. If you created a package, create one automodule per module in the package. - -.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) -.. use this format as the module name: "adafruit_foo.foo" +API Reference +############# .. automodule:: adafruit_bitmapsaver :members: diff --git a/docs/conf.py b/docs/conf.py index 0262580..fa91348 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,14 @@ # Uncomment the below if you use native CircuitPython modules such as # digitalio, micropython and busio. List the modules you use. Without it, the # autodoc module docs will fail to generate with a warning. -autodoc_mock_imports = ["displayio", "digitalio", "busio", "board"] +autodoc_mock_imports = [ + "busdisplay", + "displayio", + "digitalio", + "busio", + "board", + "framebufferio", +] intersphinx_mapping = { From 8967ac35e6db858ce736705ed1cdad2bdf4ee7b6 Mon Sep 17 00:00:00 2001 From: Neradoc Date: Wed, 2 Apr 2025 15:52:03 +0200 Subject: [PATCH 3/3] don't import display classes, use hasattr() --- adafruit_bitmapsaver.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/adafruit_bitmapsaver.py b/adafruit_bitmapsaver.py index f59d319..ce3b82e 100644 --- a/adafruit_bitmapsaver.py +++ b/adafruit_bitmapsaver.py @@ -32,11 +32,13 @@ import struct import board from displayio import Bitmap, Palette, ColorConverter -from busdisplay import BusDisplay + try: from typing import Tuple, Optional, Union from io import BufferedWriter + from busdisplay import BusDisplay + from framebufferio import FramebufferDisplay except ImportError: pass @@ -69,10 +71,10 @@ def _bytes_per_row(source_width: int) -> int: def _rotated_height_and_width( - pixel_source: Union[Bitmap, BusDisplay] + pixel_source: Union[Bitmap, BusDisplay, FramebufferDisplay] ) -> Tuple[int, int]: # flip axis if the display is rotated - if isinstance(pixel_source, BusDisplay) and (pixel_source.rotation % 180 != 0): + if hasattr(pixel_source, "rotation") and (pixel_source.rotation % 180 != 0): return pixel_source.height, pixel_source.width return pixel_source.width, pixel_source.height @@ -114,7 +116,7 @@ def rgb565_to_rgb888(rgb565): # pylint:disable=too-many-locals def _write_pixels( output_file: BufferedWriter, - pixel_source: Union[Bitmap, BusDisplay], + pixel_source: Union[Bitmap, BusDisplay, FramebufferDisplay], palette: Optional[Union[Palette, ColorConverter]], ) -> None: saving_bitmap = isinstance(pixel_source, Bitmap) @@ -139,7 +141,7 @@ def _write_pixels( color >>= 8 buffer_index += 1 else: - # pixel_source: Display + # pixel_source: display result_buffer = bytearray(2048) data = pixel_source.fill_row(y - 1, result_buffer) for i in range(width): @@ -159,15 +161,17 @@ def _write_pixels( def save_pixels( file_or_filename: Union[str, BufferedWriter], - pixel_source: Union[BusDisplay, Bitmap] = None, + pixel_source: Union[BusDisplay, FramebufferDisplay, Bitmap] = None, palette: Optional[Union[Palette, ColorConverter]] = None, ) -> None: """Save pixels to a 24 bit per pixel BMP file. If pixel_source if a displayio.Bitmap, save it's pixels through palette. - If it's a displayio.Display, a palette isn't required. + If it's a displayio display, a palette isn't required. To be supported, + a display must implement `busdisplay.BusDisplay.fill_row`. Known supported + display types are `busdisplay.BusDisplay` and `framebufferio.FramebufferDisplay`. :param file_or_filename: either the file to save to, or it's absolute name - :param pixel_source: the Bitmap or Display to save + :param pixel_source: the Bitmap or display to save :param palette: the Palette to use for looking up colors in the bitmap """ if not pixel_source: @@ -180,8 +184,8 @@ def save_pixels( raise ValueError( "Third argument must be a Palette or ColorConverter for a Bitmap save" ) - elif not isinstance(pixel_source, BusDisplay): - raise ValueError("Second argument must be a Bitmap or Display") + elif not hasattr(pixel_source, "fill_row"): + raise ValueError("Second argument must be a Bitmap or supported display type") try: if isinstance(file_or_filename, str): output_file = open( # pylint: disable=consider-using-with