Bases: Extractor
Produce a flattened or sequence image files from all 'image' instances.
These files are then used by global ExtractReview and ExtractThumbnail to create reviews with globally controllable configuration.
If no 'image' instance is created, it produces flattened image from all visible layers.
It can also create separate reviews per image instance if necessary. (toggle on an instance in Publisher UI).
'review' family could be used in other steps as a reference, as it contains flattened image by default. (Eg. artist could load this review as a single item and see full image. In most cases 'image' product type is separated by layers to better usage in animation or comp.)
Source code in client/ayon_photoshop/plugins/publish/extract_sources_review.py
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 | class ExtractSourcesReview(publish.Extractor):
"""
Produce a flattened or sequence image files from all 'image' instances.
These files are then used by global `ExtractReview` and
`ExtractThumbnail` to create reviews with globally controllable
configuration.
If no 'image' instance is created, it produces flattened image from
all visible layers.
It can also create separate reviews per `image` instance if necessary.
(toggle on an instance in Publisher UI).
'review' family could be used in other steps as a reference, as it
contains flattened image by default. (Eg. artist could load this
review as a single item and see full image. In most cases 'image'
product type is separated by layers to better usage in animation
or comp.)
"""
label = "Extract Sources for Review"
hosts = ["photoshop"]
families = ["review"]
settings_category = "photoshop"
order = publish.Extractor.order - 0.28
# Extract Options
make_image_sequence = None
def process(self, instance):
staging_dir = self.staging_dir(instance)
self.log.info("Outputting image to {}".format(staging_dir))
stub = photoshop.stub()
self.output_seq_filename = os.path.splitext(
stub.get_active_document_name())[0] + ".%04d.jpg"
layers = self._get_layers_from_image_instances(instance)
self.log.info("Layers image instance found: {}".format(layers))
additional_repre = {
"name": "jpg",
"ext": "jpg",
"frameStart": instance.data["frameStart"],
"frameEnd": instance.data["frameEnd"],
"fps": instance.data["fps"],
"stagingDir": staging_dir,
"tags": ["review"],
}
if instance.data["productType"] == "image":
self._attach_review_tag(instance)
elif self.make_image_sequence and len(layers) > 1:
self.log.debug("Extract layers to image sequence.")
img_list = self._save_sequence_images(staging_dir, layers)
instance.data["frameEnd"] = instance.data["frameStart"] + len(img_list) - 1
additional_repre["output_name"] = "mov"
additional_repre["files"] = img_list
instance.data["representations"].append(additional_repre)
else:
self.log.debug("Extract layers to flatten image.")
review_source_path = self._save_flatten_image(
staging_dir,
layers
)
additional_repre["files"] = os.path.basename(review_source_path)
additional_repre["output_name"] = "jpg"
# just intermediate repre to create a review from
additional_repre["tags"].append("delete")
instance.data["representations"].append(additional_repre)
instance.data["stagingDir"] = staging_dir
self.log.info(f"Extracted {instance} to {staging_dir}")
def _attach_review_tag(self, instance):
"""Searches for repre for which jpg review should be created.
"jpg" representation is preferred.
"""
jpg_source_repre = None
for repre in instance.data["representations"]:
if repre["name"] == "jpg":
jpg_source_repre = repre
repre["tags"].append("review")
break
if not jpg_source_repre:
repre = instance.data["representations"][0]
repre["tags"].append("review")
def _get_layers_from_image_instances(self, instance):
"""Collect all layers from image instance(s)
If `instance` is `image` it returns just layers out of it to create
separate review per instance.
If `instance` is (most likely) `review`, it collects all layers from
published instances to create one review from all of them.
Returns:
(list) of PSItem
"""
layers = []
# creating review for existing 'image' instance
if (
instance.data["productType"] == "image"
and instance.data.get("layer")
):
layers.append(instance.data["layer"])
return layers
# collect all layers from published image instances
for image_instance in instance.context:
if image_instance.data["productType"] != "image":
continue
layer = image_instance.data.get("layer")
if layer:
layers.append(layer)
return sorted(layers)
def _save_flatten_image(self, staging_dir, layers):
"""Creates flat image from 'layers' into 'staging_dir'.
Returns:
(str): path to new image
"""
img_filename = self.output_seq_filename % 0
output_image_path = os.path.join(staging_dir, img_filename)
stub = photoshop.stub()
with photoshop.maintained_visibility():
self.log.info("Extracting {}".format(layers))
if layers:
stub.hide_all_others_layers(layers)
stub.saveAs(output_image_path, 'jpg', True)
return output_image_path
def _save_sequence_images(self, staging_dir, layers):
"""Creates separate images from 'layers' into 'staging_dir'.
`layers` are actually groups matching instances.
Used as source for multi frames .mov to review at once.
Returns:
(list): paths to new images
"""
stub = photoshop.stub()
list_img_filename = []
with photoshop.maintained_visibility():
for i, layer in enumerate(layers):
self.log.info("Extracting {}".format(layer))
img_filename = self.output_seq_filename % i
output_image_path = os.path.join(staging_dir, img_filename)
list_img_filename.append(img_filename)
with photoshop.maintained_visibility():
stub.hide_all_others_layers([layer])
stub.saveAs(output_image_path, 'jpg', True)
return list_img_filename
|