Open-source project
andreavolpato/spektrafilm avatar
andreavolpato/spektrafilm

spektrafilm: modelling film from datasheet curves to a scanned print

Spectral simulation of analog photography processes

1,099 stars110 forksPythonGPL-3.0

At a glance

What is it?
spektrafilm is a Python reference implementation that turns published film stock datasheets into a spectral simulation of a negative, a print and a scan. It is aimed at people who want a film look grounded in measurements rather than a preset, and it comes with a licence and a roadmap that shape who can actually ship it.
Who is it for?
spektrafilm is worth adopting for research, for LUT authoring, and for anyone who has to defend a film look with numbers rather than taste, since the model is built on published datasheets and runs the whole negative, print and scan chain.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 103 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Film looks built from measurements instead of presets

Most film simulation is a look: a curve, a colour matrix, a grain overlay. spektrafilm takes a different route. The stated goal is to make good use of spectroscopic data from manufacturer datasheets in an end-to-end, physically based model with spectral calculations, and to turn that data into film, print and scan renderings that can be explored interactively. The author is explicit about the target: the aim is not to imitate a generic film look, but to build a model grounded in measurements that predicts real behaviour of photographic emulsions. The audience is a mix of researchers, photographers who want to reason about chemistry, and developers building tools on top of a simulation. The project describes itself as open for research, integration and production use, while also warning that it is in rapid development and that some areas are still being built and will change fast.

RAW file, virtual negative, printed and scanned again

The pipeline in the README is worth reading closely, because it explains why the code is shaped the way it is. Starting from linear RGB data taken from a camera RAW file, the simulation reconstructs the spectral data, projects the virtual light transmitted through the negative onto print paper, and uses a simplified colour enlarger with dichroic filters to balance the print. Finally it scans the virtual print using the light reflected from the print. In the middle sits the chemistry. A chemical process creates the dye densities using density curves and more complex interactions that model the couplers, and the paper is developed again with simple density curves and no couplers in that case, since print paper is already designed to reduce channel cross-talk because it only has to sample the dyes on the negative rather than a scene. The author also makes a point that the datasheet curves alone are not enough to reproduce a decent film look, because emulsions contain couplers, chemicals produced during development alongside the actual CMY dyes, and those couplers are what deliver the saturation people recognise.

Datasheets leave gaps the model has to guess around

The published data is real but partial, and the README shows how the gaps are handled. The example given is Kodak Portra 400, taken from data-sheet e4050 of 2016, and Kodak Portra Endura print paper from data-sheet e4021 of 2009. Each figure has three parts: the spectral log sensitivities of each colour layer, the log-exposure-density characteristic curves for each layer under a neutral grey gradient and a reference light, and the absorption spectra of the dyes formed during chemical development, with the minimum and mid values for the unexposed processed medium and a neutral grey middle exposure. The honest caveat sits in the same place, with the note that the CMY diffuse densities are generic because they are usually not published. So the input is a real curve set with substituted constants in specific places, and any prediction about a stock inherits that substitution. The community is working on filling the gap, and the README links a campaign to vote for the next datasheet to digitise.

Halation, grain and pre-flashing as first class effects

Because the model is physical rather than cosmetic, several effects that film photographers chase can be added in a way that is consistent with the rest of the chain. The README lists halation, film grain generated on the negative using a stochastic model, and pre-flashing of the print to retain highlights. Pre-flashing is the interesting one, because it is a real enlarger technique, the deliberate pre-exposure of the paper before the image exposure, used to hold detail in the highlights, and it only produces a sensible result if the paper's response curve is modelled properly. Grain is likewise generated rather than overlaid, since the README describes it as produced on the negative with a stochastic model, which means it survives the enlargement and printing step and appears at the right scale for the grain structure of the emulsion. Effects of this kind are the practical difference between a simulation and a filter.

Installing the package and the two entry points

The package targets a narrow Python range and ships two console entry points. The build is setuptools based, the project name is spektrafilm, and the interpreter requirement is pinned with a compatible release clause:

toml
[project]
name = "spektrafilm"
version = "0.3.4"
requires-python = "~=3.13"
license = { text = "GPLv3" }

Two scripts are registered, and they split the GUI from the LUT authoring tool:

toml
[project.scripts]
spektrafilm = "spektrafilm_gui.app:main"
spektrafilm-lut = "spektrafilm_lut_creator.cli:main"

The runtime dependencies are the numerical stack, numpy, scipy, colour-science, scikit-image, matplotlib, opt-einsum, numba, OpenImageIO and pyfftw, plus rawpy for RAW reading, exiv2 for metadata and lensfunpy for lens data. The GUI pulls in qtpy, pyside6, napari, Pillow and pyconify, and the LUT creator adds markdown. Those groups are installed by default because the package ships both entry points, even though the core physical runtime under the spektrafilm package does not import the GUI or LUT creator layers, a split the project is careful about. A dev extra adds pytest and opencolorio, which validates the emitted config.ocio files. A worked script is included at examples/run_simulation.py, and the desktop GUI lets you import RAW files or prepared linear images, explore film and paper profiles and move between fast previews and detailed final scans.

The Python repository is the reference, not the fastest path

This repository is described in the README as the reference implementation for other developments and the place where the underlying model is being grown. That framing is confirmed by the list of spin-off projects. A blazing fast Vulkan implementation of the film simulation exists in vkdt by hanatos, a fast Rust implementation is under development as spektrafilm-rs by turbasvin, an OFX plugin was developed by Aedan, and a LUT-based bridge is available in ART by agriggio. The structural decision behind all of this is stated plainly in the dependency comments in the pyproject, where the core runtime is kept as the one layer that imports nothing from the GUI or LUT creator packages. For a working photographer, the practical reading is that a full spectral computation in Python is slow, which the README admits when it says that full resolution export is very slow at the moment, and the reasonable paths are either the faster reimplementations or the LUT route. The LUT route computes the physics once and then applies the result through ordinary colour management, which is far quicker at render time and gives up the ability to change a parameter mid-render.

Three licences, one of which is not open source

The licence situation is the part to read before you plan a product around this. The code is GPLv3, and the README states that any derivative work must also be open source under the same licence, with derivative work explicitly including any software, plugin or tool that incorporates spektrafilm code or is directly inspired by its methods. JSON profiles and LUTs are CC BY-SA 4.0. LUT files themselves sit on a strict custom licence, commercial use, free share, no resale, and the project says this is what sustains open colour science. The author asks users to acknowledge spektrafilm in plugin descriptions, marketing or credits, to cite the repository and its Zenodo DOI in academic work through CITATION.cff, and to reach out if GPLv3 is not compatible with a project, stating openness to collaboration. On maintenance, the last push was on 2026-07-14, the repository is not archived, and the tags are v0.3.2 on 2026-05-28, v0.3.3 on 2026-06-06 and v0.1.0-alpha from 2025-02-07, with the project file already at version 0.3.4. One operational note is easy to miss, since the README records a git history cleanup on 2026/05/28 that took the repository from 140MB to 45MB and asks existing users to reclone.

Editorial conclusion

spektrafilm is worth adopting for research, for LUT authoring, and for anyone who has to defend a film look with numbers rather than taste, since the model is built on published datasheets and runs the whole negative, print and scan chain. It is the wrong choice when you only want a quick preset, when full resolution export time matters, or when a GPLv3 dependency cannot be accepted in a closed product, and the project itself says as much in its request to be acknowledged and cited. Before you commit, check that the film stocks you need have digitised datasheets rather than assuming coverage, plan for the 0.3.x line to keep changing, and decide early whether your pipeline will compute spectra at render time or take the LUT route through ART.

Frequently asked questions

How do I install spektrafilm and open the desktop GUI?

The package requires Python ~=3.13 and registers the console script spektrafilm, which points at spektrafilm_gui.app:main, and spektrafilm-lut, which points at spektrafilm_lut_creator.cli:main. The GUI imports RAW files or prepared linear images and lets you explore film and paper profiles, and a worked script is included at examples/run_simulation.py.

What licence applies to spektrafilm, its profiles and its LUTs?

The code is GPLv3, so any derivative work must also be open source under the same licence. JSON profiles and LUTs are CC BY-SA 4.0, while the LUT files themselves use a custom commercial use, free share, no resale licence.

Is a full resolution render with spektrafilm fast?

The README says that full resolution export is very slow at the moment, and it points to faster paths including a Vulkan implementation in vkdt, a Rust implementation under development, and a LUT-based bridge in ART. The Python repository is described as the reference implementation rather than the quickest route.

Official sources

  1. andreavolpato/spektrafilm on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/andreavolpato-spektrafilm.svg)](https://hysenlabs.com/projects/andreavolpato-spektrafilm)

Was this useful?