Skip to content

iccMAX hybrid printer reflectance: proposed plug-in entry points #596

Description

@maxderhak

Following on from the discussion in #593.

Hi Marti,

Thank you — both for taking the time to read it line by line, and for being straightforward about
where the project stands. Your proposal works for me: define the plug-in entry points first, then a
roadmap, and decide on packaging afterwards. And I agree with your instinct that a completely separate
package is the cleaner answer. I have no interest in putting you in the position of maintaining
iccMAX, or of competing with the branch you're building a business on. A narrow plug-in that reads
reflectance out of one profile class is a very different thing from a complete, GPU-accelerated iccMAX
implementation.

The channel count. I think this is worth separating carefully from the redesign you've quite
reasonably never dared to merge. I am not asking for dynamic channel counts, or for cmsMAXCHANNELS to
change, or for transforms or colour spaces to widen. Transforms in cmsxform.c would stay at
cmsMAXCHANNELS, and a wide pipeline would be evaluatable with cmsPipelineEvalFloat but never usable as
a transform — my prototype respects that boundary deliberately.

The narrow observation is that the multi-process element evaluators are already written for
MAX_STAGE_CHANNELS: Storage[2][MAX_STAGE_CHANNELS] in the pipeline evaluator, In16/Out16 at
MAX_STAGE_CHANNELS in the 16-bit path, and cmsStageSampleCLutFloat already bounds against it.
cmsStageAllocCLutFloatGranular has never bounded output channels at all. So those buffers, and the
stack they occupy, exist in master today; only cmsPipelineAlloc refuses to create a pipeline that
would use them. That's why I don't think this one carries the minimum-system-requirements cost of the
bigger redesign — nothing gets wider, an existing width simply becomes reachable. If you disagree
after looking, that's the single change I'd most want your judgement on, because everything else in
the proposal is genuinely additive and this one isn't.

The entry point list you asked for. The prototype was built specifically to find the minimum, and
it reads the reflectance out of the test profile through four registrations, none of which override
anything in the core — no re-implementation of 'cvst', 'clut', 'matf', 'mpet', 'curf', 'parf' or
'samf'. Existing hooks carried three of the four: cmsPluginMultiProcessElement for the extended CLUT
element, cmsPluginTagType plus cmsPluginTag for the embedded profile, and cmsPluginParametricCurves
for the ICC.2 formula functions.

What the core would need, in the order I'd defend it:

  1. A curve encoding hook. singleSampledCurve is an alternative encoding of a curve inside the
    standard 'cvst' element rather than a new element type, and there is no hook at that level. This is
    the one genuinely new piece of plug-in architecture, and it's the largest single thing that
    otherwise has to sit in the core — about 145 lines. It would also cover ICC.2's
    sampledCalculatorCurve later.

  2. Making parametric curve serialization plug-in aware. ReadSegmentedCurve and WriteSegmentedCurve
    each keep a private static table of parameter counts and reject function types above 2, while
    cmsPluginParametricCurves already requires plug-ins to declare FunctionTypes[] and
    ParameterCount[], and GetParametricCurveByType already does a plug-in-first lookup. So today a
    registered curve type can be evaluated but never serialized. Wiring those two functions to the
    existing lookup closes that gap and is what makes the ICC.2 formula types a plain registration.
    Roughly 27 lines. One caution I hit: a naive parameter-count lookup also claims lcms's private
    types 108 and 109, which would then serialize as bogus ICC function types — your Type > 2 check
    is currently preventing that by accident, so the replacement needs to be restricted to the
    built-in formula types.

  3. The channel ceiling above, which is not a plug-in hook.

  4. One line in _cmsReadHeader. It tests Version > 0x5000000, and the embedded profile is BCD 5.1.0,
    so cmsOpenProfileFromMem returns NULL before any handler can run. Since master already accepts
    5.0.0, and ICC.2 7.2.6 intends minor version bumps to remain processable by existing CMMs, gating
    on the major version looks to me more like a fix than a feature.

Items 1 and 2 are the plug-in architecture evolving. Items 3 and 4 are eighteen lines between them.

The plug-in implementation is on the iccmax-plugin-hybrid-printer-spectral branch of my fork if it's useful when you're drawing
up the roadmap. I'm not asking you to merge the original PR — it was written before this conversation
and it's the wrong shape now. Treat it as a reference implementation rather than a merge request, and
I'm glad to close it or convert it to a draft, whichever is less noise for you.

On timing, a month is completely fine, and August being slow is understood. Where such a plug-in is
hosted is entirely open. However, some changes to little-cms would be appreciated to make it happen.

As I mentioned earlier, I really would like to avoid adding spectra to version 4 profiles. Especially
if it is to accomplish something very similar to what I am proposing with this plug-in. I believe that
supporting something like that would be about as invasive/involved in terms of implementation (including
the need to address more than 15 channels to some extent).

Thanks again for engaging with this so seriously.

Max Derhak

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions