-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathseparate_layers.py
More file actions
295 lines (236 loc) · 9.38 KB
/
separate_layers.py
File metadata and controls
295 lines (236 loc) · 9.38 KB
1
2
3
4
5
6
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
"""
ZERO VFX Shotgun Photoshop Plugin: Separating and Saving Layers
Developed by Rishi Pandey. Summer 2019.
"""
import os
import pprint
import tempfile
import uuid
import sys
import sgtk
#ADD THE PATH OF THE PSD_TOOLS2 LIBRARY
psd_tool2Path = "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages"
sys.path.append(psd_tool2Path)
from psd_tools2 import PSDImage
HookBaseClass = sgtk.get_hook_baseclass()
class PhotoshopUploadVersionPlugin(HookBaseClass):
"""
Plugin for sending layers of photoshop documents to shotgun for review.
"""
@property
def icon(self):
"""
Path to an png icon on disk
"""
# look for icon one level up from this hook's folder in "icons" folder
return os.path.join(
self.disk_location,
os.pardir,
"icons",
"review.png"
)
@property
def name(self):
"""
One line display name describing the plugin
"""
return "Separate Layers"
@property
def description(self):
"""
Verbose, multi-line description of what the plugin does. This can
contain simple html for formatting.
"""
publisher = self.parent
shotgun_url = publisher.sgtk.shotgun_url
media_page_url = "%s/page/media_center" % (shotgun_url,)
review_url = "https://www.shotgunsoftware.com/features/#review"
return """
Separate layers and upload to Shotgun for review.<br><br>
A <b>Version</b> entry will be created in Shotgun and a transcoded
copy of the file will be attached to it. The file can then be reviewed
via the project's <a href='%s'>Media</a> page, <a href='%s'>RV</a>, or
the <a href='%s'>Shotgun Review</a> mobile app.
""" % (media_page_url, review_url, review_url)
@property
def settings(self):
"""
Dictionary defining the settings that this plugin expects to recieve
through the settings parameter in the accept, validate, publish and
finalize methods.
A dictionary on the following form::
{
"Settings Name": {
"type": "settings_type",
"default": "default_value",
"description": "One line description of the setting"
}
The type string should be one of the data types that toolkit accepts as
part of its environment configuration.
"""
return {}
@property
def item_filters(self):
"""
List of item types that this plugin is interested in.
Only items matching entries in this list will be presented to the
accept() method. Strings can contain glob patters such as *, for example
["maya.*", "file.maya"]
"""
# we use "video" since that's the mimetype category.
return ["photoshop.document"]
def accept(self, settings, item):
"""
Method called by the publisher to determine if an item is of any
interest to this plugin. Only items matching the filters defined via the
item_filters property will be presented to this method.
A publish task will be generated for each item accepted here. Returns a
dictionary with the following booleans:
- accepted: Indicates if the plugin is interested in this value at
all. Required.
- enabled: If True, the plugin will be enabled in the UI, otherwise
it will be disabled. Optional, True by default.
- visible: If True, the plugin will be visible in the UI, otherwise
it will be hidden. Optional, True by default.
- checked: If True, the plugin will be checked in the UI, otherwise
it will be unchecked. Optional, True by default.
:param settings: Dictionary of Settings. The keys are strings, matching
the keys returned in the settings property. The values are `Setting`
instances.
:param item: Item to process
:returns: dictionary with boolean keys accepted, required and enabled
"""
document = item.properties.get("document")
if not document:
self.logger.warn("Could not determine the document for item")
return {"accepted": False}
path = _document_path(document)
if not path:
# the document has not been saved before (no path determined).
# provide a save button. the document will need to be saved before
# validation will succeed.
self.logger.warn(
"The Photoshop document '%s' has not been saved." %
(document.name,),
extra=_get_save_as_action(document)
)
self.logger.info(
"Photoshop '%s' plugin accepted document: %s" %
(self.name, document.name)
)
return {
"accepted": True,
"checked": True
}
def validate(self, settings, item):
"""
check to see if there are layers before publishing
"""
"""
Validates the given item to check that it is ok to publish.
Returns a boolean to indicate validity.
:param settings: Dictionary of Settings. The keys are strings, matching
the keys returned in the settings property. The values are `Setting`
instances.
:param item: Item to process
:returns: True if item is valid, False otherwise.
"""
document = item.properties["document"]
path = _document_path(document)
psdProject = PSDImage.open(path)
for layer in psdProject:
self.logger.info("Validated {layerName}.psd".format(layerName=layer.name))
return True
def publish(self, settings, item):
"""
Executes the publish logic for the given item and settings.
:param settings: Dictionary of Settings. The keys are strings, matching
the keys returned in the settings property. The values are `Setting`
instances.
:param item: Item to process
"""
publisher = self.parent
engine = publisher.engine
document = item.properties["document"]
path = _document_path(document)
item.properties["upload_path"] = path
item
psdProject = PSDImage.open(path)
#save layers to link and create new task to do so
for layer in psdProject:
layer.compose().save(layer.name+'.tiff')
self.logger.info("Saved Layer {layerName}.psd".format(layerName=layer.name))
publish = sgtk.util.register_publish(publisher.sgtk,
item.context,
os.path.join(os.path.dirname(path),layer.name+'.tiff'),
layer.name,
version_number=None,
published_file_type="Rendered Image")
def finalize(self, settings, item):
"""
Execute the finalization pass. This pass executes once all the publish
tasks have completed, and can for example be used to version up files.
:param settings: Dictionary of Settings. The keys are strings, matching
the keys returned in the settings property. The values are `Setting`
instances.
:param item: Item to process
"""
# version = item.properties["sg_version_data"]
self.logger.info(
"Version uploaded for Photoshop document",
extra={
"action_show_in_shotgun": {
"label": "Show Version",
"tooltip": "Reveal the version in Shotgun.",
"entity": None
}
}
)
upload_path = item.properties["upload_path"]
# remove the tmp file
if item.properties.get("remove_upload", False):
try:
os.remove(upload_path)
except Exception:
self.logger.warn(
"Unable to remove temp file: %s" % (upload_path,))
pass
def _get_version_entity(self, item):
"""
Returns the best entity to link the version to.
"""
if item.context.entity:
return item.context.entity
elif item.context.project:
return item.context.project
else:
return None
def _get_save_as_action(document):
"""
Simple helper for returning a log action dict for saving the document
"""
engine = sgtk.platform.current_engine()
# default save callback
callback = lambda: engine.save_as(document)
# if workfiles2 is configured, use that for file save
if "tk-multi-workfiles2" in engine.apps:
app = engine.apps["tk-multi-workfiles2"]
if hasattr(app, "show_file_save_dlg"):
callback = app.show_file_save_dlg
return {
"action_button": {
"label": "Save As...",
"tooltip": "Save the current document",
"callback": callback
}
}
def _document_path(document):
"""
Returns the path on disk to the supplied document. May be ``None`` if the
document has not been saved.
"""
try:
path = document.fullName.fsName
except Exception:
path = None
return path