keyfork-zbar: initial commit
This commit is contained in:
parent
9d7cbc17fa
commit
946b89349f
|
@ -1531,6 +1531,7 @@ dependencies = [
|
||||||
"keyfork-entropy",
|
"keyfork-entropy",
|
||||||
"keyfork-mnemonic-util",
|
"keyfork-mnemonic-util",
|
||||||
"keyfork-prompt",
|
"keyfork-prompt",
|
||||||
|
"keyfork-qrcode",
|
||||||
"keyfork-shard",
|
"keyfork-shard",
|
||||||
"keyforkd",
|
"keyforkd",
|
||||||
"keyforkd-client",
|
"keyforkd-client",
|
||||||
|
@ -1661,6 +1662,7 @@ name = "keyfork-qrcode"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"image",
|
"image",
|
||||||
|
"keyfork-zbar",
|
||||||
"rqrr",
|
"rqrr",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"v4l",
|
"v4l",
|
||||||
|
@ -1696,6 +1698,24 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyfork-zbar"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"image",
|
||||||
|
"keyfork-zbar-sys",
|
||||||
|
"thiserror",
|
||||||
|
"v4l",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyfork-zbar-sys"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen 0.68.1",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keyforkd"
|
name = "keyforkd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -16,6 +16,8 @@ members = [
|
||||||
"keyfork-shard",
|
"keyfork-shard",
|
||||||
"keyfork-slip10-test-data",
|
"keyfork-slip10-test-data",
|
||||||
"keyfork-qrcode",
|
"keyfork-qrcode",
|
||||||
|
"keyfork-zbar",
|
||||||
|
"keyfork-zbar-sys",
|
||||||
"keyforkd",
|
"keyforkd",
|
||||||
"keyforkd-client",
|
"keyforkd-client",
|
||||||
"keyforkd-models",
|
"keyforkd-models",
|
||||||
|
|
|
@ -7,8 +7,14 @@ license = "MIT"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
decode-backend-rqrr = ["dep:rqrr"]
|
||||||
|
decode-backend-zbar = ["dep:keyfork-zbar"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
image = { version = "0.24.7", default-features = false, features = ["jpeg"] }
|
image = { version = "0.24.7", default-features = false, features = ["jpeg"] }
|
||||||
rqrr = "0.6.0"
|
keyfork-zbar = { version = "0.1.0", path = "../keyfork-zbar", optional = true }
|
||||||
|
rqrr = { version = "0.6.0", optional = true }
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
v4l = "0.14.0"
|
v4l = "0.14.0"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
use rqrr::PreparedImage;
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{Cursor, Write},
|
io::{Cursor, Write},
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
|
@ -8,13 +7,9 @@ use std::{
|
||||||
use v4l::{
|
use v4l::{
|
||||||
buffer::Type,
|
buffer::Type,
|
||||||
io::{userptr::Stream, traits::CaptureStream},
|
io::{userptr::Stream, traits::CaptureStream},
|
||||||
video::Capture,
|
Device,
|
||||||
Device, FourCC,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static MJPEG: &[u8; 4] = b"MJPG";
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum QRGenerationError {
|
pub enum QRGenerationError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
@ -37,9 +32,6 @@ pub enum QRCodeScanError {
|
||||||
|
|
||||||
#[error("Could not decode image: {0}")]
|
#[error("Could not decode image: {0}")]
|
||||||
ImageDecode(#[from] image::ImageError),
|
ImageDecode(#[from] image::ImageError),
|
||||||
|
|
||||||
#[error("Could not format FourCC as string (this is a bug!): {0}")]
|
|
||||||
FourCC(#[from] std::string::FromUtf8Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -81,24 +73,10 @@ pub fn qrencode(
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decode-backend-rqrr")]
|
||||||
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||||
let device = Device::new(index)?;
|
let device = Device::new(index)?;
|
||||||
|
|
||||||
let mut format = device.format()?;
|
|
||||||
format.width = 1280;
|
|
||||||
format.height = 720;
|
|
||||||
format.fourcc = FourCC::new(MJPEG);
|
|
||||||
let format = device.set_format(&format)?;
|
|
||||||
|
|
||||||
if MJPEG != &format.fourcc.repr {
|
|
||||||
return Err(QRCodeScanError::CameraGaveBadFormat {
|
|
||||||
expected: String::from_utf8(MJPEG.to_vec())?,
|
|
||||||
actual: String::from_utf8(format.fourcc.repr.to_vec())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
||||||
|
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
|
|
||||||
while SystemTime::now()
|
while SystemTime::now()
|
||||||
|
@ -111,7 +89,7 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
|
||||||
.with_guessed_format()?
|
.with_guessed_format()?
|
||||||
.decode()?
|
.decode()?
|
||||||
.to_luma8();
|
.to_luma8();
|
||||||
let mut image = PreparedImage::prepare(image);
|
let mut image = rqrr::PreparedImage::prepare(image);
|
||||||
for grid in image.detect_grids() {
|
for grid in image.detect_grids() {
|
||||||
if let Ok((_, content)) = grid.decode() {
|
if let Ok((_, content)) = grid.decode() {
|
||||||
return Ok(Some(content))
|
return Ok(Some(content))
|
||||||
|
@ -121,3 +99,28 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decode-backend-zbar")]
|
||||||
|
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||||
|
let device = Device::new(index)?;
|
||||||
|
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
||||||
|
let start = SystemTime::now();
|
||||||
|
let mut scanner = keyfork_zbar::image_scanner::ImageScanner::new();
|
||||||
|
|
||||||
|
while SystemTime::now()
|
||||||
|
.duration_since(start)
|
||||||
|
.unwrap_or(Duration::from_secs(0))
|
||||||
|
< timeout
|
||||||
|
{
|
||||||
|
let (buffer, _) = stream.next()?;
|
||||||
|
let image = ImageReader::new(Cursor::new(buffer))
|
||||||
|
.with_guessed_format()?
|
||||||
|
.decode()?;
|
||||||
|
let image = keyfork_zbar::image::Image::from(image);
|
||||||
|
for symbol in scanner.scan_image(&image) {
|
||||||
|
return Ok(Some(String::from_utf8_lossy(symbol.data()).to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "keyfork-zbar-sys"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bindgen = { version = "0.68", default-features = false }
|
||||||
|
pkg-config = "0.3"
|
|
@ -0,0 +1,50 @@
|
||||||
|
use std::{env::VarError, path::Path};
|
||||||
|
|
||||||
|
use pkg_config::Config;
|
||||||
|
|
||||||
|
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
fn env_var(var: &str) -> Result<String, VarError> {
|
||||||
|
println!("cargo:rerun-if-env-changed={var}");
|
||||||
|
std::env::var(var)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bindings_file() -> Result<()> {
|
||||||
|
let zbar = Config::new().atleast_version("0.23.0").probe("zbar")?;
|
||||||
|
|
||||||
|
if env_var("ZBAR_STATIC").is_ok() {
|
||||||
|
println!("cargo:rustc-link-lib=static=zbar");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut builder = bindgen::builder()
|
||||||
|
.rustified_enum("zbar_color_e")
|
||||||
|
.rustified_non_exhaustive_enum("zbar_symbol_type_e")
|
||||||
|
.rustified_enum("zbar_orientation_e")
|
||||||
|
.rustified_non_exhaustive_enum("zbar_error_e")
|
||||||
|
.rustified_non_exhaustive_enum("zbar_config_e")
|
||||||
|
.rustified_enum("zbar_modifier_e")
|
||||||
|
.rustified_enum("video_control_type_e");
|
||||||
|
|
||||||
|
for path in zbar.include_paths {
|
||||||
|
builder = builder.clang_arg(format!("-I{}", path.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let builder = builder.header("zbar-wrapper.h");
|
||||||
|
let bindings = builder.generate()?;
|
||||||
|
|
||||||
|
let out_path = Path::new(&env_var("OUT_DIR")?).join("bindings.rs");
|
||||||
|
|
||||||
|
bindings.write_to_file(out_path)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
if let Err(e) = generate_bindings_file() {
|
||||||
|
eprintln!("Building zbar-sys failed: {e}");
|
||||||
|
eprintln!("Ensure zbar headers, libclang, and pkg-config are installed");
|
||||||
|
return Err(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
|
@ -0,0 +1 @@
|
||||||
|
#include <zbar.h>
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "keyfork-zbar"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["image"]
|
||||||
|
image = ["dep:image"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
image = { version = "0.24.7", default-features = false, optional = true }
|
||||||
|
keyfork-zbar-sys = { version = "0.1.0", path = "../keyfork-zbar-sys" }
|
||||||
|
thiserror = "1.0.56"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
v4l = "0.14.0"
|
|
@ -0,0 +1,43 @@
|
||||||
|
use std::{
|
||||||
|
io::Cursor,
|
||||||
|
time::{Duration, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
|
use keyfork_zbar::{image::Image, image_scanner::ImageScanner};
|
||||||
|
|
||||||
|
use image::io::Reader as ImageReader;
|
||||||
|
use v4l::{
|
||||||
|
buffer::Type,
|
||||||
|
io::{traits::CaptureStream, userptr::Stream},
|
||||||
|
Device,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let device = Device::new(0)?;
|
||||||
|
|
||||||
|
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
||||||
|
let start = SystemTime::now();
|
||||||
|
let mut scanner = ImageScanner::new();
|
||||||
|
|
||||||
|
while SystemTime::now()
|
||||||
|
.duration_since(start)
|
||||||
|
.unwrap_or(Duration::from_secs(0))
|
||||||
|
< Duration::from_secs(30)
|
||||||
|
{
|
||||||
|
let (buffer, _) = stream.next()?;
|
||||||
|
let image = Image::from(
|
||||||
|
ImageReader::new(Cursor::new(buffer))
|
||||||
|
.with_guessed_format()?
|
||||||
|
.decode()?,
|
||||||
|
);
|
||||||
|
|
||||||
|
for symbol in scanner.scan_image(&image) {
|
||||||
|
println!("{}", String::from_utf8_lossy(symbol.data()));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Could not find a QR code");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
use super::sys;
|
||||||
|
|
||||||
|
pub struct Image {
|
||||||
|
pub(crate) inner: *mut sys::zbar_image_s,
|
||||||
|
/// Set to store the data of inner, as it will otherwise be freed when the data is dropped.
|
||||||
|
inner_data: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
/// Link: [`sys::zbar_image_create`]
|
||||||
|
pub(crate) fn alloc() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: unsafe { sys::zbar_image_create() },
|
||||||
|
inner_data: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link: [`sys::zbar_image_set_format`]
|
||||||
|
///
|
||||||
|
/// A FourCC code can be given in the format:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// self.set_format(b"Y800")
|
||||||
|
/// ````
|
||||||
|
pub(crate) fn set_format(&mut self, fourcc: &[u8; 4]) {
|
||||||
|
let fourcc: u64 = fourcc[0] as u64
|
||||||
|
| ((fourcc[1] as u64) << 8)
|
||||||
|
| ((fourcc[2] as u64) << 16)
|
||||||
|
| ((fourcc[3] as u64) << 24);
|
||||||
|
unsafe { sys::zbar_image_set_format(self.inner, fourcc) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link: [`sys::zbar_image_set_size`]
|
||||||
|
fn set_size(&mut self, width: u32, height: u32) {
|
||||||
|
unsafe { sys::zbar_image_set_size(self.inner, width, height) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link: [`sys::zbar_image_set_data`]
|
||||||
|
///
|
||||||
|
/// Accepts raw data in the configured format. See: [`Image::set_format`]
|
||||||
|
fn set_data(&mut self, data: Vec<u8>) {
|
||||||
|
unsafe {
|
||||||
|
sys::zbar_image_set_data(
|
||||||
|
self.inner,
|
||||||
|
data.as_ptr().cast(),
|
||||||
|
data.len() as u64,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// keep data in self to avoid use after free when data goes out of scope
|
||||||
|
let _ = self.inner_data.insert(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
mod impls {
|
||||||
|
use super::*;
|
||||||
|
use image::{DynamicImage, GenericImageView};
|
||||||
|
|
||||||
|
impl From<DynamicImage> for Image {
|
||||||
|
fn from(value: DynamicImage) -> Self {
|
||||||
|
let mut image = Self::alloc();
|
||||||
|
let (width, height) = value.dimensions();
|
||||||
|
image.set_size(width, height);
|
||||||
|
image.set_format(b"Y800");
|
||||||
|
image.set_data(value.to_luma8().into_raw());
|
||||||
|
image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Image {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { sys::zbar_image_destroy(self.inner) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
use super::{
|
||||||
|
image::Image,
|
||||||
|
symbol::{Symbol, SymbolType},
|
||||||
|
sys, Config,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum ImageScannerError {
|
||||||
|
#[error("Unable to set Image Scanner configuration")]
|
||||||
|
UnableToSetConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImageScanner {
|
||||||
|
inner: *mut sys::zbar_image_scanner_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageScanner {
|
||||||
|
/// Link: [`sys::zbar_image_scanner_create`]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: unsafe { sys::zbar_image_scanner_create() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link: [`sys::zbar_image_scanner_set_config`]
|
||||||
|
pub fn set_config(
|
||||||
|
&mut self,
|
||||||
|
symbol: SymbolType,
|
||||||
|
config: Config,
|
||||||
|
value: i32,
|
||||||
|
) -> Result<(), ImageScannerError> {
|
||||||
|
let result =
|
||||||
|
unsafe { sys::zbar_image_scanner_set_config(self.inner, symbol, config, value) };
|
||||||
|
|
||||||
|
if result != 0 {
|
||||||
|
return Err(ImageScannerError::UnableToSetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link: [`sys::zbar_scan_image`]
|
||||||
|
///
|
||||||
|
/// TODO: move `image` to newtype, offering conversions
|
||||||
|
/// to and from image::Image
|
||||||
|
///
|
||||||
|
/// TODO: return an iterator over scanned values
|
||||||
|
pub fn scan_image(
|
||||||
|
&mut self,
|
||||||
|
image: &Image,
|
||||||
|
) -> Vec<Symbol> {
|
||||||
|
unsafe { sys::zbar_scan_image(self.inner, image.inner) };
|
||||||
|
let mut result = vec![];
|
||||||
|
let mut symbol = unsafe { sys::zbar_image_first_symbol(image.inner) };
|
||||||
|
while !symbol.is_null() {
|
||||||
|
let symbol_type = unsafe { sys::zbar_symbol_get_type(symbol) };
|
||||||
|
let symbol_data = unsafe { sys::zbar_symbol_get_data(symbol) };
|
||||||
|
let symbol_data_len = unsafe { sys::zbar_symbol_get_data_length(symbol) };
|
||||||
|
let symbol_slice = unsafe {
|
||||||
|
std::slice::from_raw_parts(symbol_data as *const u8, symbol_data_len as usize)
|
||||||
|
};
|
||||||
|
result.push(Symbol::new(symbol_type, symbol_slice));
|
||||||
|
symbol = unsafe { sys::zbar_symbol_next(symbol) };
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ImageScanner {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ImageScanner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { sys::zbar_image_scanner_destroy(self.inner) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
//! Rustic bindings to the zbar library. Not intended to be high-level.
|
||||||
|
//!
|
||||||
|
//! This library includes a conversion from [`::image::DynamicImage`] for [`image::Image`].
|
||||||
|
//!
|
||||||
|
//! Reference: <https://github.com/mchehab/zbar>
|
||||||
|
|
||||||
|
pub use keyfork_zbar_sys as sys;
|
||||||
|
|
||||||
|
pub use sys::zbar_color_e as Color;
|
||||||
|
pub use sys::zbar_config_e as Config;
|
||||||
|
pub use sys::zbar_modifier_e as Modifier;
|
||||||
|
pub use sys::zbar_orientation_e as Orientation;
|
||||||
|
|
||||||
|
pub mod image_scanner;
|
||||||
|
pub mod image;
|
||||||
|
pub mod symbol;
|
|
@ -0,0 +1,31 @@
|
||||||
|
use super::sys;
|
||||||
|
|
||||||
|
pub use sys::zbar_symbol_type_e as SymbolType;
|
||||||
|
|
||||||
|
// TODO: config, modifiers
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Symbol {
|
||||||
|
_type: SymbolType,
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
pub(crate) fn new(_type: SymbolType, data: &[u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
_type,
|
||||||
|
data: data.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _type(&self) -> SymbolType {
|
||||||
|
self._type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> &[u8] {
|
||||||
|
self.data.as_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_data(self) -> Vec<u8> {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,10 @@ edition = "2021"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["completion"]
|
default = ["completion", "qrcode-decode-backend-rqrr"]
|
||||||
completion = ["dep:clap_complete"]
|
completion = ["dep:clap_complete"]
|
||||||
|
qrcode-decode-backend-rqrr = ["keyfork-qrcode/decode-backend-rqrr"]
|
||||||
|
qrcode-decode-backend-zbar = ["keyfork-qrcode/decode-backend-zbar"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -28,3 +30,4 @@ openpgp-card = "0.4.1"
|
||||||
keyfork-prompt = { version = "0.1.0", path = "../keyfork-prompt" }
|
keyfork-prompt = { version = "0.1.0", path = "../keyfork-prompt" }
|
||||||
keyfork-entropy = { version = "0.1.0", path = "../keyfork-entropy" }
|
keyfork-entropy = { version = "0.1.0", path = "../keyfork-entropy" }
|
||||||
clap_complete = { version = "4.4.6", optional = true }
|
clap_complete = { version = "4.4.6", optional = true }
|
||||||
|
keyfork-qrcode = { version = "0.1.0", path = "../keyfork-qrcode" }
|
||||||
|
|
Loading…
Reference in New Issue