Skip to content

Add Kodak paper profiles fitted to datasheets - #1365

Merged
marcinz606 merged 1 commit into
mainfrom
feat/datasheet-paper-profiles
Oct 11, 2026
Merged

marcinz606 merged 1 commit into
mainfrom
feat/datasheet-paper-profiles

Conversation

@marcinz606

@marcinz606 marcinz606 commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

Five new paper profiles, fitted to Kodak datasheet characteristic curves. The curves were read exactly from the PDFs' vector paths, not by eye.

Profile Mode Source Fit RMS
Kodak Polymax II RC B&W G-26, 7 filter grades 0.022 D
Kodak Polycontrast IV RC B&W G-4037, 4 filter grades 0.039 D
Kodak Portra Endura RA4 E-4021, Status A R/G/B 0.030 D
Kodak Supra Endura RA4 E-4021, Status A R/G/B 0.036 D
Kodak Ultra Endura RA4 E-4020, Status A R/G/B 0.043 D

Existing profiles are byte-identical. The Endura dye matrix moved into a shared constant with the same values.

Fit method

scripts/fit_paper_profile.py is rewritten. It renders through the app's own print_curve (default sliders, paper white on, no BPC). It does not use a copy of the curve math.

The slope is not free. grade_to_slope sets k = 2.9 / (R/100) density per log E, independent of the negative, so each curve's slope comes from its measured ISO R. With a free slope (the old script), the fit converged on soft knees (sharpness ≈ 1) under a steep line. That shape renders flat at the user's grade. d_min is the measured base. One shape is shared across a B&W grade family. For RA4, the shape is fitted on the mean curve, then each channel gets a slope gain (channel_gamma) and a base tint.

Constraints found

  • Midtone gamma headroom. Snap (±0.5) and its per-layer trims (±0.5) add to the profile's paper_midtone_gamma, and the kernel needs |γ| < 1. Unbounded fits wanted 0.5–0.63, so the fit bounds it at ±0.25. A new test holds every profile to that.
  • Dye matrix. Matrices integrated from the datasheet dye-density curves at Status A kept only 42–75% of chroma, against 76–89% for the existing papers, so prints looked dull. They hold the dyes' unwanted absorptions but not the interimage effects that offset them. The E-4021 curves also carry a ~0.15 D baseline. The new RA4 papers share the existing Endura matrix.
  • Per-channel D-max spread (Premier red 2.76 vs blue 2.44) cannot be expressed: the profile has one d_max.

Not included

  • Fuji papers: the datasheets have dye-density curves only, no characteristic curves.
  • Foma Fomaspeed Variant III: the PDF draws its curves as fragmented outlines that cannot be split by grade.
  • Ilford MG RC, MG FB Warmtone, Kentmere VC Select: raster curves only.
  • Endura Premier (E-4070, RMS 0.031) and MG FB Classic (RMS 0.034) also fit their datasheets, but the profiles keep their hand-tuned values. A switch would change existing edits and needs a THUMBNAIL_RENDER_VERSION bump.

Test plan

  • make all: 8750 passed
  • Headless app run (Xvfb): each new paper appears in the Paper dropdown for its mode, renders finite pixels and differs from Neutral
  • Existing 7 profiles field-identical to main
  • Visual check of the new papers on real scans

Add five paper profiles fitted to Kodak datasheet curves read from the
PDFs' vector paths:

- B&W: Polymax II RC (G-26, 7 grades), Polycontrast IV RC (G-4037, 4 grades)
- RA4: Portra Endura, Supra Endura (E-4021), Ultra Endura (E-4020)

scripts/fit_paper_profile.py now fits through the app's own print_curve
at the slope the Grade gives each curve's measured ISO R. The old free
slope traded against knee sharpness and converged on soft knees under a
steep line. Fit RMS: 0.022-0.043 D.

Paper midtone gamma is bounded to +-0.25 (new test), since Snap and its
per-layer trims add to it below the kernel's |gamma| < 1 bound.

The new RA4 papers share the existing Endura dye matrix. Matrices
integrated from the datasheet dye-density curves kept 42-75% of chroma
(vs 76-89%): they hold unwanted absorptions but not the interimage
effects that offset them, and the E-4021 curves carry a baseline offset.

Existing profiles are unchanged.
@marcinz606
marcinz606 merged commit ab272a0 into main Oct 11, 2026
1 check passed
@marcinz606
marcinz606 deleted the feat/datasheet-paper-profiles branch October 11, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant