Skip to content

Commit

Permalink
Add method to extract raw payload
Browse files Browse the repository at this point in the history
Some users might want to operate on the raw bit stream in the QR code, before
we removed the mask and performed error correction.

Co-authored-by: Moritz "WanzenBug" Wanzenböck <moritz@wanzenbug.xyz>
  • Loading branch information
erion-leka and WanzenBug committed Oct 7, 2024
1 parent 59a0ba6 commit be6202c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 22 deletions.
46 changes: 29 additions & 17 deletions src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{BitGrid, DeQRError, DeQRResult};
g2p!(GF16, 4, modulus: 0b1_0011);
g2p!(GF256, 8, modulus: 0b1_0001_1101);

const MAX_PAYLOAD_SIZE: usize = 8896;
pub const MAX_PAYLOAD_SIZE: usize = 8896;

/// Version of a QR Code which determines its size
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
Expand Down Expand Up @@ -47,20 +47,17 @@ pub struct MetaData {
pub mask: u16,
}

/// The bit stream contained in the QR Code
#[derive(Clone)]
pub struct RawData {
data: [u8; MAX_PAYLOAD_SIZE],
len: usize,
/// The bits of the QR Code
pub data: [u8; MAX_PAYLOAD_SIZE],
/// Length of the bit stream in bits.
pub len: usize,
}

impl RawData {
pub fn new() -> Self {
RawData {
data: [0; MAX_PAYLOAD_SIZE],
len: 0,
}
}

/// Push a new bit into the bit stream
pub fn push(&mut self, bit: bool) {
assert!((self.len >> 8) < MAX_PAYLOAD_SIZE);
let bitpos = (self.len & 7) as u8;
Expand Down Expand Up @@ -99,6 +96,7 @@ impl CorrectedDataStream {
}
self.ptr += 1;
}

ret
}
}
Expand All @@ -113,13 +111,20 @@ where
W: Write,
{
let meta = read_format(code)?;
let raw = read_data(code, &meta);
let raw = read_data(code, &meta, true);
let stream = codestream_ecc(&meta, raw)?;
decode_payload(&meta, stream, writer)?;

Ok(meta)
}

/// Return extracted metadata and the raw, uncorrected bit stream
pub fn get_raw(code: &dyn BitGrid) -> DeQRResult<(MetaData, RawData)> {
let meta = read_format(code)?;
let raw = read_data(code, &meta, false);
Ok((meta, raw))
}

fn decode_payload<W>(meta: &MetaData, mut ds: CorrectedDataStream, mut writer: W) -> DeQRResult<()>
where
W: Write,
Expand Down Expand Up @@ -514,8 +519,12 @@ where
}
}

fn read_data(code: &dyn BitGrid, meta: &MetaData) -> RawData {
let mut ds = RawData::new();
/// Reads the code in the "zigzag" pattern, optionally removing the mask
fn read_data(code: &dyn BitGrid, meta: &MetaData, remove_mask: bool) -> RawData {
let mut ds = RawData {
data: [0; MAX_PAYLOAD_SIZE],
len: 0,
};

let mut y = code.size() - 1;
let mut x = code.size() - 1;
Expand All @@ -526,10 +535,10 @@ fn read_data(code: &dyn BitGrid, meta: &MetaData) -> RawData {
x -= 1;
}
if !reserved_cell(meta.version, y, x) {
ds.push(read_bit(code, meta, y, x));
ds.push(read_bit(code, meta, y, x, remove_mask));
}
if !reserved_cell(meta.version, y, x - 1) {
ds.push(read_bit(code, meta, y, x - 1));
ds.push(read_bit(code, meta, y, x - 1, remove_mask));
}

let (new_y, new_neg_dir) = match (y, neg_dir) {
Expand All @@ -552,11 +561,14 @@ fn read_data(code: &dyn BitGrid, meta: &MetaData) -> RawData {
ds
}

fn read_bit(code: &dyn BitGrid, meta: &MetaData, y: usize, x: usize) -> bool {
// The read_bit() function can optionally consider the mask.
// This allows bits to be read as they appear "physically" in the QR code or with the mask removed, reflecting the actual code.
fn read_bit(code: &dyn BitGrid, meta: &MetaData, y: usize, x: usize, remove_mask: bool) -> bool {
let mut v = code.bit(y, x) as u8;
if mask_bit(meta.mask, y, x) {
if remove_mask && mask_bit(meta.mask, y, x) {
v ^= 1
}

v != 0
}

Expand Down
5 changes: 1 addition & 4 deletions src/identify/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ impl SkewedGridLocation {

let c = setup_perspective(img, &group, align, grid_size)?;

Some(SkewedGridLocation {
grid_size,
c,
})
Some(SkewedGridLocation { grid_size, c })
}

/// Convert into a grid referencing the underlying image as source
Expand Down
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ If you have some other form of picture storage, you can use
you to define your own source for images.
"##
)]
pub use self::decode::{MetaData, Version};
pub use self::decode::{MetaData, RawData, Version, MAX_PAYLOAD_SIZE};
pub(crate) use self::detect::{capstones_from_image, CapStone};
pub use self::identify::Point;
pub(crate) use self::identify::SkewedGridLocation;
Expand Down Expand Up @@ -94,6 +94,14 @@ where
Ok((meta, out))
}

/// Try to read metadata, and return the raw, uncorrected bit stream.
///
/// If successful, returns the metadata along with the raw bit pattern.
/// The raw data is still masked, so bits appear as in the source image.
pub fn get_raw_data(&self) -> DeQRResult<(MetaData, RawData)> {
crate::decode::get_raw(&self.grid)
}

/// Try to decode the grid.
///
/// Instead of returning a String, this methode writes the decoded result to
Expand Down

0 comments on commit be6202c

Please sign in to comment.