Skip to content

Commit

Permalink
Merge pull request #484 from kdmukai/seedqr_export_rendering_fix
Browse files Browse the repository at this point in the history
[Enhancement] Render SeedQR small registration block in solid squares
  • Loading branch information
newtonick authored Feb 23, 2024
2 parents a14aa2f + 6232e30 commit db16fa7
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 7 deletions.
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

0 comments on commit db16fa7

Please sign in to comment.