LatentOperationTonemapReinhard
Reinhard tonemapping, latent-style
- LATENT_OPERATION
Sometimes your sampler output looks like it was blasted with a flash: blown highlights, oversaturated color, a latent that's simply too hot. That's a dynamic-range problem in latent space, and this node is a deliberately surgical fix for it. LatentOperationTonemapReinhard is an experimental node that applies the classic Reinhard tonemapping curve - borrowed from HDR photography - to the magnitude of the latent vector. It doesn't change what the latent says, it tames how loud it says it.
What "tonemap the latent" means
The trick is the operation's structure. A latent vector has both a direction (what it encodes) and a magnitude (how strongly it says it). Reinhard tonemapping normalizes each latent vector to its unit direction, then compresses the magnitude through the curve m / (m + 1) - which pulls extreme magnitudes back toward sane values while leaving moderate ones almost untouched. The result: clipping and blowout get compressed without destroying the content. It's the same idea as the dynamic-thresholding tricks people use to save oversaturated generations, but done in latent space as a first-class operation instead of as a sampler hack.
One input: multiplier (default 1.0, range 0–100). It scales where the compression curve kicks in - higher lets more headroom through before compression bites. Start at 1.0; dial up if the result looks too flat, dial down if the burn is still there.
The LATENT_OPERATION type - what it actually is
Here's the part that confuses people: this node does not output a latent. It outputs a LATENT_OPERATION - a reusable function object. To use it you feed it into LatentApplyOperation (which applies the operation to a latent) or LatentApplyOperationCFG (which applies it during CFG guidance). There's a LatentOperationSharpen sibling in the same family, and the whole group is marked experimental, so expect the API to breathe.
That indirection is a feature: build the operation once, apply it wherever you need it, and you can reorder or re-use it without re-wiring the whole graph.
When to reach for it
The honest use case: you've got a workflow that regularly produces clipped, oversaturated, or "burned" output - often from aggressive guidance or from sampling near the edge of a model's latent range - and you want a deterministic fix rather than just lowering CFG and losing definition everywhere. It's the node you reach for after the obvious knobs (CFG, denoise) have failed and you've confirmed the problem is dynamic range, not prompting. It is not a general-purpose "make my images nicer" filter - applied to healthy latents it will just flatten them.
Gotchas
It's experimental, so treat it as a tool you verify per-model rather than a default. multiplier is the whole control surface - too high and the compression never engages, too low and everything goes dull and contrastless. And remember the two-step flow: build the operation here, apply it with LatentApplyOperation - forgetting that second node is the single most common way this ends up in a dead end, with a LATENT_OPERATION sitting where the graph expected a LATENT.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| multiplier | FLOAT | 1.000–100 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT_OPERATION | LATENT_OPERATION | — |