lapstack

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

RowWhat it is
LAPThe pyramid result, retouched if you retouched it
DFRThe depth-map rendering, when it ran
WAVThe weighted average, when it ran
Kept resultsEach kept result, cut to its own crop and carrying its own metadata
DepthThe depth map, eight-bit gray PNG, scaled from its own minimum to maximum
Depth 16The depth map, sixteen-bit PNG on a fixed scale (65535 = last frame)
ConfidenceSixteen-bit PNG, 65535 = 1
WinnerThe raw pyramid winner map
StereoThe stereo pair
3dThe 3D model
AnimationsFocus 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.

Note

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:

AnimationWhat it shows
Focus depthThe depth map in Turbo with the slice sweeping through the frames
In focusThe In-focus sweep
SourceThe aligned source frames under their peaking band
RockingThe 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.

Warning

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:

TokenBecomes
lapstackThe literal word
EXIF date/timeOf 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 nameA date found in the first frame's file name
Current date/timeNow
Custom textWhatever you type
Stack numbers01, in a batch
Layer namelap, 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.

Source: sites/lapstack/content/docs/app/saving.md