Skip to content

Commit 9594b5f

Browse files
authored
Merge branch 'develop' into chore/19--Collect-Instances-earlier
2 parents 4cd0ebe + 7c28c88 commit 9594b5f

4 files changed

Lines changed: 101 additions & 32 deletions

File tree

client/ayon_photoshop/plugins/publish/extract_image.py

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import os
2+
from typing import TYPE_CHECKING
23

34
import pyblish.api
45
from ayon_core.pipeline import publish
56
from ayon_core.pipeline.colorspace import get_remapped_colorspace_from_native
67
from ayon_photoshop import api as photoshop
8+
if TYPE_CHECKING:
9+
from ayon_core.pipeline import CreateContext, CreatedInstance
710

811

912
class ExtractImage(
1013
pyblish.api.ContextPlugin,
11-
publish.ColormanagedPyblishPluginMixin
14+
publish.ColormanagedPyblishPluginMixin,
15+
publish.OptionalPyblishPluginMixin
1216
):
1317
"""Extract all layers (groups) marked for publish.
1418
@@ -23,20 +27,21 @@ class ExtractImage(
2327
order = publish.Extractor.order - 0.48
2428
label = "Extract Image"
2529
hosts = ["photoshop"]
26-
27-
families = ["image", "background"]
30+
families = ["image"]
2831
formats = ["png", "jpg", "tga", "exr"]
2932
settings_category = "photoshop"
33+
optional = False
3034

3135
def process(self, context):
3236
# Filter instances
3337
filtered_instances = []
3438
for instance in context:
35-
product_base_type = instance.data.get("productBaseType")
36-
if not product_base_type:
37-
product_base_type = instance.data["productType"]
38-
if product_base_type in self.families:
39-
filtered_instances.append(instance)
39+
if (
40+
instance.data["productBaseType"] != "image"
41+
or not self.is_active(instance.data)
42+
):
43+
continue
44+
filtered_instances.append(instance)
4045

4146
if not filtered_instances:
4247
return
@@ -55,25 +60,30 @@ def process(self, context):
5560
staging_dir = self.staging_dir(instance)
5661
self.log.info(f"Outputting image to {staging_dir}")
5762

58-
# Get instance layer ID
59-
members = instance.data("members")
60-
if not members:
63+
ids = set()
64+
65+
# real layers and groups
66+
members = instance.data.get("members")
67+
if members:
68+
ids.update(int(member) for member in members)
69+
70+
# virtual groups collected by color coding or auto_image
71+
add_ids = instance.data.pop("ids", None)
72+
if add_ids:
73+
ids.update(set(add_ids))
74+
75+
if not ids:
76+
self.log.debug(
77+
f"Instance {instance} has no publishable layers, "
78+
f"skipping."
79+
)
6180
continue
62-
instance_id = int(members[0])
6381

6482
# Context manager handles all visibility: show instance path,
6583
# hide siblings, restore original state on exit
66-
with photoshop.isolated_layers_visibility(stub, instance_id, all_layers):
84+
with photoshop.isolated_layers_visibility(stub, ids, all_layers):
6785
# Perform extraction
6886
files = {}
69-
ids = set()
70-
# real layers and groups
71-
if members:
72-
ids.update(int(member) for member in members)
73-
# virtual groups collected by color coding or auto_image
74-
add_ids = instance.data.pop("ids", None)
75-
if add_ids:
76-
ids.update(set(add_ids))
7787

7888
file_basename, workfile_extension = os.path.splitext(
7989
stub.get_active_document_name()
@@ -127,3 +137,15 @@ def staging_dir(self, instance):
127137
from ayon_core.pipeline.publish import get_instance_staging_dir
128138

129139
return get_instance_staging_dir(instance)
140+
141+
@classmethod
142+
def get_attr_defs_for_context(cls, create_context: "CreateContext"):
143+
return []
144+
145+
@classmethod
146+
def get_attr_defs_for_instance(
147+
cls, create_context: "CreateContext", instance: "CreatedInstance"
148+
):
149+
if instance.product_base_type != "image":
150+
return []
151+
return cls.get_attribute_defs()

client/ayon_photoshop/plugins/publish/extract_layers.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1+
import os
12
from pathlib import Path
3+
from typing import TYPE_CHECKING
24

35
from ayon_core.pipeline import publish
46
from ayon_core.pipeline.colorspace import get_remapped_colorspace_from_native
57
from ayon_core.pipeline.publish import get_instance_staging_dir
68
from ayon_photoshop import api as photoshop
79

10+
if TYPE_CHECKING:
11+
from ayon_core.pipeline import CreateContext, CreatedInstance
12+
813

914
class ExtractLayers(
1015
publish.Extractor,
11-
publish.ColormanagedPyblishPluginMixin
16+
publish.ColormanagedPyblishPluginMixin,
17+
publish.OptionalPyblishPluginMixin
1218
):
1319
"""Export layers within the instance layerset to a PSD file.
1420
@@ -19,9 +25,17 @@ class ExtractLayers(
1925
order = publish.Extractor.order # Must be after ExtractImage
2026
hosts = ["photoshop"]
2127
families = ["image"]
28+
optional = False
2229
merge_layersets = False
30+
extension = "psd"
2331

2432
def process(self, instance):
33+
if (
34+
instance.data.get("productBaseType") != "image"
35+
or instance.data.get("creatorIdentifier") == "auto_image"
36+
or not self.is_active(instance.data)
37+
):
38+
return
2539
ps_stub = photoshop.stub()
2640
native_colorspace = ps_stub.get_color_profile_name()
2741
self.log.info(f"Document colorspace profile: {native_colorspace}")
@@ -35,16 +49,20 @@ def process(self, instance):
3549
)
3650
self.log.debug(f"ayon_colorspace: {ayon_colorspace}")
3751
# Duplicate the document to the staging directory
52+
filename = ps_stub.get_active_document_name()
53+
basename = os.path.splitext(filename)[0]
54+
filename = f"{basename}.{self.extension}"
3855
filepath = Path(
3956
get_instance_staging_dir(instance),
40-
ps_stub.get_active_document_name()
57+
filename
4158
)
4259
self.log.info(f"Duplicating document to staging directory: {filepath}")
43-
with ps_stub.duplicate_document(
44-
filepath
45-
):
60+
with ps_stub.duplicate_document(filepath):
4661
# Delete all layers except the instance layerset
4762
layer = instance.data.get("layer")
63+
if not hasattr(layer, "id"):
64+
self.log.warning("Instance layer does not have an id, skipping.")
65+
return
4866
ps_stub.delete_all_layers(
4967
exclude_layers=[layer],
5068
exclude_recursive=True
@@ -64,8 +82,8 @@ def process(self, instance):
6482
instance.data["stagingDir"] = filepath.parent
6583
representations = instance.data.setdefault("representations", [])
6684
representation = {
67-
"name": "psd",
68-
"ext": "psd",
85+
"name": self.extension,
86+
"ext": self.extension,
6987
"files": filepath.name,
7088
"stagingDir": filepath.parent,
7189
}
@@ -74,5 +92,16 @@ def process(self, instance):
7492
representation, instance.context,
7593
colorspace=ayon_colorspace
7694
)
77-
self.log.debug(f"Rrepresentation: {representation}")
95+
self.log.debug(f"Representation: {representation}")
7896
representations.append(representation)
97+
98+
@classmethod
99+
def get_attr_defs_for_instance(
100+
cls, create_context: "CreateContext", instance: "CreatedInstance"
101+
):
102+
if (
103+
instance.product_base_type != "image"
104+
or instance.creator_identifier == "auto_image"
105+
):
106+
return []
107+
return cls.get_attribute_defs()

docs/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
--8<-- "README.md"
1+
# AYON Photoshop Addon API Reference
2+
3+
--8<-- "README.md:3"

server/settings/publish_plugins.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
{"value": "exr", "label": "exr"},
2626
]
2727

28+
extract_layer_ext_enum = [
29+
{"value": "psd", "label": "psd"},
30+
{"value": "psb", "label": "psb"},
31+
]
32+
2833
color_mode_enum = [
2934
{"value": "RGB", "label": "RGB"},
3035
{"value": "CMYK", "label": "CMYK"},
@@ -122,7 +127,8 @@ class ValidateNamingPlugin(BaseSettingsModel):
122127

123128
class ExtractImagePlugin(BaseSettingsModel):
124129
"""Extracts image products and representations per published instance"""
125-
130+
enabled: bool = SettingsField(True, title="Enabled")
131+
optional: bool = SettingsField(False, title="Optional")
126132
formats: list[str] = SettingsField(
127133
title="Extract Formats",
128134
default_factory=list,
@@ -140,11 +146,17 @@ class ExtractSourceReviewPlugin(BaseSettingsModel):
140146
class ExtractLayersPlugin(BaseSettingsModel):
141147
"""Export layers within the instance layerset to a PSD file."""
142148
enabled: bool = SettingsField(False, title="Enabled")
149+
optional: bool = SettingsField(False, title="Optional")
143150
merge_layersets: bool = SettingsField(
144151
False,
145152
title="Merge Layersets",
146153
description="Merge all layersets within the instance set.",
147154
)
155+
extension: str = SettingsField(
156+
"psd",
157+
title="Export extension",
158+
enum_resolver=lambda: extract_layer_ext_enum,
159+
)
148160

149161

150162
class ValidateDocumentSettingsPlugin(BaseSettingsModel):
@@ -225,6 +237,8 @@ class PhotoshopPublishPlugins(BaseSettingsModel):
225237
"replace_char": "_"
226238
},
227239
"ExtractImage": {
240+
"enabled": True,
241+
"optional": False,
228242
"formats": [
229243
"png",
230244
"jpg",
@@ -235,7 +249,9 @@ class PhotoshopPublishPlugins(BaseSettingsModel):
235249
},
236250
"ExtractLayers": {
237251
"enabled": False,
238-
"merge_layersets": False
252+
"optional": False,
253+
"merge_layersets": False,
254+
"extension": "psd",
239255
},
240256
"ValidateDocumentSettings": {
241257
"enabled": False,

0 commit comments

Comments
 (0)