Files

219 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Production replacements for retired IDs
The former replacement previews are now the production nodes. Their historical
Python IDs still contain `Preview` from the testing period, but ComfyUI
displays the proper names below. Superseded IDs are no longer registered.
No workflow JSON is bundled in this repository. The historical local v5.3
workflow uses the production replacements but still needs current editor target
labels and gate socket wiring; v5.2 additionally uses removed node IDs.
See the [current editor wiring](SmartPhotoPrepare.md).
## Migrating a saved workflow
Restart the ComfyUI server and refresh the browser. Reconnect matching sockets
and copy old widget settings when replacing a node manually; changing a node
type does not migrate its widget values automatically. Keep a copy of the old
workflow for comparison.
| Existing node | Replacement display name | Replacement ID |
| --- | --- | --- |
| Stitch by Mask (`StitchByMaskV2`) | Stitch by Mask | `PortraitStitchPreview` |
| Simple Image Saver | Simple Image Saver | `PortraitImageSaverPreview` |
| Process Scanned Photo | Process Scanned Photo | `PortraitScannedPhotoPreview` |
| Paired Image Loader | Paired Image Loader | `PortraitPairedLoaderPreview` |
| Crop by Margins (Image) | Crop by Margins (Image) | `PortraitCropImageMarginsPreview` |
| Crop by Margins (Mask) | Crop by Margins (Mask) | `PortraitCropMaskMarginsPreview` |
Existing required/optional/hidden socket names, existing widget order/types,
defaults, and output types/order are mostly retained. The saver and paired
loader add optional widgets. Reconnect old graphs by socket name and copy the
intended settings; similarly named controls need not have identical behavior.
## Stitch by Mask
Same inputs as `StitchByMaskV2`: `image_a`, `image_b`, the existing
`PORTRAIT_EDIT_CONFIG_V2` bundle, `opacity_source`, inversion, bypass,
feather radius, and optional force-size dimensions; optional `mask`.
Same outputs: `stitched` IMAGE, `processed_mask` MASK.
Changes:
- Feathering operates on coverage first. Configured opacity is applied **once,
last**, so the effective mask cannot exceed the selected blend/stitch opacity.
Earlier versions could turn a 75% blend into nearly 100% after feathering.
- Feathering is an outward Gaussian halo, bounded by `feather_radius`, with
original soft coverage retained. There is no binary threshold or disk-dilation
pass. Retune the radius if comparing
with results saved by earlier versions.
- Constant masks retain their coverage at image edges. CPU feathering uses
OpenCV's efficient separable blur; non-CPU tensors use separable PyTorch
filtering on their current device. No shaders/models are involved.
- `processed_mask` is standard ComfyUI **BHW**.
HW and BHW1 inputs are accepted too; any 3D mask is interpreted as BHW,
including one-pixel-wide masks. Wrap HWC1 as BHW1 explicitly.
- The source A batch is authoritative. B and mask may each have one member or
match A's count. A single member broadcasts; other counts are rejected.
- RGBA is retained and blended using premultiplied color weights, preventing
transparent hidden RGB from tinting visible pixels. RGB/grayscale can be
promoted when paired with an RGBA image. Alpha-aware image resizing avoids
hidden-color bleed. RGB-only blends still use the legacy sRGB interpolation.
- Source dimensions, dtype, and device are retained unless force-size is on.
Half inputs are processed in float32; double inputs remain double. Images and
masks must be finite, normalized 0–1. Mismatches produce actionable errors.
With force-size on, output actually changes to the target dimensions; this is
intentional compositing alignment, not the analysis-only option in white balance.
Images use antialiased bilinear resizing; masks use nearest-neighbor resizing
before feathering. With force-size off, all spatial dimensions must match.
## Simple Image Saver
Same existing controls: `images`, `output_path`, `filename`, `suffix`,
`file_format` (PNG/JPG), `jpeg_quality`, `include_metadata`, and
`unique_filenames`. This remains an output node with **no graph output sockets**;
its result is the usual ComfyUI saved-image UI preview.
New optional controls:
- `png_bit_depth`: **8-bit** (default, same output precision as before) or
**16-bit**, preserving more of the working float image's precision. PNG16
supports grayscale, RGB, and RGBA, including workflow metadata. It cannot
restore detail already lost earlier in the pipeline.
- `jpeg_alpha_background`: **White** (default) or **Black**. PNG retains alpha;
JPEG composites RGBA onto this matte rather than silently discarding alpha.
Changes:
- Encode a temporary file in the destination directory and publish only a
complete, synced image. Encoding/publication failures clean up the temporary
file. Existing destination files remain intact when encoding fails.
- Unique mode atomically publishes through a no-overwrite hard link and retries
numbered collisions. This requires a destination filesystem supporting hard
links. Failure is explicit; it never silently switches to overwriting.
- `unique_filenames=false` is an explicit overwrite choice and uses atomic
replacement after successful encoding. Batch filenames keep their index.
- Relative output paths stay under ComfyUI/output, including symlink checks.
Explicit absolute paths remain supported. Necessary directories are created.
- Filename/suffix components cannot create subdirectories, contain control
characters, or use reserved device names. Excessively long names are rejected.
- Grayscale works; float16/bfloat16 and other float inputs are safely converted
for encoding. NaN/infinite inputs are rejected. Finite out-of-range pixels
are clamped for display-format export, as in the old saver.
- PNG workflow text supports Unicode. Non-finite numbers in workflow metadata
are written as JSON `null` with a warning; the live workflow is not changed.
Other invalid workflow JSON produces an error before image writes. Disabling
metadata bypasses it; the global ComfyUI setting is respected. Oversized JPEG
comments are omitted with a warning; use PNG for a large workflow.
- External-directory UI previews copy already encoded bytes, preserving JPEG
quality and PNG16 precision instead of re-encoding. If creating this preview
fails after a successful save, the error reports the real saved path.
Atomicity applies to each file, not an entire batch. Successfully published
earlier batch files remain if a later file fails. The saver does not infer or
convert a tensor's color profile; use a color-managed loader for your working
photos. It does not copy original EXIF or invent a source ICC profile.
PNG16 uses [OpenCV's documented unsigned-16-bit PNG encoder](https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html),
with workflow text written as standard [PNG text chunks](https://www.w3.org/TR/png-3/).
JPEG workflow comments use [Pillow's JPEG comment support](https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#jpeg).
## Process Scanned Photo
The original five controls remain: `image`, `straighten`, `crop_mode`, `padding`,
and `threshold`. One IMAGE output. This is still a narrow scanned-print utility,
not a subject cropper or perspective correction node.
- **Scanner Bed Only** detects a dominant rectangular print against a bright
scanner background and crops around its outer physical boundary. A distinct
print border is retained, including a Polaroid's thicker lower border.
- **Inner Photo Frame** starts from that print boundary, then seeks a broadly
supported rectangular image/paper seam to remove the actual print frame too.
It can fall back to conservative uniform-border detection for bright photos
that do not qualify for the threshold-based inner detector.
- **None** skips cropping; straightening can still operate if enabled.
Straightening uses the dominant rectangular print, not the convex hull of all
dark marks on the scanner bed. Isolated dust does not extend that rectangle.
Confidence checks require bright matching corner background, a substantial
rectangular region, and room around the print. Uncertain angle/boundary estimates
are not forced. Outer detection uses contrast with the scanner bed rather than
assuming the print's own white paper is the same thing as the scanner background.
`threshold` is the minimum scanner-background brightness for outer detection
and the bright-paper/darker-image divider for the inner threshold detector.
It also influences the fallback uniform-border tolerance. It is no longer a
single blind threshold for every stage. Adjust it to your scanner/print.
`padding` is applied once around the final crop: positive retains extra context,
negative crops further inward. Negative padding that removes the detected image
raises an explanatory error. Scanner Bed Only can conservatively retain a thin
scanner-bed fringe to avoid clipping physical print edges.
Analysis is bounded to a 2048-pixel longest side, but **the actual pixels are
never converted to 8-bit**. Crop-only processing is an exact slice of the original
floating-point data. Rotation necessarily resamples the original full-resolution
image once; dimensions expand to avoid clipping. Grayscale/RGBA, source dtype,
and source device are preserved; geometry analysis/rotation are CPU/OpenCV work.
RGBA rotation uses premultiplied colors. Differently sized batch results are
padded white at bottom/right, not resized to each other.
Limitations: one dominant print per scan; no perspective correction, semantic
paper model, or guaranteed recovery of white-on-identical-white boundaries.
Bright/textured frames, extreme dust, multiple prints, very thin low-contrast
paper edges, or prints touching canvas edges can remain ambiguous. Inspect real
scans before trusting a large batch. No settings mean “remove the subject.”
## Paired Image Loader
The original inputs remain: `source_dir`, `output_dir`, `reverse`, and
`strip_trailing_numbers`. Outputs remain **output_image, source_image, filename**
in that order. Relative directory paths retain the old behavior: relative to
the current process directory. Absolute paths are least ambiguous.
Pairs match case-insensitive basenames, not file extensions. Natural sorting
puts photo2 before photo10. A trailing `(n)` copy marker is ignored for matching
only when requested; ordinary filename digits are never stripped. `filename`
remains the actual source stem, matching the old output contract.
Changes:
- Each node instance has independent, bounded cursor state. Separate nodes do
not affect one another even when using the same folders or hidden node ID.
- Positions track the last successfully loaded basename, not an unstable numeric
index. Adding an earlier file does not shift the cursor. Switching folder pairs
preserves each folder pair's position. Removing the previous pair restarts
from the first (or last in reverse).
- Both files decode before the cursor advances. A broken second file retries
the same pair until fixed; it does not silently skip or misalign images.
- Every queued execution reloads/advances; cycling back to an earlier pair does
not reuse a cached old image. Reverse starts from the last pair and wraps.
- Ambiguous name collisions are errors unless there is exactly one common-
extension pairing. Unmatched basenames are reported once per changed list.
- Uses the tested Photo Loader preview decoder: EXIF orientation once, preserved
16-bit samples, optional 8-bit ICC conversion, and explicit alpha compositing.
New optional controls: `color_management` (Convert to sRGB / Keep encoded values)
and `alpha_background` (White / Black), with the same defaults and limitations
as [Photo Loader](PhotoLoaderPreview.md), including explicit errors for 16-bit
ICC conversions that would otherwise lose precision. Animated/multipage files
use their first image. No resize aligns the two images automatically.
## Crop by Margins: Image and Mask
Same controls: `left_px`, `top_px`, `right_px`, `bottom_px`, and `snap_multiple`.
The image preview has `image` input/output; the mask preview has `mask`
input/output. Use identical margin values for both.
The two previews share one crop-box calculation. They preserve source pixels,
precision, channels, and device without clamping, resampling, or color changes.
MASK accepts HW/BHW/BHW1 and returns standard BHW, including multi-image batches.
Every 3D MASK is BHW; use a batch dimension for HWC1 masks.
Nonnegative margins trim inward. `snap_multiple` rounds the remaining width and
height **down**, keeping the top-left fixed; any extra trim comes from right and
bottom. There is no protection-mask or semantic framing logic in these manual
nodes. Margins that remove the entire image, or a requested multiple larger than
the remaining crop, raise an explanation instead of producing a hidden
one-pixel result that does not honor the settings. No negative-margin padding,
fill-color, or enforce-even widgets exist.