@@ -127,6 +127,15 @@ def sort_key(x):
127
127
return qr
128
128
129
129
def _optimized_segments (self , data ):
130
+ """Returns optimized segments computed by SegmentOptimizer.
131
+
132
+ Args:
133
+ data (str): The data to encode.
134
+
135
+ Returns:
136
+ list: The list of segments.
137
+
138
+ """
130
139
optimizer = qr_segments .SegmentOptimizer ()
131
140
return optimizer .compute (data , self .version_name (), self ._error_correction_level )
132
141
@@ -161,6 +170,15 @@ def add_segment(self, data, encoder_class=encoder.ByteEncoder):
161
170
self ._segments .append ({"data" : data , "encoder_class" : encoder_class })
162
171
163
172
def add_segments (self , segments ):
173
+ """Add the segments.
174
+
175
+ Args:
176
+ segments (list): The list of segments.
177
+
178
+ Returns:
179
+ void
180
+
181
+ """
164
182
for segment in segments :
165
183
self .add_segment (segment ["data" ], segment ["encoder_class" ])
166
184
@@ -454,11 +472,24 @@ def _put_timing_pattern(self):
454
472
self ._qr [i ][j ] = color
455
473
456
474
def _put_version_information (self ):
475
+ """Version information placement."""
457
476
version_information = self ._compute_version_info ()
458
477
self ._put_version_information_finder_pattern_side (version_information )
459
478
self ._put_version_information_finder_sub_pattern_side (version_information )
460
479
461
480
def _put_version_information_finder_pattern_side (self , version_information ):
481
+ """Version information placement (finder pattern side).
482
+
483
+ This method computes masked version information data and puts it. The mask
484
+ pattern is 011111101010110010.
485
+
486
+ Args:
487
+ version_information (int): The version information.
488
+
489
+ Returns:
490
+ void
491
+
492
+ """
462
493
mask = 0b011111101010110010
463
494
version_information ^= mask
464
495
@@ -469,6 +500,18 @@ def _put_version_information_finder_pattern_side(self, version_information):
469
500
self ._qr [si + di ][sj + dj ] = Color .BLACK if version_information >> n & 1 else Color .WHITE
470
501
471
502
def _put_version_information_finder_sub_pattern_side (self , version_information ):
503
+ """Version information placement (finder sub pattern side).
504
+
505
+ This method computes masked version information data and puts it. The mask
506
+ pattern is 100000101001111011.
507
+
508
+ Args:
509
+ version_information (int): The version information.
510
+
511
+ Returns:
512
+ void
513
+
514
+ """
472
515
mask = 0b100000101001111011
473
516
version_information ^= mask
474
517
@@ -488,6 +531,7 @@ def _put_version_information_finder_sub_pattern_side(self, version_information):
488
531
)
489
532
490
533
def _compute_version_info (self ):
534
+ """Computes version information with BCH code."""
491
535
qr_version = rMQRVersions [self .version_name ()]
492
536
version_information_data = qr_version ["version_indicator" ]
493
537
if self ._error_correction_level == ErrorCorrectionLevel .H :
@@ -512,47 +556,135 @@ def _put_data(self, encoded_data):
512
556
list: A two-dimensional list shows where encoding region.
513
557
514
558
"""
515
- codewords = split_into_8bits (encoded_data )
516
-
517
- # Add the remainder codewords
518
559
qr_version = rMQRVersions [self .version_name ()]
519
- codewords_total = qr_version ["codewords_total" ]
560
+ codewords_num = qr_version ["codewords_total" ]
561
+
562
+ codewords = self ._make_codewords (encoded_data , codewords_num )
563
+ blocks = self ._split_into_blocks (codewords , qr_version ["blocks" ][self ._error_correction_level ])
564
+ final_codewords = self ._make_final_codewords (blocks )
565
+ mask = self ._put_final_codewords (final_codewords , qr_version ["remainder_bits" ])
566
+ return mask
567
+
568
+ def _make_codewords (self , encoded_data , codewords_num ):
569
+ """Makes codeword sequence from encoded data.
570
+
571
+ If the length of generated codeword sequence is less than the `codewords_num`,
572
+ appends the reminder codewords 11101100 and 00010001 alternately to meet the
573
+ requirements of number of codewords.
574
+
575
+ Args:
576
+ encoded_data (str): The encoded data.
577
+ codewords_num (int): The number of codewords.
578
+
579
+ Returns:
580
+ list: The list of codeword strings.
581
+
582
+ """
583
+ codewords = split_into_8bits (encoded_data )
520
584
while True :
521
- if len (codewords ) >= codewords_total :
585
+ if len (codewords ) >= codewords_num :
522
586
break
523
587
codewords .append ("11101100" )
524
- if len (codewords ) >= codewords_total :
588
+ if len (codewords ) >= codewords_num :
525
589
break
526
590
codewords .append ("00010001" )
591
+ return codewords
527
592
528
- data_codewords_per_block , rs_codewords_per_block = self ._split_into_blocks (
529
- codewords , qr_version ["blocks" ][self ._error_correction_level ]
530
- )
593
+ def _split_into_blocks (self , codewords , blocks_definition ):
594
+ """Splits codewords into several blocks.
595
+
596
+ Args:
597
+ codewords (list): The list of codeword strings.
598
+ blocks_definition: The list of dict.
599
+
600
+ Returns:
601
+ list: The list of Block object.
602
+
603
+ """
604
+ data_idx = 0
605
+ blocks = []
606
+ for block_definition in blocks_definition :
607
+ for i in range (block_definition ["num" ]):
608
+ data_codewords_num = block_definition ["k" ]
609
+ ecc_codewords_num = block_definition ["c" ] - block_definition ["k" ]
610
+ codewords_in_block = codewords [data_idx : data_idx + data_codewords_num ]
611
+ block = Block (data_codewords_num , ecc_codewords_num )
612
+ block .set_data_and_compute_ecc (codewords_in_block )
613
+ blocks .append (block )
614
+ data_idx += data_codewords_num
615
+ return blocks
616
+
617
+ def _make_final_codewords (self , blocks ):
618
+ """Makes the final message codeword sequence.
619
+
620
+ This method computes the final codeword sequence from the given blocks. For example,
621
+ we consider the following blocks. The blocks consists of three blocks. Block1 contains
622
+ two data blocks and three ecc blocks. Block2 contains three data blocks and three ecc blocks.
623
+ Block3 contains three data blocks and three ecc blocks.
624
+
625
+ Block1: Data#1 Data#2 ------ Ecc#1 Ecc#2 Ecc#3
626
+ Block2: Data#3 Data#4 Data#5 Ecc#4 Ecc#5 Ecc#6
627
+ Block3: Data#6 Data#7 Data#8 Ecc#7 Ecc#8 Ecc#9
628
+
629
+ The final codeword sequence for this example is placed in the following order.
531
630
532
- # Construct the final message codeword sequence
533
- # Data codewords
631
+ [Data#1, Data#3, Data#6, Data#2, Data#4, Data#7, Data#5, Data#8,
632
+ Ecc#1, Ecc#4, Ecc#7, Ecc#2, Ecc#5, Ecc#8, Ecc#3, Ecc#6, Ecc#9]
633
+
634
+ Args:
635
+ blocks (list): The list of Block objects.
636
+
637
+ Returns:
638
+ list: The list of codeword strings.
639
+
640
+ """
534
641
final_codewords = []
535
- for i in range (len (data_codewords_per_block [- 1 ])):
536
- for data_codewords in data_codewords_per_block :
537
- if i >= len (data_codewords ):
538
- continue
539
- final_codewords .append (data_codewords [i ])
540
- self ._logger .debug (f"Put QR data codeword { i } : { data_codewords [i ]} " )
642
+ # Add data codewords
643
+ # The last block always has the most codewords.
644
+ for i in range (blocks [- 1 ].data_length ()):
645
+ for block in blocks :
646
+ try :
647
+ data_codeword = block .get_data_at (i )
648
+ except IndexError :
649
+ break
650
+ else :
651
+ final_codewords .append (data_codeword )
652
+ self ._logger .debug (f"Put QR data codeword { i } : { data_codeword } " )
653
+
654
+ # Add ecc codewords
655
+ # The last block always has the most codewords.
656
+ for i in range (blocks [- 1 ].ecc_length ()):
657
+ for block in blocks :
658
+ try :
659
+ ecc_codeword = block .get_ecc_at (i )
660
+ except IndexError :
661
+ break
662
+ else :
663
+ final_codewords .append (ecc_codeword )
664
+ self ._logger .debug (f"Put RS data codewords { i } : { ecc_codeword } " )
665
+ return final_codewords
541
666
542
- # RS Codewords
543
- for i in range (len (rs_codewords_per_block [- 1 ])):
544
- for rs_codewords in rs_codewords_per_block :
545
- if i >= len (rs_codewords ):
546
- continue
547
- final_codewords .append (rs_codewords [i ])
548
- self ._logger .debug (f"Put RS data codewords { i } : { rs_codewords [i ]} " )
667
+ def _put_final_codewords (self , final_codewords , reminder_bits_num ):
668
+ """Puts the final codeword sequence.
549
669
550
- # Codeword placement
670
+ This method puts the final codeword sequence into the encoding region of the rMQR Code.
671
+ The `final_codewords` is computed by self._make_final_codewords method. Also, this method
672
+ computes a two-dimensional list shows where encoding region at the same time.
673
+ And returns the list.
674
+
675
+ Args:
676
+ final_codewords (list): The list of the final codeword strings.
677
+ reminder_bits_num (int): The number of modules without data.
678
+
679
+ Returns:
680
+ list: A two-dimensional list shows where encoding region.
681
+
682
+ """
551
683
dy = - 1 # Up
552
684
current_codeword_idx = 0
553
685
current_bit_idx = 0
554
686
cx , cy = self ._width - 2 , self ._height - 6
555
- remainder_bits = qr_version [ "remainder_bits" ]
687
+ remaining_remainder_bits = reminder_bits_num
556
688
mask_area = [[False for i in range (self ._width )] for j in range (self ._height )]
557
689
558
690
while True :
@@ -563,7 +695,7 @@ def _put_data(self, encoded_data):
563
695
# Remainder bits
564
696
self ._qr [cy ][x ] = Color .WHITE
565
697
mask_area [cy ][x ] = True
566
- remainder_bits -= 1
698
+ remaining_remainder_bits -= 1
567
699
else :
568
700
# Codewords
569
701
self ._qr [cy ][x ] = (
@@ -577,10 +709,10 @@ def _put_data(self, encoded_data):
577
709
current_bit_idx = 0
578
710
current_codeword_idx += 1
579
711
580
- if current_codeword_idx == len (final_codewords ) and remainder_bits == 0 :
712
+ if current_codeword_idx == len (final_codewords ) and remaining_remainder_bits == 0 :
581
713
break
582
714
583
- if current_codeword_idx == len (final_codewords ) and remainder_bits == 0 :
715
+ if current_codeword_idx == len (final_codewords ) and remaining_remainder_bits == 0 :
584
716
break
585
717
586
718
# Update current coordinates
@@ -595,27 +727,6 @@ def _put_data(self, encoded_data):
595
727
596
728
return mask_area
597
729
598
- def _split_into_blocks (self , codewords , blocks_definition ):
599
- data_idx , error_idx = 0 , 0
600
- data_codewords_per_block = []
601
- rs_codewords_per_block = []
602
- for block_definition in blocks_definition :
603
- for i in range (block_definition ["num" ]):
604
- data_codewords_num = block_definition ["k" ]
605
- rs_codewords_num = block_definition ["c" ] - block_definition ["k" ]
606
- g = GeneratorPolynomials [rs_codewords_num ]
607
-
608
- codewords_in_block = codewords [data_idx : data_idx + data_codewords_num ]
609
- rs_codewords_in_block = compute_reed_solomon (codewords_in_block , g , rs_codewords_num )
610
-
611
- data_codewords_per_block .append (codewords_in_block )
612
- rs_codewords_per_block .append (rs_codewords_in_block )
613
-
614
- data_idx += data_codewords_num
615
- error_idx += rs_codewords_num
616
-
617
- return data_codewords_per_block , rs_codewords_per_block
618
-
619
730
def _apply_mask (self , mask_area ):
620
731
"""Data masking.
621
732
@@ -661,3 +772,68 @@ def validate_version(version_name):
661
772
662
773
"""
663
774
return version_name in rMQRVersions
775
+
776
+
777
+ class Block :
778
+ """A class represents data block.
779
+
780
+ This class represents data block. A block consists data part and error correction
781
+ code (ecc) part.
782
+
783
+ """
784
+
785
+ def __init__ (self , data_codewords_num , ecc_codewords_num ):
786
+ self ._data_codewords_num = data_codewords_num
787
+ self ._data_codewords = []
788
+ self ._ecc_codewords_num = ecc_codewords_num
789
+ self ._ecc_codewords = []
790
+
791
+ def set_data_and_compute_ecc (self , data_codewords ):
792
+ """Set data and compute ecc.
793
+
794
+ Args:
795
+ data_codewords (list): The list of codeword strings.
796
+
797
+ Returns:
798
+ void
799
+
800
+ """
801
+ self ._data_codewords = data_codewords
802
+ self ._compute_ecc_codewords ()
803
+
804
+ def get_data_at (self , index ):
805
+ """Get data codeword at the index.
806
+
807
+ Args:
808
+ index (int): The index.
809
+
810
+ Return:
811
+ str: The data codeword.
812
+
813
+ """
814
+ return self ._data_codewords [index ]
815
+
816
+ def get_ecc_at (self , index ):
817
+ """Get ecc codeword at the index.
818
+
819
+ Args:
820
+ index (int): The index.
821
+
822
+ Return:
823
+ str: The ecc codeword.
824
+
825
+ """
826
+ return self ._ecc_codewords [index ]
827
+
828
+ def data_length (self ):
829
+ """Get the number of data codewords"""
830
+ return len (self ._data_codewords )
831
+
832
+ def ecc_length (self ):
833
+ """Get the number of ecc codewords"""
834
+ return len (self ._ecc_codewords )
835
+
836
+ def _compute_ecc_codewords (self ):
837
+ """Computes the ecc codewords with the data codewords."""
838
+ g = GeneratorPolynomials [self ._ecc_codewords_num ]
839
+ self ._ecc_codewords = compute_reed_solomon (self ._data_codewords , g , self ._ecc_codewords_num )
0 commit comments