@@ -98,13 +98,15 @@ def elements( self ):
9898
9999
100100class Text ( Region ):
101+ SIZE_RATIO = 3 / 4
102+
101103 def __init__ ( self , * args , font = None , text = None , size = None , size_ratio = None , align = None ,
102104 foreground = None , background = None , bold = None , italic = None , underline = None ,
103105 ** kwds ):
104106 self .font = font
105107 self .text = text
106108 self .size = size
107- self .size_ratio = size_ratio or 3 / 4
109+ self .size_ratio = size_ratio or self . SIZE_RATIO
108110 self .align = align
109111 self .foreground = foreground
110112 self .background = background
@@ -258,18 +260,18 @@ def layout_wallet(
258260 # Assign each different Crypto name a different color, in template labels crypto-{f,b}1, crypto-{f,b}2, ...
259261 for c_n in range ( len ( COLOR )):
260262 public .add_region_proportional (
261- Text ( f'crypto-f{ c_n } ' , x1 = 1 / 8 , y1 = - 1 / 16 , x2 = 7 / 8 , y2 = 8 / 16 , foreground = int ( COLOR [c_n ], 16 ), rotate = - 45 )
263+ Text ( f'crypto-f{ c_n } ' , x1 = 1 / 8 , y1 = - 1 / 16 , x2 = 7 / 8 , y2 = 7 / 16 , foreground = int ( COLOR [c_n ], 16 ), rotate = - 45 )
262264 )
263265 private .add_region_proportional (
264- Text ( f'crypto-b{ c_n } ' , x1 = 2 / 8 , y1 = - 1 / 16 , x2 = 7 / 8 , y2 = 8 / 16 , foreground = int ( COLOR [c_n ], 16 ), rotate = - 45 )
266+ Text ( f'crypto-b{ c_n } ' , x1 = 2 / 8 , y1 = - 1 / 16 , x2 = 7 / 8 , y2 = 7 / 16 , foreground = int ( COLOR [c_n ], 16 ), rotate = - 45 )
265267 )
266268
267269 # Public addresses are vertical on left- and right-hand of public Region. In order to fit the
268270 # longer ETH addresses into a space with a fixed-width font, we know that the ratio of the width
269271 # to the height has to be about 1/20. Rotation is downward around upper-left corner; so,
270272 # lower-left corner will shift 1 height leftward and upward; so start 1 height right and down.
271273 address_length = public .y2 - public .y1
272- address_height = address_length * 1 / 19
274+ address_height = address_length * 1 / 20
273275 public .add_region (
274276 Image (
275277 'address-l-bg' ,
@@ -282,6 +284,7 @@ def layout_wallet(
282284 ).add_region (
283285 Text (
284286 'address-l' ,
287+ font = 'mono' ,
285288 rotate = - 90 ,
286289 )
287290 )
@@ -300,13 +303,14 @@ def layout_wallet(
300303 ).add_region (
301304 Text (
302305 'address-r' ,
306+ font = 'mono' ,
303307 rotate = + 90 ,
304308 )
305309 )
306310
307311 # Make Public QR Code square w/ min of height, width, anchored at lower-left corner
308312 public .add_region_proportional (
309- Text ( 'address-qr-top ' , x1 = 1 / 16 , y1 = 5 / 16 , x2 = 1 , y2 = 6 / 16 )
313+ Text ( 'address-qr-t ' , x1 = 1 / 16 , y1 = 5 / 16 , x2 = 1 , y2 = 6 / 16 )
310314 )
311315 public_qr = public .add_region_proportional (
312316 Image ( 'address-qr' , x1 = 1 / 16 , y1 = 6 / 16 , x2 = 1 , y2 = 15 / 16 )
@@ -315,12 +319,13 @@ def layout_wallet(
315319 public_qr .x2 = public_qr .x1 + public_qr_size
316320 public_qr .y1 = public_qr .y2 - public_qr_size
317321 public .add_region_proportional (
318- Text ( 'address-qr-bot ' , x1 = 1 / 16 , y1 = 15 / 16 , x2 = 1 , y2 = 16 / 16 )
322+ Text ( 'address-qr-b ' , x1 = 1 / 16 , y1 = 15 / 16 , x2 = 1 , y2 = 16 / 16 )
319323 )
320324
321325 # Private region
326+
322327 private .add_region_proportional (
323- Text ( 'private-qr-top ' , x1 = 0 / 16 , y1 = 5 / 16 , x2 = 1 , y2 = 6 / 16 )
328+ Text ( 'private-qr-t ' , x1 = 0 / 16 , y1 = 5 / 16 , x2 = 1 , y2 = 6 / 16 )
324329 )
325330 private_qr = private .add_region_proportional (
326331 Image ( 'private-qr' , x1 = 0 / 16 , y1 = 6 / 16 , x2 = 1 , y2 = 15 / 16 )
@@ -329,33 +334,56 @@ def layout_wallet(
329334 private_qr .x2 = private_qr .x1 + private_qr_size
330335 private_qr .y1 = private_qr .y2 - private_qr_size
331336 private .add_region_proportional (
332- Text ( 'private-qr-bot' , x1 = 0 / 16 , y1 = 15 / 16 , x2 = 1 , y2 = 16 / 16 )
337+ Text ( 'private-qr-b' , x1 = 0 / 16 , y1 = 15 / 16 , x2 = 1 , y2 = 16 / 16 )
338+ )
339+
340+ # Hint above; but same computed width as private_qr
341+ private_h_t = private .add_region_proportional (
342+ Text ( 'private-hint-t' , x1 = 0 / 16 , y1 = 0 / 16 , x2 = 1 , y2 = 1 / 16 )
333343 )
344+ private_h_t .x2 = private_qr .x2
345+ private_h_bg = private .add_region_proportional (
346+ Image ( 'private-hint-bg' ,x1 = 0 / 16 , y1 = 1 / 16 , x2 = 1 , y2 = 4 / 16 )
347+ )
348+ private_h_bg .x2 = private_qr .x2
349+ private_h = private .add_region_proportional (
350+ Text ( 'private-hint' , x1 = 0 / 16 , y1 = 1 / 16 , x2 = 1 , y2 = 3 / 16 )
351+ )
352+ private_h .x2 = private_qr .x2
334353
335354 # We'll use the right side of the private region, each line rotated 90 degrees down and right.
336355 # So, we need the upper-left corner of the private-bg anchored at the upper-right corner of
337356 # private.
338357 private_length = private .y2 - private .y1 # line length is y-height
339- private_fontsize = 8 # points == 1/72 inch
340- private_height = private .x2 - private_qr .x2 # line height is
341- private_fontwidth = private_length
358+ private_fontsize = 6. 8 # points == 1/72 inch
359+ private_height = private .x2 - private_qr .x2 - .05
360+ private_lineheight = private_fontsize / 72 / Text . SIZE_RATIO * .9 # in.
342361
343- public .add_region (
362+ private .add_region (
344363 Image (
345364 'private-bg' ,
346365 x1 = private .x2 ,
347366 y1 = private .y1 ,
348- x2 = private .x2 + private_length + private_height ,
367+ x2 = private .x2 + private_length ,
349368 y2 = private .y1 + private_height ,
350369 rotate = - 90 ,
351370 )
352- ).add_region (
353- Text (
354- 'private' ,
355- size = private_fontsize ,
356- rotate = - 90 ,
357- )
358371 )
372+ # Now, add private key lines down the edge from right to left, rotating each into place
373+ for l in range ( int ( private_height // private_lineheight )):
374+ private .add_region (
375+ Text (
376+ f"private-{ l } " ,
377+ font = 'mono' ,
378+ x1 = private .x2 - private_lineheight * l ,
379+ y1 = private .y1 ,
380+ x2 = private .x2 + private_length ,
381+ y2 = private .y1 + private_lineheight ,
382+ size = private_fontsize ,
383+ rotate = - 90 ,
384+ )
385+ )
386+
359387 return wallet
360388
361389
@@ -511,7 +539,8 @@ def write_pdfs(
511539 json_pwd = None , # If JSON wallet output desired, supply password
512540 text = None , # Truthy outputs SLIP-39 recover phrases to stdout
513541 wallet_pwd = None , # If paper wallet images desired, supply password
514- wallet_format = None , # ... and a format (eg. 'third')
542+ wallet_pwd_hint = None , # an optional password hint
543+ wallet_format = None , # and a paper wallet format (eg. 'third')
515544):
516545 """Writes a PDF containing a unique SLIP-39 encoded seed for each of the names specified.
517546
@@ -629,9 +658,9 @@ def write_pdfs(
629658 pdf .add_page ( orientation = 'P' )
630659 page_n = p
631660 try :
632- private_bip38 = account .bip38 ( 'password' )
661+ private_enc = account .encrypted ( 'password' )
633662 except NotImplementedError as exc :
634- log .exception ( f"{ account .crypto } doesn't support BIP-38: { exc } " )
663+ log .exception ( f"{ account .crypto } doesn't support BIP-38 or JSON wallet encryption : { exc } " )
635664 continue
636665
637666 wall_n += 1
@@ -653,9 +682,9 @@ def write_pdfs(
653682 wall_tpl ['address-l' ] = account .address
654683 wall_tpl ['address-r-bg' ] = os .path .join ( images , '1x1-ffffff7f.png' )
655684 wall_tpl ['address-r' ] = account .address
656- wall_tpl ['address-qr-top ' ] = 'PUBLIC ADDRESS'
685+ wall_tpl ['address-qr-t ' ] = 'PUBLIC ADDRESS'
657686 wall_tpl ['address-qr' ] = public_qr .make_image ( back_color = "transparent" ).get_image ()
658- wall_tpl ['address-qr-bot ' ] = 'DEPOSIT/VERIFY'
687+ wall_tpl ['address-qr-b ' ] = 'DEPOSIT/VERIFY'
659688
660689
661690 private_qr = qrcode .QRCode (
@@ -664,18 +693,24 @@ def write_pdfs(
664693 box_size = 10 ,
665694 border = 1 ,
666695 )
667- private_qr .add_data ( private_bip38 )
696+ private_qr .add_data ( private_enc )
668697
669698 wall_tpl ['private-bg' ] = os .path .join ( images , '1x1-ffffff7f.png' )
670699 def chunker ( sequence , size ):
671700 while sequence :
672701 yield sequence [:size ]
673702 sequence = sequence [size :]
674-
675- wall_tpl ['private' ] = '\n ' .join ( chunker ( private_bip38 , 32 ))
676- wall_tpl ['private-qr-top' ] = 'PRIVATE KEY'
703+
704+ # If not enough lines, will throw Exception, as it should! We don't want
705+ # to emit a Paper Wallet without the entire encrypted private key present.
706+ for l ,line in enumerate ( chunker ( private_enc , 40 )):
707+ wall_tpl [f"private-{ l } " ]= line
708+ wall_tpl ['private-hint-t' ] = 'PASSPHRASE HINT:'
709+ wall_tpl ['private-hint-bg' ] = os .path .join ( images , '1x1-ffffff7f.png' )
710+ wall_tpl ['private-hint' ] = wallet_pwd_hint
711+ wall_tpl ['private-qr-t' ] = 'PRIVATE KEY'
677712 wall_tpl ['private-qr' ] = private_qr .make_image ( back_color = "transparent" ).get_image ()
678- wall_tpl ['private-qr-bot ' ] = 'SPEND'
713+ wall_tpl ['private-qr-b ' ] = 'SPEND'
679714
680715 wall_tpl .render ( offsetx = offsetx , offsety = offsety )
681716
0 commit comments