libreflow.extensions.sk.export-psd-layers 1.1.6__tar.gz → 1.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/CHANGELOG.md +13 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6/src/libreflow.extensions.sk.export_psd_layers.egg-info → libreflow_extensions_sk_export_psd_layers-1.1.8}/PKG-INFO +14 -1
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow/extensions/sk/export_psd_layers/__init__.py +333 -54
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow/extensions/sk/export_psd_layers/_version.py +3 -3
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8/src/libreflow.extensions.sk.export_psd_layers.egg-info}/PKG-INFO +14 -1
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/MANIFEST.in +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/README.md +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/setup.cfg +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/setup.py +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow/__init__.py +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow/extensions/__init__.py +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow/extensions/sk/__init__.py +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow.extensions.sk.export_psd_layers.egg-info/SOURCES.txt +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow.extensions.sk.export_psd_layers.egg-info/dependency_links.txt +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow.extensions.sk.export_psd_layers.egg-info/requires.txt +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/src/libreflow.extensions.sk.export_psd_layers.egg-info/top_level.txt +0 -0
- {libreflow_extensions_sk_export_psd_layers-1.1.6 → libreflow_extensions_sk_export_psd_layers-1.1.8}/versioneer.py +0 -0
|
@@ -19,6 +19,19 @@ Types of changes
|
|
|
19
19
|
|
|
20
20
|
## [Unreleased]
|
|
21
21
|
|
|
22
|
+
## [1.1.8] - 2025-10-07
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
* Export resized to psd canvas - warning message for layers with a bouding box twice as large as the viewbox
|
|
27
|
+
|
|
28
|
+
## [1.1.7] - 2025-08-19
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
* Warning message when publishing regarding resolution and colour depth.
|
|
33
|
+
* Message in the window when creating a new working copy.
|
|
34
|
+
|
|
22
35
|
## [1.1.6] - 2025-08-07
|
|
23
36
|
|
|
24
37
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libreflow.extensions.sk.export_psd_layers
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.8
|
|
4
4
|
Home-page: https://gitlab.com/lfs.coop/libreflow/libreflow_launcher
|
|
5
5
|
Author: Thomas Thiebaut
|
|
6
6
|
Author-email: autor@les-fees-speciales.coop
|
|
@@ -50,6 +50,19 @@ Types of changes
|
|
|
50
50
|
|
|
51
51
|
## [Unreleased]
|
|
52
52
|
|
|
53
|
+
## [1.1.8] - 2025-10-07
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
* Export resized to psd canvas - warning message for layers with a bouding box twice as large as the viewbox
|
|
58
|
+
|
|
59
|
+
## [1.1.7] - 2025-08-19
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
* Warning message when publishing regarding resolution and colour depth.
|
|
64
|
+
* Message in the window when creating a new working copy.
|
|
65
|
+
|
|
53
66
|
## [1.1.6] - 2025-08-07
|
|
54
67
|
|
|
55
68
|
### Fixed
|
|
@@ -1,22 +1,26 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
import json
|
|
1
3
|
import os
|
|
2
4
|
import re
|
|
3
|
-
import json
|
|
4
|
-
import gazu
|
|
5
5
|
import time
|
|
6
6
|
|
|
7
|
+
import gazu
|
|
7
8
|
from kabaret import flow
|
|
8
|
-
from libreflow.flows.default.flow.film import Film
|
|
9
9
|
from libreflow.baseflow.file import (
|
|
10
|
-
|
|
11
|
-
TrackedFile,
|
|
10
|
+
CreateWorkingCopyAction,
|
|
12
11
|
FileRevisionNameChoiceValue,
|
|
13
|
-
UploadPNGToKitsu,
|
|
14
12
|
PublishAndRenderPlayblast,
|
|
13
|
+
PublishFileAction,
|
|
14
|
+
TrackedFile,
|
|
15
|
+
UploadPNGToKitsu,
|
|
15
16
|
)
|
|
17
|
+
from libreflow.flows.default.flow.film import Film
|
|
16
18
|
from psd_tools import PSDImage
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class ExportPSDLayers(flow.Action):
|
|
22
|
+
"""Exports Photoshop (PSD/PSB) layers for background layout and color tasks."""
|
|
23
|
+
|
|
20
24
|
ICON = ("icons.flow", "photoshop")
|
|
21
25
|
|
|
22
26
|
_file = flow.Parent()
|
|
@@ -28,6 +32,15 @@ class ExportPSDLayers(flow.Action):
|
|
|
28
32
|
revision = flow.Param(None, FileRevisionNameChoiceValue)
|
|
29
33
|
|
|
30
34
|
def allow_context(self, context):
|
|
35
|
+
"""Check whether the given context is valid for running the action.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
context: Context object, usually representing the current project/task.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
bool: True if the action can be executed in this context, False otherwise.
|
|
42
|
+
|
|
43
|
+
"""
|
|
31
44
|
return (
|
|
32
45
|
context
|
|
33
46
|
and self._file.format.get() in ["psd", "psb"]
|
|
@@ -35,24 +48,45 @@ class ExportPSDLayers(flow.Action):
|
|
|
35
48
|
self._file.get_revision_names(
|
|
36
49
|
sync_status="Available", published_only=True
|
|
37
50
|
)
|
|
38
|
-
)
|
|
51
|
+
)
|
|
52
|
+
> 0
|
|
39
53
|
)
|
|
40
54
|
|
|
41
55
|
def needs_dialog(self):
|
|
56
|
+
"""Indicate whether this action requires a dialog to be displayed.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
bool: always True.
|
|
60
|
+
|
|
61
|
+
"""
|
|
42
62
|
msg = ""
|
|
43
63
|
if self._task.name() == "bg_layout":
|
|
44
64
|
msg = "<b>Layout : Photoshop Project layers will be exported separately</b>"
|
|
45
65
|
elif self._task.name() == "bg_color":
|
|
46
|
-
msg =
|
|
47
|
-
|
|
66
|
+
msg = (
|
|
67
|
+
"<b>BG Color : Photoshop Project will be exported as a single image</b>"
|
|
68
|
+
)
|
|
69
|
+
|
|
48
70
|
self.message.set(msg)
|
|
49
71
|
return True
|
|
50
72
|
|
|
51
73
|
def get_buttons(self):
|
|
74
|
+
"""Return the buttons displayed in the dialog.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
list[str]: list of button labels, typically ['Export', 'Cancel'].
|
|
78
|
+
|
|
79
|
+
"""
|
|
52
80
|
self.revision.revert_to_default()
|
|
53
81
|
return ["Export", "Cancel"]
|
|
54
82
|
|
|
55
83
|
def ensure_render_folder(self):
|
|
84
|
+
"""Ensure the render output folder exists for the current file.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
flow.File: The folder object where rendered files will be stored.
|
|
88
|
+
|
|
89
|
+
"""
|
|
56
90
|
folder_name = self._file.complete_name.get()
|
|
57
91
|
folder_name += "_render"
|
|
58
92
|
|
|
@@ -65,6 +99,12 @@ class ExportPSDLayers(flow.Action):
|
|
|
65
99
|
return self._files[folder_name]
|
|
66
100
|
|
|
67
101
|
def ensure_render_folder_revision(self):
|
|
102
|
+
"""Ensure the render folder has the correct revision.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
flow.Revision: The revision object in the render folder.
|
|
106
|
+
|
|
107
|
+
"""
|
|
68
108
|
folder = self.ensure_render_folder()
|
|
69
109
|
revision_name = self.revision.get()
|
|
70
110
|
source_revision = self._file.get_revision(self.revision.get())
|
|
@@ -82,37 +122,55 @@ class ExportPSDLayers(flow.Action):
|
|
|
82
122
|
self._files.touch()
|
|
83
123
|
|
|
84
124
|
return revision
|
|
85
|
-
|
|
125
|
+
|
|
86
126
|
def get_default_file(self):
|
|
127
|
+
"""Retrieve the default file for exporting a BG color image.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
flow.File or None: The default file object, or None if not found.
|
|
131
|
+
|
|
132
|
+
"""
|
|
87
133
|
mng = self.root().project().get_task_manager()
|
|
88
134
|
default_files = mng.default_files.get()
|
|
89
135
|
for file_name, task_names in default_files.items():
|
|
90
|
-
if
|
|
136
|
+
if "bg_color.png" in file_name:
|
|
91
137
|
task = default_files[file_name][0]
|
|
92
|
-
file_mapped_name = file_name.replace(".",
|
|
138
|
+
file_mapped_name = file_name.replace(".", "_")
|
|
93
139
|
break
|
|
94
140
|
|
|
95
141
|
dft_task = mng.default_tasks[task]
|
|
96
|
-
if not dft_task.files.has_mapped_name(file_mapped_name):
|
|
142
|
+
if not dft_task.files.has_mapped_name(file_mapped_name): # check default file
|
|
97
143
|
# print(f'Scene Builder - default task {task_name} has no default file {filename} -> use default template')
|
|
98
144
|
return None
|
|
99
145
|
|
|
100
146
|
dft_file = dft_task.files[file_mapped_name]
|
|
101
147
|
return dft_file
|
|
102
|
-
|
|
148
|
+
|
|
103
149
|
def _ensure_file(self, name, format, path_format, source_revision):
|
|
150
|
+
"""Ensure a file exists in the project with the given name and revision.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
name (str): The base name of the file.
|
|
154
|
+
format (str): The file extension (e.g., "png").
|
|
155
|
+
path_format (str): The default path format for the file.
|
|
156
|
+
source_revision (flow.Revision): The source revision to copy comments from.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
flow.Revision: The revision object created or retrieved.
|
|
160
|
+
|
|
161
|
+
"""
|
|
104
162
|
mapped_name = "%s_%s" % (name, format)
|
|
105
163
|
|
|
106
164
|
file = None
|
|
107
|
-
|
|
165
|
+
|
|
108
166
|
if not self._files.has_mapped_name(mapped_name):
|
|
109
167
|
if format:
|
|
110
168
|
file = self._files.add_file(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
169
|
+
name=name,
|
|
170
|
+
extension=format,
|
|
171
|
+
tracked=True,
|
|
172
|
+
default_path_format=path_format,
|
|
173
|
+
)
|
|
116
174
|
else:
|
|
117
175
|
file = self._files.add_folder(name, tracked=True)
|
|
118
176
|
else:
|
|
@@ -127,7 +185,7 @@ class ExportPSDLayers(flow.Action):
|
|
|
127
185
|
r = file.get_revision(revision_name)
|
|
128
186
|
|
|
129
187
|
r.comment.set(source_revision.comment.get())
|
|
130
|
-
|
|
188
|
+
|
|
131
189
|
file.ensure_last_revision_oid()
|
|
132
190
|
|
|
133
191
|
r.set_sync_status("Available")
|
|
@@ -140,13 +198,22 @@ class ExportPSDLayers(flow.Action):
|
|
|
140
198
|
os.remove(img_path)
|
|
141
199
|
|
|
142
200
|
self._files.touch()
|
|
143
|
-
|
|
201
|
+
|
|
144
202
|
return r
|
|
145
203
|
|
|
146
204
|
def run(self, button):
|
|
205
|
+
"""Execute the render action.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
button (str): The label of the button pressed by the user (e.g., 'Export' or 'Cancel').
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Any: the result of the parent run method if executed, or None if canceled.
|
|
212
|
+
|
|
213
|
+
"""
|
|
147
214
|
if button == "Cancel":
|
|
148
215
|
return
|
|
149
|
-
|
|
216
|
+
|
|
150
217
|
session = self.root().session()
|
|
151
218
|
log_format = "[EXPORT LAYERS] {message}"
|
|
152
219
|
|
|
@@ -163,23 +230,22 @@ class ExportPSDLayers(flow.Action):
|
|
|
163
230
|
# Open photoshop file
|
|
164
231
|
psb = PSDImage.open(source_revision.get_path())
|
|
165
232
|
|
|
166
|
-
|
|
167
233
|
############# BG LAYOUT PROCESS #############
|
|
168
234
|
|
|
169
|
-
if self._task.name() == "bg_layout"
|
|
235
|
+
if self._task.name() == "bg_layout":
|
|
170
236
|
|
|
171
237
|
render_revision = self.ensure_render_folder_revision()
|
|
172
238
|
# JSON structure for layers order
|
|
173
239
|
layers_data = {
|
|
174
240
|
"from": os.path.basename(source_revision.get_path()),
|
|
175
241
|
"layers": [],
|
|
176
|
-
"hidden_layers": []
|
|
242
|
+
"hidden_layers": [],
|
|
177
243
|
}
|
|
178
244
|
|
|
179
245
|
# Export image layers
|
|
180
246
|
if os.path.exists(render_revision.get_path()) is False:
|
|
181
247
|
os.makedirs(render_revision.get_path())
|
|
182
|
-
|
|
248
|
+
|
|
183
249
|
folder_name = os.path.basename(render_revision.get_path())
|
|
184
250
|
|
|
185
251
|
# frame_bbox = (0, 0, 0, 0)
|
|
@@ -201,22 +267,49 @@ class ExportPSDLayers(flow.Action):
|
|
|
201
267
|
# # frame_bbox[2] - 5,
|
|
202
268
|
# # frame_bbox[3] - 5,
|
|
203
269
|
# # )
|
|
204
|
-
|
|
270
|
+
|
|
205
271
|
# print(frame_bbox)
|
|
206
272
|
|
|
273
|
+
# Stop exporting action when find layers with a bouding box twice as large as the viewbox
|
|
274
|
+
layers_to_crop = []
|
|
275
|
+
for descendant in psb.descendants():
|
|
276
|
+
if not descendant.is_group():
|
|
277
|
+
v_left, v_top, v_right, v_bottom = psb.viewbox
|
|
278
|
+
v_width, v_height = v_right - v_left, v_bottom - v_top
|
|
279
|
+
|
|
280
|
+
bbox_left, bbox_top, bbox_right, bbox_bottom = descendant.bbox
|
|
281
|
+
bbox_width, bbox_height = (
|
|
282
|
+
bbox_right - bbox_left,
|
|
283
|
+
bbox_bottom - bbox_top,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if not (bbox_height <= v_height * 2 and bbox_width <= v_width * 2):
|
|
287
|
+
layers_to_crop.append(descendant.name)
|
|
288
|
+
|
|
289
|
+
if len(layers_to_crop) != 0:
|
|
290
|
+
session.log_warning(
|
|
291
|
+
log_format.format(
|
|
292
|
+
message=f"You need to crop these layers : {layers_to_crop}"
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
return None
|
|
296
|
+
|
|
207
297
|
for layer in reversed(psb):
|
|
298
|
+
|
|
208
299
|
# Remove invalid characters
|
|
209
|
-
layer_name = layer.name.replace(
|
|
300
|
+
layer_name = layer.name.replace(" ", "-")
|
|
210
301
|
match_invalid = re.search(r"[~\"#%&*:<>?/\\{|}]+", layer.name)
|
|
211
302
|
if match_invalid:
|
|
212
|
-
layer_name = layer_name.replace(match_invalid.group(0),
|
|
303
|
+
layer_name = layer_name.replace(match_invalid.group(0), "")
|
|
213
304
|
|
|
214
305
|
output_path = os.path.join(
|
|
215
306
|
render_revision.get_path(),
|
|
216
307
|
"{folder}-{layer}.png".format(folder=folder_name, layer=layer_name),
|
|
217
308
|
)
|
|
218
309
|
|
|
219
|
-
session.log_info(
|
|
310
|
+
session.log_info(
|
|
311
|
+
log_format.format(message=f"Exporting layer {layer_name}")
|
|
312
|
+
)
|
|
220
313
|
|
|
221
314
|
if not layer.visible:
|
|
222
315
|
layer.visible = True
|
|
@@ -227,59 +320,67 @@ class ExportPSDLayers(flow.Action):
|
|
|
227
320
|
layer_name
|
|
228
321
|
)
|
|
229
322
|
|
|
230
|
-
image = layer.composite(viewport=psb.viewbox)
|
|
323
|
+
image = layer.composite(viewport=psb.viewbox, force=True)
|
|
231
324
|
image.save(output_path)
|
|
325
|
+
session.log_info(f"Layer {layer_name} exported !")
|
|
326
|
+
gc.collect()
|
|
232
327
|
|
|
233
|
-
|
|
234
328
|
# Export JSON data
|
|
235
329
|
json_object = json.dumps(layers_data)
|
|
236
330
|
json_path = os.path.join(render_revision.get_path(), "layers.json")
|
|
237
|
-
|
|
238
|
-
session.log_info(log_format.format(message=
|
|
331
|
+
|
|
332
|
+
session.log_info(log_format.format(message="Saving layers.json"))
|
|
239
333
|
with open(json_path, "w") as outfile:
|
|
240
334
|
outfile.write(json_object)
|
|
241
|
-
|
|
242
|
-
session.log_info(log_format.format(message=
|
|
243
|
-
|
|
335
|
+
|
|
336
|
+
session.log_info(log_format.format(message="Export complete"))
|
|
337
|
+
|
|
244
338
|
############# BG COLOR PROCESS #############
|
|
245
|
-
|
|
246
|
-
if self._task.name() == "bg_color"
|
|
339
|
+
|
|
340
|
+
if self._task.name() == "bg_color":
|
|
247
341
|
|
|
248
342
|
default_file = self.get_default_file()
|
|
249
343
|
|
|
250
344
|
if default_file is not None:
|
|
251
|
-
|
|
345
|
+
|
|
252
346
|
render_revision = self._ensure_file(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
347
|
+
name="bg_color",
|
|
348
|
+
format="png",
|
|
349
|
+
path_format=default_file.path_format.get(),
|
|
350
|
+
source_revision=source_revision,
|
|
351
|
+
)
|
|
258
352
|
|
|
259
353
|
output_path = render_revision.get_path()
|
|
260
354
|
|
|
261
355
|
info_layer = psb.find("INFO")
|
|
262
|
-
if info_layer
|
|
356
|
+
if info_layer:
|
|
357
|
+
info_layer.visible = False
|
|
263
358
|
|
|
264
359
|
LO_layer = psb.find("REF_LAYOUT")
|
|
265
|
-
if LO_layer
|
|
360
|
+
if LO_layer:
|
|
361
|
+
LO_layer.visible = False
|
|
266
362
|
|
|
267
363
|
DES_layer = psb.find("REF_DESIGN")
|
|
268
|
-
if DES_layer
|
|
364
|
+
if DES_layer:
|
|
365
|
+
DES_layer.visible = False
|
|
269
366
|
|
|
270
367
|
chara_layer = psb.find("character")
|
|
271
|
-
if chara_layer
|
|
368
|
+
if chara_layer:
|
|
369
|
+
chara_layer.visible = False
|
|
272
370
|
|
|
273
371
|
utils_layer = psb.find("_utils")
|
|
274
|
-
if utils_layer
|
|
372
|
+
if utils_layer:
|
|
373
|
+
utils_layer.visible = False
|
|
275
374
|
|
|
276
|
-
image = psb.composite(viewport=psb.viewbox,force=True)
|
|
375
|
+
image = psb.composite(viewport=psb.viewbox, force=True)
|
|
277
376
|
image.save(output_path)
|
|
278
377
|
|
|
279
|
-
session.log_info(log_format.format(message=
|
|
378
|
+
session.log_info(log_format.format(message="Export complete"))
|
|
280
379
|
|
|
281
380
|
else:
|
|
282
|
-
self.root().session().log_error(
|
|
381
|
+
self.root().session().log_error(
|
|
382
|
+
"[Export PSD] BG Color Image default file do not exist"
|
|
383
|
+
)
|
|
283
384
|
|
|
284
385
|
return self.get_result(close=True)
|
|
285
386
|
|
|
@@ -424,6 +525,10 @@ class ExportPSDLayersBatch(flow.Action):
|
|
|
424
525
|
class PublishandExportPSD(PublishAndRenderPlayblast):
|
|
425
526
|
ICON = ('icons.libreflow', 'publish')
|
|
426
527
|
|
|
528
|
+
_shot = flow.Parent(5)
|
|
529
|
+
_sequence = flow.Parent(7)
|
|
530
|
+
_film = flow.Parent(9)
|
|
531
|
+
|
|
427
532
|
def allow_context(self, context):
|
|
428
533
|
return (
|
|
429
534
|
context
|
|
@@ -431,7 +536,56 @@ class PublishandExportPSD(PublishAndRenderPlayblast):
|
|
|
431
536
|
and self._file.format.get() in ["psd", "psb"]
|
|
432
537
|
)
|
|
433
538
|
|
|
539
|
+
def get_bg_layout(self):
|
|
540
|
+
source_file = None
|
|
541
|
+
shot_entity = (
|
|
542
|
+
self.root()
|
|
543
|
+
.project()
|
|
544
|
+
.films[self._film.name()]
|
|
545
|
+
.sequences[self._sequence.name()]
|
|
546
|
+
.shots[self._shot.name()]
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
bg_layout_task = shot_entity.tasks["bg_layout"]
|
|
550
|
+
if bg_layout_task.files.has_file("bg_layout", "psb"):
|
|
551
|
+
# Get the file path as parent
|
|
552
|
+
source_file = bg_layout_task.files["bg_layout_psb"].get_head_revision()
|
|
553
|
+
|
|
554
|
+
return source_file
|
|
555
|
+
|
|
434
556
|
def get_buttons(self):
|
|
557
|
+
msg = "<h2>Publish and Export Preview</h2>"
|
|
558
|
+
|
|
559
|
+
if "bg_color" in self._file.name():
|
|
560
|
+
bg_layout_file = self.get_bg_layout()
|
|
561
|
+
bg_layout_psb = PSDImage.open(bg_layout_file.get_path())
|
|
562
|
+
working_copy_path = self._file.get_working_copy().get_path()
|
|
563
|
+
psb = PSDImage.open(working_copy_path)
|
|
564
|
+
|
|
565
|
+
if psb.size != bg_layout_psb.size:
|
|
566
|
+
msg += (f"""<h3><font color=#D66500>
|
|
567
|
+
Does not conform to the size of bg_layout.
|
|
568
|
+
</font></h3>
|
|
569
|
+
<h4><font color=#D66500>
|
|
570
|
+
BG_layout size = {bg_layout_psb.size}
|
|
571
|
+
</font></h4>
|
|
572
|
+
""")
|
|
573
|
+
|
|
574
|
+
if psb.depth != 16:
|
|
575
|
+
msg += (
|
|
576
|
+
"<h3><font color=#D66500>"
|
|
577
|
+
"This file is not in 16-bit format."
|
|
578
|
+
"</font></h3>"
|
|
579
|
+
"<h4><font color=#D66500>"
|
|
580
|
+
"To convert to 16 Bits/Channel, choose `Image > Mode > 16 Bits/Channel`."
|
|
581
|
+
"</font></h4>"
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
self.message.set(msg)
|
|
585
|
+
return ["Cancel"]
|
|
586
|
+
|
|
587
|
+
self.message.set(msg)
|
|
588
|
+
|
|
435
589
|
return ["Publish and Export Preview", "Cancel"]
|
|
436
590
|
|
|
437
591
|
def _configure_and_render(self, revision_name, upload_after_publish):
|
|
@@ -708,6 +862,129 @@ class UploadPSDPreview(UploadPNGToKitsu):
|
|
|
708
862
|
rev.set_status("on_kitsu")
|
|
709
863
|
|
|
710
864
|
|
|
865
|
+
class PublishPSDFile(PublishFileAction):
|
|
866
|
+
|
|
867
|
+
_task = flow.Parent(3)
|
|
868
|
+
_shot = flow.Parent(5)
|
|
869
|
+
_sequence = flow.Parent(7)
|
|
870
|
+
_film = flow.Parent(9)
|
|
871
|
+
|
|
872
|
+
def __init__(self, name, parent):
|
|
873
|
+
super(PublishPSDFile, self).__init__(parent, name)
|
|
874
|
+
|
|
875
|
+
def get_bg_layout(self):
|
|
876
|
+
source_file = None
|
|
877
|
+
shot_entity = (
|
|
878
|
+
self.root()
|
|
879
|
+
.project()
|
|
880
|
+
.films[self._film.name()]
|
|
881
|
+
.sequences[self._sequence.name()]
|
|
882
|
+
.shots[self._shot.name()]
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
bg_layout_task = shot_entity.tasks["bg_layout"]
|
|
886
|
+
if bg_layout_task.files.has_file("bg_layout", "psb"):
|
|
887
|
+
# Get the file path as parent
|
|
888
|
+
source_file = bg_layout_task.files["bg_layout_psb"].get_head_revision()
|
|
889
|
+
|
|
890
|
+
return source_file
|
|
891
|
+
|
|
892
|
+
def get_buttons(self):
|
|
893
|
+
self.check_default_values()
|
|
894
|
+
|
|
895
|
+
msg = "<h2>Publish</h2>"
|
|
896
|
+
|
|
897
|
+
working_copies = self._file.get_working_copies()
|
|
898
|
+
if working_copies:
|
|
899
|
+
user_names = [wc.user.get() for wc in working_copies]
|
|
900
|
+
user_names = ["<b>" + n + "</b>" for n in user_names]
|
|
901
|
+
msg += (
|
|
902
|
+
"<h3><font color=#D66500><br>"
|
|
903
|
+
"This file is currently being edited by one or more users ({})."
|
|
904
|
+
"</font></h3>".format(", ".join(user_names))
|
|
905
|
+
)
|
|
906
|
+
|
|
907
|
+
if "bg_color" in self._file.name():
|
|
908
|
+
bg_layout_file = self.get_bg_layout()
|
|
909
|
+
bg_layout_psb = PSDImage.open(bg_layout_file.get_path())
|
|
910
|
+
working_copy_path = self._file.get_working_copy().get_path()
|
|
911
|
+
psb = PSDImage.open(working_copy_path)
|
|
912
|
+
|
|
913
|
+
if psb.size != bg_layout_psb.size:
|
|
914
|
+
msg += f"""<h3><font color=#D66500>
|
|
915
|
+
Does not conform to the size of bg_layout.
|
|
916
|
+
</font></h3>
|
|
917
|
+
<h4><font color=#D66500>
|
|
918
|
+
BG_layout size = {bg_layout_psb.size}
|
|
919
|
+
</font></h4>
|
|
920
|
+
"""
|
|
921
|
+
|
|
922
|
+
if psb.depth != 16:
|
|
923
|
+
msg += (
|
|
924
|
+
"<h3><font color=#D66500>"
|
|
925
|
+
"This file is not in 16-bit format."
|
|
926
|
+
"</font></h3>"
|
|
927
|
+
"<h4><font color=#D66500>"
|
|
928
|
+
"To convert to 16 Bits/Channel, choose `Image > Mode > 16 Bits/Channel`."
|
|
929
|
+
"</font></h4>"
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
self.message.set(msg)
|
|
933
|
+
return ["Cancel"]
|
|
934
|
+
|
|
935
|
+
self.message.set(msg)
|
|
936
|
+
|
|
937
|
+
return ["Publish", "Cancel"]
|
|
938
|
+
|
|
939
|
+
class CreateWorkingCopy(CreateWorkingCopyAction):
|
|
940
|
+
def __init__(self, parent, name):
|
|
941
|
+
super(CreateWorkingCopy, self).__init__(parent, name)
|
|
942
|
+
|
|
943
|
+
def get_buttons(self):
|
|
944
|
+
msg = "<h3>Create a working copy</h3>"
|
|
945
|
+
|
|
946
|
+
if "bg_color" in self._task.name() and "psb" in self._file.name():
|
|
947
|
+
msg += """<h3>
|
|
948
|
+
Remember to change the colour depth to <u>16 bits</u> in Photoshop.
|
|
949
|
+
</h3>
|
|
950
|
+
<h4>
|
|
951
|
+
To convert to 16 Bits/Channel, choose <u>`Image > Mode > 16 Bits/Channel`</u>.
|
|
952
|
+
</h4>"""
|
|
953
|
+
|
|
954
|
+
# Buttons for Use Base File mode
|
|
955
|
+
if self.use_base_file:
|
|
956
|
+
msg += f"<font color=#FFA34D>WARNING: You should start working on this file \
|
|
957
|
+
from the latest version of {self.base_file_name} in {self.from_task} task.</font>"
|
|
958
|
+
self.message.set(msg)
|
|
959
|
+
return ["Create from base file", "Create from scratch", "Cancel"]
|
|
960
|
+
|
|
961
|
+
if self._file.has_working_copy(from_current_user=True):
|
|
962
|
+
msg += "<font color=#FFA34D>WARNING: You already have a working copy to your name. \
|
|
963
|
+
Choosing to create a new one will overwrite your changes.</font>"
|
|
964
|
+
|
|
965
|
+
self.message.set(msg)
|
|
966
|
+
|
|
967
|
+
self.from_revision.revert_to_default()
|
|
968
|
+
|
|
969
|
+
return ["Create", "Create from scratch", "Cancel"]
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
def publish_psd_file(parent):
|
|
973
|
+
if isinstance(parent, TrackedFile) and "psb" in parent.name():
|
|
974
|
+
r = flow.Child(PublishPSDFile).ui(label="Publish")
|
|
975
|
+
r.name = "publish_action"
|
|
976
|
+
r.index = 25
|
|
977
|
+
return r
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
def create_working_copy(parent):
|
|
981
|
+
if isinstance(parent, TrackedFile) and "psb" in parent.name():
|
|
982
|
+
r = flow.Child(CreateWorkingCopy).ui(label="Create working copy")
|
|
983
|
+
r.name = "create_working_copy_action"
|
|
984
|
+
r.index = 25
|
|
985
|
+
return r
|
|
986
|
+
|
|
987
|
+
|
|
711
988
|
def publish_and_export_preview(parent):
|
|
712
989
|
if isinstance(parent, TrackedFile):
|
|
713
990
|
r = flow.Child(PublishandExportPSD)
|
|
@@ -755,5 +1032,7 @@ def install_extensions(session):
|
|
|
755
1032
|
export_psd_preview,
|
|
756
1033
|
upload_preview,
|
|
757
1034
|
publish_and_export_preview,
|
|
1035
|
+
publish_psd_file,
|
|
1036
|
+
create_working_copy,
|
|
758
1037
|
]
|
|
759
1038
|
}
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-10-07T12:13:47+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "1.1.
|
|
14
|
+
"full-revisionid": "9b4d99a24c5df5c15e21e86f38c101e653930ad1",
|
|
15
|
+
"version": "1.1.8"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libreflow.extensions.sk.export_psd_layers
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.8
|
|
4
4
|
Home-page: https://gitlab.com/lfs.coop/libreflow/libreflow_launcher
|
|
5
5
|
Author: Thomas Thiebaut
|
|
6
6
|
Author-email: autor@les-fees-speciales.coop
|
|
@@ -50,6 +50,19 @@ Types of changes
|
|
|
50
50
|
|
|
51
51
|
## [Unreleased]
|
|
52
52
|
|
|
53
|
+
## [1.1.8] - 2025-10-07
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
* Export resized to psd canvas - warning message for layers with a bouding box twice as large as the viewbox
|
|
58
|
+
|
|
59
|
+
## [1.1.7] - 2025-08-19
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
* Warning message when publishing regarding resolution and colour depth.
|
|
64
|
+
* Message in the window when creating a new working copy.
|
|
65
|
+
|
|
53
66
|
## [1.1.6] - 2025-08-07
|
|
54
67
|
|
|
55
68
|
### Fixed
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|