feat(nodes): restore canvas functionality (non-latents)

This commit is contained in:
psychedelicious 2023-05-25 00:28:04 +10:00 committed by Kent Keirsey
parent 29c952dcf6
commit 1fb307abf4

View File

@ -14,14 +14,17 @@ from invokeai.app.models.image import ImageCategory, ImageType
from invokeai.app.util.misc import SEED_MAX, get_random_seed from invokeai.app.util.misc import SEED_MAX, get_random_seed
from invokeai.backend.generator.inpaint import infill_methods from invokeai.backend.generator.inpaint import infill_methods
from .baseinvocation import BaseInvocation, InvocationContext, InvocationConfig from .baseinvocation import BaseInvocation, InvocationContext, InvocationConfig
from .image import ImageOutput, build_image_output from .image import ImageOutput
from ...backend.generator import Txt2Img, Img2Img, Inpaint, InvokeAIGenerator from ...backend.generator import Txt2Img, Img2Img, Inpaint, InvokeAIGenerator
from ...backend.stable_diffusion import PipelineIntermediateState from ...backend.stable_diffusion import PipelineIntermediateState
from ..util.step_callback import stable_diffusion_step_callback from ..util.step_callback import stable_diffusion_step_callback
SAMPLER_NAME_VALUES = Literal[tuple(InvokeAIGenerator.schedulers())] SAMPLER_NAME_VALUES = Literal[tuple(InvokeAIGenerator.schedulers())]
INFILL_METHODS = Literal[tuple(infill_methods())] INFILL_METHODS = Literal[tuple(infill_methods())]
DEFAULT_INFILL_METHOD = 'patchmatch' if 'patchmatch' in get_args(INFILL_METHODS) else 'tile' DEFAULT_INFILL_METHOD = (
"patchmatch" if "patchmatch" in get_args(INFILL_METHODS) else "tile"
)
class SDImageInvocation(BaseModel): class SDImageInvocation(BaseModel):
"""Helper class to provide all Stable Diffusion raster image invocations with additional config""" """Helper class to provide all Stable Diffusion raster image invocations with additional config"""
@ -92,7 +95,7 @@ class TextToImageInvocation(BaseInvocation, SDImageInvocation):
# each time it is called. We only need the first one. # each time it is called. We only need the first one.
generate_output = next(outputs) generate_output = next(outputs)
image_dto = context.services.images_new.create( image_dto = context.services.images.create(
image=generate_output.image, image=generate_output.image,
image_type=ImageType.RESULT, image_type=ImageType.RESULT,
image_category=ImageCategory.GENERAL, image_category=ImageCategory.GENERAL,
@ -100,35 +103,13 @@ class TextToImageInvocation(BaseInvocation, SDImageInvocation):
node_id=self.id, node_id=self.id,
) )
# Results are image and seed, unwrap for now and ignore the seed return ImageOutput(
# TODO: pre-seed? image=ImageField(
# TODO: can this return multiple results? Should it? image_name=image_dto.image_name,
# image_type = ImageType.RESULT image_type=image_dto.image_type,
# image_name = context.services.images.create_name( ),
# context.graph_execution_state_id, self.id width=image_dto.width,
# ) height=image_dto.height,
# metadata = context.services.metadata.build_metadata(
# session_id=context.graph_execution_state_id, node=self
# )
# context.services.images.save(
# image_type, image_name, generate_output.image, metadata
# )
# context.services.images_db.set(
# id=image_name,
# image_type=ImageType.RESULT,
# image_category=ImageCategory.GENERAL,
# session_id=context.graph_execution_state_id,
# node_id=self.id,
# metadata=GeneratedImageOrLatentsMetadata(),
# )
return build_image_output(
image_type=image_dto.image_type,
image_name=image_dto.image_name,
image=generate_output.image,
) )
@ -164,7 +145,7 @@ class ImageToImageInvocation(TextToImageInvocation):
image = ( image = (
None None
if self.image is None if self.image is None
else context.services.images.get( else context.services.images.get_pil_image(
self.image.image_type, self.image.image_name self.image.image_type, self.image.image_name
) )
) )
@ -194,26 +175,23 @@ class ImageToImageInvocation(TextToImageInvocation):
# each time it is called. We only need the first one. # each time it is called. We only need the first one.
generator_output = next(outputs) generator_output = next(outputs)
result_image = generator_output.image image_dto = context.services.images.create(
image=generator_output.image,
# Results are image and seed, unwrap for now and ignore the seed image_type=ImageType.RESULT,
# TODO: pre-seed? image_category=ImageCategory.GENERAL,
# TODO: can this return multiple results? Should it? session_id=context.graph_execution_state_id,
image_type = ImageType.RESULT node_id=self.id,
image_name = context.services.images.create_name(
context.graph_execution_state_id, self.id
) )
metadata = context.services.metadata.build_metadata( return ImageOutput(
session_id=context.graph_execution_state_id, node=self image=ImageField(
image_name=image_dto.image_name,
image_type=image_dto.image_type,
),
width=image_dto.width,
height=image_dto.height,
) )
context.services.images.save(image_type, image_name, result_image, metadata)
return build_image_output(
image_type=image_type,
image_name=image_name,
image=result_image,
)
class InpaintInvocation(ImageToImageInvocation): class InpaintInvocation(ImageToImageInvocation):
"""Generates an image using inpaint.""" """Generates an image using inpaint."""
@ -223,16 +201,38 @@ class InpaintInvocation(ImageToImageInvocation):
# Inputs # Inputs
mask: Union[ImageField, None] = Field(description="The mask") mask: Union[ImageField, None] = Field(description="The mask")
seam_size: int = Field(default=96, ge=1, description="The seam inpaint size (px)") seam_size: int = Field(default=96, ge=1, description="The seam inpaint size (px)")
seam_blur: int = Field(default=16, ge=0, description="The seam inpaint blur radius (px)") seam_blur: int = Field(
default=16, ge=0, description="The seam inpaint blur radius (px)"
)
seam_strength: float = Field( seam_strength: float = Field(
default=0.75, gt=0, le=1, description="The seam inpaint strength" default=0.75, gt=0, le=1, description="The seam inpaint strength"
) )
seam_steps: int = Field(default=30, ge=1, description="The number of steps to use for seam inpaint") seam_steps: int = Field(
tile_size: int = Field(default=32, ge=1, description="The tile infill method size (px)") default=30, ge=1, description="The number of steps to use for seam inpaint"
infill_method: INFILL_METHODS = Field(default=DEFAULT_INFILL_METHOD, description="The method used to infill empty regions (px)") )
inpaint_width: Optional[int] = Field(default=None, multiple_of=8, gt=0, description="The width of the inpaint region (px)") tile_size: int = Field(
inpaint_height: Optional[int] = Field(default=None, multiple_of=8, gt=0, description="The height of the inpaint region (px)") default=32, ge=1, description="The tile infill method size (px)"
inpaint_fill: Optional[ColorField] = Field(default=ColorField(r=127, g=127, b=127, a=255), description="The solid infill method color") )
infill_method: INFILL_METHODS = Field(
default=DEFAULT_INFILL_METHOD,
description="The method used to infill empty regions (px)",
)
inpaint_width: Optional[int] = Field(
default=None,
multiple_of=8,
gt=0,
description="The width of the inpaint region (px)",
)
inpaint_height: Optional[int] = Field(
default=None,
multiple_of=8,
gt=0,
description="The height of the inpaint region (px)",
)
inpaint_fill: Optional[ColorField] = Field(
default=ColorField(r=127, g=127, b=127, a=255),
description="The solid infill method color",
)
inpaint_replace: float = Field( inpaint_replace: float = Field(
default=0.0, default=0.0,
ge=0.0, ge=0.0,
@ -257,14 +257,14 @@ class InpaintInvocation(ImageToImageInvocation):
image = ( image = (
None None
if self.image is None if self.image is None
else context.services.images.get( else context.services.images.get_pil_image(
self.image.image_type, self.image.image_name self.image.image_type, self.image.image_name
) )
) )
mask = ( mask = (
None None
if self.mask is None if self.mask is None
else context.services.images.get(self.mask.image_type, self.mask.image_name) else context.services.images.get_pil_image(self.mask.image_type, self.mask.image_name)
) )
# Handle invalid model parameter # Handle invalid model parameter
@ -290,23 +290,19 @@ class InpaintInvocation(ImageToImageInvocation):
# each time it is called. We only need the first one. # each time it is called. We only need the first one.
generator_output = next(outputs) generator_output = next(outputs)
result_image = generator_output.image image_dto = context.services.images.create(
image=generator_output.image,
# Results are image and seed, unwrap for now and ignore the seed image_type=ImageType.RESULT,
# TODO: pre-seed? image_category=ImageCategory.GENERAL,
# TODO: can this return multiple results? Should it? session_id=context.graph_execution_state_id,
image_type = ImageType.RESULT node_id=self.id,
image_name = context.services.images.create_name(
context.graph_execution_state_id, self.id
) )
metadata = context.services.metadata.build_metadata( return ImageOutput(
session_id=context.graph_execution_state_id, node=self image=ImageField(
) image_name=image_dto.image_name,
image_type=image_dto.image_type,
context.services.images.save(image_type, image_name, result_image, metadata) ),
return build_image_output( width=image_dto.width,
image_type=image_type, height=image_dto.height,
image_name=image_name,
image=result_image,
) )