Saving
Press 2 Save (or the 2 key). The Save step takes over the whole window and shows one
card: a file list of everything this run can produce, each row with a checkbox, a
thumbnail and the exact file name, followed by the settings that shape them.
Tick what you want and save — to a folder you choose (folder…, Chrome and Edge via the File System Access API) or as ordinary downloads. When several files are saved at once a browser may ask permission.
The file list
| Row | What it is |
|---|---|
| LAP | The pyramid result, retouched if you retouched it |
| DFR | The depth-map rendering, when it ran |
| WAV | The weighted average, when it ran |
| Kept results | Each kept result, cut to its own crop and carrying its own metadata |
| Depth | The depth map, eight-bit gray PNG, scaled from its own minimum to maximum |
| Depth 16 | The depth map, sixteen-bit PNG on a fixed scale (65535 = last frame) |
| Confidence | Sixteen-bit PNG, 65535 = 1 |
| Winner | The raw pyramid winner map |
| Stereo | The stereo pair |
| 3d | The 3D model |
| Animations | Focus depth sweep, In focus sweep, Source frames with peaking, Rocking |
Format and bit depth
The stacked images can be saved as:
- PNG at the input bit depth — sixteen-bit if the input was sixteen-bit or raw. This is the one to pick for anything you will edit further.
- Eight-bit PNG
- JPEG, with a quality slider
- DNG, linear (camera space) — only after a run made with the linear DNG option; see below
Output keeps the input's bit depth by default, and sixteen bits need PNG or TIFF. A raw counts as sixteen-bit.
Linear DNG
linear DNG in the Run ▾ menu, before the run. The Run button then reads → DNG.
This is Helicon Focus's "RAW in, DNG out", and it has to be decided before the run because it changes how the frames are developed.
With it on, the raws are not developed to sRGB at all. Each is decoded to the camera's own linear space — black and white levels, demosaic, the sensor's crop, turned by its orientation, and nothing else — and the stack is fused in a look space built from frame 0's as-shot white balance and the camera's D65 matrix followed by the sRGB curve. That is the ordinary development, except that nothing is clipped: the curve is extended above 1 and mirrored below 0, so a highlight past white or a color outside sRGB keeps its value and the transform stays invertible.
Two things follow. The fusion makes the same decisions it would have made on a normally developed stack (the luminance it selects by is the ordinary one), and every frame is developed alike, with frame 0's white balance applied to all — which is exactly what a stack needs.
The result is then taken back through the inverse curve, the inverse matrix and the inverse
white balance into camera space, and written as a DNG 1.4 with LinearRaw photometric
interpretation, sixteen bits per sample, the camera's color matrices and illuminants,
AsShotNeutral, UniqueCameraModel, Make and Model, the first frame's Exif IFD and XMP, and
Orientation 1.
A raw converter then develops the stacked image like one of the raws — exposure, white balance, profile and highlight recovery all still open, with the camera data above the balanced white preserved where an sRGB development would have clipped it.
Checked on five Nikon Z 8 NEFs: darktable develops the DNG and the first NEF to the same colors and brightness.
A stack must be all raws or none. Frames that are not raws are taken as sRGB — their linear values are the "camera space", ColorMatrix1 is XYZ → sRGB at D65 and the neutral is 1, 1, 1 — so any stack can come out as a DNG, but only a raw stack's carries more than its files did.
The browser's frames are sixteen-bit, so a highlight past the balanced white is clipped there where the command line keeps it. The color matrices, neutral and metadata are the same.
The slabs, the weighted average and the stereo pair are DNGs too; the rocking views are TIFFs (a video is made from them) and the depth maps are PNGs.
Cropping
Every file, animations included, is cropped to the area all aligned frames cover — see alignment. The run reports the window; the card's Crop section shows its size, has the switch, and offers set a window…. The viewer shows the window as the bright part of the image while cropping is on.
Metadata
The stacked images carry the first frame's EXIF, ICC profile and XMP, read from the first frame's own bytes during the run. The card's Metadata section says what was found and has the switch.
A raw's EXIF Orientation is reset to 1 in every output, since the frame was already turned as it was decoded and a viewer must not turn the result again.
Formats and metadata has the details of what is carried where.
Animations
Four animations, each rendered exactly as the viewer shows that layer:
| Animation | What it shows |
|---|---|
| Focus depth | The depth map in Turbo with the slice sweeping through the frames |
| In focus | The In-focus sweep |
| Source | The aligned source frames under their peaking band |
| Rocking | The stacked image rocking from side to side |
Settings: every Nth frame, speed, loop direction (back and forth, or forward), and a long edge. The card estimates the file size.
A full-resolution GIF of a long 45-megapixel stack runs to gigabytes. Set a long edge, a frame step, or both.
The Source and In-focus frames are decoded and re-aligned at full resolution by the engine and then scaled to the chosen long edge, so the animation is made from real pixels rather than from the proxies on screen.
GIF
Frames are quantized (median cut, Floyd–Steinberg) and LZW-encoded in the worker, with the bytes streaming back, so the file never sits in WebAssembly memory as a whole.
MP4 and WebM
The section's format makes the same animations videos instead:
- MP4 (H.264) — High, Main or Constrained Baseline at whatever level the size needs
- WebM (VP9) — profile 0, falling back to VP8
Each frame is drawn as for the GIF and encoded by the browser's own encoder through WebCodecs, then written into the container by the page itself. Whichever the browser supports at that size wins, so a 4K rocking animation that no encoder will take asks you for a smaller long edge.
Video quality sets the bit rate in bits per pixel per second (0.2 / 0.1 / 0.05). The size is made even for 4:2:0 chroma, a keyframe goes in every two seconds, and the rocking is one sine cycle so a player's loop is seamless.
A browser without WebCodecs (Firefox before 130, older Safari) gets the GIF alone. Videos carry no content credentials.
File names
Names are built from tokens joined with _, lower case:
| Token | Becomes |
|---|---|
lapstack | The literal word |
| EXIF date/time | Of the first frame, read from its JPEG APP1, TIFF or PNG eXIf structure — falling back to the XMP packet's CreateDate, which may be all a raw converter's TIFF has |
| Date/time in the name | A date found in the first frame's file name |
| Current date/time | Now |
| Custom text | Whatever you type |
| Stack number | s01, in a batch |
| Layer name | lap, dfr, stereo, 3d, depth, depth16, winner, depth-slice, infocus, peaking, rocking |
Content credentials
C2PA content credentials can be attached to every saved file.
A self-signed ES256 certificate is generated in the browser for the signed as name and
kept in localStorage; the private key never leaves your machine. The manifest carries a
c2pa.created action (compositeCapture) and an org.lapstack.stack assertion recording the
frames, the fusion parameters and the retouch strokes, and is embedded and signed.
Verifiers will show the manifest, the assertions and the content hash as valid, and the signer as unknown — a self-signed certificate is on no trust list. That is the honest state of affairs: the credential proves the file has not been altered since lapstack wrote it and records how it was made, but it does not attest to who you are.
The C2PA library is large, so it is a second WebAssembly module that the worker loads on the first signed save.