1use unicode_segmentation::UnicodeSegmentation;
18
19use crate::{
20 EncodeHints, Exceptions,
21 common::{
22 BitArray, BitFieldBaseType, CharacterSet, Eci, Result,
23 reedsolomon::{PredefinedGenericGF, ReedSolomonEncoder, get_predefined_genericgf},
24 },
25 qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
26};
27
28use super::{BlockPair, ByteMatrix, MinimalEncoder, QRCode, mask_util, matrix_util};
29
30static SHIFT_JIS_CHARSET: CharacterSet = CharacterSet::Shift_JIS;
31
32const ALPHANUMERIC_TABLE: [i8; 96] = [
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, ];
41
42pub const DEFAULT_BYTE_MODE_ENCODING: CharacterSet = CharacterSet::ISO8859_1;
43
44pub fn calculateMaskPenalty(matrix: &ByteMatrix) -> u32 {
47 mask_util::applyMaskPenaltyRule1(matrix)
48 + mask_util::applyMaskPenaltyRule2(matrix)
49 + mask_util::applyMaskPenaltyRule3(matrix)
50 + mask_util::applyMaskPenaltyRule4(matrix)
51}
52
53pub fn encode(content: &str, ecLevel: ErrorCorrectionLevel) -> Result<QRCode> {
61 encode_with_hints(content, ecLevel, &EncodeHints::default())
62}
63
64pub fn encode_with_hints(
65 content: &str,
66 ec_level: ErrorCorrectionLevel,
67 hints: &EncodeHints,
68) -> Result<QRCode> {
69 let version;
70 let mut header_and_data_bits;
71 let mode;
72
73 let has_gs1_format_hint = matches!(hints.Gs1Format, Some(true));
74
75 let has_compaction_hint = if let Some(vb) = &hints.QrCompact {
76 vb.parse::<bool>().unwrap_or_default()
77 } else {
78 false
79 };
80
81 let mut encoding = None; let mut has_encoding_hint = hints.CharacterSet.is_some();
84 if has_encoding_hint {
85 if let Some(v) = &hints.CharacterSet {
86 encoding = Some(CharacterSet::get_character_set_by_name(v).ok_or(Exceptions::WRITER)?)
87 }
88 }
89
90 if has_compaction_hint {
91 mode = Mode::BYTE;
92
93 let priority_encoding = encoding; let rn = MinimalEncoder::encode_with_details(
96 content,
97 None,
98 priority_encoding,
99 has_gs1_format_hint,
100 ec_level,
101 )?;
102
103 header_and_data_bits = BitArray::new();
104 rn.getBits(&mut header_and_data_bits)?;
105 version = rn.getVersion();
106 } else {
107 let encoding = if let Some(encoding) = encoding {
109 encoding
110 } else if let Ok(_encs) = DEFAULT_BYTE_MODE_ENCODING.encode(content) {
111 DEFAULT_BYTE_MODE_ENCODING
112 } else {
113 has_encoding_hint = true;
114 CharacterSet::UTF8
115 };
116
117 mode = chooseModeWithEncoding(content, encoding);
120
121 let mut header_bits = BitArray::new();
124
125 if mode == Mode::BYTE && has_encoding_hint {
127 appendECI(encoding.into(), &mut header_bits)?;
128 }
129
130 if has_gs1_format_hint {
132 appendModeInfo(Mode::FNC1_FIRST_POSITION, &mut header_bits)?;
134 }
135
136 appendModeInfo(mode, &mut header_bits)?;
138
139 let mut data_bits = BitArray::new();
142 appendBytes(content, mode, &mut data_bits, encoding)?;
143
144 if hints.QrVersion.is_some() {
145 let versionNumber = if let Some(v) = &hints.QrVersion {
146 v.parse::<u32>().unwrap_or_default()
147 } else {
148 0
149 };
150
151 version = Version::getVersionForNumber(versionNumber)?;
152 let bitsNeeded = calculateBitsNeeded(mode, &header_bits, &data_bits, version);
153 if !willFit(bitsNeeded, version, &ec_level) {
154 return Err(Exceptions::writer_with(
155 "Data too big for requested version",
156 ));
157 }
158 } else {
159 version = recommendVersion(&ec_level, mode, &header_bits, &data_bits)?;
160 }
161
162 header_and_data_bits = BitArray::new();
163 header_and_data_bits.appendBitArray(header_bits);
164 let num_letters = if mode == Mode::BYTE {
166 data_bits.getSizeInBytes()
167 } else {
168 content.graphemes(true).count()
169 };
170 appendLengthInfo(num_letters as u32, version, mode, &mut header_and_data_bits)?;
171 header_and_data_bits.appendBitArray(data_bits);
173 }
174
175 let ec_blocks = version.getECBlocksForLevel(ec_level);
176 let num_data_bytes = version.getTotalCodewords() - ec_blocks.getTotalECCodewords();
177
178 terminateBits(num_data_bytes, &mut header_and_data_bits)?;
180
181 let final_bits = interleaveWithECBytes(
183 &header_and_data_bits,
184 version.getTotalCodewords(),
185 num_data_bytes,
186 ec_blocks.getNumBlocks(),
187 )?;
188
189 let mut qrCode = QRCode::new();
190
191 qrCode.setECLevel(ec_level);
192 qrCode.setMode(mode);
193 qrCode.setVersion(version);
194
195 let dimension = version.getDimensionForVersion();
197 let mut matrix = ByteMatrix::new(dimension, dimension);
198
199 let mut mask_pattern = -1;
201 if let Some(v) = &hints.QrMaskPattern {
202 let hint_mask_pattern = v.parse::<i32>().unwrap_or(-1);
203
204 mask_pattern = if QRCode::isValidMaskPattern(hint_mask_pattern) {
205 hint_mask_pattern
206 } else {
207 -1
208 };
209 }
210
211 if mask_pattern == -1 {
212 mask_pattern = chooseMaskPattern(&final_bits, &ec_level, version, &mut matrix)? as i32;
213 }
214 qrCode.setMaskPattern(mask_pattern);
215
216 matrix_util::buildMatrix(&final_bits, &ec_level, version, mask_pattern, &mut matrix)?;
218 qrCode.setMatrix(matrix);
219
220 Ok(qrCode)
221}
222
223fn recommendVersion(
229 ec_level: &ErrorCorrectionLevel,
230 mode: Mode,
231 header_bits: &BitArray,
232 data_bits: &BitArray,
233) -> Result<VersionRef> {
234 let provisional_bits_needed = calculateBitsNeeded(
238 mode,
239 header_bits,
240 data_bits,
241 Version::getVersionForNumber(1)?,
242 );
243 let provisional_version = chooseVersion(provisional_bits_needed, ec_level)?;
244
245 let bits_needed = calculateBitsNeeded(mode, header_bits, data_bits, provisional_version);
247
248 chooseVersion(bits_needed, ec_level)
249}
250
251fn calculateBitsNeeded(
252 mode: Mode,
253 header_bits: &BitArray,
254 data_bits: &BitArray,
255 version: VersionRef,
256) -> u32 {
257 (header_bits.get_size() + mode.getCharacterCountBits(version) as usize + data_bits.get_size())
258 as u32
259}
260
261pub fn getAlphanumericCode(code: u32) -> i8 {
266 let code = code as usize;
267 if code < ALPHANUMERIC_TABLE.len() {
268 ALPHANUMERIC_TABLE[code]
269 } else {
270 -1
271 }
272}
273
274pub fn chooseMode(content: &str) -> Mode {
275 chooseModeWithEncoding(content, CharacterSet::ISO8859_1)
276}
277
278fn chooseModeWithEncoding(content: &str, encoding: CharacterSet) -> Mode {
283 if SHIFT_JIS_CHARSET == encoding && isOnlyDoubleByteKanji(content) {
284 return Mode::KANJI;
286 }
287 let mut has_numeric = false;
288 let mut has_alphanumeric = false;
289 for c in content.chars() {
290 if c.is_ascii_digit() {
291 has_numeric = true;
292 } else if getAlphanumericCode(c as u32) != -1 {
293 has_alphanumeric = true;
294 } else {
295 return Mode::BYTE;
296 }
297 }
298 if has_alphanumeric {
299 return Mode::ALPHANUMERIC;
300 }
301 if has_numeric {
302 return Mode::NUMERIC;
303 }
304 Mode::BYTE
305}
306
307pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
308 let bytes = if let Ok(byt) = SHIFT_JIS_CHARSET.encode(content) {
309 byt
310 } else {
311 return false;
312 };
313
314 let length = bytes.len();
315 if length % 2 != 0 {
316 return false;
317 }
318 let mut i = 0;
319 while i < length {
320 let byte1 = bytes[i];
321 if !(0x81..=0x9F).contains(&byte1) && !(0xE0..=0xEB).contains(&byte1) {
322 return false;
323 }
324 i += 2;
325 }
326 true
327}
328
329fn chooseMaskPattern(
330 bits: &BitArray,
331 ec_level: &ErrorCorrectionLevel,
332 version: VersionRef,
333 matrix: &mut ByteMatrix,
334) -> Result<u32> {
335 let mut min_penalty = u32::MAX; let mut best_mask_pattern = -1;
337 for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
339 let mut matrix = matrix.clone();
340 matrix_util::buildMatrix(bits, ec_level, version, maskPattern, &mut matrix)?;
341 let penalty = calculateMaskPenalty(&matrix);
342 if penalty < min_penalty {
343 min_penalty = penalty;
344 best_mask_pattern = maskPattern;
345 }
346 }
347 Ok(best_mask_pattern as u32)
348}
349
350fn chooseVersion(numInputBits: u32, ecLevel: &ErrorCorrectionLevel) -> Result<VersionRef> {
351 for versionNum in 1..=40 {
352 let version = Version::getVersionForNumber(versionNum)?;
353 if willFit(numInputBits, version, ecLevel) {
354 return Ok(version);
355 }
356 }
357 Err(Exceptions::writer_with(format!(
358 "data too big {numInputBits}/{ecLevel:?}"
359 )))
360}
361
362pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrectionLevel) -> bool {
367 let num_bytes = version.getTotalCodewords();
370 let ec_blocks = version.getECBlocksForLevel(*ecLevel);
372 let num_ec_bytes = ec_blocks.getTotalECCodewords();
373 let num_data_bytes = num_bytes - num_ec_bytes;
375 let total_input_bytes = numInputBits.div_ceil(8);
376 num_data_bytes >= total_input_bytes
377}
378
379pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<()> {
383 let capacity = num_data_bytes * 8;
384 if bits.get_size() > capacity as usize {
385 return Err(Exceptions::writer_with(format!(
386 "data bits cannot fit in the QR Code{capacity} > "
387 )));
388 }
389 for _i in 0..4 {
391 if bits.get_size() >= capacity as usize {
392 break;
393 }
394 bits.appendBit(false);
395 }
396 let num_bits_in_last_byte = bits.get_size() & 0x07;
399 if num_bits_in_last_byte > 0 {
400 for _i in num_bits_in_last_byte..8 {
401 bits.appendBit(false);
402 }
403 }
404 let num_padding_bytes = num_data_bytes as isize - bits.getSizeInBytes() as isize;
406 for i in 0..num_padding_bytes {
407 if i >= num_padding_bytes {
408 break;
409 }
410 bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
411 }
412 if bits.get_size() != capacity as usize {
413 return Err(Exceptions::writer_with("Bits size does not equal capacity"));
414 }
415 Ok(())
416}
417
418pub fn getNumDataBytesAndNumECBytesForBlockID(
424 num_total_bytes: u32,
425 num_data_bytes: u32,
426 num_rsblocks: u32,
427 block_id: u32,
428 ) -> Result<(u32, u32)> {
431 if block_id >= num_rsblocks {
432 return Err(Exceptions::writer_with("Block ID too large"));
433 }
434 let num_rs_blocks_in_group2 = num_total_bytes % num_rsblocks;
436 let num_rs_blocks_in_group1 = num_rsblocks - num_rs_blocks_in_group2;
438 let num_total_bytes_in_group1 = num_total_bytes / num_rsblocks;
440 let num_total_bytes_in_group2 = num_total_bytes_in_group1 + 1;
442 let num_data_bytes_in_group1 = num_data_bytes / num_rsblocks;
444 let num_data_bytes_in_group2 = num_data_bytes_in_group1 + 1;
446 let num_ec_bytes_in_group1 = num_total_bytes_in_group1 - num_data_bytes_in_group1;
448 let numEcBytesInGroup2 = num_total_bytes_in_group2 - num_data_bytes_in_group2;
450 if num_ec_bytes_in_group1 != numEcBytesInGroup2 {
453 return Err(Exceptions::writer_with("EC bytes mismatch"));
454 }
455 if num_rsblocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
457 return Err(Exceptions::writer_with("RS blocks mismatch"));
458 }
459 if num_total_bytes
461 != ((num_data_bytes_in_group1 + num_ec_bytes_in_group1) * num_rs_blocks_in_group1)
462 + ((num_data_bytes_in_group2 + numEcBytesInGroup2) * num_rs_blocks_in_group2)
463 {
464 return Err(Exceptions::writer_with("total bytes mismatch"));
465 }
466
467 Ok(if block_id < num_rs_blocks_in_group1 {
468 (num_data_bytes_in_group1, num_ec_bytes_in_group1)
469 } else {
470 (num_data_bytes_in_group2, numEcBytesInGroup2)
471 })
472}
473
474pub fn interleaveWithECBytes(
479 bits: &BitArray,
480 num_total_bytes: u32,
481 num_data_bytes: u32,
482 num_rsblocks: u32,
483) -> Result<BitArray> {
484 if bits.getSizeInBytes() as u32 != num_data_bytes {
486 return Err(Exceptions::writer_with(
487 "Number of bits and data bytes does not match",
488 ));
489 }
490
491 let mut data_bytes_offset = 0;
494 let mut max_num_data_bytes = 0;
495 let mut max_num_ec_bytes = 0;
496
497 let mut blocks = Vec::new();
499
500 for i in 0..num_rsblocks {
501 let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
502 num_total_bytes,
503 num_data_bytes,
504 num_rsblocks,
505 i,
506 )?;
509
510 let size = numDataBytesInBlock;
511 let mut dataBytes = vec![0u8; size as usize];
512 bits.toBytes(8 * data_bytes_offset, &mut dataBytes, 0, size as usize);
513 let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize)?;
514 blocks.push(BlockPair::new(dataBytes, ec_bytes.clone()));
515
516 max_num_data_bytes = max_num_data_bytes.max(size);
517 max_num_ec_bytes = max_num_ec_bytes.max(ec_bytes.len());
518 data_bytes_offset += numDataBytesInBlock as usize;
519 }
520 if num_data_bytes != data_bytes_offset as u32 {
521 return Err(Exceptions::writer_with("Data bytes does not match offset"));
522 }
523
524 let mut result = BitArray::new();
525
526 for i in 0..max_num_data_bytes as usize {
528 for block in &blocks {
529 let data_bytes = block.getDataBytes();
530 if i < data_bytes.len() {
531 result.appendBits(data_bytes[i] as BitFieldBaseType, 8)?;
532 }
533 }
534 }
535 for i in 0..max_num_ec_bytes {
537 for block in &blocks {
538 let ec_bytes = block.getErrorCorrectionBytes();
539 if i < ec_bytes.len() {
540 result.appendBits(ec_bytes[i] as BitFieldBaseType, 8)?;
541 }
542 }
543 }
544 if num_total_bytes != result.getSizeInBytes() as u32 {
545 return Err(Exceptions::writer_with(format!(
547 "Interleaving error: {} and {} differ.",
548 num_total_bytes,
549 result.getSizeInBytes()
550 )));
551 }
552
553 Ok(result)
554}
555
556pub fn generateECBytes(dataBytes: &[u8], num_ec_bytes_in_block: usize) -> Result<Vec<u8>> {
557 let num_data_bytes = dataBytes.len();
558 let mut to_encode = vec![0; num_data_bytes + num_ec_bytes_in_block];
559 for i in 0..num_data_bytes {
560 to_encode[i] = dataBytes[i] as i32;
561 }
562
563 ReedSolomonEncoder::new(get_predefined_genericgf(
564 PredefinedGenericGF::QrCodeField256,
565 ))?
566 .encode(&mut to_encode, num_ec_bytes_in_block)?;
567
568 let mut ecBytes = vec![0u8; num_ec_bytes_in_block];
569 for i in 0..num_ec_bytes_in_block {
570 ecBytes[i] = to_encode[num_data_bytes + i] as u8;
571 }
572 Ok(ecBytes)
573}
574
575pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<()> {
579 bits.appendBits(mode.getBits() as BitFieldBaseType, 4)
580}
581
582pub fn appendLengthInfo(
586 num_letters: u32,
587 version: VersionRef,
588 mode: Mode,
589 bits: &mut BitArray,
590) -> Result<()> {
591 let numBits = mode.getCharacterCountBits(version);
592 if num_letters >= (1 << numBits) {
593 return Err(Exceptions::writer_with(format!(
594 "{} is bigger than {}",
595 num_letters,
596 ((1 << numBits) - 1)
597 )));
598 }
599 bits.appendBits(num_letters as BitFieldBaseType, numBits as usize)
600}
601
602pub fn appendBytes(
606 content: &str,
607 mode: Mode,
608 bits: &mut BitArray,
609 encoding: CharacterSet,
610) -> Result<()> {
611 match mode {
612 Mode::NUMERIC => appendNumericBytes(content, bits),
613 Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits),
614 Mode::BYTE => append8BitBytes(content, bits, encoding),
615 Mode::KANJI => appendKanjiBytes(content, bits),
616 _ => Err(Exceptions::writer_with(format!("Invalid mode: {mode:?}"))),
617 }
618}
619
620pub fn appendNumericBytes(content: &str, bits: &mut BitArray) -> Result<()> {
621 let length = content.len();
622 let mut i = 0;
623 let content_byte_cache: Vec<u8> = content.chars().map(|c| c as u8).collect();
624 while i < length {
625 let num1 = content_byte_cache[i] - b'0';
626 if i + 2 < length {
627 let num2 = content_byte_cache[i + 1] - b'0';
629 let num3 = content_byte_cache[i + 2] - b'0';
630 bits.appendBits(
631 num1 as BitFieldBaseType * 100
632 + num2 as BitFieldBaseType * 10
633 + num3 as BitFieldBaseType,
634 10,
635 )?;
636 i += 3;
637 } else if i + 1 < length {
638 let num2 = content_byte_cache[i + 1] - b'0';
640 bits.appendBits(num1 as BitFieldBaseType * 10 + num2 as BitFieldBaseType, 7)?;
641 i += 2;
642 } else {
643 bits.appendBits(num1 as BitFieldBaseType, 4)?;
645 i += 1;
646 }
647 }
648 Ok(())
649}
650
651pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<()> {
652 let length = content.len();
653 let content_byte_cache: Vec<u32> = content.chars().map(|c| c as u32).collect();
654 let mut i = 0;
655 while i < length {
656 let code1 = getAlphanumericCode(content_byte_cache[i]);
657 if code1 == -1 {
658 return Err(Exceptions::WRITER);
659 }
660 if i + 1 < length {
661 let code2 = getAlphanumericCode(content_byte_cache[i + 1]);
662 if code2 == -1 {
663 return Err(Exceptions::WRITER);
664 }
665 bits.appendBits((code1 as i16 * 45 + code2 as i16) as BitFieldBaseType, 11)?;
667 i += 2;
668 } else {
669 bits.appendBits(code1 as BitFieldBaseType, 6)?;
671 i += 1;
672 }
673 }
674 Ok(())
675}
676
677pub fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: CharacterSet) -> Result<()> {
678 let bytes = encoding
679 .encode(content)
680 .map_err(|e| Exceptions::writer_with(format!("error {e}")))?;
681 for b in bytes {
682 bits.appendBits(b as BitFieldBaseType, 8)?;
683 }
684 Ok(())
685}
686
687pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<()> {
688 let sjis = &SHIFT_JIS_CHARSET;
689
690 let bytes = sjis
691 .encode(content)
692 .map_err(|e| Exceptions::writer_with(format!("error {e}")))?;
693 if bytes.len() % 2 != 0 {
694 return Err(Exceptions::writer_with("Kanji byte size not even"));
695 }
696 let max_i = bytes.len() - 1; let mut i = 0;
698 while i < max_i {
699 let byte1 = bytes[i]; let byte2 = bytes[i + 1]; let code: u16 = ((byte1 as u16) << 8u16) | byte2 as u16;
702 let mut subtracted: i32 = -1;
703 if (0x8140..=0x9ffc).contains(&code) {
704 subtracted = code as i32 - 0x8140;
705 } else if (0xe040..=0xebbf).contains(&code) {
706 subtracted = code as i32 - 0xc140;
707 }
708 if subtracted == -1 {
709 return Err(Exceptions::writer_with("Invalid byte sequence"));
710 }
711 let encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
712 bits.appendBits(encoded as BitFieldBaseType, 13)?;
713
714 i += 2;
715 }
716 Ok(())
717}
718
719fn appendECI(eci: Eci, bits: &mut BitArray) -> Result<()> {
720 bits.appendBits(Mode::ECI.getBits() as BitFieldBaseType, 4)?;
721 bits.appendBits(eci as BitFieldBaseType, 8)
723}