@@ -27,10 +27,22 @@ public NumericDataSegment(string numericText)
2727 /// <param name="version">The QR code version (1-40, or -1 to -4 for Micro QR)</param>
2828 /// <returns>The total number of bits required for this segment</returns>
2929 public override int GetBitLength ( int version )
30+ {
31+ return GetBitLength ( Text . Length , version ) ;
32+ }
33+
34+ /// <summary>
35+ /// Calculates the total bit length for encoding numeric text of a given length for a specific QR code version.
36+ /// Includes mode indicator, count indicator, and data bits.
37+ /// </summary>
38+ /// <param name="textLength">The length of the numeric text</param>
39+ /// <param name="version">The QR code version (1-40, or -1 to -4 for Micro QR)</param>
40+ /// <returns>The total number of bits required</returns>
41+ public static int GetBitLength ( int textLength , int version )
3042 {
3143 int modeIndicatorLength = 4 ;
3244 int countIndicatorLength = GetCountIndicatorLength ( version , EncodingMode . Numeric ) ;
33- int dataLength = Text . Length / 3 * 10 + ( Text . Length % 3 == 1 ? 4 : Text . Length % 3 == 2 ? 7 : 0 ) ;
45+ int dataLength = textLength / 3 * 10 + ( textLength % 3 == 1 ? 4 : textLength % 3 == 2 ? 7 : 0 ) ;
3446 int length = modeIndicatorLength + countIndicatorLength + dataLength ;
3547
3648 return length ;
@@ -45,19 +57,33 @@ public override int GetBitLength(int version)
4557 /// <returns>The next index in the BitArray after the last bit written</returns>
4658 public override int WriteTo ( BitArray bitArray , int startIndex , int version )
4759 {
48- var index = startIndex ;
60+ return WriteTo ( Text , 0 , Text . Length , bitArray , startIndex , version ) ;
61+ }
62+
63+ /// <summary>
64+ /// Writes a portion of numeric text to a BitArray at the specified index.
65+ /// Includes mode indicator, count indicator, and data bits.
66+ /// </summary>
67+ /// <param name="text">The full numeric text</param>
68+ /// <param name="startIndex">The starting index in the text to encode from</param>
69+ /// <param name="length">The number of characters to encode</param>
70+ /// <param name="bitArray">The target BitArray to write to</param>
71+ /// <param name="bitIndex">The starting index in the BitArray</param>
72+ /// <param name="version">The QR code version (1-40, or -1 to -4 for Micro QR)</param>
73+ /// <returns>The next index in the BitArray after the last bit written</returns>
74+ public static int WriteTo ( string text , int startIndex , int length , BitArray bitArray , int bitIndex , int version )
75+ {
76+ var index = bitIndex ;
4977
5078 // write mode indicator
5179 index = DecToBin ( ( int ) EncodingMode . Numeric , 4 , bitArray , index ) ;
5280
5381 // write count indicator
5482 int countIndicatorLength = GetCountIndicatorLength ( version , EncodingMode . Numeric ) ;
55- index = DecToBin ( Text . Length , countIndicatorLength , bitArray , index ) ;
83+ index = DecToBin ( length , countIndicatorLength , bitArray , index ) ;
5684
5785 // write data - encode numeric text
58- var data = PlainTextToBinaryNumeric ( Text ) ;
59- data . CopyTo ( bitArray , 0 , index , data . Length ) ;
60- index += data . Length ;
86+ index = PlainTextToBinaryNumeric ( text , startIndex , length , bitArray , index ) ;
6187
6288 return index ;
6389 }
@@ -74,10 +100,26 @@ private static BitArray PlainTextToBinaryNumeric(string plainText)
74100 // Calculate the length of the BitArray needed to encode the text.
75101 // Groups of three digits are encoded in 10 bits, remaining groups of two or one digits take 7 or 4 bits respectively.
76102 var bitArray = new BitArray ( plainText . Length / 3 * 10 + ( plainText . Length % 3 == 1 ? 4 : plainText . Length % 3 == 2 ? 7 : 0 ) ) ;
77- var index = 0 ;
103+ PlainTextToBinaryNumeric ( plainText , 0 , plainText . Length , bitArray , 0 ) ;
104+ return bitArray ;
105+ }
106+
107+ /// <summary>
108+ /// Converts a portion of numeric plain text into a binary format specifically optimized for QR codes, writing directly to an existing BitArray.
109+ /// Numeric compression groups up to 3 digits into 10 bits, less for remaining digits if they do not complete a group of three.
110+ /// </summary>
111+ /// <param name="plainText">The numeric text to be encoded, which should only contain digit characters.</param>
112+ /// <param name="offset">The starting index in the text to encode from.</param>
113+ /// <param name="length">The number of characters to encode.</param>
114+ /// <param name="bitArray">The target BitArray to write to.</param>
115+ /// <param name="bitIndex">The starting index in the BitArray where bits will be written.</param>
116+ /// <returns>The next index in the BitArray after the last bit written.</returns>
117+ private static int PlainTextToBinaryNumeric ( string plainText , int offset , int length , BitArray bitArray , int bitIndex )
118+ {
119+ var endIndex = offset + length ;
78120
79121 // Process each group of three digits.
80- for ( int i = 0 ; i < plainText . Length - 2 ; i += 3 )
122+ for ( int i = offset ; i < endIndex - 2 ; i += 3 )
81123 {
82124 // Parse the next three characters as a decimal integer.
83125#if HAS_SPAN
@@ -86,29 +128,22 @@ private static BitArray PlainTextToBinaryNumeric(string plainText)
86128 var dec = int . Parse ( plainText . Substring ( i , 3 ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
87129#endif
88130 // Convert the decimal to binary and store it in the BitArray.
89- index = DecToBin ( dec , 10 , bitArray , index ) ;
131+ bitIndex = DecToBin ( dec , 10 , bitArray , bitIndex ) ;
132+ offset += 3 ;
133+ length -= 3 ;
90134 }
91135
92136 // Handle any remaining digits if the total number is not a multiple of three.
93- if ( plainText . Length % 3 == 2 ) // Two remaining digits are encoded in 7 bits.
137+ if ( length > 0 ) // Two remaining digits are encoded in 7 bits; one remaining digit is encoded in 4 bits.
94138 {
95139#if HAS_SPAN
96- var dec = int . Parse ( plainText . AsSpan ( plainText . Length / 3 * 3 , 2 ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
140+ var dec = int . Parse ( plainText . AsSpan ( offset , length ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
97141#else
98- var dec = int . Parse ( plainText . Substring ( plainText . Length / 3 * 3 , 2 ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
142+ var dec = int . Parse ( plainText . Substring ( offset , length ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
99143#endif
100- index = DecToBin ( dec , 7 , bitArray , index ) ;
101- }
102- else if ( plainText . Length % 3 == 1 ) // One remaining digit is encoded in 4 bits.
103- {
104- #if HAS_SPAN
105- var dec = int . Parse ( plainText . AsSpan ( plainText . Length / 3 * 3 , 1 ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
106- #else
107- var dec = int . Parse ( plainText . Substring ( plainText . Length / 3 * 3 , 1 ) , NumberStyles . None , CultureInfo . InvariantCulture ) ;
108- #endif
109- index = DecToBin ( dec , 4 , bitArray , index ) ;
144+ bitIndex = DecToBin ( dec , length == 2 ? 7 : 4 , bitArray , bitIndex ) ;
110145 }
111146
112- return bitArray ;
147+ return bitIndex ;
113148 }
114149}
0 commit comments