Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Render SeedQR small registration block in solid squares #484

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 58 additions & 4 deletions src/seedsigner/helpers/qr.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import qrcode
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import CircleModuleDrawer, GappedSquareModuleDrawer
from PIL import Image
from PIL import Image, ImageDraw
import subprocess

class QR:
Expand All @@ -13,19 +13,73 @@ def __init__(self) -> None:
return

def qrimage(self, data, width=240, height=240, border=3, style=None, background_color="#444"):
qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=5, border=border )
box_size = 5
qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=box_size, border=border )
qr.add_data(data)
qr.make(fit=True)
if not style or style == QR.STYLE__DEFAULT:
return qr.make_image(fill_color="black", back_color=background_color).resize((width,height)).convert('RGBA')
else:
if style == QR.STYLE__ROUNDED:
return qr.make_image(
qr_image = qr.make_image(
fill_color="black",
back_color=background_color,
image_factory=StyledPilImage,
module_drawer=CircleModuleDrawer()
).resize((width,height)).convert('RGBA')
)

qr_image_width, _ = qr_image.size
qr_code_dims = int(qr_image_width / box_size) - 2*border

if qr_code_dims > 21:
# The ROUNDED style mis-renders the small lower-right registration box in 25x25
# and 29x29.
draw = ImageDraw.Draw(qr_image)
if qr_code_dims == 25:
# registration block starts at 16, 16 and is 5x5
starting_point = 16 + border

elif qr_code_dims == 29:
# The registration block starts at 20,20 and is 5x5
starting_point = 20 + border

else:
raise Exception(f"Unrecognized qrimage size: {qr_code_dims}")

# Render black rectangular lines on top of the qr_image to square off
# the registration block.
lines = [
(
# top
(starting_point*box_size, starting_point*box_size),
(starting_point*box_size + 5*box_size - 1, starting_point*box_size + box_size - 1)
),
(
# right
(starting_point*box_size + 4*box_size, starting_point*box_size),
(starting_point*box_size + 5*box_size - 1, starting_point*box_size + 5*box_size - 1)
),
(
# left
(starting_point*box_size, starting_point*box_size),
(starting_point*box_size + box_size - 1, starting_point*box_size + 5*box_size - 1)
),
(
# bottom
(starting_point*box_size + box_size, starting_point*box_size + 4*box_size),
(starting_point*box_size + 5*box_size - 1, starting_point*box_size + 5*box_size - 1)
),
(
# center dot
(starting_point*box_size + 2*box_size, starting_point*box_size + 2*box_size),
(starting_point*box_size + 3*box_size - 1, starting_point*box_size + 3*box_size - 1)
)
]

for line in lines:
draw.rectangle(line, fill="black")

return qr_image.resize((width,height)).convert('RGBA')

elif style == QR.STYLE__GRID:
return qr.make_image(
Expand Down
10 changes: 7 additions & 3 deletions tests/screenshot_generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ def test_generate_screenshots(target_locale):
mnemonic_12b = ["abandon"] * 11 + ["about"]
seed_12 = Seed(mnemonic=mnemonic_12, passphrase="cap*BRACKET3stove", wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
seed_12b = Seed(mnemonic=mnemonic_12b, wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
seed_24 = Seed(mnemonic=mnemonic_24, passphrase="some-PASS*phrase9", wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
seed_24 = Seed(mnemonic=mnemonic_24, wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
seed_24_w_passphrase = Seed(mnemonic=mnemonic_24, passphrase="some-PASS*phrase9", wordlist_language_code=SettingsConstants.WORDLIST_LANGUAGE__ENGLISH)
controller.storage.seeds.append(seed_12)
controller.storage.seeds.append(seed_12b)
controller.storage.set_pending_seed(seed_24)
controller.storage.seeds.append(seed_24)
controller.storage.set_pending_seed(seed_24_w_passphrase)
UnhandledExceptionViewFood = ["IndexError", "line 1, in some_buggy_code.py", "list index out of range"]

# Pending mnemonic for ToolsCalcFinalWordShowFinalWordView
Expand Down Expand Up @@ -155,8 +157,10 @@ def test_generate_screenshots(target_locale):
(seed_views.SeedWordsBackupTestSuccessView, dict(seed_num=0)),
(seed_views.SeedTranscribeSeedQRFormatView, dict(seed_num=0)),
(seed_views.SeedTranscribeSeedQRWarningView, dict(seed_num=0)),
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=0, seedqr_format=QRType.SEED__SEEDQR, num_modules=25), "SeedTranscribeSeedQRWholeQRView_12_Standard"),
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=0, seedqr_format=QRType.SEED__COMPACTSEEDQR, num_modules=21), "SeedTranscribeSeedQRWholeQRView_12_Compact"),
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=0, seedqr_format=QRType.SEED__SEEDQR, num_modules=25), "SeedTranscribeSeedQRWholeQRView_12_Standard"),
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=2, seedqr_format=QRType.SEED__COMPACTSEEDQR, num_modules=25), "SeedTranscribeSeedQRWholeQRView_24_Compact"),
(seed_views.SeedTranscribeSeedQRWholeQRView, dict(seed_num=2, seedqr_format=QRType.SEED__SEEDQR, num_modules=29), "SeedTranscribeSeedQRWholeQRView_24_Standard"),

# Screenshot doesn't render properly due to how the transparency mask is pre-rendered
# (seed_views.SeedTranscribeSeedQRZoomedInView, dict(seed_num=0, seedqr_format=QRType.SEED__SEEDQR)),
Expand Down