Zero Attributes, No Information.
Metadata stripper for images and audio. Removes EXIF, GPS coordinates, timestamps, software tags, and generation parameters at the binary level. No dependencies.
Written in x86-64 assembly (NASM) with a minimal C entry point.
Usage
zani <FILES...> # strip metadata (in-place)
zani -b <FILES...> # strip with .bak backup
zani <FILES...> -o <DIR> # strip metadata (output to DIR)
zani -i <FILES...> # inspect metadata only
zani -v # version
Wildcards work as expected:
zani *.png *.jpg
Supported Formats
| Format | Strategy | Status |
|---|---|---|
| PNG | strip | ✓ |
| JPEG | strip | ✓ |
| GIF | strip | ✓ |
| WAV | strip | planned |
| FLAC | strip | planned |
| WebP | strip | planned |
strip removes metadata chunks entirely and rewrites the file.
See docs/formats.md for details on what metadata is removed from each format.
What Gets Removed
- EXIF data (camera model, lens, serial number)
- GPS coordinates and altitude
- Timestamps (creation, modification, capture)
- Software and encoder identification
- AI generation parameters (Stable Diffusion, ComfyUI, etc.)
- Color profiles and ICC data
- Embedded comments and XMP
- Photoshop / Lightroom resource blocks
Architecture
main.c (C) argc/argv parsing, glob expansion
|
| zani_process()
v
zani.asm magic byte detection, format dispatch
|
+---> fmt/png.asm chunk walker, metadata filter, CRC32
+---> fmt/jpeg.asm marker walker, scan data passthrough
+---> fmt/gif.asm extension block filter
+---> fmt/wav.asm RIFF chunk filter
+---> fmt/flac.asm metadata block filter
+---> ...
|
+---> core/mmap.asm mmap file mapping, zero wipe
+---> core/scan.asm AVX2/SSE2 byte scanner
+---> core/crc32.asm SSE4.2 hardware / software CRC32
+---> core/detect.asm branchless lookup tables
+---> core/backup.asm sendfile copy (.bak creation)
+---> core/io.asm syscall wrappers, endian conversion
The C layer handles argument parsing only. Everything that touches file data is hand-written x86-64 assembly.
Why Assembly
This is a privacy tool. The design priorities are:
- Auditability -- every byte of the binary is accounted for.
- Zero dependencies -- no libc in the hot path, no runtime, no allocator.
- Performance -- not because metadata stripping needs to be fast, but because the techniques that make it auditable also make it fast.
Run make bench to measure hot-path throughput on your hardware.
Build
Requires nasm and gcc on Linux x86-64.
make # standard build
make debug # debug symbols, no optimization
make release # -O3
make test # run test suite
make size # print binary size breakdown
See docs/build.md for project structure and adding new formats.
Design Decisions
Strip vs. Wipe --
Formats like PNG and JPEG have self-contained chunks with no cross-references.
Removing a chunk doesn't affect anything else. Formats like MP4 store absolute
byte offsets to media data (stco/co64 atoms). Deleting metadata shifts those
offsets and breaks playback. Zero-filling preserves all offsets while destroying
the metadata content.
mmap over read/write --
A 10 MB JPEG processed with buffered I/O requires thousands of syscalls.
Memory mapping reduces this to three: mmap, msync, munmap. For the wipe
strategy this is especially effective since we modify memory directly without
copying.
Runtime CPU detection -- CPUID is checked once at startup. AVX2-capable machines get 32-byte SIMD paths. Older machines fall back to SSE2 (16 bytes) automatically. Same binary runs everywhere.
CRC32 hardware acceleration --
PNG requires CRC32 for every chunk. SSE4.2 provides a dedicated crc32
instruction that processes 8 bytes per cycle. Machines without it use a
256-entry lookup table.
License
CC0 1.0 Universal. Public domain.