From 031fff87f9d1d46201115b4baf963ef1e34f4c7a Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Mon, 26 Jun 2023 10:41:43 -0700 Subject: [PATCH 01/80] added inpaint panel --- ui/ui_panels.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index c21d4f8..3c91ed0 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -498,6 +498,62 @@ def draw(self, context): row.operator(operators.AIR_OT_upscale_last_sd_image.bl_idname, icon="FULLSCREEN_ENTER") +# Inpainting +class AIR_PT_inpaint(bpy.types.Panel): + bl_label = "Inpaint" + bl_idname = "AIR_PT_inpaint" + bl_parent_id = "AIR_PT_main" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return utils.is_installation_valid() and context.scene.air_props.is_enabled + + def draw(self, context): + layout = self.layout + scene = context.scene + props = scene.air_props + + width_guess = 220 + + # Auto Run + row = layout.row() + row.prop(props, 'auto_run') + + # Generate Image + layout.separator() + + row = layout.row() + row.label(text="Run Manually:") + + row = layout.row() + row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data + row.operator(operators.AIR_OT_generate_new_image_from_render.bl_idname) + + row = layout.row() + row.enabled = props.last_generated_image_filename != "" + row.operator(operators.AIR_OT_generate_new_image_from_last_sd_image.bl_idname) + + layout.separator() + + row = layout.row() + row.label(text="Automatically Save Images:") + + row = layout.row() + row.prop(props, "do_autosave_before_images") + + row = layout.row() + row.prop(props, "do_autosave_after_images") + + row = layout.row() + row.prop(props, "autosave_image_path", text="Path") + + if (props.do_autosave_before_images or props.do_autosave_after_images) and not props.autosave_image_path: + utils.label_multiline(layout, text="Please specify a path", icon="ERROR", width=width_guess) + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" bl_idname = "AIR_PT_animation" From 73776caf1a52d31d04220cc4d82238e3458df163 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Mon, 26 Jun 2023 10:44:20 -0700 Subject: [PATCH 02/80] added inpaint panel --- ui/ui_panels.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 3c91ed0..61dd988 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -624,6 +624,7 @@ def draw(self, context): AIR_PT_advanced_options, AIR_PT_controlnet, AIR_PT_operation, + AIR_PT_inpaint, AIR_PT_upscale, AIR_PT_animation, ] From f6d518c67fa4cf1dc6a226d6770cc91b4d427489 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 11:53:25 -0700 Subject: [PATCH 03/80] added mask path --- properties.py | 6 ++++++ ui/ui_panels.py | 37 +++---------------------------------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/properties.py b/properties.py index c12b526..50ca4e2 100644 --- a/properties.py +++ b/properties.py @@ -275,6 +275,12 @@ class AIRProperties(bpy.types.PropertyGroup): items=get_available_controlnet_modules, description="Which ControlNet module (preprocessor) to use (these come with the ControlNet extension)", ) + inpaint_mask_path: bpy.props.StringProperty( + name="Inpaint Mask Path", + default="", + description="Mask file for Stable Diffusion Inpaint" + subtype="FILE_PATH" + ) classes = [ diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 61dd988..f35691c 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -510,7 +510,7 @@ class AIR_PT_inpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled + return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" def draw(self, context): layout = self.layout @@ -519,40 +519,9 @@ def draw(self, context): width_guess = 220 - # Auto Run - row = layout.row() - row.prop(props, 'auto_run') - - # Generate Image - layout.separator() - - row = layout.row() - row.label(text="Run Manually:") - row = layout.row() - row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data - row.operator(operators.AIR_OT_generate_new_image_from_render.bl_idname) + row.prop(props, "inpaint_mask_path", text="Mask") - row = layout.row() - row.enabled = props.last_generated_image_filename != "" - row.operator(operators.AIR_OT_generate_new_image_from_last_sd_image.bl_idname) - - layout.separator() - - row = layout.row() - row.label(text="Automatically Save Images:") - - row = layout.row() - row.prop(props, "do_autosave_before_images") - - row = layout.row() - row.prop(props, "do_autosave_after_images") - - row = layout.row() - row.prop(props, "autosave_image_path", text="Path") - - if (props.do_autosave_before_images or props.do_autosave_after_images) and not props.autosave_image_path: - utils.label_multiline(layout, text="Please specify a path", icon="ERROR", width=width_guess) class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" @@ -624,8 +593,8 @@ def draw(self, context): AIR_PT_advanced_options, AIR_PT_controlnet, AIR_PT_operation, - AIR_PT_inpaint, AIR_PT_upscale, + AIR_PT_inpaint, AIR_PT_animation, ] From c8b7cc43caf971f8d548dfb4454a7a27aaec9f6e Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 11:54:36 -0700 Subject: [PATCH 04/80] fixed error --- properties.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/properties.py b/properties.py index 50ca4e2..ee85eb8 100644 --- a/properties.py +++ b/properties.py @@ -278,8 +278,8 @@ class AIRProperties(bpy.types.PropertyGroup): inpaint_mask_path: bpy.props.StringProperty( name="Inpaint Mask Path", default="", - description="Mask file for Stable Diffusion Inpaint" - subtype="FILE_PATH" + description="Mask file for Stable Diffusion Inpaint", + subtype="FILE_PATH", ) From 3d899e4c7e67ce78df8627666050f416b7b88c5f Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 12:31:04 -0700 Subject: [PATCH 05/80] added info giver --- operators.py | 9 +++++++++ ui/ui_panels.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/operators.py b/operators.py index 7d51dba..b93e539 100644 --- a/operators.py +++ b/operators.py @@ -969,7 +969,15 @@ def execute(self, context): automatic1111_api.choose_controlnet_defaults(context) return {'FINISHED'} +class AIR_OT_info(bpy.types.Operator): + bl_idname = "ai_render.info" + bl_label = "print info" + def execute(self, context): + msg = type(context.scene) + msg = str(msg) + handle_error(msg) + return {'FINISHED'} classes = [ AIR_OT_enable, @@ -989,6 +997,7 @@ def execute(self, context): AIR_OT_automatic1111_load_controlnet_models, AIR_OT_automatic1111_load_controlnet_modules, AIR_OT_automatic1111_load_controlnet_models_and_modules, + AIR_OT_info, ] diff --git a/ui/ui_panels.py b/ui/ui_panels.py index f35691c..1a3ebf3 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -522,6 +522,8 @@ def draw(self, context): row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") + row.operator(operators.AIR_OT_info.bl_idname, icon="FULLSCREEN_ENTER") + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" From 48093c412c5a5b9a1492b0222e170cd15550abda Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 12:49:06 -0700 Subject: [PATCH 06/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index b93e539..541d1dd 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - msg = type(context.scene) + msg = type(context.scene.keys()) msg = str(msg) handle_error(msg) return {'FINISHED'} From 36353897a26c93f3495861df5816b4e8bcd2f8a2 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:37:39 -0700 Subject: [PATCH 07/80] added info giver --- operators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 541d1dd..c429852 100644 --- a/operators.py +++ b/operators.py @@ -974,9 +974,10 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - msg = type(context.scene.keys()) + msg = (context.scene.keys()) msg = str(msg) handle_error(msg) + return {'FINISHED'} classes = [ From 86bbe2d5d9c0a15991b679d08bfc0c1c774be149 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:39:40 -0700 Subject: [PATCH 08/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index c429852..5f1078e 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - msg = (context.scene.keys()) + msg = dir(context.scene) msg = str(msg) handle_error(msg) From 831d60a64ffdbdd96a962adfb56eaa737c8bad8b Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:41:12 -0700 Subject: [PATCH 09/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 5f1078e..f8e996a 100644 --- a/operators.py +++ b/operators.py @@ -976,7 +976,7 @@ class AIR_OT_info(bpy.types.Operator): def execute(self, context): msg = dir(context.scene) msg = str(msg) - handle_error(msg) + print(msg) return {'FINISHED'} From 99848ae9ff9ad14ec6004000f3cbed6fb3074818 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:44:18 -0700 Subject: [PATCH 10/80] added info giver --- operators.py | 1 + 1 file changed, 1 insertion(+) diff --git a/operators.py b/operators.py index f8e996a..d2eb082 100644 --- a/operators.py +++ b/operators.py @@ -977,6 +977,7 @@ def execute(self, context): msg = dir(context.scene) msg = str(msg) print(msg) + print(dir(bpy.data)) return {'FINISHED'} From de5ab71645bd6c129a0b4ea55feb83817c823ad6 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:45:51 -0700 Subject: [PATCH 11/80] added info giver --- operators.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/operators.py b/operators.py index d2eb082..aad1757 100644 --- a/operators.py +++ b/operators.py @@ -974,10 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - msg = dir(context.scene) - msg = str(msg) - print(msg) - print(dir(bpy.data)) + handle_error(str(dir(bpy.data))) return {'FINISHED'} From d97593653b66cc9beccc00d4665714715ec7191b Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:47:08 -0700 Subject: [PATCH 12/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index aad1757..f2e048b 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - handle_error(str(dir(bpy.data))) + handle_error(str(dir(bpy.data.masks))) return {'FINISHED'} From 13de3792e737ed580e29890746b0f103b3f88540 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 13:49:01 -0700 Subject: [PATCH 13/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index f2e048b..31e21dd 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - handle_error(str(dir(bpy.data.masks))) + handle_error(str(bpy.data.masks.items())) return {'FINISHED'} From 016d216fd0b9e2e80b247248feba1bf7d63958ce Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 14:32:59 -0700 Subject: [PATCH 14/80] added info giver --- properties.py | 11 ++++++----- ui/ui_panels.py | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/properties.py b/properties.py index ee85eb8..7496715 100644 --- a/properties.py +++ b/properties.py @@ -38,6 +38,8 @@ def get_available_controlnet_modules(self, context): else: return [] +def get_available_masks(self, context): + return bpy.data.masks.keys() def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" @@ -275,11 +277,10 @@ class AIRProperties(bpy.types.PropertyGroup): items=get_available_controlnet_modules, description="Which ControlNet module (preprocessor) to use (these come with the ControlNet extension)", ) - inpaint_mask_path: bpy.props.StringProperty( - name="Inpaint Mask Path", - default="", - description="Mask file for Stable Diffusion Inpaint", - subtype="FILE_PATH", + inpaint_mask: bpy.props.EnumProperty( + name="Inpaint Mask", + items=get_available_masks, + description="Which Inpaint Mask to use" ) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 1a3ebf3..1c21aa2 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -520,8 +520,9 @@ def draw(self, context): width_guess = 220 row = layout.row() - row.prop(props, "inpaint_mask_path", text="Mask") + row.prop(props, "inpaint_mask", text="Mask") + row = layout.row() row.operator(operators.AIR_OT_info.bl_idname, icon="FULLSCREEN_ENTER") From 1505d7dec38ec5568f20621979c83b13179a0456 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 14:37:05 -0700 Subject: [PATCH 15/80] added info giver --- operators.py | 2 +- properties.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operators.py b/operators.py index 31e21dd..49da1cb 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - handle_error(str(bpy.data.masks.items())) + handle_error(str(bpy.data.masks.keys())) return {'FINISHED'} diff --git a/properties.py b/properties.py index 7496715..0666471 100644 --- a/properties.py +++ b/properties.py @@ -39,7 +39,7 @@ def get_available_controlnet_modules(self, context): return [] def get_available_masks(self, context): - return bpy.data.masks.keys() + return bpy.data.masks.items() def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" From 740b8c6cb9fcaa7c455091e00b7bd4e2ce1da849 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 14:42:17 -0700 Subject: [PATCH 16/80] added info giver --- properties.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/properties.py b/properties.py index 0666471..6cc9e02 100644 --- a/properties.py +++ b/properties.py @@ -39,7 +39,7 @@ def get_available_controlnet_modules(self, context): return [] def get_available_masks(self, context): - return bpy.data.masks.items() + return list(bpy.data.masks.items()) def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" From 9183b6a6cab57a2fcbd0079ee89347b1a8bb6f96 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 14:56:40 -0700 Subject: [PATCH 17/80] added info giver --- properties.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/properties.py b/properties.py index 6cc9e02..89cdad9 100644 --- a/properties.py +++ b/properties.py @@ -39,7 +39,10 @@ def get_available_controlnet_modules(self, context): return [] def get_available_masks(self, context): - return list(bpy.data.masks.items()) + mask_list = [] + for k, v in bpy.data.masks.items(): + mask_list += (v, k, '') + return mask_list def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" From 55c98f8684c2479bd9c215ddc89d7b615625fdc2 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:04:01 -0700 Subject: [PATCH 18/80] added info giver --- operators.py | 2 +- properties.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 49da1cb..32a14d3 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - handle_error(str(bpy.data.masks.keys())) + handle_error(str(properties.)) return {'FINISHED'} diff --git a/properties.py b/properties.py index 89cdad9..f4ba4c1 100644 --- a/properties.py +++ b/properties.py @@ -42,6 +42,7 @@ def get_available_masks(self, context): mask_list = [] for k, v in bpy.data.masks.items(): mask_list += (v, k, '') + print(mask_list) return mask_list def ensure_sampler(context): From 627235c100192aaf808287775cadc41ac3d72811 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:05:53 -0700 Subject: [PATCH 19/80] added info giver --- operators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 32a14d3..eaea6b5 100644 --- a/operators.py +++ b/operators.py @@ -974,7 +974,8 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "print info" def execute(self, context): - handle_error(str(properties.)) + from properties import get_available_masks + handle_error(str(get_available_masks(self, context))) return {'FINISHED'} From aaea1bb70bd4bd131216250e71c8616aa60f6090 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:08:23 -0700 Subject: [PATCH 20/80] added info giver --- properties.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/properties.py b/properties.py index f4ba4c1..9923051 100644 --- a/properties.py +++ b/properties.py @@ -40,8 +40,8 @@ def get_available_controlnet_modules(self, context): def get_available_masks(self, context): mask_list = [] - for k, v in bpy.data.masks.items(): - mask_list += (v, k, '') + for k in bpy.data.masks: + mask_list += (bpy.data.masks[k], k, '') print(mask_list) return mask_list From a2492a8e6017903e90be80912e17832fddc64800 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:11:34 -0700 Subject: [PATCH 21/80] added info giver --- operators.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/operators.py b/operators.py index eaea6b5..8247c47 100644 --- a/operators.py +++ b/operators.py @@ -969,12 +969,18 @@ def execute(self, context): automatic1111_api.choose_controlnet_defaults(context) return {'FINISHED'} +def get_available_masks(self, context): + mask_list = [] + for k in bpy.data.masks: + mask_list += (bpy.data.masks[k], k, '') + print(mask_list) + return mask_list + class AIR_OT_info(bpy.types.Operator): bl_idname = "ai_render.info" bl_label = "print info" def execute(self, context): - from properties import get_available_masks handle_error(str(get_available_masks(self, context))) return {'FINISHED'} From 83297611cee6ad5a326a4a25f0dcf63e2c516fda Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:12:48 -0700 Subject: [PATCH 22/80] added info giver --- operators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operators.py b/operators.py index 8247c47..8116474 100644 --- a/operators.py +++ b/operators.py @@ -971,8 +971,8 @@ def execute(self, context): def get_available_masks(self, context): mask_list = [] - for k in bpy.data.masks: - mask_list += (bpy.data.masks[k], k, '') + for k, v in bpy.data.masks.items(): + mask_list += (v, k, '') print(mask_list) return mask_list From 81210a59ab97c4357ea1d3fa66c41df11a2c23f5 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:13:59 -0700 Subject: [PATCH 23/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 8116474..3130721 100644 --- a/operators.py +++ b/operators.py @@ -972,7 +972,7 @@ def execute(self, context): def get_available_masks(self, context): mask_list = [] for k, v in bpy.data.masks.items(): - mask_list += (v, k, '') + mask_list += [(v, k, '')] print(mask_list) return mask_list From e669955d7bc68db031493e8620f70dd8ecae43ee Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:15:21 -0700 Subject: [PATCH 24/80] added info giver --- properties.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/properties.py b/properties.py index 9923051..8000ccf 100644 --- a/properties.py +++ b/properties.py @@ -40,9 +40,8 @@ def get_available_controlnet_modules(self, context): def get_available_masks(self, context): mask_list = [] - for k in bpy.data.masks: - mask_list += (bpy.data.masks[k], k, '') - print(mask_list) + for k, v in bpy.data.masks.items(): + mask_list += [(v, k, '')] return mask_list def ensure_sampler(context): From 4a696bb94a2c98a6db2b919596b6e25fa5654ebf Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:22:22 -0700 Subject: [PATCH 25/80] added info giver --- operators.py | 5 ++--- properties.py | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/operators.py b/operators.py index 3130721..f57b3ab 100644 --- a/operators.py +++ b/operators.py @@ -971,9 +971,8 @@ def execute(self, context): def get_available_masks(self, context): mask_list = [] - for k, v in bpy.data.masks.items(): - mask_list += [(v, k, '')] - print(mask_list) + for k in bpy.data.masks: + mask_list.append((k,k,"")) return mask_list class AIR_OT_info(bpy.types.Operator): diff --git a/properties.py b/properties.py index 8000ccf..62fbe85 100644 --- a/properties.py +++ b/properties.py @@ -40,8 +40,8 @@ def get_available_controlnet_modules(self, context): def get_available_masks(self, context): mask_list = [] - for k, v in bpy.data.masks.items(): - mask_list += [(v, k, '')] + for k in bpy.data.masks: + mask_list.append((k,k,"")) return mask_list def ensure_sampler(context): From 1ac761176375f1c8c869e561faa63106be4f2abe Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:25:45 -0700 Subject: [PATCH 26/80] added info giver --- properties.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/properties.py b/properties.py index 62fbe85..ea3fcf2 100644 --- a/properties.py +++ b/properties.py @@ -282,7 +282,7 @@ class AIRProperties(bpy.types.PropertyGroup): ) inpaint_mask: bpy.props.EnumProperty( name="Inpaint Mask", - items=get_available_masks, + items=[('A','B','C'), ('A','B','C'), ('A','B','C'), ('A','B','C'), ('A','B','C')], description="Which Inpaint Mask to use" ) From c4ec34a91d54c7cd7fc3503ef53b906860b6b4ed Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 15:30:14 -0700 Subject: [PATCH 27/80] added info giver --- properties.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/properties.py b/properties.py index ea3fcf2..e313038 100644 --- a/properties.py +++ b/properties.py @@ -40,8 +40,8 @@ def get_available_controlnet_modules(self, context): def get_available_masks(self, context): mask_list = [] - for k in bpy.data.masks: - mask_list.append((k,k,"")) + for k, v in bpy.data.masks.items(): + mask_list.append((str(k),str(k),"")) return mask_list def ensure_sampler(context): @@ -282,7 +282,7 @@ class AIRProperties(bpy.types.PropertyGroup): ) inpaint_mask: bpy.props.EnumProperty( name="Inpaint Mask", - items=[('A','B','C'), ('A','B','C'), ('A','B','C'), ('A','B','C'), ('A','B','C')], + items=get_available_masks, description="Which Inpaint Mask to use" ) From e3d2b4c42e8afc0e34c93ff13f9ceffdd1a1e54a Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:01:56 -0700 Subject: [PATCH 28/80] Added frontend for inpaint --- operators.py | 34 ++++++++++++++++++++++++---------- ui/ui_panels.py | 7 ++++++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/operators.py b/operators.py index f57b3ab..10bd7a8 100644 --- a/operators.py +++ b/operators.py @@ -969,21 +969,36 @@ def execute(self, context): automatic1111_api.choose_controlnet_defaults(context) return {'FINISHED'} -def get_available_masks(self, context): - mask_list = [] - for k in bpy.data.masks: - mask_list.append((k,k,"")) - return mask_list +class AIR_OT_inpaint_from_render(bpy.types.Operator): + "Inpaint a new Stable Diffusion image - without re-rendering - from the last rendered image" + bl_idname = "ai_render.inpaint_from_render" + bl_label = "Inpaint Image From Last Render" + + def execute(self, context): + do_pre_render_setup(context.scene) + do_pre_api_setup(context.scene) + + # post to the api (on a different thread, outside the operator) + task_queue.add(functools.partial(sd_generate, context.scene)) + + return {'FINISHED'} -class AIR_OT_info(bpy.types.Operator): - bl_idname = "ai_render.info" - bl_label = "print info" + +class AIR_OT_inpaint_from_last_sd_image(bpy.types.Operator): + "Generate a new Stable Diffusion image - without re-rendering - using the most recent Stable Diffusion image as the starting point" + bl_idname = "ai_render.inpaint_from_last_sd_image" + bl_label = "Inpaint Image From Last AI Image" def execute(self, context): - handle_error(str(get_available_masks(self, context))) + do_pre_render_setup(context.scene) + do_pre_api_setup(context.scene) + + # post to the api (on a different thread, outside the operator) + task_queue.add(functools.partial(sd_generate, context.scene, None, True)) return {'FINISHED'} + classes = [ AIR_OT_enable, AIR_OT_disable, @@ -1002,7 +1017,6 @@ def execute(self, context): AIR_OT_automatic1111_load_controlnet_models, AIR_OT_automatic1111_load_controlnet_modules, AIR_OT_automatic1111_load_controlnet_models_and_modules, - AIR_OT_info, ] diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 1c21aa2..6462e3e 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -523,7 +523,12 @@ def draw(self, context): row.prop(props, "inpaint_mask", text="Mask") row = layout.row() - row.operator(operators.AIR_OT_info.bl_idname, icon="FULLSCREEN_ENTER") + row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask + row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) + + row = layout.row() + row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask + row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) class AIR_PT_animation(bpy.types.Panel): From 36468f425347f8e502d733fd088800f76a8abe78 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:04:06 -0700 Subject: [PATCH 29/80] Added frontend for inpaint --- operators.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/operators.py b/operators.py index 10bd7a8..c7d2630 100644 --- a/operators.py +++ b/operators.py @@ -1017,6 +1017,8 @@ def execute(self, context): AIR_OT_automatic1111_load_controlnet_models, AIR_OT_automatic1111_load_controlnet_modules, AIR_OT_automatic1111_load_controlnet_models_and_modules, + AIR_OT_inpaint_from_render, + AIR_OT_inpaint_from_last_sd_image, ] From 768c6d8bc6e055bb748becb28559b06b2c8fddf9 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:08:26 -0700 Subject: [PATCH 30/80] Added frontend for inpaint --- ui/ui_panels.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 6462e3e..aa31529 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -522,6 +522,9 @@ def draw(self, context): row = layout.row() row.prop(props, "inpaint_mask", text="Mask") + row = layout.row() + row.label(text="Hello") + row = layout.row() row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) From 11e031343c5bfac4225da969388c35746c5f4c3d Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:10:22 -0700 Subject: [PATCH 31/80] Added frontend for inpaint --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index aa31529..bf44114 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -526,7 +526,7 @@ def draw(self, context): row.label(text="Hello") row = layout.row() - row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask + row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) row = layout.row() From 0750ef779f15bf8e99ace28b93d14454ebfd75b8 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:12:05 -0700 Subject: [PATCH 32/80] Added frontend for inpaint --- ui/ui_panels.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index bf44114..6462e3e 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -523,10 +523,7 @@ def draw(self, context): row.prop(props, "inpaint_mask", text="Mask") row = layout.row() - row.label(text="Hello") - - row = layout.row() - row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data + row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) row = layout.row() From 89bd72f043e41363d7a01ec545457f6da31c1c01 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 17:13:22 -0700 Subject: [PATCH 33/80] Added frontend for inpaint --- ui/ui_panels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 6462e3e..e80ba10 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -523,11 +523,11 @@ def draw(self, context): row.prop(props, "inpaint_mask", text="Mask") row = layout.row() - row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask + row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask != "" row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) row = layout.row() - row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask + row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) From aea8e9ec3a72877733b9defc61a7a796b39b43bb Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:16:18 -0700 Subject: [PATCH 34/80] Added frontend for inpaint --- operators.py | 120 +++++++++++++++++++++++++++++++++++++++++------- ui/ui_panels.py | 4 -- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/operators.py b/operators.py index c7d2630..550c6cb 100644 --- a/operators.py +++ b/operators.py @@ -539,7 +539,97 @@ def sd_upscale(scene): # return success return True +# Inpainting +def sd_inpaint(scene): + """Post to the API to generate a Stable Diffusion image and then process it""" + props = scene.air_props + + # get the prompt if we haven't been given one + if props.use_animated_prompts: + prompt, negative_prompt = validate_and_process_animated_prompt_text_for_single_frame(scene, scene.frame_current) + if not prompt: + return False + else: + prompt = get_full_prompt(scene) + negative_prompt = props.negative_prompt_text.strip() + + + # validate the parameters we will send + if not validate_params(scene, prompt): + return False + + # generate a new seed, if we want a random one + generate_new_random_seed(scene) + + # prepare the output filenames + timestamp = int(time.time()) + before_output_filename_prefix = f"ai-render-{timestamp}-1-before" + after_output_filename_prefix = f"ai-render-{timestamp}-2-after" + animation_output_filename_prefix = "ai-render-" + + # if we want to use the last SD image, try loading it now + if not props.last_generated_image_filename: + return handle_error("Couldn't find the last Stable Diffusion image", "last_generated_image_filename") + try: + img_file = open(props.last_generated_image_filename, 'rb') + except: + return handle_error("Couldn't load the last Stable Diffusion image. It's probably been deleted or moved. You'll need to restore it or render a new image.", "load_last_generated_image") + + # load mask here + if props.inpaint_mask == "": + return handle_error("Couldn't find the Inpaint Mask", "inpaint_mask") + + temp_mask_file = None + # prepare data for the API request + params = { + "prompt": prompt, + "negative_prompt": negative_prompt, + "width": utils.get_output_width(scene), + "height": utils.get_output_height(scene), + "image_similarity": props.image_similarity, + "seed": props.seed, + "cfg_scale": props.cfg_scale, + "steps": props.steps, + "sampler": props.sampler, + } + + # get the backend we're using + sd_backend = utils.get_active_backend() + + # TODO: + # send to whichever API we're using + start_time = time.time() + generated_image_file = sd_backend.generate(params, img_file, after_output_filename_prefix, props) + + # if we didn't get a successful image, stop here (an error will have been handled by the api function) + if not generated_image_file: + return False + # autosave the after image, if we should + if utils.should_autosave_after_image(props): + generated_image_file = save_after_image(scene, after_output_filename_prefix, generated_image_file) + + # store this image filename as the last generated image + props.last_generated_image_filename = generated_image_file + + # if we're rendering an animation manually, save the image to the animation output path + if props.is_rendering_animation_manually: + generated_image_file = save_animation_image(scene, animation_output_filename_prefix, generated_image_file) + + # load the image into our scene + try: + img = bpy.data.images.load(generated_image_file, check_existing=False) + except: + return handle_error("Couldn't load the image from Stable Diffusion", "load_sd_image") + + # view the image in the AIR workspace + try: + utils.view_sd_result_in_air_image_editor(img) + except: + return handle_error("Couldn't switch the view to the image from Stable Diffusion", "view_sd_image") + + # return success + return True class AIR_OT_enable(bpy.types.Operator): "Enable AI Render in this scene" @@ -969,23 +1059,9 @@ def execute(self, context): automatic1111_api.choose_controlnet_defaults(context) return {'FINISHED'} -class AIR_OT_inpaint_from_render(bpy.types.Operator): - "Inpaint a new Stable Diffusion image - without re-rendering - from the last rendered image" - bl_idname = "ai_render.inpaint_from_render" - bl_label = "Inpaint Image From Last Render" - - def execute(self, context): - do_pre_render_setup(context.scene) - do_pre_api_setup(context.scene) - - # post to the api (on a different thread, outside the operator) - task_queue.add(functools.partial(sd_generate, context.scene)) - - return {'FINISHED'} - class AIR_OT_inpaint_from_last_sd_image(bpy.types.Operator): - "Generate a new Stable Diffusion image - without re-rendering - using the most recent Stable Diffusion image as the starting point" + "Inpaint a new Stable Diffusion image - without re-rendering - using the most recent Stable Diffusion image as the starting point" bl_idname = "ai_render.inpaint_from_last_sd_image" bl_label = "Inpaint Image From Last AI Image" @@ -994,10 +1070,20 @@ def execute(self, context): do_pre_api_setup(context.scene) # post to the api (on a different thread, outside the operator) - task_queue.add(functools.partial(sd_generate, context.scene, None, True)) + task_queue.add(functools.partial(sd_generate, context.scene)) return {'FINISHED'} +class AIR_OT_info(bpy.types.Operator): + "Info" + bl_idname = "ai_render.info" + bl_label = "Info" + def execute(self, context): + mask = bpy.data.masks['Mask'] + msg = str(dir(mask)) + handle_error(msg) + return {'FINISHED'} + classes = [ AIR_OT_enable, @@ -1017,8 +1103,8 @@ def execute(self, context): AIR_OT_automatic1111_load_controlnet_models, AIR_OT_automatic1111_load_controlnet_modules, AIR_OT_automatic1111_load_controlnet_models_and_modules, - AIR_OT_inpaint_from_render, AIR_OT_inpaint_from_last_sd_image, + AIR_OT_info, ] diff --git a/ui/ui_panels.py b/ui/ui_panels.py index e80ba10..fc24bed 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -522,10 +522,6 @@ def draw(self, context): row = layout.row() row.prop(props, "inpaint_mask", text="Mask") - row = layout.row() - row.enabled = 'Render Result' in bpy.data.images and bpy.data.images['Render Result'].has_data and props.inpaint_mask != "" - row.operator(operators.AIR_OT_inpaint_from_render.bl_idname) - row = layout.row() row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) From c15029509015c82c9c3d5b0eafcaaf3bb58c1e7b Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:17:50 -0700 Subject: [PATCH 35/80] Added frontend for inpaint --- ui/ui_panels.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index fc24bed..fd1d770 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -526,6 +526,9 @@ def draw(self, context): row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) + row = layout.row() + row.operator(operators.AIR_OT_info.bl_idname) + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" From c0d8dd7714337d5471c84995b04dc5c78dcf0771 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:27:26 -0700 Subject: [PATCH 36/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 550c6cb..a5e56c5 100644 --- a/operators.py +++ b/operators.py @@ -1079,7 +1079,7 @@ class AIR_OT_info(bpy.types.Operator): bl_idname = "ai_render.info" bl_label = "Info" def execute(self, context): - mask = bpy.data.masks['Mask'] + mask = bpy.data.masks['Mask'].__doc__ msg = str(dir(mask)) handle_error(msg) return {'FINISHED'} From 67372fce3b51caa5afd96405b1c0d6740d494096 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:33:28 -0700 Subject: [PATCH 37/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index a5e56c5..afadac6 100644 --- a/operators.py +++ b/operators.py @@ -1080,7 +1080,7 @@ class AIR_OT_info(bpy.types.Operator): bl_label = "Info" def execute(self, context): mask = bpy.data.masks['Mask'].__doc__ - msg = str(dir(mask)) + msg = str((mask)) handle_error(msg) return {'FINISHED'} From 84d6a8c1cafcd707b0bd1d9ba90920b494ab5f48 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:34:25 -0700 Subject: [PATCH 38/80] added info giver --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index afadac6..9f17d67 100644 --- a/operators.py +++ b/operators.py @@ -1079,7 +1079,7 @@ class AIR_OT_info(bpy.types.Operator): bl_idname = "ai_render.info" bl_label = "Info" def execute(self, context): - mask = bpy.data.masks['Mask'].__doc__ + mask = bpy.data.masks['Mask'].__doc__() msg = str((mask)) handle_error(msg) return {'FINISHED'} From f0289fa027a6a9ea4b3705adafc75c0b42cf5980 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:35:44 -0700 Subject: [PATCH 39/80] info --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 9f17d67..759e3a2 100644 --- a/operators.py +++ b/operators.py @@ -1079,7 +1079,7 @@ class AIR_OT_info(bpy.types.Operator): bl_idname = "ai_render.info" bl_label = "Info" def execute(self, context): - mask = bpy.data.masks['Mask'].__doc__() + mask = type(bpy.data.masks['Mask']) msg = str((mask)) handle_error(msg) return {'FINISHED'} From 81082e20c93f6d13d9d3006fc9974008b369267b Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 18:42:59 -0700 Subject: [PATCH 40/80] info --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 759e3a2..c31daa8 100644 --- a/operators.py +++ b/operators.py @@ -1079,7 +1079,7 @@ class AIR_OT_info(bpy.types.Operator): bl_idname = "ai_render.info" bl_label = "Info" def execute(self, context): - mask = type(bpy.data.masks['Mask']) + mask = (bpy.data.masks['Mask'].values()) msg = str((mask)) handle_error(msg) return {'FINISHED'} From 7dac84edde9d79c6b6eaaf648223888e8a7fd802 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Tue, 27 Jun 2023 19:47:40 -0700 Subject: [PATCH 41/80] info --- properties.py | 9 +++++---- ui/ui_panels.py | 7 ++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/properties.py b/properties.py index e313038..b5d5d63 100644 --- a/properties.py +++ b/properties.py @@ -280,10 +280,11 @@ class AIRProperties(bpy.types.PropertyGroup): items=get_available_controlnet_modules, description="Which ControlNet module (preprocessor) to use (these come with the ControlNet extension)", ) - inpaint_mask: bpy.props.EnumProperty( - name="Inpaint Mask", - items=get_available_masks, - description="Which Inpaint Mask to use" + inpaint_mask_path: bpy.props.StringProperty( + name="Inpaint Mask Path", + default="", + description="Upload Inpaint Mask", + subtype="FILE_PATH", ) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index fd1d770..588e661 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -520,15 +520,12 @@ def draw(self, context): width_guess = 220 row = layout.row() - row.prop(props, "inpaint_mask", text="Mask") + row.prop(props, "inpaint_mask_path", text="Mask") row = layout.row() - row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask != "" + row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask_path != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) - row = layout.row() - row.operator(operators.AIR_OT_info.bl_idname) - class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" From 46e39f93f0ccdd2adbb7a651ba74b0b82d156687 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:13:51 -0700 Subject: [PATCH 42/80] info --- operators.py | 15 +++++++++------ properties.py | 11 ++++++++++- sd_backends/shark_api.py | 24 ++++++++++++++++++++++++ ui/ui_panels.py | 6 ++++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/operators.py b/operators.py index c31daa8..585db23 100644 --- a/operators.py +++ b/operators.py @@ -576,21 +576,24 @@ def sd_inpaint(scene): return handle_error("Couldn't load the last Stable Diffusion image. It's probably been deleted or moved. You'll need to restore it or render a new image.", "load_last_generated_image") # load mask here - if props.inpaint_mask == "": + if props.inpaint_mask_path == "": return handle_error("Couldn't find the Inpaint Mask", "inpaint_mask") + try: + mask_file = open(props.mask_file_path, 'rb') + except: + return handle_error("Couldn't load the uploaded inpaint mask file", "inpaint_mask_path") - temp_mask_file = None # prepare data for the API request params = { "prompt": prompt, "negative_prompt": negative_prompt, "width": utils.get_output_width(scene), "height": utils.get_output_height(scene), - "image_similarity": props.image_similarity, "seed": props.seed, "cfg_scale": props.cfg_scale, "steps": props.steps, - "sampler": props.sampler, + "is_full_res" : props.inpaint_full_res, + "full_res_padding" : props.inpaint_padding, } # get the backend we're using @@ -599,7 +602,7 @@ def sd_inpaint(scene): # TODO: # send to whichever API we're using start_time = time.time() - generated_image_file = sd_backend.generate(params, img_file, after_output_filename_prefix, props) + generated_image_file = sd_backend.inpaint(params, img_file, after_output_filename_prefix, props) # if we didn't get a successful image, stop here (an error will have been handled by the api function) if not generated_image_file: @@ -1070,7 +1073,7 @@ def execute(self, context): do_pre_api_setup(context.scene) # post to the api (on a different thread, outside the operator) - task_queue.add(functools.partial(sd_generate, context.scene)) + task_queue.add(functools.partial(sd_inpaint, context.scene)) return {'FINISHED'} diff --git a/properties.py b/properties.py index b5d5d63..06eb7e8 100644 --- a/properties.py +++ b/properties.py @@ -286,7 +286,16 @@ class AIRProperties(bpy.types.PropertyGroup): description="Upload Inpaint Mask", subtype="FILE_PATH", ) - + inpaint_full_res : bpy.props.BoolProperty( + name="Inpaint Full Res", + default=True, + ) + inpaint_padding : bpy.props.IntProperty( + name="Inpaint Padding", + max=256, + min=0, + default=32, + ) classes = [ AIRProperties diff --git a/sd_backends/shark_api.py b/sd_backends/shark_api.py index dcc51d6..189df6c 100644 --- a/sd_backends/shark_api.py +++ b/sd_backends/shark_api.py @@ -74,6 +74,30 @@ def upscale(img_file, filename_prefix, props): return handle_error(response) +def inpaint(params, img_file, mask_file, filename_prefix, props): + + params["image"] = "data:image/png;base64," + base64.b64encode(img_file.read()).decode() + img_file.close() + + params["mask"] = "data:image/png;base64," + base64.b64encode(mask_file.read()).decode() + mask_file.close() + + try: + server_url = get_server_url("/sdapi/v1/inpaint") + except: + return operators.handle_error(f"You need to specify a location for the local Stable Diffusion server in the add-on preferences. [Get help]({config.HELP_WITH_SHARK_INSTALLATION_URL})", "local_server_url_missing") + + response = do_post(server_url, params) + + if response is False: + return False + + if response.status_code == 200: + return handle_success(response, filename_prefix) + else: + return handle_error(response) + + def handle_success(response, filename_prefix): # ensure we have the type of response we are expecting diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 588e661..2c50144 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,6 +519,12 @@ def draw(self, context): width_guess = 220 + row = layout.row() + row.props(props, "inpaint_padding", text="Padding") + + row = layout.row() + row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") + row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From b211d6004e4324794ea5d72870251cbb5b4bdbf2 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:19:20 -0700 Subject: [PATCH 43/80] info --- ui/ui_panels.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 2c50144..a5994ca 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,11 +519,11 @@ def draw(self, context): width_guess = 220 - row = layout.row() - row.props(props, "inpaint_padding", text="Padding") + # row = layout.row() + # row.props(props, "inpaint_padding", text="Padding") - row = layout.row() - row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") + # row = layout.row() + # row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From de42ab0ead04cd5b92379315f9b9efc7e0fbf848 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:20:41 -0700 Subject: [PATCH 44/80] info --- ui/ui_panels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index a5994ca..9b4d20c 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,8 +519,8 @@ def draw(self, context): width_guess = 220 - # row = layout.row() - # row.props(props, "inpaint_padding", text="Padding") + row = layout.row() + row.props(props, "inpaint_padding") # row = layout.row() # row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") From 3e01503bd9c6ecb8a98c2b8b71212395afc13e56 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:21:38 -0700 Subject: [PATCH 45/80] info --- ui/ui_panels.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 9b4d20c..37256d9 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,11 +519,11 @@ def draw(self, context): width_guess = 220 - row = layout.row() - row.props(props, "inpaint_padding") - # row = layout.row() - # row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") + # row.props(props, "inpaint_padding") + + row = layout.row() + row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From daca80c8d7540eb35d2985d28b53556879a6014b Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:27:09 -0700 Subject: [PATCH 46/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 37256d9..b7e9916 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -523,7 +523,7 @@ def draw(self, context): # row.props(props, "inpaint_padding") row = layout.row() - row.props(props, "inpaint_full_res", text="Inpaint at Full Resolution") + row.props(props, "inpaint_full_res", text="") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 8520300f44afcefc81fa49d49b1cc8cb2417f9e6 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:28:37 -0700 Subject: [PATCH 47/80] info --- ui/ui_panels.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index b7e9916..c340cfe 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -522,6 +522,9 @@ def draw(self, context): # row = layout.row() # row.props(props, "inpaint_padding") + row = layout.row() + row.label(text="Hello") + row = layout.row() row.props(props, "inpaint_full_res", text="") From 387a474e37cc5a5c5f2ee0a7c124ffe0ed0442b2 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:30:40 -0700 Subject: [PATCH 48/80] info --- properties.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/properties.py b/properties.py index 06eb7e8..929b383 100644 --- a/properties.py +++ b/properties.py @@ -286,11 +286,11 @@ class AIRProperties(bpy.types.PropertyGroup): description="Upload Inpaint Mask", subtype="FILE_PATH", ) - inpaint_full_res : bpy.props.BoolProperty( + inpaint_full_res: bpy.props.BoolProperty( name="Inpaint Full Res", default=True, ) - inpaint_padding : bpy.props.IntProperty( + inpaint_padding: bpy.props.IntProperty( name="Inpaint Padding", max=256, min=0, From 062b33255f72909d8dc68e8099054e46ea777185 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:32:19 -0700 Subject: [PATCH 49/80] info --- properties.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/properties.py b/properties.py index 929b383..e01aaad 100644 --- a/properties.py +++ b/properties.py @@ -289,12 +289,14 @@ class AIRProperties(bpy.types.PropertyGroup): inpaint_full_res: bpy.props.BoolProperty( name="Inpaint Full Res", default=True, + description="" ) inpaint_padding: bpy.props.IntProperty( name="Inpaint Padding", max=256, min=0, default=32, + description="" ) classes = [ From d8ebe978ba1f1f312edf7f2707b0892409a8fb41 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:35:19 -0700 Subject: [PATCH 50/80] info --- properties.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/properties.py b/properties.py index e01aaad..dd3c9a5 100644 --- a/properties.py +++ b/properties.py @@ -289,14 +289,14 @@ class AIRProperties(bpy.types.PropertyGroup): inpaint_full_res: bpy.props.BoolProperty( name="Inpaint Full Res", default=True, - description="" + description="", ) inpaint_padding: bpy.props.IntProperty( name="Inpaint Padding", max=256, min=0, default=32, - description="" + description="", ) classes = [ From 467f767a780ba37178f6f5c78e69cd0b45bd5dac Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:36:12 -0700 Subject: [PATCH 51/80] info --- ui/ui_panels.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index c340cfe..588e661 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,15 +519,6 @@ def draw(self, context): width_guess = 220 - # row = layout.row() - # row.props(props, "inpaint_padding") - - row = layout.row() - row.label(text="Hello") - - row = layout.row() - row.props(props, "inpaint_full_res", text="") - row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 7edf1cb968df29e341bb91e8a00f288fb1194f29 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:38:42 -0700 Subject: [PATCH 52/80] info --- ui/ui_panels.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 588e661..5c36c9f 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -519,6 +519,9 @@ def draw(self, context): width_guess = 220 + row = layout.row() + row.props(props, "inpaint_full_res", text="Bla") + row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 098f8251599cea710d2c66c7589ae5653f9230a7 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:40:04 -0700 Subject: [PATCH 53/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 5c36c9f..199ad00 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -520,7 +520,7 @@ def draw(self, context): width_guess = 220 row = layout.row() - row.props(props, "inpaint_full_res", text="Bla") + row.props(props, "do_autosave_after_images", text="Bla") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 875af18d9d621f793eca19f6b782c537e3127812 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:41:35 -0700 Subject: [PATCH 54/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 199ad00..e0f9c96 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -520,7 +520,7 @@ def draw(self, context): width_guess = 220 row = layout.row() - row.props(props, "do_autosave_after_images", text="Bla") + row.prop(props, "do_autosave_after_images") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 1fe23573556cc2e1853b176a935ea943e406147f Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:42:40 -0700 Subject: [PATCH 55/80] info --- properties.py | 16 ++++++++-------- ui/ui_panels.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/properties.py b/properties.py index dd3c9a5..38ed0b0 100644 --- a/properties.py +++ b/properties.py @@ -287,17 +287,17 @@ class AIRProperties(bpy.types.PropertyGroup): subtype="FILE_PATH", ) inpaint_full_res: bpy.props.BoolProperty( - name="Inpaint Full Res", + name="Inpaint at Full Resolution", default=True, description="", ) - inpaint_padding: bpy.props.IntProperty( - name="Inpaint Padding", - max=256, - min=0, - default=32, - description="", - ) + # inpaint_padding: bpy.props.IntProperty( + # name="Inpaint Padding", + # max=256, + # min=0, + # default=32, + # description="", + # ) classes = [ AIRProperties diff --git a/ui/ui_panels.py b/ui/ui_panels.py index e0f9c96..fda104c 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -520,7 +520,7 @@ def draw(self, context): width_guess = 220 row = layout.row() - row.prop(props, "do_autosave_after_images") + row.prop(props, "inpaint_full_res") row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 55472d04f59a725dc796f0c7dfb84c6571c8a761 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:45:47 -0700 Subject: [PATCH 56/80] info --- properties.py | 14 +++++++------- ui/ui_panels.py | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/properties.py b/properties.py index 38ed0b0..7acc0a9 100644 --- a/properties.py +++ b/properties.py @@ -291,13 +291,13 @@ class AIRProperties(bpy.types.PropertyGroup): default=True, description="", ) - # inpaint_padding: bpy.props.IntProperty( - # name="Inpaint Padding", - # max=256, - # min=0, - # default=32, - # description="", - # ) + inpaint_padding: bpy.props.IntProperty( + name="Inpaint Padding", + max=256, + min=0, + default=32, + description="", + ) classes = [ AIRProperties diff --git a/ui/ui_panels.py b/ui/ui_panels.py index fda104c..f929e17 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -522,6 +522,12 @@ def draw(self, context): row = layout.row() row.prop(props, "inpaint_full_res") + row = layout.row() + sub = row.column() + sub.label(text="Padding") + sub = row.column() + sub.prop(props, 'inpaint_padding', text="", slider=False) + row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From a88363af7ad554d68fa2b67e854e369a71dba941 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:46:44 -0700 Subject: [PATCH 57/80] info --- ui/ui_panels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index f929e17..293cf59 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -524,9 +524,9 @@ def draw(self, context): row = layout.row() sub = row.column() - sub.label(text="Padding") + sub.label(text="Padding:") sub = row.column() - sub.prop(props, 'inpaint_padding', text="", slider=False) + sub.prop(props, 'inpaint_padding', text="", slider=True) row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From a6c977ef993709cc0d763f8b3859fdbc57fd8fea Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:47:44 -0700 Subject: [PATCH 58/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 293cf59..5d2b13e 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -526,7 +526,7 @@ def draw(self, context): sub = row.column() sub.label(text="Padding:") sub = row.column() - sub.prop(props, 'inpaint_padding', text="", slider=True) + sub.prop(props, 'inpaint_padding', text="", slider=False) row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From a8d0413dac821daee173ee888656700aced5eb4c Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:54:33 -0700 Subject: [PATCH 59/80] info --- operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 585db23..9c072f7 100644 --- a/operators.py +++ b/operators.py @@ -577,7 +577,7 @@ def sd_inpaint(scene): # load mask here if props.inpaint_mask_path == "": - return handle_error("Couldn't find the Inpaint Mask", "inpaint_mask") + return handle_error(f"Couldn't find the Inpaint Mask: {props.inpaint_mask_path}") try: mask_file = open(props.mask_file_path, 'rb') except: From 45d78a95641fdeaf3c184d85498e40f3d04d4a0a Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 10:57:12 -0700 Subject: [PATCH 60/80] info --- operators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/operators.py b/operators.py index 9c072f7..ce52bb3 100644 --- a/operators.py +++ b/operators.py @@ -577,9 +577,9 @@ def sd_inpaint(scene): # load mask here if props.inpaint_mask_path == "": - return handle_error(f"Couldn't find the Inpaint Mask: {props.inpaint_mask_path}") + return handle_error("Couldn't find the Inpaint Mask File", "inpaint_mask_path") try: - mask_file = open(props.mask_file_path, 'rb') + mask_file = open(props.inpaint_mask_path, 'rb') except: return handle_error("Couldn't load the uploaded inpaint mask file", "inpaint_mask_path") @@ -602,7 +602,7 @@ def sd_inpaint(scene): # TODO: # send to whichever API we're using start_time = time.time() - generated_image_file = sd_backend.inpaint(params, img_file, after_output_filename_prefix, props) + generated_image_file = sd_backend.inpaint(params, img_file, mask_file, after_output_filename_prefix, props) # if we didn't get a successful image, stop here (an error will have been handled by the api function) if not generated_image_file: From 46d2518ec27f3c40a67020c80fd6bcf2e824420c Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 12:58:39 -0700 Subject: [PATCH 61/80] info --- operators.py | 1 - properties.py | 49 ++++++++++++++++++++++++++++++++++++++++++++----- ui/ui_panels.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/operators.py b/operators.py index ce52bb3..277dfa7 100644 --- a/operators.py +++ b/operators.py @@ -599,7 +599,6 @@ def sd_inpaint(scene): # get the backend we're using sd_backend = utils.get_active_backend() - # TODO: # send to whichever API we're using start_time = time.time() generated_image_file = sd_backend.inpaint(params, img_file, mask_file, after_output_filename_prefix, props) diff --git a/properties.py b/properties.py index 7acc0a9..3bce5a9 100644 --- a/properties.py +++ b/properties.py @@ -38,11 +38,14 @@ def get_available_controlnet_modules(self, context): else: return [] -def get_available_masks(self, context): - mask_list = [] - for k, v in bpy.data.masks.items(): - mask_list.append((str(k),str(k),"")) - return mask_list + +def get_outpaint_directions(self, context): + return [ + ("up", "up", ""), + ("down", "down", ""), + ("left", "left", ""), + ("right", "right", ""), + ] def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" @@ -296,8 +299,44 @@ class AIRProperties(bpy.types.PropertyGroup): max=256, min=0, default=32, + step=4, description="", ) + outpaint_direction: bpy.props.EnumProperty( + name="Outpaint Direction", + items=get_outpaint_directions, + description="The image will expand in this direction", + ) + outpaint_pixels_to_expand: bpy.props.IntProperty( + name="Outpaint Pixels to Expand", + min=8, + max=256, + step=8, + default=8, + description="", + ) + outpaint_mask_blur: bpy.props.IntProperty( + name="Outpaint Mask Blur" + description="this changes how much the inpainting mask is blurred. This helps to avoid sharp edges on the image.", + min=0, + max=64, + step=1, + default=0, + ) + outpaint_noise_q: bpy.props.FloatProperty( + min=0.0, + max=4.0, + default=1.0, + step=0.01, + name="Outpaint Noise Quotient", + ) + outpaint_color_variation: bpy.props.FloatProperty( + min=0.0, + max=1.0, + default=0.05, + step=0.01, + name="Outpaint Color Variation", + ) classes = [ AIRProperties diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 5d2b13e..60e09a3 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -535,6 +535,52 @@ def draw(self, context): row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask_path != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) +class AIR_PT_outpaint(bpy.types.Panel): + bl_label = "Outpaint" + bl_idname = "AIR_PT_outpaint" + bl_parent_id = "AIR_PT_main" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" + + def draw(self, context): + layout = self.layout + scene = context.scene + props = scene.air_props + + row = layout.row() + row.prop(props, "outpaint_direction", text="Outpaint Direction") + + row = layout.row() + sub = row.column() + sub.label("Pixels to Expand:") + sub = row.column() + sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Mask Blur:") + sub = row.column() + sub.prop(props, "outpaint_mask_blur", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Noise Quotient:") + sub = row.column() + sub.prop(props, "outpaint_noise_q", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Color Variation:") + sub = row.column() + sub.prop(props, "outpaint_color_variation", text="", slider=False) + + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" @@ -608,6 +654,7 @@ def draw(self, context): AIR_PT_operation, AIR_PT_upscale, AIR_PT_inpaint, + AIR_PT_outpaint, AIR_PT_animation, ] From 6a3bc2d39f09d3d7b9b949ed6b35c1a6d061d82d Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 12:59:17 -0700 Subject: [PATCH 62/80] info --- properties.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/properties.py b/properties.py index 3bce5a9..1add8f5 100644 --- a/properties.py +++ b/properties.py @@ -316,7 +316,7 @@ class AIRProperties(bpy.types.PropertyGroup): description="", ) outpaint_mask_blur: bpy.props.IntProperty( - name="Outpaint Mask Blur" + name="Outpaint Mask Blur", description="this changes how much the inpainting mask is blurred. This helps to avoid sharp edges on the image.", min=0, max=64, @@ -338,6 +338,7 @@ class AIRProperties(bpy.types.PropertyGroup): name="Outpaint Color Variation", ) + classes = [ AIRProperties ] From feb17d638f0ad4d3bff91e7f4b35a07b6e9d15b1 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:02:30 -0700 Subject: [PATCH 63/80] info --- ui/ui_panels.py | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 60e09a3..0cba696 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -549,36 +549,36 @@ def poll(cls, context): return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" def draw(self, context): - layout = self.layout - scene = context.scene - props = scene.air_props - - row = layout.row() - row.prop(props, "outpaint_direction", text="Outpaint Direction") - - row = layout.row() - sub = row.column() - sub.label("Pixels to Expand:") - sub = row.column() - sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) - - row = layout.row() - sub = row.column() - sub.label("Mask Blur:") - sub = row.column() - sub.prop(props, "outpaint_mask_blur", text="", slider=False) - - row = layout.row() - sub = row.column() - sub.label("Noise Quotient:") - sub = row.column() - sub.prop(props, "outpaint_noise_q", text="", slider=False) - - row = layout.row() - sub = row.column() - sub.label("Color Variation:") - sub = row.column() - sub.prop(props, "outpaint_color_variation", text="", slider=False) + # layout = self.layout + # scene = context.scene + # props = scene.air_props + + # row = layout.row() + # row.prop(props, "outpaint_direction", text="Outpaint Direction") + + # row = layout.row() + # sub = row.column() + # sub.label("Pixels to Expand:") + # sub = row.column() + # sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + + # row = layout.row() + # sub = row.column() + # sub.label("Mask Blur:") + # sub = row.column() + # sub.prop(props, "outpaint_mask_blur", text="", slider=False) + + # row = layout.row() + # sub = row.column() + # sub.label("Noise Quotient:") + # sub = row.column() + # sub.prop(props, "outpaint_noise_q", text="", slider=False) + + # row = layout.row() + # sub = row.column() + # sub.label("Color Variation:") + # sub = row.column() + # sub.prop(props, "outpaint_color_variation", text="", slider=False) From 42e78fd6e74e236a933e0639fafdd816d37ebf53 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:03:20 -0700 Subject: [PATCH 64/80] info --- ui/ui_panels.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 0cba696..4480b66 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -549,9 +549,9 @@ def poll(cls, context): return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" def draw(self, context): - # layout = self.layout - # scene = context.scene - # props = scene.air_props + layout = self.layout + scene = context.scene + props = scene.air_props # row = layout.row() # row.prop(props, "outpaint_direction", text="Outpaint Direction") @@ -580,7 +580,7 @@ def draw(self, context): # sub = row.column() # sub.prop(props, "outpaint_color_variation", text="", slider=False) - + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" From c6be4a6725ea9fcaf4e46d645d562bc7254379cc Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:05:38 -0700 Subject: [PATCH 65/80] info --- ui/ui_panels.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 4480b66..1a84e10 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -546,7 +546,8 @@ class AIR_PT_outpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" + # return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" + return True def draw(self, context): layout = self.layout @@ -579,7 +580,7 @@ def draw(self, context): # sub.label("Color Variation:") # sub = row.column() # sub.prop(props, "outpaint_color_variation", text="", slider=False) - + class AIR_PT_animation(bpy.types.Panel): From a03bfbb0d64516c638b9a62a005873bba6d84196 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:06:53 -0700 Subject: [PATCH 66/80] info --- ui/ui_panels.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 1a84e10..502c617 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -546,8 +546,7 @@ class AIR_PT_outpaint(bpy.types.Panel): @classmethod def poll(cls, context): - # return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" - return True + return utils.is_installation_valid() and context.scene.air_props.is_enabled def draw(self, context): layout = self.layout From 7b3929e472780554c6fef2d0bbd8691d01e4ef88 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:07:34 -0700 Subject: [PATCH 67/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 502c617..240eb38 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -546,7 +546,7 @@ class AIR_PT_outpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled + return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" def draw(self, context): layout = self.layout From 29cf80a6b49841cec244efec482c35ba10007a83 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:08:15 -0700 Subject: [PATCH 68/80] info --- ui/ui_panels.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 240eb38..702a3f4 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -553,14 +553,14 @@ def draw(self, context): scene = context.scene props = scene.air_props - # row = layout.row() - # row.prop(props, "outpaint_direction", text="Outpaint Direction") + row = layout.row() + row.prop(props, "outpaint_direction", text="Outpaint Direction") - # row = layout.row() - # sub = row.column() - # sub.label("Pixels to Expand:") - # sub = row.column() - # sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + row = layout.row() + sub = row.column() + sub.label("Pixels to Expand:") + sub = row.column() + sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) # row = layout.row() # sub = row.column() From 8395b14fb45b3fc931da7b83bea6db221aace4de Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:10:45 -0700 Subject: [PATCH 69/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 702a3f4..160114a 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -560,7 +560,7 @@ def draw(self, context): sub = row.column() sub.label("Pixels to Expand:") sub = row.column() - sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + # sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) # row = layout.row() # sub = row.column() From c5a060535dc38107f3c48f9522adfaba8b97da89 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:12:05 -0700 Subject: [PATCH 70/80] info --- ui/ui_panels.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 160114a..498c6f6 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -560,25 +560,25 @@ def draw(self, context): sub = row.column() sub.label("Pixels to Expand:") sub = row.column() - # sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) - - # row = layout.row() - # sub = row.column() - # sub.label("Mask Blur:") - # sub = row.column() - # sub.prop(props, "outpaint_mask_blur", text="", slider=False) - - # row = layout.row() - # sub = row.column() - # sub.label("Noise Quotient:") - # sub = row.column() - # sub.prop(props, "outpaint_noise_q", text="", slider=False) - - # row = layout.row() - # sub = row.column() - # sub.label("Color Variation:") - # sub = row.column() - # sub.prop(props, "outpaint_color_variation", text="", slider=False) + sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Mask Blur:") + sub = row.column() + sub.prop(props, "outpaint_mask_blur", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Noise Quotient:") + sub = row.column() + sub.prop(props, "outpaint_noise_q", text="", slider=False) + + row = layout.row() + sub = row.column() + sub.label("Color Variation:") + sub = row.column() + sub.prop(props, "outpaint_color_variation", text="", slider=False) From 1cc3dced13f2f08499904f24b27f8322efbfb142 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:14:03 -0700 Subject: [PATCH 71/80] info --- ui/ui_panels.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 498c6f6..c299100 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -554,29 +554,31 @@ def draw(self, context): props = scene.air_props row = layout.row() - row.prop(props, "outpaint_direction", text="Outpaint Direction") + sub = row.columns() + sub.label(text="Outpaint Direction:") + row.prop(props, "outpaint_direction", text="") row = layout.row() sub = row.column() - sub.label("Pixels to Expand:") + sub.label(text="Pixels to Expand:") sub = row.column() sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) row = layout.row() sub = row.column() - sub.label("Mask Blur:") + sub.label(text="Mask Blur:") sub = row.column() sub.prop(props, "outpaint_mask_blur", text="", slider=False) row = layout.row() sub = row.column() - sub.label("Noise Quotient:") + sub.label(text="Noise Quotient:") sub = row.column() sub.prop(props, "outpaint_noise_q", text="", slider=False) row = layout.row() sub = row.column() - sub.label("Color Variation:") + sub.label(text="Color Variation:") sub = row.column() sub.prop(props, "outpaint_color_variation", text="", slider=False) From 2001d9bb8769e0ec746c45bde1efb988eb8bffb4 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:15:04 -0700 Subject: [PATCH 72/80] info --- ui/ui_panels.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index c299100..c5ac3eb 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -554,9 +554,10 @@ def draw(self, context): props = scene.air_props row = layout.row() - sub = row.columns() + sub = row.column() sub.label(text="Outpaint Direction:") - row.prop(props, "outpaint_direction", text="") + sub = row.column() + sub.prop(props, "outpaint_direction", text="") row = layout.row() sub = row.column() From 1c25298ea4f76a623ad4dd9b322af2c559bf4c6f Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:17:25 -0700 Subject: [PATCH 73/80] info --- ui/ui_panels.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index c5ac3eb..46983f6 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -526,7 +526,7 @@ def draw(self, context): sub = row.column() sub.label(text="Padding:") sub = row.column() - sub.prop(props, 'inpaint_padding', text="", slider=False) + sub.prop(props, 'inpaint_padding', text="", slider=True) row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") @@ -563,25 +563,25 @@ def draw(self, context): sub = row.column() sub.label(text="Pixels to Expand:") sub = row.column() - sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) + sub.prop(props, "outpaint_pixels_to_expand", text="", slider=True) row = layout.row() sub = row.column() sub.label(text="Mask Blur:") sub = row.column() - sub.prop(props, "outpaint_mask_blur", text="", slider=False) + sub.prop(props, "outpaint_mask_blur", text="", slider=True) row = layout.row() sub = row.column() sub.label(text="Noise Quotient:") sub = row.column() - sub.prop(props, "outpaint_noise_q", text="", slider=False) + sub.prop(props, "outpaint_noise_q", text="", slider=True) row = layout.row() sub = row.column() sub.label(text="Color Variation:") sub = row.column() - sub.prop(props, "outpaint_color_variation", text="", slider=False) + sub.prop(props, "outpaint_color_variation", text="", slider=True) From 0fa8df29ab3a0d76d820206e98debf14e1a2f16a Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:19:55 -0700 Subject: [PATCH 74/80] info --- ui/ui_panels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 46983f6..d8bcd24 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -563,13 +563,13 @@ def draw(self, context): sub = row.column() sub.label(text="Pixels to Expand:") sub = row.column() - sub.prop(props, "outpaint_pixels_to_expand", text="", slider=True) + sub.prop(props, "outpaint_pixels_to_expand", text="", slider=False) row = layout.row() sub = row.column() sub.label(text="Mask Blur:") sub = row.column() - sub.prop(props, "outpaint_mask_blur", text="", slider=True) + sub.prop(props, "outpaint_mask_blur", text="", slider=False) row = layout.row() sub = row.column() From 2f793d8c6a1f0a1988b43bc2c5b0e04137f26f96 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:20:09 -0700 Subject: [PATCH 75/80] info --- ui/ui_panels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/ui_panels.py b/ui/ui_panels.py index d8bcd24..e75ea33 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -526,7 +526,7 @@ def draw(self, context): sub = row.column() sub.label(text="Padding:") sub = row.column() - sub.prop(props, 'inpaint_padding', text="", slider=True) + sub.prop(props, 'inpaint_padding', text="", slider=False) row = layout.row() row.prop(props, "inpaint_mask_path", text="Mask") From 061b770ed9d7ac76e6632f616993dccee4384ccd Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:30:13 -0700 Subject: [PATCH 76/80] info --- operators.py | 20 ++++++++++++-------- ui/ui_panels.py | 7 +++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/operators.py b/operators.py index 277dfa7..9412f05 100644 --- a/operators.py +++ b/operators.py @@ -1076,14 +1076,18 @@ def execute(self, context): return {'FINISHED'} -class AIR_OT_info(bpy.types.Operator): - "Info" - bl_idname = "ai_render.info" - bl_label = "Info" +class AIR_OT_outpaint_from_last_sd_image(bpy.types.Operator): + "Inpaint a new Stable Diffusion image - without re-rendering - using the most recent Stable Diffusion image as the starting point" + bl_idname = "ai_render.outpaint_from_last_sd_image" + bl_label = "Outpaint Image From Last AI Image" + def execute(self, context): - mask = (bpy.data.masks['Mask'].values()) - msg = str((mask)) - handle_error(msg) + do_pre_render_setup(context.scene) + do_pre_api_setup(context.scene) + + # post to the api (on a different thread, outside the operator) + task_queue.add(functools.partial(sd_outpaint, context.scene)) + return {'FINISHED'} @@ -1106,7 +1110,7 @@ def execute(self, context): AIR_OT_automatic1111_load_controlnet_modules, AIR_OT_automatic1111_load_controlnet_models_and_modules, AIR_OT_inpaint_from_last_sd_image, - AIR_OT_info, + AIR_OT_outpaint_from_last_sd_image, ] diff --git a/ui/ui_panels.py b/ui/ui_panels.py index e75ea33..72008ba 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -569,7 +569,7 @@ def draw(self, context): sub = row.column() sub.label(text="Mask Blur:") sub = row.column() - sub.prop(props, "outpaint_mask_blur", text="", slider=False) + sub.prop(props, "outpaint_mask_blur", text="", slider=True) row = layout.row() sub = row.column() @@ -583,7 +583,10 @@ def draw(self, context): sub = row.column() sub.prop(props, "outpaint_color_variation", text="", slider=True) - + row = layout.row() + row.enabled = props.last_generated_image_filename != "" + row.operator(operators.AIR_OT_outpaint_from_last_sd_image.bl_idname) + class AIR_PT_animation(bpy.types.Panel): bl_label = "Animation" From 376813b878e3768364727a2d0a39e99dc417b3ca Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 13:43:07 -0700 Subject: [PATCH 77/80] info --- operators.py | 93 +++++++++++++++++++++++++++++++++++++++- sd_backends/shark_api.py | 21 +++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/operators.py b/operators.py index 9412f05..dc899cc 100644 --- a/operators.py +++ b/operators.py @@ -564,7 +564,7 @@ def sd_inpaint(scene): # prepare the output filenames timestamp = int(time.time()) before_output_filename_prefix = f"ai-render-{timestamp}-1-before" - after_output_filename_prefix = f"ai-render-{timestamp}-2-after" + after_output_filename_prefix = f"ai-render-{timestamp}-2-inpainted" animation_output_filename_prefix = "ai-render-" # if we want to use the last SD image, try loading it now @@ -633,6 +633,97 @@ def sd_inpaint(scene): # return success return True + +# Outpainting +def sd_outpaint(scene): + """Post to the API to generate a Stable Diffusion image and then process it""" + props = scene.air_props + + # get the prompt if we haven't been given one + if props.use_animated_prompts: + prompt, negative_prompt = validate_and_process_animated_prompt_text_for_single_frame(scene, scene.frame_current) + if not prompt: + return False + else: + prompt = get_full_prompt(scene) + negative_prompt = props.negative_prompt_text.strip() + + + # validate the parameters we will send + if not validate_params(scene, prompt): + return False + + # generate a new seed, if we want a random one + generate_new_random_seed(scene) + + # prepare the output filenames + timestamp = int(time.time()) + before_output_filename_prefix = f"ai-render-{timestamp}-1-before" + after_output_filename_prefix = f"ai-render-{timestamp}-2-outpainted" + animation_output_filename_prefix = "ai-render-" + + # if we want to use the last SD image, try loading it now + if not props.last_generated_image_filename: + return handle_error("Couldn't find the last Stable Diffusion image", "last_generated_image_filename") + try: + img_file = open(props.last_generated_image_filename, 'rb') + except: + return handle_error("Couldn't load the last Stable Diffusion image. It's probably been deleted or moved. You'll need to restore it or render a new image.", "load_last_generated_image") + + + # prepare data for the API request + params = { + "prompt": prompt, + "negative_prompt": negative_prompt, + "width": utils.get_output_width(scene), + "height": utils.get_output_height(scene), + "seed": props.seed, + "cfg_scale": props.cfg_scale, + "steps": props.steps, + "pixels": props.outpaint_pixels_to_expand, + "mask_blur": props.outpaint_mask_blur, + "directions": [props.outpaint_direction], + "noise_q": props.outpaint_noise_q, + "color_variation": props.outpaint_color_variation, + } + + # get the backend we're using + sd_backend = utils.get_active_backend() + + # send to whichever API we're using + start_time = time.time() + generated_image_file = sd_backend.outpaint(params, img_file, after_output_filename_prefix, props) + + # if we didn't get a successful image, stop here (an error will have been handled by the api function) + if not generated_image_file: + return False + + # autosave the after image, if we should + if utils.should_autosave_after_image(props): + generated_image_file = save_after_image(scene, after_output_filename_prefix, generated_image_file) + + # store this image filename as the last generated image + props.last_generated_image_filename = generated_image_file + + # if we're rendering an animation manually, save the image to the animation output path + if props.is_rendering_animation_manually: + generated_image_file = save_animation_image(scene, animation_output_filename_prefix, generated_image_file) + + # load the image into our scene + try: + img = bpy.data.images.load(generated_image_file, check_existing=False) + except: + return handle_error("Couldn't load the image from Stable Diffusion", "load_sd_image") + + # view the image in the AIR workspace + try: + utils.view_sd_result_in_air_image_editor(img) + except: + return handle_error("Couldn't switch the view to the image from Stable Diffusion", "view_sd_image") + + # return success + return True + class AIR_OT_enable(bpy.types.Operator): "Enable AI Render in this scene" bl_idname = "ai_render.enable" diff --git a/sd_backends/shark_api.py b/sd_backends/shark_api.py index 189df6c..8ccc09a 100644 --- a/sd_backends/shark_api.py +++ b/sd_backends/shark_api.py @@ -96,6 +96,27 @@ def inpaint(params, img_file, mask_file, filename_prefix, props): return handle_success(response, filename_prefix) else: return handle_error(response) + + +def outpaint(params, img_file, filename_prefix, props): + + params["init_images"] = ["data:image/png;base64," + base64.b64encode(img_file.read()).decode()] + img_file.close() + + try: + server_url = get_server_url("/sdapi/v1/outpaint") + except: + return operators.handle_error(f"You need to specify a location for the local Stable Diffusion server in the add-on preferences. [Get help]({config.HELP_WITH_SHARK_INSTALLATION_URL})", "local_server_url_missing") + + response = do_post(server_url, params) + + if response is False: + return False + + if response.status_code == 200: + return handle_success(response, filename_prefix) + else: + return handle_error(response) def handle_success(response, filename_prefix): From f01b9f972618776373c2719c2e068cb6bc97f009 Mon Sep 17 00:00:00 2001 From: Ayaan Shah Date: Wed, 28 Jun 2023 17:43:26 -0700 Subject: [PATCH 78/80] Added error for other backends --- sd_backends/shark_api.py | 2 -- ui/ui_panels.py | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/sd_backends/shark_api.py b/sd_backends/shark_api.py index 8ccc09a..177c9c3 100644 --- a/sd_backends/shark_api.py +++ b/sd_backends/shark_api.py @@ -8,8 +8,6 @@ utils, ) - -# img2img generate should prabably work as is # TODO: Controlnet Supprt # TODO: Support Model Choice diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 72008ba..83401ea 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -510,7 +510,11 @@ class AIR_PT_inpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" + return utils.is_installation_valid() and context.scene.air_props.is_enabled + + @classmethod + def does_backend_support_inpainting(cls, context): + return utils.sd_backend(context) == "shark" def draw(self, context): layout = self.layout @@ -519,6 +523,12 @@ def draw(self, context): width_guess = 220 + if not AIR_PT_inpaint.does_backend_support_inpainting(context): + box = layout.box() + utils.label_multiline(box, text=f"Inpainting is not supported by {utils.sd_backend_formatted_name()}. If you'd like to inpaint your image, switch to SHARK by nod.ai in AI Render's preferences.", icon="ERROR", width=width_guess) + return + + row = layout.row() row.prop(props, "inpaint_full_res") @@ -546,13 +556,25 @@ class AIR_PT_outpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.sd_backend(context) == "shark" + return utils.is_installation_valid() and context.scene.air_props.is_enabled + + @classmethod + def does_backend_support_outpainting(cls, context): + return utils.sd_backend(context) == "shark" def draw(self, context): layout = self.layout scene = context.scene props = scene.air_props + width_guess = 220 + + if not AIR_PT_outpaint.does_backend_support_outpainting(context): + box = layout.box() + utils.label_multiline(box, text=f"Outpainting is not supported by {utils.sd_backend_formatted_name()}. If you'd like to outpaint your image, switch to SHARK by nod.ai in AI Render's preferences.", icon="ERROR", width=width_guess) + return + + row = layout.row() sub = row.column() sub.label(text="Outpaint Direction:") From 0610e5017b24adc3e2f16c9bd769b25d3e3bed2f Mon Sep 17 00:00:00 2001 From: Ben Rugg Date: Mon, 3 Jul 2023 10:57:34 -0500 Subject: [PATCH 79/80] Only show inpaint/outpaint for backends that suppport them --- operators.py | 23 +++++++++++++---------- properties.py | 1 + sd_backends/automatic1111_api.py | 8 ++++++++ sd_backends/shark_api.py | 16 ++++++++++++---- sd_backends/stability_api.py | 8 ++++++++ sd_backends/stablehorde_api.py | 8 ++++++++ ui/ui_panels.py | 27 ++++----------------------- 7 files changed, 54 insertions(+), 37 deletions(-) diff --git a/operators.py b/operators.py index dc899cc..bc48dcb 100644 --- a/operators.py +++ b/operators.py @@ -539,9 +539,10 @@ def sd_upscale(scene): # return success return True + # Inpainting def sd_inpaint(scene): - """Post to the API to generate a Stable Diffusion image and then process it""" + """Post to the API to generate a Stable Diffusion image with inpainting, and then process it""" props = scene.air_props # get the prompt if we haven't been given one @@ -552,7 +553,7 @@ def sd_inpaint(scene): else: prompt = get_full_prompt(scene) negative_prompt = props.negative_prompt_text.strip() - + # validate the parameters we will send if not validate_params(scene, prompt): @@ -574,7 +575,7 @@ def sd_inpaint(scene): img_file = open(props.last_generated_image_filename, 'rb') except: return handle_error("Couldn't load the last Stable Diffusion image. It's probably been deleted or moved. You'll need to restore it or render a new image.", "load_last_generated_image") - + # load mask here if props.inpaint_mask_path == "": return handle_error("Couldn't find the Inpaint Mask File", "inpaint_mask_path") @@ -582,7 +583,7 @@ def sd_inpaint(scene): mask_file = open(props.inpaint_mask_path, 'rb') except: return handle_error("Couldn't load the uploaded inpaint mask file", "inpaint_mask_path") - + # prepare data for the API request params = { "prompt": prompt, @@ -613,7 +614,7 @@ def sd_inpaint(scene): # store this image filename as the last generated image props.last_generated_image_filename = generated_image_file - + # if we're rendering an animation manually, save the image to the animation output path if props.is_rendering_animation_manually: generated_image_file = save_animation_image(scene, animation_output_filename_prefix, generated_image_file) @@ -636,7 +637,7 @@ def sd_inpaint(scene): # Outpainting def sd_outpaint(scene): - """Post to the API to generate a Stable Diffusion image and then process it""" + """Post to the API to generate a Stable Diffusion image with outpainting, and then process it""" props = scene.air_props # get the prompt if we haven't been given one @@ -647,7 +648,7 @@ def sd_outpaint(scene): else: prompt = get_full_prompt(scene) negative_prompt = props.negative_prompt_text.strip() - + # validate the parameters we will send if not validate_params(scene, prompt): @@ -669,8 +670,8 @@ def sd_outpaint(scene): img_file = open(props.last_generated_image_filename, 'rb') except: return handle_error("Couldn't load the last Stable Diffusion image. It's probably been deleted or moved. You'll need to restore it or render a new image.", "load_last_generated_image") - - + + # prepare data for the API request params = { "prompt": prompt, @@ -704,7 +705,7 @@ def sd_outpaint(scene): # store this image filename as the last generated image props.last_generated_image_filename = generated_image_file - + # if we're rendering an animation manually, save the image to the animation output path if props.is_rendering_animation_manually: generated_image_file = save_animation_image(scene, animation_output_filename_prefix, generated_image_file) @@ -724,6 +725,7 @@ def sd_outpaint(scene): # return success return True + class AIR_OT_enable(bpy.types.Operator): "Enable AI Render in this scene" bl_idname = "ai_render.enable" @@ -1167,6 +1169,7 @@ def execute(self, context): return {'FINISHED'} + class AIR_OT_outpaint_from_last_sd_image(bpy.types.Operator): "Inpaint a new Stable Diffusion image - without re-rendering - using the most recent Stable Diffusion image as the starting point" bl_idname = "ai_render.outpaint_from_last_sd_image" diff --git a/properties.py b/properties.py index 1add8f5..c329e76 100644 --- a/properties.py +++ b/properties.py @@ -47,6 +47,7 @@ def get_outpaint_directions(self, context): ("right", "right", ""), ] + def ensure_sampler(context): # """Ensure that the sampler is set to a valid value""" scene = context.scene diff --git a/sd_backends/automatic1111_api.py b/sd_backends/automatic1111_api.py index 0c9ba76..19af053 100644 --- a/sd_backends/automatic1111_api.py +++ b/sd_backends/automatic1111_api.py @@ -279,6 +279,14 @@ def supports_reloading_upscaler_models(): return True +def supports_inpainting(): + return False + + +def supports_outpainting(): + return False + + def min_image_size(): return 128 * 128 diff --git a/sd_backends/shark_api.py b/sd_backends/shark_api.py index 177c9c3..27c842e 100644 --- a/sd_backends/shark_api.py +++ b/sd_backends/shark_api.py @@ -73,7 +73,7 @@ def upscale(img_file, filename_prefix, props): def inpaint(params, img_file, mask_file, filename_prefix, props): - + params["image"] = "data:image/png;base64," + base64.b64encode(img_file.read()).decode() img_file.close() @@ -94,10 +94,10 @@ def inpaint(params, img_file, mask_file, filename_prefix, props): return handle_success(response, filename_prefix) else: return handle_error(response) - + def outpaint(params, img_file, filename_prefix, props): - + params["init_images"] = ["data:image/png;base64," + base64.b64encode(img_file.read()).decode()] img_file.close() @@ -236,6 +236,14 @@ def supports_reloading_upscaler_models(): return False +def supports_inpainting(): + return True + + +def supports_outpainting(): + return True + + def get_upscaler_models(context): # NOTE: Shark does not look at model in API Req and defaults to stabilityai return [ @@ -258,4 +266,4 @@ def get_samplers(): def default_sampler(): - return 'k_euler' \ No newline at end of file + return 'k_euler' diff --git a/sd_backends/stability_api.py b/sd_backends/stability_api.py index 3672a72..a306281 100644 --- a/sd_backends/stability_api.py +++ b/sd_backends/stability_api.py @@ -280,6 +280,14 @@ def supports_reloading_upscaler_models(): return False +def supports_inpainting(): + return False + + +def supports_outpainting(): + return False + + def min_image_size(): return 256 * 1024 diff --git a/sd_backends/stablehorde_api.py b/sd_backends/stablehorde_api.py index 093d960..7ee4a17 100644 --- a/sd_backends/stablehorde_api.py +++ b/sd_backends/stablehorde_api.py @@ -216,6 +216,14 @@ def supports_reloading_upscaler_models(): return False +def supports_inpainting(): + return False + + +def supports_outpainting(): + return False + + def min_image_size(): return 128 * 128 diff --git a/ui/ui_panels.py b/ui/ui_panels.py index 83401ea..e621bd5 100644 --- a/ui/ui_panels.py +++ b/ui/ui_panels.py @@ -510,11 +510,7 @@ class AIR_PT_inpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled - - @classmethod - def does_backend_support_inpainting(cls, context): - return utils.sd_backend(context) == "shark" + return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.get_active_backend().supports_inpainting() def draw(self, context): layout = self.layout @@ -523,12 +519,6 @@ def draw(self, context): width_guess = 220 - if not AIR_PT_inpaint.does_backend_support_inpainting(context): - box = layout.box() - utils.label_multiline(box, text=f"Inpainting is not supported by {utils.sd_backend_formatted_name()}. If you'd like to inpaint your image, switch to SHARK by nod.ai in AI Render's preferences.", icon="ERROR", width=width_guess) - return - - row = layout.row() row.prop(props, "inpaint_full_res") @@ -545,6 +535,7 @@ def draw(self, context): row.enabled = props.last_generated_image_filename != "" and props.inpaint_mask_path != "" row.operator(operators.AIR_OT_inpaint_from_last_sd_image.bl_idname) + class AIR_PT_outpaint(bpy.types.Panel): bl_label = "Outpaint" bl_idname = "AIR_PT_outpaint" @@ -556,12 +547,8 @@ class AIR_PT_outpaint(bpy.types.Panel): @classmethod def poll(cls, context): - return utils.is_installation_valid() and context.scene.air_props.is_enabled - - @classmethod - def does_backend_support_outpainting(cls, context): - return utils.sd_backend(context) == "shark" - + return utils.is_installation_valid() and context.scene.air_props.is_enabled and utils.get_active_backend().supports_outpainting() + def draw(self, context): layout = self.layout scene = context.scene @@ -569,12 +556,6 @@ def draw(self, context): width_guess = 220 - if not AIR_PT_outpaint.does_backend_support_outpainting(context): - box = layout.box() - utils.label_multiline(box, text=f"Outpainting is not supported by {utils.sd_backend_formatted_name()}. If you'd like to outpaint your image, switch to SHARK by nod.ai in AI Render's preferences.", icon="ERROR", width=width_guess) - return - - row = layout.row() sub = row.column() sub.label(text="Outpaint Direction:") From 1f6e961342fc0e609f041ee8bb51dd70957ef952 Mon Sep 17 00:00:00 2001 From: Ben Rugg Date: Mon, 3 Jul 2023 10:58:26 -0500 Subject: [PATCH 80/80] Bump version --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 7004ee7..283934c 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ "name": "AI Render - Stable Diffusion in Blender", "description": "Create amazing images using Stable Diffusion AI", "author": "Ben Rugg", - "version": (0, 8, 0), + "version": (0, 9, 0), "blender": (3, 0, 0), "location": "Render Properties > AI Render", "warning": "",