整卷

整卷标签页将当前文件夹中的所有已显影帧以印样表形式展示。在此可对整卷应用统一的色调效果——色调、颜色、裁剪与片基——实时双通道预览会在您移动滑块时立即在每一帧上呈现效果,停止操作后自动持久化。您也可以从基础面板复制单帧的显影设置,并按分组应用到整卷。

印样表

印样表占据整卷标签页的主区域。胶片按六帧一行横向排列,每行称为一个,与 35 mm 胶卷的实际条长对应。图块的纵横比会自动适应本卷的实际帧形:通过 contactSheet.ts 中的 pickTileAspect() 计算所有横向帧的中位纵横比,使横向帧恰好填满图块边缘。纵向帧则在同等图块高度内信箱式显示,确保无论方向如何,每行高度保持一致。

点击任意帧,可在全屏帧预览叠加层(由 FramePreview.svelte 渲染)中查看该帧——这是一个以全分辨率 GPU 视口展示该帧已提交的显影设置与裁剪的界面。按 Esc 或点击背景可关闭。叠加层为只读模式:仅展示帧的当前状态,不会打开单帧编辑器。

印样表上方工具栏有两个控件。片边开关(标签 roll.filmEdge)在胶片条模式与普通印样网格模式之间切换——详见下文片边渲染导出印样按钮(标签 roll.export.button)通过系统保存对话框将印样导出为 PNG 文件——详见导出 →

镜像模式与入口确认

打开整卷标签页时,OpenEnlarge 会检查当前文件夹中是否有帧已具备显影编辑(色调/颜色、裁剪、片基或白点)。若存在,将弹出确认对话框——"覆盖 N 张已编辑的胶片?"(标签 confirmOverwrite.title)——提示应用整卷设置将替换各帧的独立编辑。点击全部覆盖confirmOverwrite.overwrite)继续,或点击取消confirmOverwrite.cancel)返回图库。勾选不再询问confirmOverwrite.dontAsk)可在后续访问此卷时跳过对话框。若所有帧均无编辑,镜像模式将立即启用,无需显示对话框。

确认后,整卷进入镜像模式:对右侧面板中整卷控件的任何更改都会实时映射到印样表中的所有帧。若无冲突,镜像模式在标签页打开时即处于激活状态。

实时预览与持久化(双通道模型)

镜像模式运行两个异步通道:

通道 1——预览在最后一次滑块移动后 120 ms 触发(防抖处理)。以草稿外观重新渲染每帧的缩略图并立即更新印样表,最多 5 帧并行渲染。印样表中的缩略图随结果到来逐帧替换;尚未更新的帧保持上一次的预览图。此通道不写入磁盘,也不更新任何已存储的编辑。

通道 2——持久化在最后一次更改后 600 ms 触发。它将草稿外观写入每帧的已存储编辑(editsById),若整卷裁剪已设定则将裁剪几何保存到所有帧,并通过复用通道 1 已渲染的预览图更新目录缩略图——无需二次渲染。两个通道在您实际操作控件之前(rollDraftTouched 为 false)均处于休眠状态,因此仅仅打开整卷标签页不会还原您在单帧标签页中针对各帧所做的编辑。

草稿状态在重新进入同一卷时得以保留(切换标签页后滑块位置不丢失),但当活动文件夹切换时会重置为新的默认草稿。

整卷控件

右侧面板(由 RollAdjust.svelte 渲染)标题为「整卷色调」roll.adjust.heading),包含与单帧基础面板相同的滑块:色温、色调、曝光、对比度、高光、阴影、白色、黑色、自然饱和度与饱和度,以及色调曲线。重置按钮(basic.reset)将外观恢复默认,同时保留草稿中的片基与白点不变。

标题下方、滑块上方有两个图标工具按钮,分别开启参考帧编辑模式:

  • 裁剪roll.crop.tool)——在参考帧上打开完整裁剪编辑器;结果应用到所有帧。
  • 片基roll.base.heading)——在参考帧上打开片基采样模式,并以拾取值重新校准整卷片基;新片基将设为文件夹默认值并重新播种到所有帧。用于覆盖自动计算的整卷片基(详见下文)。

自动整卷片基:显影一卷胶片时,OpenEnlarge 会自动计算统一的整卷片基——即各帧自动检测到的片基样本经置信度过滤后的逐通道中位值——并将其存储为文件夹默认值。所有帧随后以该共享片基播种。已设置逐帧 base_override 或手动选取白平衡的帧不受影响。首次打开时,尚无存储片基的旧卷将自动迁移。上方的片基参考帧编辑模式是在自动片基需要修正时使用的手动重新校准工具;它将替换存储的文件夹片基并重新播种整卷。

两种模式均采用相同的参考帧编辑布局:所选帧占据主区域,所有帧的横向胶片条沿底部排列,可在不退出模式的情况下切换参考帧;右侧面板显示相应控件,或在片基模式下保持为空(单次拾取后自动关闭)。裁剪模式下,按 Enter 或点击裁剪按钮提交几何设置;按 Esc 放弃。

标量滑块是相对的。色温、色调、曝光、对比度、高光、阴影、白色、黑色、自然饱和度与饱和度都以偏移方式叠加在每帧自身值之上,而非覆盖——因此逐帧差异得以保留(每帧保留自己的自动亮度曝光与白平衡;本就更通透的帧仍相对更通透)。移动整卷滑块会让每帧偏移相同的量,打开某帧即可看到其偏移后的值。色调曲线与片基对每帧一致施加。

用「色调与颜色」分组复制色温:应用到整卷…basic.applyToRoll)会让色温/色调随「色调与颜色」分组一起携带。(针对每帧的相对偏移复制——以 mired 进行,使偏移在不同基准色温下保持一致——计划中;在此之前色温按其滑块值复制。)

复制并应用到整卷

您也可以从整卷标签页之外将单帧的显影设置推送到整卷。在基础面板中,点击应用到整卷…按钮(basic.applyToRoll)将打开分组选择对话框——「应用到本胶卷的全部 N 张?」confirmApply.rollTitle)——包含五个复选框:

  • 色调与颜色applyGroups.toneColor)——除片基、白点、曝光、模式、胶片配置、HDR 与正片标志之外的所有显影参数。
  • 裁切applyGroups.crop)——该帧的完整 CropRect(纵横比、方向、rot90、flipH、flipV、angle、rect),以完全相同的方式应用到每帧。
  • 片基applyGroups.base)——该帧的 base_override RGB 三元组,应用到所有帧。
  • 曝光applyGroups.exposure)——该帧的绝对曝光值,应用到所有帧。
  • 白点applyGroups.whitePoint)——该帧的 d_max_override,应用到所有帧。

同样的分组选择框也会在图库中将已复制的设置(⌘C / ⌘V)粘贴到多张图像时出现。单张图像粘贴时默认仅应用「色调与颜色」分组,不显示对话框。应用辅助函数实现于 roll/apply.tsapplyToneColorToAllapplyCropToAllapplyBaseToAllapplyExposureToAllapplyWhitePointToAll),整卷镜像路径与复制/粘贴路径共用同一套函数。

片边渲染

片边开关在两种印样布局之间切换,切换时带有短暂的淡入淡出动画:

胶片条模式(片边开启):每条六帧用胶片片基包裹。帧上方:一行 CSS 渲染的齿孔,随后是等宽字体的顺序帧编号。帧下方:条形码图形、在整条宽度上重复三次的可编辑文字标记,以及方向箭头。文字标记可通过片边开启时工具栏中出现的片边文字输入框(roll.edgeText)实时编辑,其占位文字为「片边标记文字」(roll.edgeTextPlaceholder)。片基背景为深色(#131210),帧区域位于黑色行上。

印样网格模式(片边关闭):每条六帧以普通行排列。每帧显示在暖白色背景(#d8d3c4)上,带 3 px 内边距和投影,帧下方以等宽字体打印顺序编号。这与传统暗室印样的视觉效果一致。

导出印样按钮将当前激活的布局(含片边文字)通过 exportSheet.ts 渲染为固定分辨率的 PNG 文件(每个图块帧宽 260 px,每条 6 帧)。导出过程使用 Canvas 2D API 忠实复现屏幕布局中的齿孔、帧编号、条形码、片边文字与箭头元素。

深入原理

草稿状态(roll/draft.ts):rollDraft(类型为 RollDraft 的 Svelte writable store)持有 params: InvertParamscrop: CropRect | nullrollDraftTouched 是一个布尔 store,每次进入整卷标签页时初始值为 false;用户首次触动任意滑块、裁剪、片基采样或白点拾取后置为 trueRoll.svelte 中的双通道预览/持久化响应链($: if (mirrorEnabled) { schedulePreview($rollDraft); schedulePersist($rollDraft); })在 rollDraftTouched 为 false 时处于休眠状态。enterRollDraft(folder) 仅在文件夹切换时重置草稿;重新进入同一卷时保留滑块位置。

实时预览并发(Roll.svelte):预览批次最多以 5 个 api.thumbnail() 调用并行运行。单调递增的 previewToken 用于丢弃过时批次,防止慢速渲染覆盖更新结果。requestAnimationFrame 合并循环以最高约 60 次/秒的频率提交累积中的 previewMap。若批次进行中到达新草稿,将排入 previewPending,在当前批次完成后立即启动。

色调/颜色子集(roll/apply.ts):toneColorOf(p)InvertParams 对象中去除 EXCLUDE 集合(modestockbase_overrided_max_overridehdrpositiveexposure)。这是跨所有帧镜像的「共享外观」;片基、白点、曝光等逐帧校准字段仅在明确勾选时才传播。整卷面板的标量滑块以相对方式施加:apply.ts 中的 applyRollDelta / rollPreviewFrame 把滑块偏移(自上次已施加偏移以来的增量,由 rollApplied 跟踪)叠加到每帧自身值上,逐帧差异得以保留;结构性外观(色调曲线、颜色分级)仍对每帧一致广播。

图块纵横比(contactSheet.ts):pickTileAspect(aspects) 取所有横向帧(纵横比 ≥ 1)的中位值,若全为纵向或卷为空则回退到全帧或默认 3:2。每帧的有效纵横比在 Roll.svelte 中通过结合原始元数据尺寸 orientDims(w, h, rot90) 与归一化裁剪矩形尺寸(ow*rw / oh*rh)计算得出。

裁剪后 D-max 重分析(Roll.svelte applyCropAndExit()):用户提交整卷裁剪时,该函数通过 api.analyze() 对参考帧的新裁剪区域重新分析 D-max,并将结果写入草稿。若分析失败(例如该帧尚未显影),则保留原有值。

下一篇:导出 →

OpenEnlarge —— 开源胶片扫描编辑器 · MIT 许可