v2 Planning: Enhanced Coefficient Domain & Metadata Embedding

Date: 2026-08-31 • Predecessor: v1.5-implementation (a44bfe2) • Status: PLANNING PHASE

Problem v2 Solves (vs v1.5)

v1.5's Limitations

1. External metadata: Restore requires external parameters (salt, region, schema_version) passed separately

→ Files not self-contained; easy to lose metadata

2. Boundary artifacts: JPEG block boundaries have slight lossy effects (acceptable but noted)

→ Could be eliminated with rigorous MCU alignment

3. No progressive JPEG support: Only baseline DCT handled

→ Limits use cases in progressive-heavy workflows

4. Float precision in scipy DCT: 1.2-byte accuracy is good, but not perfect

→ libjpeg could improve to sub-byte with native coefficient access

v2 Architecture: Self-Contained Files

Core Enhancement: APP15 Metadata Embedding

Approach: Store metadata in JPEG APP15 segment (user-defined application data)

Why APP15: Not used by most codecs; preserved during JPEG re-encoding

Content:

• schema_version (1 byte)

• salt (16 bytes)

• region (x, y, w, h as 4×4 bytes = 16 bytes)

• block_count (4 bytes)

• reserved (3 bytes for future use)

Total: ~50 bytes overhead per image

Restore Workflow Simplification

v1.5 (current): restore image.jpg output.jpg --passphrase PASS --region X,Y,W,H --salt HEX

v2 (proposed): restore image.jpg output.jpg --passphrase PASS

(metadata auto-extracted from APP15)

Implementation Plan

Phase 1: APP15 Metadata I/O (0.5 day)

Task 1: Create metadata.py functions for APP15 encoding

• encode_app15(): Pack salt/region/version into binary blob

• decode_app15(): Extract blob from JPEG image

Task 2: Integrate with Pillow's JPEG handling

• Use PIL.Image.app[15] to read/write segments

• Test round-trip: embed → save → load → extract

Phase 2: CLI Updates (0.5 day)

Task 1: Update scramble_image() to embed metadata

• After saving scrambled JPEG, inject APP15 metadata

Task 2: Update restore_image() to extract metadata

• Check for APP15; if present, use it; else fall back to external params

Task 3: CLI help text updates

• Show both v1.5 (external params) and v2 (embedded) examples

Phase 3: Enhanced Coefficient Handling (1 day)

Task 1: Evaluate libjpeg-turbo availability

• If available: Integrate for native DCT coefficient access

• If not: Use scipy but with improved clipping/rounding documentation

Task 2: MCU alignment research

• Understand JPEG MCU (Minimum Coded Unit) boundaries

• Align region permutation to MCU boundaries to eliminate edge artifacts

Task 3: Coefficient overflow handling

• Document how coefficients outside [-1024, 1023] are handled

• Add tests for edge cases (high-contrast regions)

Phase 4: Progressive JPEG Support (1 day)

Task 1: Detect progressive vs baseline in input

Task 2: Handle progressive scan structure

• Research PIL's progressive JPEG capabilities

• Determine if permutation works across scans

Task 3: Testing

• Generate progressive JPEG test cases

• Validate round-trip with progressive input

Phase 5: Integration & Testing (1 day)

Task 1: Full integration tests

• v2 scramble → v2 restore (APP15 embedded)

• v2 backward compat: Restore v1 files with external params

Task 2: Sample generation

• Generate 3 v2 samples (self-contained files)

• Compare file sizes with v1.5 (should be ~50 bytes larger)

Task 3: Performance profiling

• Measure scramble/restore time (target: <2s for 4K image)

Phase 6: Documentation (0.5 day)

Task 1: Update README with v2 examples

Task 2: Create v2 design spec (ideas/jpeg-obscura/v2-design)

Task 3: Session lessons (ideas/jpeg-obscura/v2-session-lessons)

Risk Assessment

High Risk

1. APP15 segment corruption: JPEG re-encoding might strip APP15

Mitigation: Test with multiple JPEG encoders; verify preservation

2. libjpeg-turbo integration: FFI complexity, version compatibility

Mitigation: Keep scipy as fallback; use ctypes if needed

3. MCU alignment complexity: Region snapping might not align to MCU boundaries

Mitigation: Document as edge case; accept small boundary artifacts for MVP

Medium Risk

1. Progressive JPEG complexity: Scan structure handling is non-trivial

Mitigation: Accept baseline-only for v2.0; progressive in v2.1

2. Backward compatibility: Ensure v1.5 files still restore correctly

Mitigation: Comprehensive test suite for both formats

Testing Strategy for v2

Unit Tests

✓ APP15 encoding/decoding (pack/unpack binary blob)

✓ Metadata round-trip (embed → extract → verify)

✓ Backward compat: v1.5 files (no APP15) should restore with external params

Integration Tests

✓ v2 scramble (APP15 embedded) → v2 restore (APP15 extracted)

✓ v2 restore → original accuracy (target: mean Δ < 1.5 bytes)

✓ v1.5 scramble → v2 restore (backward compat)

✓ File portability: v2 scrambled file to different machine, restore succeeds

Visual Tests

✓ Side-by-side comparison: v1.5 vs v2 restoration (visual similarity)

✓ Progressive JPEG samples (if implemented)

Go/No-Go Criteria

Must Have

✓ APP15 metadata embedding works (embed → JPEG save → JPEG load → extract)

✓ Backward compat with v1.5 (restore still works with external params)

✓ Restoration accuracy maintained (mean Δ < 1.5 bytes)

✓ CLI simplified: restore image.jpg output.jpg --passphrase PASS works

Should Have

✓ Enhanced coefficient handling (libjpeg-turbo or scipy improvements)

✓ MCU alignment handling (document limitations if not fully solved)

✓ Performance profiling (scramble <2s for 4K)

Nice to Have

✓ Progressive JPEG support

✓ Streaming API (large image support)

✓ Batch processing API

Compatibility Matrix

Version Interoperability

v0.5 scramble → v0.5 restore: ✓

v0.5 scramble → v1 restore: ✗ (different schema)

v1 scramble → v1 restore: ✓

v1 scramble → v1.5 restore: ✓ (backward compat)

v1.5 scramble → v2 restore: ✓ (backward compat with external params)

v2 scramble → v2 restore: ✓ (APP15 embedded)

v2 scramble → v1.5 restore: ✗ (no APP15 support in v1.5)

Security Considerations for v2

APP15 Metadata Confidentiality

Risk: Region coordinates visible in APP15 segment

Mitigation: Metadata is not sensitive (region is visible from encrypted image anyway)

Salt is stored in plaintext in APP15 (necessary for KDF)

APP15 Tampering

Risk: Attacker modifies APP15 to wrong region/salt

Mitigation: Wrong salt → wrong key derivation → garbage output (detected)

No authentication of APP15 needed (confidentiality is in permutation, not metadata)

Estimated Timeline

Total: 3.5 days (0.5 + 0.5 + 1 + 1 + 1 + 0.5)

Assumes: libjpeg-turbo optional; progressive JPEG deferred; MCU alignment documented but not fixed

Slack: +0.5 days for testing/debugging

Dependencies

New Dependencies

• libjpeg-turbo (optional, for enhanced coefficient access)

• PIL (already present)

No New Dependencies Required For MVP

APP15 handling via PIL

Coefficient handling via scipy (already present)

Post-v2 Roadmap (v3+)

v3: Performance & Scale

• GPU acceleration (DCT via cuFFT)

• Streaming API (process images larger than RAM)

• Batch processing (multiple images/regions)

• Parallel permutation (multi-threaded for large block counts)

v4: Advanced Features

• Selective obscuring (obscure multiple regions with different keys)

• Reveal-on-demand (progressive unobscuring)

• Time-locked obscuring (reveal only after timestamp)

Conclusion

v2 focuses on practical usability (self-contained files via APP15) and robustness (enhanced coefficient handling, backward compat). Estimated 3.5-day effort for MVP; full implementation depends on libjpeg-turbo availability and progressive JPEG requirements.

tags v2, planning, roadmap, metadata, app15