DocSafe logo
IEEE Access · 2026

DocSafe: Toward Practical Print-Proof Image Steganography via Frequency Decomposition and Covariance Alignment

Farhad Shadmand1   Iurii Medvedev1   Luiz Schirmer2   Nuno Gonçalves1

1Institute of Systems and Robotics, University of Coimbra, Portugal  •  2Colégio Técnico Industrial, Universidade Federal de Santa Maria, Brazil

DocSafe end-to-end pipeline: encoding a message into an image, printing it, and decoding it back from a smartphone photo
Figure 1. The full DocSafe pipeline: an image, a mask, and a message are encoded into a stamp-like residual; the printed result is captured by a phone and decoded back to the original message.

Abstract

Data-hiding techniques such as robust steganography and invisible watermarking matter for aesthetic stamps, copyright protection, privacy-preserving communication, and content provenance. Existing print-proof steganography methods, however, often struggle to embed messages in small image regions or to decode them from very low-resolution printed outputs.

We introduce DocSafe, a framework that embeds binary messages of up to 256 bits into images while producing stamp-like outputs robust to both digital and physical distortions. The method enables region-aware embedding via spatial masks, analyzes how wavelet sub-band frequencies affect robustness, and evaluates covariance-based losses — identifying Stein divergence for the encoder and the Affine-Invariant Riemannian Metric (AIRM) for the decoder as the most effective configuration. A lightweight decoder architecture further improves both imperceptibility and decoding accuracy.

DocSafe achieves 100% bit accuracy from printed images as small as 2×2 cm on face data and 3×3 cm on object data — state-of-the-art results for print-proof steganography, including when messages are confined to specific regions via spatial masks. It also improves visual quality (ColorHisto 0.05, FID 11.11) while maintaining strong decoding accuracy under a range of digital noise conditions.

256 bitsmessage capacity embedded per 256×256×3 image
100%bit accuracy printed at 2×2 cm (face) / 3×3 cm (object)
11.11FID on object data — best among all compared methods
77 MBdecoder size — down from 235 MB in StampOne's U-shaped decoder

Foundations: frequency analysis & covariance loss

DocSafe's design rests on two controlled analyses run before the final architecture was fixed: which wavelet frequency sub-bands actually help, and which covariance-alignment loss actually stabilizes training.

Which frequencies matter, for what

Following StampOne, every input is decomposed with a gradient operator and a Haar wavelet transform into Low-Low (LL), High-Low (HL), Low-High (LH), and High-High (HH) sub-bands, and a learnable depthwise-convolution layer weighs each sub-band's contribution. Reading off those learned weights after training reveals three different priorities: the original image favors HH and LH (45% and 24% of the weight); the message favors the gradient and HL channels (31% and 30%); and the decoder, reconstructing from an encoded image, again favors the gradient and HH (44% and 26%).

Learned depthwise-convolution weights per wavelet sub-band, for the original image, the message, and the decoder input
Figure 2. Learned frequency-channel weights for (A) the original image, (B) the message during embedding, and (C) the encoded image during decoding — each input leans on a different sub-band.

A controlled ablation (six models, each restricted to a different sub-band combination) confirmed that using the full sub-band set (M-ALL) beats every single-band restriction on both perceptual quality and decoding accuracy — the individual sub-bands are complementary, not redundant.

Which covariance loss stabilizes training

To fight the domain shift between synthetic training noise and real printed/captured distortions, DocSafe aligns the covariance matrices of paired batches (e.g. original vs. encoded images) using a Vision-Transformer-style patch embedding. Four covariance metrics were compared — Log-Euclidean Distance, the Affine-Invariant Riemannian Metric (AIRM), Jeffrey Divergence, and Stein Divergence.

Bit accuracy over training steps for five covariance-loss configurations
Figure 3. AIRM is the only covariance formulation that trains stably for the decoder; Log-Euclidean and Stein fail to converge (bit accuracy stuck around 0.54).
Encoded image and residual examples for four different encoder covariance losses
Figure 4. For the encoder, the ranking flips: Stein divergence (M-Stein) gives the best visual fidelity among the four covariance losses tested.
Encoder covariance lossSSIM ↑LPIPS ↓ColorHisto ↓FID ↓
M-AIRM-NoPatches0.790.040.0530.54
M-AIRM0.820.030.0516.77
M-Stein (used in DocSafe)0.860.030.0414.83
M-Jeffrey0.800.060.1225.30

The upshot — and a key finding of this work — is that covariance metrics are task-specific: AIRM is the right choice for aligning the decoder's recovered message, while Stein divergence is the right choice for aligning the encoder's output image.

Method

Built on the two analyses above, DocSafe pairs an encoder inherited from StampOne — extended with a mask-aware Message Embedding Network — with a fully redesigned, BiSeNet-inspired lightweight decoder.

DocSafe full architecture: encoder with U-Net and MEN, decoder with low- and high-frequency branches
Figure 5. Full architecture. Encoder: gradient/wavelet preprocessing, Message Embedding Network (MEN), U-shape network, and CNN, producing a mask-gated residual. Decoder: a dual-branch design — a low-frequency Spatial Path and a high-frequency Context Path (ResNet + attention) — fused before message recovery.

Message Embedding Networks (MEN)

Unlike StampOne, which spreads the message uniformly across the whole image, DocSafe targets semantically relevant regions via a mask. Three MEN variants trade off domain specificity for generalization: MEN-1 (linear projection + Snake activation, depth-map guided) excels on structured domains like faces but doesn't generalize to COCO; MEN-2 (learnable embedding + LeakyReLU) and MEN-3 (learnable embedding + Snake/GELU) trade a little domain-specific quality for much better robustness on heterogeneous, real-world images.

Three Message Embedding Network variants: MEN-1 with a linear layer, MEN-2 and MEN-3 with learnable embeddings
Figure 6. MEN-1 uses a linear layer; MEN-2 and MEN-3 use a learnable embedding layer (as in NLP models) with different activation functions.

Decoder: a lightweight dual-branch design

Rather than a conventional U-shaped decoder, DocSafe uses a Spatial Path (three Conv2D + SiLU layers preserving low-frequency spatial detail) fused with a Context Path (a trimmed ResNet-18/34 backbone with an Attention Refinement Module capturing high-frequency detail), combined via signal-gated attention. The result matches or beats the original StampOne U-shaped decoder's accuracy at roughly a third of the memory footprint (77 MB vs. 235 MB).

Discriminators & losses

The encoder discriminator uses two Adam optimizers — one purely reinforcing real-image recognition, one jointly minimizing the real/encoded discriminator gap — for more stable adversarial training. The decoder uses a spectral discriminator (FFT + high-pass filter on the original vs. recovered message) inspired by StampOne, encouraging accurate high-frequency reconstruction. Overall, the encoder loss combines Stein divergence, a log-chroma color-histogram loss, LPIPS, and MSE; the decoder loss combines the AIRM covariance loss with binary cross-entropy.

Noise augmentation

Training applies progressive Gaussian noise, JPEG artifacts, grayscale conversion, affine transforms, and cropping between encoder and decoder, so the decoder learns to tolerate the kind of distortion a printed-and-photographed image actually accumulates.

Masked vs. unmasked embedding

Encoded images without spatial masking, compared across StegaStamp, CodeFace, RiemStega, StampOne, and DocSafe variants
Figure 7. Without masking, the message is spread across the whole image. DocSafe M-1 gives the highest visual quality but only generalizes to face data; M-2/M-3 trade some quality for reliable decoding on object data.
Encoded images with spatial masking, embedding the message only within the masked object or face region
Figure 8. With a spatial mask applied, the message is confined to the masked region only (e.g. a bottle label or a face) — the rest of the image is left untouched.

Results

DocSafe is compared against CodeFace, StegaStamp, RiemStega, StampOne, and RoSteALS. StampOne's Attention-VNet variant is the primary baseline; all methods embed 256 bits (DocSafe, StampOne) or 100 bits (CodeFace, StegaStamp, RiemStega) per 256×256×3 (or 400×400×3) image.

Encoded image quality — face data (2,000 FFHQ images)

Method(A) no mask(B) with mask
PSNR↑SSIM↑LPIPS↓ColorHisto↓FID↓ PSNR↑SSIM↑LPIPS↓ColorHisto↓FID↓
StegaStamp27.820.690.180.4336.92-----
Code Face32.310.930.300.0820.70-----
RiemStega32.010.900.020.0621.66-----
StampOne28.610.810.300.1033.63-----
DocSafe (M-1)31.010.850.030.0516.7731.170.900.030.0516.77
DocSafe (M-2)27.390.800.060.0535.7528.420.820.060.0535.72
DocSafe (M-3)29.060.860.090.0822.0230.680.880.040.0422.0
RoSteALS32.810.950.040.0913.49-----

Encoded image quality — object data (4,000 COCO images)

Method(A) no mask(B) with mask
PSNR↑SSIM↑LPIPS↓ColorHisto↓FID↓ PSNR↑SSIM↑LPIPS↓ColorHisto↓FID↓
StegaStamp22.360.660.200.2815.07-----
Code Face25.370.900.300.0816.7-----
RiemStega24.610.890.040.078.66-----
StampOne24.360.810.330.1016.23-----
DocSafe (M-1)23.830.800.100.124.1124.210.810.100.084.10
DocSafe (M-2)24.120.790.040.0513.2424.320.810.030.0513.23
DocSafe (M-3)24.370.840.130.087.1724.640.850.120.067.15
RoSteALS25.120.900.040.0920.28-----

RoSteALS scores well on digital perceptual metrics but — as shown below — cannot decode anything once printed.

Print-proof decoding — String Accuracy (%), face data (40 printed FFHQ images)

Method(A) no mask(B) with mask
5×5cm4×4cm3×3cm2×2cm5×5cm4×4cm3×3cm2×2cm
StegaStamp72706548----
Code Face55503815----
RiemStega1001008525----
StampOne1001009562----
DocSafe (M-1)100100100100100100100100
DocSafe (M-2)1001001008310010010064
DocSafe (M-3)10010055451001007545
RoSteALS00000000

DocSafe M-1 is the first method in this comparison to hold 100% string accuracy down to a 2×2 cm printed portrait — with or without masking — comfortably ahead of StampOne (62% at 2×2cm) and RiemStega (25%).

Print-proof decoding — String Accuracy (%), object data (40 printed COCO images)

Method(A) no mask(B) with mask
5×5cm4×4cm3×3cm2×2cm5×5cm4×4cm3×3cm2×2cm
StegaStamp82828272----
RiemStega1001008522----
StampOne1001009562----
DocSafe (M-1)602525022000
DocSafe (M-2)100100100851001008568
DocSafe (M-3)10010087601001007245
RoSteALS00000000

On the harder, heterogeneous COCO object set, the face-specialized M-1 struggles — exactly why M-2/M-3 exist. DocSafe M-2 reaches 100% at 3×3cm and 85% at 2×2cm, a 5–23 point improvement over StampOne at the same sizes. CodeFace and prior full-image methods can't be evaluated under masking at all: they have no mechanism to confine embedding to a region.

Digital robustness (2,000 FFHQ images)

MethodJPEG (%)Gaussian (std)Resolution (px)
7060500.080.060.0460²80²100²
StegaStamp100100100100100100558091
Code Face80848855758621136
RoSteALS879094233553819798
RiemStega9910010098991005599100
StampOne100100100981001008498100
DocSafe (M-1)80851009810010085100100
DocSafe (M-2)828710098981008098100
DocSafe (M-3)828710090971008098100

DocSafe leads at low resolution and matches the field on Gaussian noise and mild JPEG, but trails StampOne/RiemStega under heavier JPEG compression (70–60% quality) — a known trade-off, not yet closed.

Code

DocSafe is published as the DocSafe Python package with a documented encoder/decoder entry point.

pip install DocSafe
from DocSafe import encoder, decoder

encoder_router = encoder(model="M1", path_model="pre_trained_models/", secret_size=100)
encoder_router.load_network(device="cpu")

images = encoder_router.read_image(path=["test_images/original_images.jpg"])
image_batch = encoder_router.preprocess_images(images)
encoded = encoder_router(original_images=image_batch, messages="viste", mask=None)
encoder_router.save_encoded_image("encoded.png")

decoder_router = decoder(model="M1", path_model="pre_trained_models/", secret_size=100)
decoder_router.load_network(device="cpu")

encoded_images = decoder_router.read_image(path=["encoded.png"])
encoded_batch = decoder_router.preprocess_images(encoded_images)
messages = decoder_router(encoded_images=encoded_batch, mask=None)
print(messages)

Full source and setup instructions are on GitHub → farhadsh1992/DocSafe. Pretrained weights are not bundled in the package (~600 MB, past PyPI's practical limits) — they're available on request: farhad.shadmand@isr.uc.pt.

BibTeX

@article{shadmand2026docsafe,
  title     = {DocSafe: Toward Practical Print-Proof Image Steganography via Frequency
               Decomposition and Covariance Alignment},
  author    = {Shadmand, Farhad and Medvedev, Iurii and Schirmer, Luiz and Gon\c{c}alves, Nuno},
  journal   = {IEEE Access},
  volume    = {14},
  pages     = {54213--54228},
  year      = {2026},
  publisher = {IEEE},
  doi       = {10.1109/ACCESS.2026.3680290}
}