Skip to content

Commit e4c49a6

Browse files
committed
feat: anti-crop for images with limitations
1 parent 19b3ffb commit e4c49a6

4 files changed

Lines changed: 285 additions & 372 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "infinishield"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55
description = "Invisible robust watermarking system for multimedia files"
66

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,10 @@ make sanity # Full check: fmt + lint + build + all tests (debug & rel
138138

139139
## Current Limitations
140140

141-
- **Feature-point message limit** — cropping-resistant mode supports max 7-byte messages. Longer messages fall back to global DWT (no cropping resistance).
142-
- **Single channel** — watermark is embedded in the green channel; keypoints detected from the red channel (ensures stability across embed/extract).
143-
- **No rotation resistance** — cropping is handled; rotation and scaling are not (planned for future via patch rotation normalization).
141+
- **Short messages only for cropping resistance** — messages up to 7 bytes (e.g., "Infini") survive cropping. Longer messages (e.g., "Copyright: InfiniLabs") still work but lose cropping protection.
142+
- **No rotation or scaling resistance** — the watermark survives cropping and compression, but not if the image is rotated or resized.
143+
- **Raster images only** — JPEG, PNG, WebP, BMP, TIFF, GIF. SVG and video support is planned.
144+
- **Lossy output degrades watermark** — saving as JPEG or WebP compresses the watermark. PNG or BMP output is recommended. A warning is printed for lossy formats.
144145

145146
## Project Structure
146147

src/common/temp_input_for_inference.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,28 @@ pub struct TempInputForInference {
3939
patch_buf: Vec<f64>,
4040
/// Maximum patch side length this context was allocated for.
4141
max_patch_size: usize,
42-
/// Pre-allocated PN chip sequence buffer (COEFFS_PER_BLOCK elements).
42+
/// Pre-allocated PN chip sequence buffer.
4343
pn_buf: Vec<f64>,
44+
/// Number of coefficients per block (block_size²).
45+
coeffs_per_block: usize,
4446
/// Seed for PN sequence generation (derived from password).
4547
seed: [u8; 32],
4648
}
4749

4850
impl TempInputForInference {
49-
/// Create a new inference buffer pre-allocated for patches up to
50-
/// `max_patch_size × max_patch_size` pixels.
51+
/// Create a new inference buffer with the default BLOCK_SIZE (16×16).
5152
pub fn new(max_patch_size: usize) -> Self {
53+
Self::with_block_size(max_patch_size, BLOCK_SIZE)
54+
}
55+
56+
/// Create a new inference buffer with a custom block size.
57+
pub fn with_block_size(max_patch_size: usize, block_size: usize) -> Self {
58+
let coeffs = block_size * block_size;
5259
Self {
5360
patch_buf: vec![0.0; max_patch_size * max_patch_size],
5461
max_patch_size,
55-
pn_buf: vec![0.0; COEFFS_PER_BLOCK],
62+
pn_buf: vec![0.0; coeffs],
63+
coeffs_per_block: coeffs,
5664
seed: [0u8; 32],
5765
}
5866
}
@@ -81,10 +89,10 @@ impl TempInputForInference {
8189
block_seed.copy_from_slice(&block_seed_hash);
8290

8391
let mut rng = ChaCha20Rng::from_seed(block_seed);
84-
for v in self.pn_buf.iter_mut() {
92+
for v in self.pn_buf.iter_mut().take(self.coeffs_per_block) {
8593
*v = if rng.gen_bool(0.5) { 1.0 } else { -1.0 };
8694
}
87-
&self.pn_buf
95+
&self.pn_buf[..self.coeffs_per_block]
8896
}
8997

9098
/// Load a rectangular region from a 2D coefficient array into the patch buffer.
@@ -142,7 +150,7 @@ impl TempInputForInference {
142150

143151
/// Get the PN buffer (read-only, from last `generate_pn_chip` call).
144152
pub fn pn_buffer(&self) -> &[f64] {
145-
&self.pn_buf
153+
&self.pn_buf[..self.coeffs_per_block]
146154
}
147155

148156
/// Embed a single bit into BLOCK_SIZE×BLOCK_SIZE coefficients in the patch buffer
@@ -152,7 +160,7 @@ impl TempInputForInference {
152160
/// The PN chip must have been generated prior to calling this.
153161
pub fn embed_spread_spectrum(&mut self, offset: usize, bit: bool, alpha: f64) {
154162
let signal = if bit { 1.0 } else { -1.0 };
155-
for i in 0..COEFFS_PER_BLOCK {
163+
for i in 0..self.coeffs_per_block {
156164
self.patch_buf[offset + i] += alpha * self.pn_buf[i] * signal;
157165
}
158166
}
@@ -163,11 +171,11 @@ impl TempInputForInference {
163171
/// Returns `(bit, confidence)` where confidence is normalized correlation strength.
164172
pub fn extract_spread_spectrum(&self, offset: usize) -> (bool, f64) {
165173
let mut correlation = 0.0;
166-
for i in 0..COEFFS_PER_BLOCK {
174+
for i in 0..self.coeffs_per_block {
167175
correlation += self.patch_buf[offset + i] * self.pn_buf[i];
168176
}
169177
let bit = correlation >= 0.0;
170-
let confidence = (correlation.abs() / COEFFS_PER_BLOCK as f64).min(1.0);
178+
let confidence = (correlation.abs() / self.coeffs_per_block as f64).min(1.0);
171179
(bit, confidence)
172180
}
173181
}

0 commit comments

Comments
 (0)