3030using System . Collections . Generic ;
3131using System . Diagnostics ;
3232using System . Linq ;
33- using System . Text ;
3433
3534namespace Net . Codecrete . QrCodeGenerator
3635{
@@ -101,9 +100,14 @@ public static QrCode EncodeText(string text, Ecc ecl)
101100 /// If multiple QR codes are required, <em>Structured Append</em> data is included to link the QR codes.
102101 /// </para>
103102 /// <para>
104- /// The text is split at character boundaries even though the underlying UTF-8 encoding requires
105- /// multiple bytes for some characters. This increases compatibility with QR code scanners assuming
106- /// that each individual QR codes contains a valid UTF-8 string.
103+ /// Each QR code might use multiple segments with different encoding modes
104+ /// to maximize the amount of text that can be stored in each QR code.
105+ /// </para>
106+ /// <para>
107+ /// Each QR code will contain a valid string as it is ensured that splitting only occurs
108+ /// at character boundaries and not in the middle of a multi-byte encoding of a character.
109+ /// This increases compatibility with QR code scanners that incorrectly assume that each
110+ /// individual QR code in the series contains a valid UTF-8 string.
107111 /// </para>
108112 /// </summary>
109113 /// <param name="text">The text to be encoded. The full range of Unicode characters may be used.</param>
@@ -118,36 +122,17 @@ public static List<QrCode> EncodeTextInMultipleCodes(string text, Ecc ecl, int v
118122 Objects . RequireNonNull ( text ) ;
119123 Objects . RequireNonNull ( ecl ) ;
120124
121- var textBytes = Encoding . UTF8 . GetBytes ( text ) ;
122- var numCharCountBits = QrSegment . Mode . Byte . NumCharCountBits ( version ) ;
123- var numDataCodewords = GetNumDataCodewords ( version , ecl ) ;
124-
125- if ( ( numCharCountBits + 7 ) / 8 + textBytes . Length <= numDataCodewords )
126- {
127- // text is short enough to fit into a single QR code
128- var segment = QrSegment . MakeBytes ( textBytes ) ;
129- var qrCode = EncodeSegments ( new List < QrSegment > { segment } , ecl , minVersion : version , maxVersion : version , boostEcl : boostEcl ) ;
125+ // Test if text fits in a single QR code
126+ try {
127+ var segments = QrSegmentAdvanced . MakeSegmentsOptimally ( text , ecl , version , version ) ;
128+ var qrCode = EncodeSegments ( segments , ecl , minVersion : version , maxVersion : version , boostEcl : boostEcl ) ;
130129 return new List < QrCode > { qrCode } ;
131- }
132-
133- var overhead = ( 2 * 4 + numCharCountBits + 16 + 7 ) / 8 ; // 2 mode indicators + char count + structured append + byte alignment
134- var maxSliceSize = numDataCodewords - overhead ;
135- int numSlices = ( textBytes . Length + maxSliceSize - 1 ) / maxSliceSize ;
136-
137- var segments = QrSegment . MakeStructuredAppendSegments ( textBytes , numSlices , considerUtf8Boundaries : true ) ;
138- if ( segments . Max ( s => s [ 1 ] . NumChars ) > maxSliceSize )
139- {
140- numSlices ++ ;
141- segments = QrSegment . MakeStructuredAppendSegments ( textBytes , numSlices , considerUtf8Boundaries : true ) ;
142- }
143-
144- if ( numSlices > 16 )
130+ } catch ( DataTooLongException )
145131 {
146- throw new DataTooLongException ( "Text is too long to fit in 16 QR codes with the given version and ECL" ) ;
132+ // Continue with multiple QR codes
147133 }
148134
149- int balancedSliceSize = ( textBytes . Length + numSlices - 1 ) / numSlices ;
150- return segments
135+ return QrSegmentAdvanced . MakeSegmentsForMultipleCodes ( text , ecl , version )
151136 . Select ( segmentList => EncodeSegments ( segmentList , ecl , minVersion : version , maxVersion : version , boostEcl : boostEcl ) )
152137 . ToList ( ) ;
153138 }
@@ -753,7 +738,7 @@ private byte[] AddEccAndInterleave(byte[] data)
753738 Objects . RequireNonNull ( data ) ;
754739 if ( data . Length != GetNumDataCodewords ( Version , ErrorCorrectionLevel ) )
755740 {
756- throw new ArgumentOutOfRangeException ( ) ;
741+ throw new ArgumentOutOfRangeException ( nameof ( data ) , "Length of data does not match version and ecl" ) ;
757742 }
758743
759744 // Calculate parameter numbers
@@ -801,7 +786,7 @@ private void DrawCodewords(byte[] data)
801786 Objects . RequireNonNull ( data ) ;
802787 if ( data . Length != GetNumRawDataModules ( Version ) / 8 )
803788 {
804- throw new ArgumentOutOfRangeException ( ) ;
789+ throw new ArgumentOutOfRangeException ( nameof ( data ) , "data length does not match version" ) ;
805790 }
806791
807792 var i = 0 ; // Bit index into the data
@@ -865,7 +850,7 @@ private void ApplyMask(uint mask)
865850 case 6 : invert = ( x * y % 2 + x * y % 3 ) % 2 == 0 ; break ;
866851 case 7 : invert = ( ( x + y ) % 2 + x * y % 3 ) % 2 == 0 ; break ;
867852 }
868- _modules [ y , x ] ^= invert & ! _isFunction [ y , x ] ;
853+ _modules [ y , x ] ^= invert && ! _isFunction [ y , x ] ;
869854 }
870855 }
871856 }
0 commit comments