|
15 | 15 | * limitations under the License.
|
16 | 16 | */
|
17 | 17 |
|
| 18 | +use core::mem::MaybeUninit; |
| 19 | + |
| 20 | +use qrcodegen_no_heap::{QrCode, QrCodeEcc, Version}; |
| 21 | + |
18 | 22 | use crate::{
|
19 | 23 | error::ErrorCode,
|
20 | 24 | tlv::{TLVWriter, TagType},
|
@@ -319,47 +323,162 @@ fn estimate_struct_overhead(first_field_size: usize) -> usize {
|
319 | 323 | first_field_size + 4 + 2
|
320 | 324 | }
|
321 | 325 |
|
322 |
| -pub(super) fn print_qr_code(qr_code: &str) { |
323 |
| - info!("QR Code: {}", qr_code); |
| 326 | +pub(crate) fn print_qr_code(qr_code_text: &str) -> Result<(), Error> { |
| 327 | + info!("QR Code Text: {}", qr_code_text); |
| 328 | + |
| 329 | + let mut tmp_buf = MaybeUninit::<[u8; Version::MAX.buffer_len()]>::uninit(); |
| 330 | + let mut out_buf = MaybeUninit::<[u8; 7000]>::uninit(); |
| 331 | + |
| 332 | + let tmp_buf = unsafe { tmp_buf.assume_init_mut() }; |
| 333 | + let out_buf = unsafe { out_buf.assume_init_mut() }; |
324 | 334 |
|
325 |
| - #[cfg(feature = "std")] |
326 |
| - { |
327 |
| - use qrcode::{render::unicode, QrCode, Version}; |
| 335 | + let qr_code = compute_qr_code(qr_code_text, out_buf, tmp_buf)?; |
328 | 336 |
|
329 |
| - let needed_version = compute_qr_version(qr_code); |
330 |
| - let code = |
331 |
| - QrCode::with_version(qr_code, Version::Normal(needed_version), qrcode::EcLevel::M) |
332 |
| - .unwrap(); |
333 |
| - let image = code |
334 |
| - .render::<unicode::Dense1x2>() |
335 |
| - .dark_color(unicode::Dense1x2::Light) |
336 |
| - .light_color(unicode::Dense1x2::Dark) |
337 |
| - .build(); |
| 337 | + info!( |
| 338 | + "\n{}", |
| 339 | + TextImage::Unicode.render(&qr_code, 4, false, out_buf)? |
| 340 | + ); |
338 | 341 |
|
339 |
| - info!("\n{}", image); |
| 342 | + Ok(()) |
| 343 | +} |
| 344 | + |
| 345 | +#[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 346 | +pub enum TextImage { |
| 347 | + Ascii, |
| 348 | + Ansi, |
| 349 | + Unicode, |
| 350 | +} |
| 351 | + |
| 352 | +impl TextImage { |
| 353 | + pub fn render<'a>( |
| 354 | + &self, |
| 355 | + qr_code: &QrCode, |
| 356 | + border: u8, |
| 357 | + invert: bool, |
| 358 | + out_buf: &'a mut [u8], |
| 359 | + ) -> Result<&'a str, Error> { |
| 360 | + let mut offset = 0; |
| 361 | + |
| 362 | + for c in self.render_iter(qr_code, border, invert) { |
| 363 | + let mut dst = [0; 4]; |
| 364 | + let bytes = c.encode_utf8(&mut dst).as_bytes(); |
| 365 | + |
| 366 | + if offset + bytes.len() > out_buf.len() { |
| 367 | + return Err(ErrorCode::BufferTooSmall)?; |
| 368 | + } else { |
| 369 | + out_buf[offset..offset + bytes.len()].copy_from_slice(bytes); |
| 370 | + offset += bytes.len(); |
| 371 | + } |
| 372 | + } |
| 373 | + |
| 374 | + Ok(unsafe { core::str::from_utf8_unchecked(&out_buf[..offset]) }) |
| 375 | + } |
| 376 | + |
| 377 | + pub fn render_iter<'a>( |
| 378 | + &self, |
| 379 | + qr_code: &'a QrCode<'a>, |
| 380 | + border: u8, |
| 381 | + invert: bool, |
| 382 | + ) -> impl Iterator<Item = char> + 'a { |
| 383 | + let border: i32 = border as _; |
| 384 | + let console_type = *self; |
| 385 | + |
| 386 | + (-border..qr_code.size() + border) |
| 387 | + .filter(move |y| console_type != Self::Unicode || (y - -border) % 2 == 0) |
| 388 | + .flat_map(move |y| (-border..qr_code.size() + border + 1).map(move |x| (x, y))) |
| 389 | + .map(move |(x, y)| { |
| 390 | + if x < qr_code.size() + border { |
| 391 | + let white = !qr_code.get_module(x, y) ^ invert; |
| 392 | + |
| 393 | + match console_type { |
| 394 | + Self::Ascii => { |
| 395 | + if white { |
| 396 | + "#" |
| 397 | + } else { |
| 398 | + " " |
| 399 | + } |
| 400 | + } |
| 401 | + Self::Ansi => { |
| 402 | + let prev_white = if x > -border { |
| 403 | + Some(qr_code.get_module(x - 1, y)) |
| 404 | + } else { |
| 405 | + None |
| 406 | + } |
| 407 | + .map(|prev_white| !prev_white ^ invert); |
| 408 | + |
| 409 | + if prev_white != Some(white) { |
| 410 | + if white { |
| 411 | + "\x1b[47m " |
| 412 | + } else { |
| 413 | + "\x1b[40m " |
| 414 | + } |
| 415 | + } else { |
| 416 | + " " |
| 417 | + } |
| 418 | + } |
| 419 | + Self::Unicode => { |
| 420 | + if white == !qr_code.get_module(x, y + 1) ^ invert { |
| 421 | + if white { |
| 422 | + "\u{2588}" |
| 423 | + } else { |
| 424 | + " " |
| 425 | + } |
| 426 | + } else if white { |
| 427 | + "\u{2580}" |
| 428 | + } else { |
| 429 | + "\u{2584}" |
| 430 | + } |
| 431 | + } |
| 432 | + } |
| 433 | + } else { |
| 434 | + "\x1b[0m\n" |
| 435 | + } |
| 436 | + }) |
| 437 | + .flat_map(str::chars) |
340 | 438 | }
|
341 | 439 | }
|
342 | 440 |
|
343 | 441 | pub fn compute_qr_code<'a>(
|
344 |
| - dev_det: &BasicInfoConfig, |
345 |
| - comm_data: &CommissioningData, |
346 |
| - discovery_capabilities: DiscoveryCapabilities, |
347 |
| - buf: &'a mut [u8], |
348 |
| -) -> Result<&'a str, Error> { |
349 |
| - let qr_code_data = QrSetupPayload::new(dev_det, comm_data, discovery_capabilities); |
350 |
| - payload_base38_representation(&qr_code_data, buf) |
| 442 | + qr_code_text: &str, |
| 443 | + tmp_buf: &mut [u8], |
| 444 | + out_buf: &'a mut [u8], |
| 445 | +) -> Result<QrCode<'a>, Error> { |
| 446 | + let needed_version = compute_qr_code_version(qr_code_text); |
| 447 | + |
| 448 | + let code = QrCode::encode_text( |
| 449 | + qr_code_text, |
| 450 | + tmp_buf, |
| 451 | + out_buf, |
| 452 | + QrCodeEcc::Medium, |
| 453 | + Version::new(needed_version), |
| 454 | + Version::new(needed_version), |
| 455 | + None, |
| 456 | + false, |
| 457 | + ) |
| 458 | + .map_err(|_| ErrorCode::BufferTooSmall)?; |
| 459 | + |
| 460 | + Ok(code) |
351 | 461 | }
|
352 | 462 |
|
353 |
| -#[cfg(feature = "std")] |
354 |
| -fn compute_qr_version(qr_data: &str) -> i16 { |
355 |
| - match qr_data.len() { |
| 463 | +pub fn compute_qr_code_version(qr_code_text: &str) -> u8 { |
| 464 | + match qr_code_text.len() { |
356 | 465 | 0..=38 => 2,
|
357 | 466 | 39..=61 => 3,
|
358 | 467 | 62..=90 => 4,
|
359 | 468 | _ => 5,
|
360 | 469 | }
|
361 | 470 | }
|
362 | 471 |
|
| 472 | +pub fn compute_qr_code_text<'a>( |
| 473 | + dev_det: &BasicInfoConfig, |
| 474 | + comm_data: &CommissioningData, |
| 475 | + discovery_capabilities: DiscoveryCapabilities, |
| 476 | + buf: &'a mut [u8], |
| 477 | +) -> Result<&'a str, Error> { |
| 478 | + let qr_code_data = QrSetupPayload::new(dev_det, comm_data, discovery_capabilities); |
| 479 | + payload_base38_representation(&qr_code_data, buf) |
| 480 | +} |
| 481 | + |
363 | 482 | fn populate_bits(
|
364 | 483 | bits: &mut [u8],
|
365 | 484 | offset: &mut usize,
|
|
0 commit comments