diff --git a/qrcode/image/styles/moduledrawers/__init__.py b/qrcode/image/styles/moduledrawers/__init__.py index 99217d49..bf0df8a3 100644 --- a/qrcode/image/styles/moduledrawers/__init__.py +++ b/qrcode/image/styles/moduledrawers/__init__.py @@ -1,6 +1,7 @@ # For backwards compatibility, importing the PIL drawers here. try: from .pil import CircleModuleDrawer # noqa: F401 + from .pil import GappedCircleModuleDrawer # noqa: F401 from .pil import GappedSquareModuleDrawer # noqa: F401 from .pil import HorizontalBarsDrawer # noqa: F401 from .pil import RoundedModuleDrawer # noqa: F401 diff --git a/qrcode/image/styles/moduledrawers/pil.py b/qrcode/image/styles/moduledrawers/pil.py index 398010c6..6c63fa48 100644 --- a/qrcode/image/styles/moduledrawers/pil.py +++ b/qrcode/image/styles/moduledrawers/pil.py @@ -94,6 +94,39 @@ def drawrect(self, box, is_active: bool): self.img._img.paste(self.circle, (box[0][0], box[0][1])) +class GappedCircleModuleDrawer(StyledPilQRModuleDrawer): + """ + Draws the modules as circles that are not contiguous. + + The size_ratio determines how wide the circles are relative to the width of + the space they are printed in + """ + + circle = None + + def __init__(self, size_ratio=0.9): + self.size_ratio = size_ratio + + def initialize(self, *args, **kwargs): + super().initialize(*args, **kwargs) + box_size = self.img.box_size + fake_size = box_size * ANTIALIASING_FACTOR + self.circle = Image.new( + self.img.mode, + (fake_size, fake_size), + self.img.color_mask.back_color, + ) + ImageDraw.Draw(self.circle).ellipse( + (0, 0, fake_size, fake_size), fill=self.img.paint_color + ) + smaller_size = int(self.size_ratio * box_size) + self.circle = self.circle.resize((smaller_size, smaller_size), Image.Resampling.LANCZOS) + + def drawrect(self, box, is_active: bool): + if is_active: + self.img._img.paste(self.circle, (box[0][0], box[0][1])) + + class RoundedModuleDrawer(StyledPilQRModuleDrawer): """ Draws the modules with all 90 degree corners replaced with rounded edges.