A parser + light processing library for the Hasselblad/Imacon FlexColor film-scanning software (the driver behind the Flextight X1/X5, the 343/848/949 sensors and the iXpress backs). The scanner code ships the per-film recipes as plain plist XML, and the per-sensor calibration as plist color profiles — this repo parses both, recovers their structure, and can apply a film profile's tone curves to a linear scan.
python -m flexcolor profiles path/to/FlexColor/curves
python -m flexcolor profile Kodak_Portra_160_NC.xml
python -m flexcolor lut LUTTable39MPC.xml
python -m flexcolor apply Kodak_Portra_160_NC.xml in.tif -o out.tif
The Flextight scanners have a beloved, distinctive "Flextight look" people reproduce with Lightroom presets. Those presets guess. The software itself ships the real thing:
- Per-film image-setting plists — one per film stock (Kodak Portra 160
NC/VC, Gold, Ektachrome-profiled, Fuji Superia/NPS/NPH, Ilford, Konica,
Agfa, Mitsubishi, Polaroid, …). Each carries
FilmType(1 = color, 2 = B&W),Mode, and 7Gradationstone curves (piecewise points that encode the film's character), plus endpoints, color matrix, ICC profile refs. - Per-sensor
LUTTable*.xmlcolor profiles — 3×3 color matrices (mf/mfd/mtflash/TS variants), white points, clip points, and four 18,690-float LUT tables (the sensor calibration response). - The engine —
FlexColor.dll(10.5 MB, CxImage-based OLE server) that consumes these, with the.3frraw format (SGILog/LogLuv compressed TIFF).
This is the same playbook as the sibling project noritsu-tool: recover the format and the math from the shipped binaries rather than approximate it from a preset.
pip install numpy pillow
Per-film profile (Apple plist XML, ImageSetting → ImageCorrection):
| key | meaning |
|---|---|
FilmType |
1 = color negative, 2 = B&W |
Mode |
0/2 presets |
Gradations |
7 tone curves; each Points list of (X, Y, DY) |
EndPoints |
black/white clip (list of 2) |
ColorCorr |
36-value color correction |
Gamma, Contrast, Saturation, Brightness |
global sliders |
ApplyCC/Curves/Histogram |
stage toggles |
InputProfile/RGBProfile/CMYKProfile |
embedded ICC refs |
Per-sensor LUTTable profile (ColorProfile, Version 2.0):
| key | meaning |
|---|---|
mf/mfd/mt |
3×3 color matrices (flash / flash-daylight / tungsten) |
vf/vt |
white points |
tf/tt |
temps |
CbS/CbE/CrS/CrE |
hard clip points |
LUTTableFlashStd/TSStd/FlashRepro/TSRepro |
18,690-float calibration LUTs |
From the public FlexColor 4.8.9.1 installer (fc4891win.zip, Hasselblad's
archive CDN). Extraction chain: WinZip SFX → nested installer → embedded MSI +
MSCF cabinet → 231 files (engine DLL + ~100 film plists + LUT tables + ICC +
firmware). See docs/FLEXCOLOR_JOURNEY.md for the full account and
docs/FLEXCOLOR_FORMAT.md for the byte/spec detail.
The proprietary files (DLLs, film plists, ICCs) are not redistributed here; point the tools at your own FlexColor install.
- ✅ Format recovery: per-film plists + LUTTable profiles fully parsed.
- ✅ Curve application: piecewise tone curves reconstructable per film.
- ✅
.3fr/.fffdecode: LogLuv32 (PackBits-style RLE), LogLuv24 (uvcode index), and uncompressed 16-bit RGB variants -> XYZ -> linear sRGB, with a normalized negative converter for external inversion tools. - 🔶 Engine math partially recovered by decompilation: per-channel 16-bit LUT
apply, min-span/point normalization, pow-based neg-gamma LUT builder
(
CGammaNegCurve), andCPointCurveinterpolation (linear per segment for <=2 points; de Boor B-spline basis for >=3 points, medium confidence). Exact rendering still needs the B-spline orientation + a real sample to validate. - 🔲 Full engine-equivalent render (needs the exact curve/grad math; the matrices/LUTs + LogLuv decode give a strong starting point).
- The profiles differ meaningfully by film (e.g. Portra 160 NC carries a real 4-point S-curve; Tri-X, Superia and Gold default to linear) — confirming these encode real per-film character, not generic presets.
docs/FLEXCOLOR_FORMAT.md— the recovered format spec.docs/FLEXCOLOR_JOURNEY.md— the chronological unpacking account.docs/FLEXCOLOR_BLOG.md— the written-up story.