mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 00:34:40 +01:00
qrcode_paintable: Use an upscaled texture
This is more efficient and draws without gaps in betweek black squares.
This commit is contained in:
parent
7fd6186886
commit
fab729c6be
1 changed files with 38 additions and 40 deletions
|
@ -1,35 +1,22 @@
|
||||||
use gtk::{gdk, glib, graphene, prelude::*, subclass::prelude::*};
|
use gtk::{gdk, glib, graphene, gsk, prelude::*, subclass::prelude::*};
|
||||||
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub struct QRCodeData {
|
pub struct QRCodeData {
|
||||||
pub width: i32,
|
pub size: i32,
|
||||||
pub height: i32,
|
pub items: Vec<bool>,
|
||||||
pub items: Vec<Vec<bool>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> From<B> for QRCodeData {
|
impl<B: AsRef<[u8]>> From<B> for QRCodeData {
|
||||||
fn from(data: B) -> Self {
|
fn from(data: B) -> Self {
|
||||||
let code = qrencode::QrCode::new(data).unwrap();
|
let code = qrencode::QrCode::new(data).unwrap();
|
||||||
let items = code
|
let items = code
|
||||||
.render::<char>()
|
.to_colors()
|
||||||
.quiet_zone(false)
|
.iter()
|
||||||
.module_dimensions(1, 1)
|
.map(|color| matches!(color, qrencode::types::Color::Dark))
|
||||||
.build()
|
.collect::<Vec<bool>>();
|
||||||
.split('\n')
|
|
||||||
.map(|line| {
|
|
||||||
line.chars()
|
|
||||||
.map(|c| !c.is_whitespace())
|
|
||||||
.collect::<Vec<bool>>()
|
|
||||||
})
|
|
||||||
.collect::<Vec<Vec<bool>>>();
|
|
||||||
|
|
||||||
let width = items.first().unwrap().len() as i32;
|
let size = code.width() as i32;
|
||||||
let height = items.len() as i32;
|
Self { size, items }
|
||||||
Self {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
items,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,30 +42,23 @@ mod imp {
|
||||||
impl PaintableImpl for QRCodePaintable {
|
impl PaintableImpl for QRCodePaintable {
|
||||||
fn snapshot(&self, snapshot: &gdk::Snapshot, width: f64, height: f64) {
|
fn snapshot(&self, snapshot: &gdk::Snapshot, width: f64, height: f64) {
|
||||||
if let Some(ref qrcode) = *self.qrcode.borrow() {
|
if let Some(ref qrcode) = *self.qrcode.borrow() {
|
||||||
let padding_squares = 3.max(qrcode.height / 10);
|
let padding_squares = 3.max(qrcode.size / 10);
|
||||||
let square_height = height as f32 / (qrcode.height + 2 * padding_squares) as f32;
|
let square_height = height as f32 / (qrcode.size + 2 * padding_squares) as f32;
|
||||||
let square_width = width as f32 / (qrcode.width + 2 * padding_squares) as f32;
|
let square_width = width as f32 / (qrcode.size + 2 * padding_squares) as f32;
|
||||||
let padding = square_height * padding_squares as f32;
|
let padding = square_height * padding_squares as f32;
|
||||||
|
|
||||||
let rect = graphene::Rect::new(0.0, 0.0, width as f32, height as f32);
|
let rect = graphene::Rect::new(0.0, 0.0, width as f32, height as f32);
|
||||||
snapshot.append_color(&gdk::RGBA::WHITE, &rect);
|
snapshot.append_color(&gdk::RGBA::WHITE, &rect);
|
||||||
qrcode.items.iter().enumerate().for_each(|(y, line)| {
|
|
||||||
line.iter().enumerate().for_each(|(x, is_dark)| {
|
|
||||||
if *is_dark {
|
|
||||||
let mut black = gdk::RGBA::BLACK;
|
|
||||||
black.set_alpha(0.85);
|
|
||||||
|
|
||||||
let position = graphene::Rect::new(
|
let inner_rect = graphene::Rect::new(
|
||||||
(x as f32) * square_width + padding,
|
padding,
|
||||||
(y as f32) * square_height + padding,
|
padding,
|
||||||
square_width,
|
square_width * qrcode.size as f32,
|
||||||
square_height,
|
square_height * qrcode.size as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
snapshot.append_color(&black, &position);
|
let texture = texture(qrcode);
|
||||||
};
|
snapshot.append_scaled_texture(&texture, gsk::ScalingFilter::Nearest, &inner_rect);
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,3 +81,21 @@ impl Default for QRCodePaintable {
|
||||||
glib::Object::new()
|
glib::Object::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn texture(qrcode: &QRCodeData) -> gdk::Texture {
|
||||||
|
let size = qrcode.size;
|
||||||
|
|
||||||
|
const G8_SIZE: usize = 1;
|
||||||
|
const WHITE: u8 = 0xff; // #ffffff
|
||||||
|
const BLACK: u8 = 0x24; // #242424
|
||||||
|
|
||||||
|
let bytes: Vec<u8> = qrcode
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.map(|is_black| if *is_black { BLACK } else { WHITE })
|
||||||
|
.collect();
|
||||||
|
let bytes = glib::Bytes::from_owned(bytes);
|
||||||
|
let stride = G8_SIZE * size as usize;
|
||||||
|
|
||||||
|
gdk::MemoryTexture::new(size, size, gdk::MemoryFormat::G8, &bytes, stride).upcast()
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue