A proxy stored the pixels and the camera tone curve only. An edit that
reads the file's own facts — a Kelvin white balance through the camera
colour model, Camera local tone mapping's gain table map, an AI mask's
semantic matte — rendered differently once the original went offline,
because the catalog's header facts cannot carry them.
The facts now ride in a tail after the JPEG (a length-prefixed JSON blob,
then one byte plane per matte), counted from the file's end so a header
rewritten in place keeps pointing at it; is_valid requires the JPEG to
end right before the tail. ENCODE_VERSION becomes 3, so proxies an older
build wrote are rebuilt when their original is readable (offline ones
keep their older look, as before). smart::encode now takes the source's
SourceInfo and decode returns the restored one.
Tests:
- tests_import::smart_previews_keep_the_decoder_facts_offline_edits_need:
a proxy's own pixels and facts render bit-identically offline for a
Kelvin white balance (6144/6144 pixels differ before), a stored sky
matte, and a gain table map
- smart::tests::facts_and_mattes_travel_with_the_proxy: the facts and
mattes round-trip; a proxy cut inside its tail is invalid; an old
proxy, and one whose header lies about the tail, read as no facts