Skip to content

Rust decoder loses watermarks: decode-path resize uses non-antialiased ResizeAlg::Interpolation #37

Description

@KevinClauson

Hi, I found that the TrustMark Python library was detecting watermarks that the Rust library was not, so I dug a bit deeper. My fix on my end is pinning the Rust library back to an earlier commit.

Worth noting the failure is silent: ECC returns 61 bits but flags them not-detected, so the CLI prints Corrupt or missing watermark and exits 0 — indistinguishable from an unwatermarked image.

Root cause: rust/src/image_processing.rs:69-73. fast_image_resize distinguishes ResizeAlg::Convolution (scaled support, antialiased) from ResizeAlg::Interpolation (documented as "like Convolution but with fixed kernel size" / "similar to OpenCV except INTER_AREA") a fixed 2x2 kernel means no antialiasing however large the ratio. The decoder uses the latter; PIL's Image.BILINEAR on the Python side is antialiased. Decoding a multi-megapixel image at 256x256 is a 4-7x downscale, so this drops most of the pixels. The same TryFrom conversion is used by encode (lib.rs:130, :141), so the residual is computed from an aliased downscale too, decode is where I looked.

Regression: 3b3aabe ("perf: switch from image-rs to fast_image_resize…") replaced .resize_exact(size, size, FilterType::Triangle), which is antialiased in image, so the change reads as unintended — a like-for-like swap of "bilinear" for "bilinear". Parent bff6dcd (2025-04-15) uses the antialiased path. Only five commits have ever touched the file; 9234078 ("fix: integer truncation bug") is in remove_boundary_artifact, off the decode path.

Repro, without patching anything: take an image the binary reports as undetected and hand it the same content pre-resized to exactly 256x256 with an antialiased filter, so the internal resize becomes an identity op. The unmodified binary then detects it, while the full-size original still doesn't — same binary, same models, same pixels, only the resize does or doesn't do work. I couldn't build a patched CLI in my environment to confirm the fix directly.

Suggested fix: ResizeAlg::Convolution(FilterType::Bilinear) still SIMD-accelerated, so most of 3b3aabe's win is retained.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions