diff --git a/backend/src/api.py b/backend/src/api.py index 3429784a9..b88a2fbc4 100644 --- a/backend/src/api.py +++ b/backend/src/api.py @@ -127,10 +127,21 @@ def register( decorators: List[Callable] | None = None, see_also: List[str] | str | None = None, features: List[FeatureId] | FeatureId | None = None, + limited_to_8bpc: bool | str = False, ): if not isinstance(description, str): description = "\n\n".join(description) + if limited_to_8bpc: + description += "\n\n#### Limited color depth\n\n" + if isinstance(limited_to_8bpc, str): + description += f" {limited_to_8bpc}" + else: + description += ( + "This node will internally convert input images to 8 bits/channel." + " This is generally only a problem if you intend to save the output with 16 bits/channel or higher." + ) + def to_list(x: List[S] | S | None) -> List[S]: if x is None: return [] diff --git a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/image_to_image.py b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/image_to_image.py index f3e1a5928..9870b73f1 100644 --- a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/image_to_image.py +++ b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/image_to_image.py @@ -100,6 +100,7 @@ def nearest_valid(n: number) = floor(n / 8) * 8; ], decorators=[cached], features=web_ui, + limited_to_8bpc=True, ) def image_to_image_node( image: np.ndarray, diff --git a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/inpaint.py b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/inpaint.py index d2a72d387..330ad896a 100644 --- a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/inpaint.py +++ b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/inpaint.py @@ -129,6 +129,7 @@ def nearest_valid(n: number) = floor(n / 8) * 8; ], decorators=[cached], features=web_ui, + limited_to_8bpc=True, ) def inpaint_node( image: np.ndarray, diff --git a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/outpaint.py b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/outpaint.py index 9258d1af6..03c739731 100644 --- a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/outpaint.py +++ b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/outpaint.py @@ -159,6 +159,7 @@ def nearest_valid(n: number) = ceil(n / 64) * 64; ], decorators=[cached], features=web_ui, + limited_to_8bpc=True, ) def outpaint_node( image: np.ndarray, diff --git a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/upscale.py b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/upscale.py index e80e75fde..d2e54f464 100644 --- a/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/upscale.py +++ b/backend/src/packages/chaiNNer_external/external_stable_diffusion/automatic1111/upscale.py @@ -127,6 +127,7 @@ def nearest_valid(n: number) = max(1, floor(n)); ], decorators=[cached], features=web_ui, + limited_to_8bpc=True, ) def upscale_node( image: np.ndarray, diff --git a/backend/src/packages/chaiNNer_ncnn/ncnn/processing/upscale_image.py b/backend/src/packages/chaiNNer_ncnn/ncnn/processing/upscale_image.py index a171c525f..8703b68c0 100644 --- a/backend/src/packages/chaiNNer_ncnn/ncnn/processing/upscale_image.py +++ b/backend/src/packages/chaiNNer_ncnn/ncnn/processing/upscale_image.py @@ -142,6 +142,7 @@ def estimate_cpu(): outputs=[ ImageOutput(image_type="""convenientUpscale(Input0, Input1)"""), ], + limited_to_8bpc=True, ) def upscale_image_node( img: np.ndarray, model: NcnnModelWrapper, tile_size: TileSize diff --git a/backend/src/packages/chaiNNer_onnx/onnx/processing/remove_background.py b/backend/src/packages/chaiNNer_onnx/onnx/processing/remove_background.py index 9380a0a72..3cb4bf541 100644 --- a/backend/src/packages/chaiNNer_onnx/onnx/processing/remove_background.py +++ b/backend/src/packages/chaiNNer_onnx/onnx/processing/remove_background.py @@ -42,6 +42,7 @@ ), ImageOutput("Mask", image_type=navi.Image(size_as="Input0"), channels=1), ], + limited_to_8bpc=True, ) def remove_background_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_pytorch/pytorch/restoration/upscale_face.py b/backend/src/packages/chaiNNer_pytorch/pytorch/restoration/upscale_face.py index dc5a14f0e..9c8a698d2 100644 --- a/backend/src/packages/chaiNNer_pytorch/pytorch/restoration/upscale_face.py +++ b/backend/src/packages/chaiNNer_pytorch/pytorch/restoration/upscale_face.py @@ -146,6 +146,7 @@ def upscale( channels=3, ) ], + limited_to_8bpc=True, ) def upscale_face_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image/batch_processing/video_frame_iterator.py b/backend/src/packages/chaiNNer_standard/image/batch_processing/video_frame_iterator.py index eeb2817cb..6cfea036d 100644 --- a/backend/src/packages/chaiNNer_standard/image/batch_processing/video_frame_iterator.py +++ b/backend/src/packages/chaiNNer_standard/image/batch_processing/video_frame_iterator.py @@ -197,6 +197,7 @@ def iterator_helper_write_output_frame_node( }, ], side_effects=True, + limited_to_8bpc="The video will be read and written as 8-bit RGB.", ) async def video_frame_iterator_node(path: str, context: IteratorContext) -> None: logger.debug(f"{ffmpeg_path=}, {ffprobe_path=}") diff --git a/backend/src/packages/chaiNNer_standard/image/io/save_image.py b/backend/src/packages/chaiNNer_standard/image/io/save_image.py index 614f8d472..2ae2f3b21 100644 --- a/backend/src/packages/chaiNNer_standard/image/io/save_image.py +++ b/backend/src/packages/chaiNNer_standard/image/io/save_image.py @@ -199,6 +199,7 @@ class TiffColorDepth(Enum): ], outputs=[], side_effects=True, + limited_to_8bpc="Image will be saved with 8 bits/channel by default. Some formats support higher bit depths.", ) def save_image_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image/io/view_image_external.py b/backend/src/packages/chaiNNer_standard/image/io/view_image_external.py index 76ca82dc7..a2ee34200 100644 --- a/backend/src/packages/chaiNNer_standard/image/io/view_image_external.py +++ b/backend/src/packages/chaiNNer_standard/image/io/view_image_external.py @@ -27,6 +27,7 @@ inputs=[ImageInput()], outputs=[], side_effects=True, + limited_to_8bpc="The temporary file is an 8-bit PNG.", ) def view_image_external_node(img: np.ndarray) -> None: tempdir = mkdtemp(prefix="chaiNNer-") diff --git a/backend/src/packages/chaiNNer_standard/image_adjustment/adjustments/threshold_adaptive.py b/backend/src/packages/chaiNNer_standard/image_adjustment/adjustments/threshold_adaptive.py index 8e35e8d58..1321aae51 100644 --- a/backend/src/packages/chaiNNer_standard/image_adjustment/adjustments/threshold_adaptive.py +++ b/backend/src/packages/chaiNNer_standard/image_adjustment/adjustments/threshold_adaptive.py @@ -36,6 +36,7 @@ NumberInput("Mean Subtraction"), ], outputs=[ImageOutput(image_type="Input0")], + limited_to_8bpc=True, ) def threshold_adaptive_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_factor.py b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_factor.py index e738f9fe2..b1818008d 100644 --- a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_factor.py +++ b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_factor.py @@ -41,6 +41,7 @@ assume_normalized=True, ) ], + limited_to_8bpc=True, ) def resize_factor_node( img: np.ndarray, scale: float, interpolation: InterpolationMethod diff --git a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_resolution.py b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_resolution.py index 61d954a79..5e9b75be5 100644 --- a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_resolution.py +++ b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_resolution.py @@ -35,6 +35,7 @@ assume_normalized=True, ) ], + limited_to_8bpc=True, ) def resize_resolution_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_to_side.py b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_to_side.py index 738cb4c00..6d1172879 100644 --- a/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_to_side.py +++ b/backend/src/packages/chaiNNer_standard/image_dimension/resize/resize_to_side.py @@ -167,6 +167,7 @@ def compareCondition(b: uint): bool { assume_normalized=True, ) ], + limited_to_8bpc=True, ) def resize_to_side_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_filter/blur/median_blur.py b/backend/src/packages/chaiNNer_standard/image_filter/blur/median_blur.py index be0584642..4b28a31d8 100644 --- a/backend/src/packages/chaiNNer_standard/image_filter/blur/median_blur.py +++ b/backend/src/packages/chaiNNer_standard/image_filter/blur/median_blur.py @@ -20,6 +20,7 @@ SliderInput("Radius", minimum=0, maximum=1000, default=1, scale="log"), ], outputs=[ImageOutput(image_type="Input0")], + limited_to_8bpc=True, ) def median_blur_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_filter/correction/average_color_fix.py b/backend/src/packages/chaiNNer_standard/image_filter/correction/average_color_fix.py index 434e924e7..98ee20fe4 100644 --- a/backend/src/packages/chaiNNer_standard/image_filter/correction/average_color_fix.py +++ b/backend/src/packages/chaiNNer_standard/image_filter/correction/average_color_fix.py @@ -34,6 +34,7 @@ ), ], outputs=[ImageOutput(image_type="Input0")], + limited_to_8bpc=True, ) def average_color_fix_node( input_img: np.ndarray, ref_img: np.ndarray, scale_factor: float diff --git a/backend/src/packages/chaiNNer_standard/image_filter/noise/fast_nl_means.py b/backend/src/packages/chaiNNer_standard/image_filter/noise/fast_nl_means.py index 16e9b6458..8650d844a 100644 --- a/backend/src/packages/chaiNNer_standard/image_filter/noise/fast_nl_means.py +++ b/backend/src/packages/chaiNNer_standard/image_filter/noise/fast_nl_means.py @@ -43,6 +43,7 @@ NumberInput("Search radius", minimum=1, default=10, maximum=30, precision=0), ], outputs=[ImageOutput(image_type="Input0")], + limited_to_8bpc=True, ) def fast_nl_means_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_utility/compositing/add_caption.py b/backend/src/packages/chaiNNer_standard/image_utility/compositing/add_caption.py index 0abb2dee8..7af16eef8 100644 --- a/backend/src/packages/chaiNNer_standard/image_utility/compositing/add_caption.py +++ b/backend/src/packages/chaiNNer_standard/image_utility/compositing/add_caption.py @@ -34,6 +34,7 @@ assume_normalized=True, ) ], + limited_to_8bpc=True, ) def add_caption_node( img: np.ndarray, caption: str, size: int, position: CaptionPosition diff --git a/backend/src/packages/chaiNNer_standard/image_utility/miscellaneous/inpaint.py b/backend/src/packages/chaiNNer_standard/image_utility/miscellaneous/inpaint.py index a927e7f33..25fd1c627 100644 --- a/backend/src/packages/chaiNNer_standard/image_utility/miscellaneous/inpaint.py +++ b/backend/src/packages/chaiNNer_standard/image_utility/miscellaneous/inpaint.py @@ -57,6 +57,7 @@ class InpaintAlgorithm(Enum): ) ).with_never_reason("The given image and mask must have the same resolution.") ], + limited_to_8bpc=True, ) def inpaint_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/image_utility/modification/rotate.py b/backend/src/packages/chaiNNer_standard/image_utility/modification/rotate.py index 5af8a2357..a98787d5b 100644 --- a/backend/src/packages/chaiNNer_standard/image_utility/modification/rotate.py +++ b/backend/src/packages/chaiNNer_standard/image_utility/modification/rotate.py @@ -120,6 +120,7 @@ def transform(x: number, y: number) { assume_normalized=True, ) ], + limited_to_8bpc=True, ) def rotate_node( img: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/material_textures/conversion/metal_to_specular.py b/backend/src/packages/chaiNNer_standard/material_textures/conversion/metal_to_specular.py index 9c73e4de1..4ad35797a 100644 --- a/backend/src/packages/chaiNNer_standard/material_textures/conversion/metal_to_specular.py +++ b/backend/src/packages/chaiNNer_standard/material_textures/conversion/metal_to_specular.py @@ -81,6 +81,7 @@ def metal_to_spec( channels=1, ), ], + limited_to_8bpc=True, ) def metal_to_specular_node( albedo: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/material_textures/conversion/specular_to_metal.py b/backend/src/packages/chaiNNer_standard/material_textures/conversion/specular_to_metal.py index 5a6a34fea..a52e091d3 100644 --- a/backend/src/packages/chaiNNer_standard/material_textures/conversion/specular_to_metal.py +++ b/backend/src/packages/chaiNNer_standard/material_textures/conversion/specular_to_metal.py @@ -109,6 +109,7 @@ def spec_to_metal( channels=1, ), ], + limited_to_8bpc=True, ) def specular_to_metal_node( diff: np.ndarray, diff --git a/backend/src/packages/chaiNNer_standard/utility/clipboard/copy_to_clipboard.py b/backend/src/packages/chaiNNer_standard/utility/clipboard/copy_to_clipboard.py index 293c2a2cb..c4d103d51 100644 --- a/backend/src/packages/chaiNNer_standard/utility/clipboard/copy_to_clipboard.py +++ b/backend/src/packages/chaiNNer_standard/utility/clipboard/copy_to_clipboard.py @@ -18,6 +18,7 @@ ], outputs=[], side_effects=True, + limited_to_8bpc="The image will be copied to clipboard with 8 bits/channel.", ) def copy_to_clipboard_node(value: str | np.ndarray) -> None: if isinstance(value, np.ndarray):