use qrcode::render::unicode::Dense1x2;
use qrcode::QrCode;
use ratatui_core::buffer::Buffer;
use ratatui_core::layout::{Rect, Size};
use ratatui_core::style::{Style, Styled};
use ratatui_core::text::Text;
use ratatui_core::widgets::Widget;
pub struct QrCodeWidget {
qr_code: QrCode,
quiet_zone: QuietZone,
scaling: Scaling,
colors: Colors,
style: Style,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
pub enum QuietZone {
#[default]
Enabled,
Disabled,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Scaling {
Min,
Max,
Exact(u16, u16),
}
impl Default for Scaling {
fn default() -> Self {
Self::Exact(1, 1)
}
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
pub enum Colors {
#[default]
Normal,
Inverted,
}
impl QrCodeWidget {
#[must_use]
pub fn new(qr_code: QrCode) -> Self {
Self {
qr_code,
quiet_zone: QuietZone::default(),
scaling: Scaling::default(),
colors: Colors::default(),
style: Style::default(),
}
}
#[must_use]
pub const fn quiet_zone(mut self, quiet_zone: QuietZone) -> Self {
self.quiet_zone = quiet_zone;
self
}
#[must_use]
pub const fn scaling(mut self, scaling: Scaling) -> Self {
self.scaling = scaling;
self
}
#[must_use]
pub const fn colors(mut self, colors: Colors) -> Self {
self.colors = colors;
self
}
#[must_use]
pub fn style(mut self, style: impl Into<Style>) -> Self {
self.style = style.into();
self
}
#[must_use]
pub fn size(&self, area: Rect) -> Size {
let qr_width: u16 = match self.quiet_zone {
QuietZone::Enabled => 8,
QuietZone::Disabled => 0,
} + self.qr_code.width() as u16;
let (x, y) = match self.scaling {
Scaling::Exact(x, y) => (x, y),
Scaling::Min => {
let x = area.width.div_ceil(qr_width);
let y = (area.height * 2).div_ceil(qr_width);
(x, y)
}
Scaling::Max => {
let x = area.width / qr_width;
let y = (area.height * 2) / qr_width;
(x, y)
}
};
let (x, y) = (x.max(1), y.max(1));
let width = qr_width * x;
let height = (qr_width * y).div_ceil(2);
Size::new(width, height)
}
}
impl Styled for QrCodeWidget {
type Item = Self;
fn style(&self) -> Style {
self.style
}
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
impl Widget for QrCodeWidget {
fn render(self, area: Rect, buf: &mut Buffer) {
(&self).render(area, buf);
}
}
impl Widget for &QrCodeWidget {
fn render(self, area: Rect, buf: &mut Buffer) {
let mut renderer = self.qr_code.render::<Dense1x2>();
match self.quiet_zone {
QuietZone::Enabled => renderer.quiet_zone(true),
QuietZone::Disabled => renderer.quiet_zone(false),
};
match self.scaling {
Scaling::Min => renderer.min_dimensions(area.width as u32, area.height as u32 * 2),
Scaling::Max => renderer.max_dimensions(area.width as u32, area.height as u32 * 2),
Scaling::Exact(width, height) => {
renderer.module_dimensions(width as u32, height as u32)
}
};
match self.colors {
Colors::Normal => renderer
.dark_color(Dense1x2::Dark)
.light_color(Dense1x2::Light),
Colors::Inverted => renderer
.dark_color(Dense1x2::Light)
.light_color(Dense1x2::Dark),
};
Text::raw(renderer.build())
.style(self.style)
.render(area, buf);
}
}
#[cfg(test)]
mod tests {
use rstest::{fixture, rstest};
use super::*;
#[fixture]
fn empty_widget() -> QrCodeWidget {
let empty_qr = QrCode::new("").expect("failed to create QR code");
QrCodeWidget::new(empty_qr).quiet_zone(QuietZone::Disabled)
}
#[rstest]
#[case::smaller_exact((22,12), Scaling::Exact(1, 1), (21, 11))]
#[case::smaller_max((22, 12), Scaling::Max, (21, 11))]
#[case::smaller_min((22,12),Scaling::Min, (42, 21))]
#[case::same_exact((21, 11), Scaling::Exact(1, 1), (21, 11))]
#[case::same_max((21, 11), Scaling::Max, (21, 11))]
#[case::same_min((21, 11), Scaling::Min, (21, 21))]
#[rstest]
#[case::larger_exact((20, 10), Scaling::Exact(1, 1), (21, 11))]
#[case::larger_max((20, 10), Scaling::Max, (21, 11))]
#[case::larger_min((20, 10), Scaling::Min, (21, 11))]
#[rstest]
#[case::huge_exact((71, 71), Scaling::Exact(1, 1), (21, 11))]
#[case::huge_max((71, 71), Scaling::Max,(63, 63))]
#[case::huge_min((71, 71), Scaling::Min, (84, 74))]
fn size(
empty_widget: QrCodeWidget,
#[case] rect: (u16, u16),
#[case] scaling: Scaling,
#[case] expected: (u16, u16),
) {
let rect = Rect::new(0, 0, rect.0, rect.1);
let widget = empty_widget.scaling(scaling);
assert_eq!(widget.size(rect), Size::from(expected));
}
#[rstest]
#[case::huge_exact(Scaling::Exact(1, 1), (29, 15))]
#[case::huge_max(Scaling::Max, (58, 58))]
#[case::huge_min(Scaling::Min, (87, 73))]
fn size_with_quiet_zone(
empty_widget: QrCodeWidget,
#[case] scaling: Scaling,
#[case] expected: (u16, u16),
) {
let rect = Rect::new(0, 0, 71, 71);
let widget = empty_widget.quiet_zone(QuietZone::Enabled).scaling(scaling);
assert_eq!(widget.size(rect), Size::from(expected));
}
#[rstest]
fn render_exact_into_fitting_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 11));
empty_widget.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█",
"█ ███ █ █▀▀ ▀ █ ███ █",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
])
);
}
#[rstest]
fn render_max_into_fitting_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 11));
empty_widget
.scaling(Scaling::Max)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█",
"█ ███ █ █▀▀ ▀ █ ███ █",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
])
);
}
#[rstest]
fn render_min_into_fitting_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 11));
empty_widget
.scaling(Scaling::Min)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"███████ ██ █ ███████",
"█ █ ██ █ █",
"█ ███ █ ███ █ █ ███ █",
"█ ███ █ █ █ ███ █",
"█ ███ █ ██ █ █ ███ █",
"█ █ ████ █ █",
"███████ █ █ █ ███████",
" ██ ",
"█ █████ ███ █████ ",
" █ █ █ █████ █ █ ",
" ████ █ ██ ",
])
);
}
#[rstest]
fn render_exact_into_larger_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 22, 12));
empty_widget.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█ ",
"█ ███ █ █▀▀ ▀ █ ███ █ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀ ",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█ ",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀ ",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
" ",
])
);
}
#[rstest]
fn render_max_into_larger_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 22, 12));
empty_widget
.scaling(Scaling::Max)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█ ",
"█ ███ █ █▀▀ ▀ █ ███ █ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀ ",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█ ",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀ ",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
" ",
])
);
}
#[rstest]
fn render_min_into_larger_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 22, 12));
empty_widget
.scaling(Scaling::Min)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"██████████████ ████",
"██ ██ ",
"██ ██████ ██ ██████",
"██ ██████ ██ ██ ",
"██ ██████ ██ ████ ",
"██ ██ ██████",
"██████████████ ██ ██",
" ████ ",
"██ ██████████ ████",
" ██ ██ ██ ██",
" ████████ ",
"██████ ████ ██",
])
);
}
#[rstest]
fn render_exact_into_smaler_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 10));
empty_widget.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀",
"█ ███ █ █▀▀ ▀ █ ███ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀",
"█ ███ █ █▀██▄█▄ ▀█▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
])
);
}
#[rstest]
fn render_max_into_smaller_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 10));
empty_widget
.scaling(Scaling::Max)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀",
"█ ███ █ █▀▀ ▀ █ ███ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀",
"█ ███ █ █▀██▄█▄ ▀█▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
])
);
}
#[rstest]
fn render_min_into_smaller_area(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 10));
empty_widget
.scaling(Scaling::Min)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀",
"█ ███ █ █▀▀ ▀ █ ███ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀",
"█ ███ █ █▀██▄█▄ ▀█▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
])
);
}
#[rstest]
fn render_exact_double_height(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 21));
empty_widget.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█",
"█ ███ █ █▀▀ ▀ █ ███ █",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
])
);
}
#[rstest]
fn render_max_double_height(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 21));
empty_widget
.scaling(Scaling::Max)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"███████ ██ █ ███████",
"█ █ ██ █ █",
"█ ███ █ ███ █ █ ███ █",
"█ ███ █ █ █ ███ █",
"█ ███ █ ██ █ █ ███ █",
"█ █ ████ █ █",
"███████ █ █ █ ███████",
" ██ ",
"█ █████ ███ █████ ",
" █ █ █ █████ █ █ ",
" ████ █ ██ ",
"███ ██ █████ █ █ ",
"█ █ ███ █ █ █ █ █ ",
" ███ █ █ █ ",
"███████ ███ █ █████",
"█ █ ███ ██ █ █",
"█ ███ █ ████ █ █████",
"█ ███ █ █ █████ █ ",
"█ ███ █ █ █ ██ ",
"█ █ ████ █ ",
"███████ █ █ █ █ ",
])
);
}
#[rstest]
fn render_min_double_height(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 21));
empty_widget
.scaling(Scaling::Min)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"███████ ██ █ ███████",
"█ █ ██ █ █",
"█ ███ █ ███ █ █ ███ █",
"█ ███ █ █ █ ███ █",
"█ ███ █ ██ █ █ ███ █",
"█ █ ████ █ █",
"███████ █ █ █ ███████",
" ██ ",
"█ █████ ███ █████ ",
" █ █ █ █████ █ █ ",
" ████ █ ██ ",
"███ ██ █████ █ █ ",
"█ █ ███ █ █ █ █ █ ",
" ███ █ █ █ ",
"███████ ███ █ █████",
"█ █ ███ ██ █ █",
"█ ███ █ ████ █ █████",
"█ ███ █ █ █████ █ ",
"█ ███ █ █ █ ██ ",
"█ █ ████ █ ",
"███████ █ █ █ █ ",
])
);
}
#[rstest]
fn render_exact_double_width(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 42, 11));
empty_widget.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█ ",
"█ ███ █ █▀▀ ▀ █ ███ █ ",
"█ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █ ",
"▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀ ",
"▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
"▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
"▀ ▀ ▀▀▀ █▄█ █ █ █ ",
"█▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█ ",
"█ ███ █ █▀██▄█▄ ▀█▀▀▀ ",
"█ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
"▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
])
);
}
#[rstest]
fn render_max_double_width(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 42, 11));
empty_widget
.scaling(Scaling::Max)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"██▀▀▀▀▀▀▀▀▀▀██ ▀▀▀▀▄▄██ ██▀▀▀▀▀▀▀▀▀▀██",
"██ ██████ ██ ██▀▀▀▀ ▀▀ ██ ██████ ██",
"██ ▀▀▀▀▀▀ ██ ████▄▄▄▄▀▀ ██ ▀▀▀▀▀▀ ██",
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ██▄▄▀▀ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀",
"▀▀ ▀▀██▀▀██▀▀▄▄ ▀▀████▄▄▄▄██▀▀▀▀██▀▀▄▄ ",
"▄▄▄▄▄▄ ▀▀████▀▀▄▄▄▄██▄▄██▀▀ ▄▄ ▄▄ ",
"▀▀ ▀▀ ▀▀▀▀▀▀ ██▄▄██ ██ ██ ██ ",
"██▀▀▀▀▀▀▀▀▀▀██ ▄▄████▀▀ ▀▀ ▄▄██▀▀██▀▀██",
"██ ██████ ██ ██▀▀████▄▄██▄▄ ▀▀██▀▀▀▀▀▀",
"██ ▀▀▀▀▀▀ ██ ▀▀ ▄▄██▄▄██▀▀ ▄▄ ",
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ",
])
);
}
#[rstest]
fn render_min_double_width(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 42, 11));
empty_widget
.scaling(Scaling::Min)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"██████████████ ████ ██ ██████████████",
"██ ██ ████ ██ ██",
"██ ██████ ██ ██████ ██ ██ ██████ ██",
"██ ██████ ██ ██ ██ ██████ ██",
"██ ██████ ██ ████ ██ ██ ██████ ██",
"██ ██ ████████ ██ ██",
"██████████████ ██ ██ ██ ██████████████",
" ████ ",
"██ ██████████ ██████ ██████████ ",
" ██ ██ ██ ██████████ ██ ██ ",
" ████████ ██ ████ ",
])
);
}
#[rstest]
fn render_inverted(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 21, 11));
empty_widget
.colors(Colors::Inverted)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
" ▄▄▄▄▄ ██▄▄▀ █ ▄▄▄▄▄ ",
" █ █ █ ▄▄█▄█ █ █ ",
" █▄▄▄█ █ ▀▀▄█ █▄▄▄█ ",
"▄▄▄▄▄▄▄█ ▀▄█▄█▄▄▄▄▄▄▄",
"▄█▄ ▄ ▄▀█▄ ▀▀ ▄▄ ▄▀█",
"▀▀▀███▄ ▄▀▀ ▀ ▄█▀█▀█",
"▄█▄█▄▄▄█ ▀ █ ██ ██ ██",
" ▄▄▄▄▄ █▀ ▄█▄█▀ ▄ ▄ ",
" █ █ █ ▄ ▀ ▀█▄ ▄▄▄",
" █▄▄▄█ █▄██▀ ▀ ▄█▀███",
" ▀ ▀▀▀ ▀▀ ▀▀ ▀▀",
])
);
}
#[rstest]
fn render_with_quiet_zone(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 29, 15));
empty_widget
.quiet_zone(QuietZone::Enabled)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
" ",
" ",
" █▀▀▀▀▀█ ▀▀▄█ █▀▀▀▀▀█ ",
" █ ███ █ █▀▀ ▀ █ ███ █ ",
" █ ▀▀▀ █ ██▄▄▀ █ ▀▀▀ █ ",
" ▀▀▀▀▀▀▀ █▄▀ ▀ ▀▀▀▀▀▀▀ ",
" ▀ ▀█▀█▀▄ ▀██▄▄█▀▀█▀▄ ",
" ▄▄▄ ▀██▀▄▄█▄█▀ ▄ ▄ ",
" ▀ ▀ ▀▀▀ █▄█ █ █ █ ",
" █▀▀▀▀▀█ ▄██▀ ▀ ▄█▀█▀█ ",
" █ ███ █ █▀██▄█▄ ▀█▀▀▀ ",
" █ ▀▀▀ █ ▀ ▄█▄█▀ ▄ ",
" ▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ",
" ",
" ",
])
);
}
#[rstest]
fn render_with_quiet_zone_and_inverted(empty_widget: QrCodeWidget) {
let mut buf = Buffer::empty(Rect::new(0, 0, 29, 15));
empty_widget
.quiet_zone(QuietZone::Enabled)
.colors(Colors::Inverted)
.render(buf.area, &mut buf);
assert_eq!(
buf,
Buffer::with_lines([
"█████████████████████████████",
"█████████████████████████████",
"████ ▄▄▄▄▄ ██▄▄▀ █ ▄▄▄▄▄ ████",
"████ █ █ █ ▄▄█▄█ █ █ ████",
"████ █▄▄▄█ █ ▀▀▄█ █▄▄▄█ ████",
"████▄▄▄▄▄▄▄█ ▀▄█▄█▄▄▄▄▄▄▄████",
"████▄█▄ ▄ ▄▀█▄ ▀▀ ▄▄ ▄▀█████",
"████▀▀▀███▄ ▄▀▀ ▀ ▄█▀█▀█████",
"████▄█▄█▄▄▄█ ▀ █ ██ ██ ██████",
"████ ▄▄▄▄▄ █▀ ▄█▄█▀ ▄ ▄ ████",
"████ █ █ █ ▄ ▀ ▀█▄ ▄▄▄████",
"████ █▄▄▄█ █▄██▀ ▀ ▄█▀███████",
"████▄▄▄▄▄▄▄█▄███▄██▄██▄██████",
"█████████████████████████████",
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀",
])
);
}
}