# PhotoRevive (CLI prototype)
PhotoRevive is a working command-line prototype for the "Pro" tier of the
Media Rescue Lab product cluster. It is a CLI-native, scriptable tool for
professionals with large offline media libraries spanning many
directories (a photographer's entire archive across years of folders,
for example): point it at multiple directories at once and it walks all
of them, classifies every candidate image file as OK, CORRUPT, or
UNKNOWN, and prints one consolidated report across the whole batch. It
also implements a real, narrow, best-effort repair for one specific,
common corruption pattern: a JPEG file that is missing its trailing
End-Of-Image (EOI) marker because it was truncated (an interrupted
download or copy that got cut off), but whose actual image data is
otherwise intact. This differs from the sibling MediaRescue tool, which
is a browser-based app where a person drags in photos from ONE folder
at a time and sees which ones fail to decode, interactively, and does
not attempt any repair — it is detection-only. PhotoRevive covers the
same detection technique (attempt to decode; on failure, check whether
the file's header even looks like the format its extension claims) but
does it as a batch CLI job across many directories at once, and adds a
real repair attempt on top of detection.
Be clear about scope: the repair capability here covers exactly one
well-understood truncation pattern (missing JPEG EOI marker). It is not
general JPEG or video repair, it does not recover deleted files, it does
not reconstruct fragmented or partially-overwritten video, and it has no
camera/memory-card profile support. Those all require raw disk access
and much more sophisticated recovery techniques than a file-level image
decoder can provide, and are tracked as roadmap items, not shipped
capabilities of this prototype. See ../plan.md for the full product plan,
including the v1/v2 feature scope and how this narrow slice fits into it.
## Build from source
Requires Go 1.24+, no external dependencies (stdlib image/jpeg,
image/png, image/gif only).
go build -o photorevive .
Cross-compile for another platform:
GOOS=windows GOARCH=amd64 go build -o photorevive.exe .
GOOS=darwin GOARCH=arm64 go build -o photorevive .
## Usage
photorevive scan
[ ...] [--json]
photorevive repair [ ...] --out-dir [--apply]
photorevive help
### scan
Recursively walks each given directory independently, but reports all
findings together in one consolidated summary across every directory
passed on the command line. For every file with an extension of .jpg,
.jpeg, .png, .gif, or .bmp, PhotoRevive tries to decode it with Go's
standard image.Decode:
- Decode succeeds -> OK. Dimensions are recorded.
- Decode fails -> PhotoRevive checks the file's first few bytes
against the magic number expected for the format implied by its
extension (JPEG: FF D8 FF, PNG: 89 50 4E 47, GIF: 47 49 46 38,
BMP: 42 4D).
- Header matches -> CORRUPT (it really does look like that
format, but something inside it is broken or truncated).
- Header does not match -> UNKNOWN (it is probably not a real
image file at all, or is some other/unsupported format wearing
the wrong extension).
The report is read-only — scan never writes or modifies anything. It
prints per-directory OK/CORRUPT/UNKNOWN counts plus grand totals across
all directories, and lists the path of every CORRUPT and UNKNOWN file
(OK files are only counted, not listed individually, so the report
stays readable against a library of thousands of files). Pass --json to
get the same information as machine-readable JSON, including the full
per-file classification list (paths, status, detected dimensions, file
size, and a human-readable detail string), suitable for piping into
other tooling.
Note on BMP: Go's standard library does not ship a BMP decoder (only
image/jpeg, image/png, and image/gif register with image.Decode).
PhotoRevive still recognizes the .bmp extension and checks its magic
bytes, but because there is never a working decoder to try, a .bmp file
will report CORRUPT via the header-matches-but-decode-failed path even
when it is a perfectly valid bitmap. This is a known limitation of a
stdlib-only build, not a bug in the detection logic, and BMP support
should be considered magic-byte sniffing only until a BMP decoder is
added.
### repair
Runs the same scan/classification logic as "scan" across all the given
directories, then looks at every file classified CORRUPT. For files
that are JPEGs (magic bytes FF D8 FF) and do NOT already end with the
FF D9 End-Of-Image marker, PhotoRevive attempts the repair: it reads the
original file into memory, appends FF D9 to a copy (the original file on
disk is never touched), and tries to decode the in-memory copy.
- If the copy now decodes -> REPAIRED (or WOULD-REPAIR in dry run).
The image data up to the truncation point was intact; only the
terminator was missing.
- If the copy still fails to decode -> REPAIR-FAILED (or WOULD-FAIL
in dry run). This means the corruption goes deeper than a missing
end marker — real data was lost partway through the file — and
appending two bytes cannot fix that. No output file is written for
a failed repair; nothing broken or partial is left behind in
--out-dir.
- CORRUPT files that are not JPEGs (PNG/GIF/BMP), or JPEGs that
already end with FF D9 but still fail to decode (a different kind
of corruption than this tool targets), are reported as
SKIP (not a JPEG-EOI-repairable case) and never touched.
- OK and UNKNOWN files are never repair candidates at all; only
CORRUPT files are considered.
Without --apply, repair is a dry run: it performs the exact same
in-memory repair-and-verify logic (append FF D9, try to decode) so the
WOULD-REPAIR / WOULD-FAIL preview is an accurate prediction of what
--apply would actually do, not a guess — but --out-dir is never created
or written to.
With --apply, every file that verified as repairable is written into
--out-dir, preserving its path relative to its source directory (nested
under a folder named after that source directory, to avoid collisions
when the same relative path exists under two different libraries being
repaired in the same run). A final summary line reports the count of
REPAIRED / REPAIR-FAILED / SKIP files across the whole batch.
## Prebuilt binaries
See ../downloads/ for prebuilt binaries (Windows/macOS/Linux) and
CHECKSUMS.txt for their SHA-256 hashes. These are unsigned indie builds —
Windows SmartScreen and macOS Gatekeeper will warn on first run, which is
expected until a code-signing certificate is in place.