Complete implementation of reversible JPEG region scrambling. v0.5 through v2 multi-region complete, tested, and deployed to production.
• Boundary row corruption between adjacent regions (open, 2026-08-31) — visible scattered-block and boundary-line artifacts in v2-MR samples that the reported mean-Δ metrics didn't surface. Root cause not yet confirmed in code.
• Core design & requirements — Concept, use cases, phased roadmap
• v0.5 detailed spec — Implementation design, test plan
• v0.5 implementation | test results | lessons learned
• v1 design | v1 complete | v1 checkpoint
• v1.5 planning | v1.5 complete
✅ DELIVERED: 8× accuracy improvement (1.2 bytes vs v1's 10 bytes)
✅ Samples: 9 files deployed to WebDAV/samples1_v1_5
✅ DELIVERED: Self-contained files with embedded metadata
✅ Samples: 9 files deployed to WebDAV/samples2_v2
✅ DELIVERED: Multiple independent encrypted regions per image
⚠️ Quality: 1.09-2.54 bytes mean Δ per region — : this metric did not catch a real boundary-row defect visible on inspection
✅ Samples: 9 files deployed to WebDAV/samples3_v2_multi
• Complete session lessons — v1.5, v2, multi-region (5 major sections, 50+ lessons)
Float Precision Loss: XOR on float32 values isn't self-inverse (24-bit mantissa < 32-bit int range)
DCT Domain: Permutation works on floats; diffusion doesn't (precision loss)
Graceful Fallback: If APP15/XMP not preserved, fallback to external metadata
Multi-Region Keys: salt_with_idx = base_salt + bytes([region_index]) ensures unique keys
Git: ~/py/jpeg-obscura
Main commits:
• v1.5-implementation (a44bfe2): DCT permutation core
• v2-implementation (35dcbdbe): XMP metadata embedding
• 8a20b8e: v2 multi-region sample generation
1. samples1_v1_5: 9 files (v1.5 single-region)
2. samples2_v2: 9 files (v2 single-region with metadata)
3. samples3_v2_multi: 9 files (v2 multi-region)
palace_*: Buckingham Palace facade (5 or 1 region)
detail_*: Architectural stonework (5 or 1 region)
subject_*: Center composition (4 or 1 region)
Files per set: original, scrambled, restored
v0.5: 0.23 bytes mean Δ (permutation only)
v1: 9.8 bytes mean Δ (permutation + XOR diffusion in pixel domain)
v1.5: 1.2 bytes mean Δ (DCT permutation only, 8× improvement)
v2: 1.2 bytes mean Δ (same DCT core + metadata infrastructure)
v2-MR: 1.09-2.54 bytes per region (mean — see Known Issues re: outlier blocks this hides)
Permutation: 10^23,000+ possible arrangements (unchanged)
KDF: scrypt N=32768 (~0.1s per attempt)
Per-region: Unique key via region index in salt + passphrase
v2.1: Reliable APP15/XMP preservation (libjpeg-turbo integration)
v2.1: Fix boundary row corruption (see Known Issues)
v3: GPU acceleration, streaming API, performance optimization
Source: src/jpeg_obscura/ (8 core modules + CLI)
Tests: test_*.py
Samples: samples/ (v1.5, v2, v2-MR generation scripts)
Documentation: This notes system (not git)