This repository has been archived by the owner on Sep 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #232 from tokejepsen/2.x/feature/photoshop
Initial Photoshop integration.
- Loading branch information
Showing
11 changed files
with
325 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import os | ||
|
||
from avalon import api | ||
import pyblish.api | ||
|
||
|
||
def install(): | ||
print("Installing Pype config...") | ||
|
||
plugins_directory = os.path.join( | ||
os.path.dirname(os.path.dirname(os.path.dirname(__file__))), | ||
"plugins", | ||
"photoshop" | ||
) | ||
|
||
pyblish.api.register_plugin_path( | ||
os.path.join(plugins_directory, "publish") | ||
) | ||
api.register_plugin_path( | ||
api.Loader, os.path.join(plugins_directory, "load") | ||
) | ||
api.register_plugin_path( | ||
api.Creator, os.path.join(plugins_directory, "create") | ||
) | ||
|
||
pyblish.api.register_callback( | ||
"instanceToggled", on_pyblish_instance_toggled | ||
) | ||
|
||
|
||
def on_pyblish_instance_toggled(instance, old_value, new_value): | ||
"""Toggle layer visibility on instance toggles.""" | ||
instance[0].Visible = new_value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from avalon import photoshop | ||
|
||
|
||
class CreateImage(photoshop.Creator): | ||
"""Image folder for publish.""" | ||
|
||
name = "imageDefault" | ||
label = "Image" | ||
family = "image" | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(CreateImage, self).__init__(*args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from avalon import api, photoshop | ||
|
||
|
||
class ImageLoader(api.Loader): | ||
"""Load images | ||
Stores the imported asset in a container named after the asset. | ||
""" | ||
|
||
families = ["image"] | ||
representations = ["*"] | ||
|
||
def load(self, context, name=None, namespace=None, data=None): | ||
with photoshop.maintained_selection(): | ||
layer = photoshop.import_smart_object(self.fname) | ||
|
||
self[:] = [layer] | ||
|
||
return photoshop.containerise( | ||
name, | ||
namespace, | ||
layer, | ||
context, | ||
self.__class__.__name__ | ||
) | ||
|
||
def update(self, container, representation): | ||
layer = container.pop("layer") | ||
|
||
with photoshop.maintained_selection(): | ||
photoshop.replace_smart_object( | ||
layer, api.get_representation_path(representation) | ||
) | ||
|
||
photoshop.imprint( | ||
layer, {"representation": str(representation["_id"])} | ||
) | ||
|
||
def remove(self, container): | ||
container["layer"].Delete() | ||
|
||
def switch(self, container, representation): | ||
self.update(container, representation) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import os | ||
|
||
import pyblish.api | ||
from avalon import photoshop | ||
|
||
|
||
class CollectCurrentFile(pyblish.api.ContextPlugin): | ||
"""Inject the current working file into context""" | ||
|
||
order = pyblish.api.CollectorOrder - 0.5 | ||
label = "Current File" | ||
hosts = ["photoshop"] | ||
|
||
def process(self, context): | ||
context.data["currentFile"] = os.path.normpath( | ||
photoshop.app().ActiveDocument.FullName | ||
).replace("\\", "/") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import pythoncom | ||
|
||
from avalon import photoshop | ||
|
||
import pyblish.api | ||
|
||
|
||
class CollectInstances(pyblish.api.ContextPlugin): | ||
"""Gather instances by LayerSet and file metadata | ||
This collector takes into account assets that are associated with | ||
an LayerSet and marked with a unique identifier; | ||
Identifier: | ||
id (str): "pyblish.avalon.instance" | ||
""" | ||
|
||
label = "Instances" | ||
order = pyblish.api.CollectorOrder | ||
hosts = ["photoshop"] | ||
families_mapping = { | ||
"image": [] | ||
} | ||
|
||
def process(self, context): | ||
# Necessary call when running in a different thread which pyblish-qml | ||
# can be. | ||
pythoncom.CoInitialize() | ||
|
||
for layer in photoshop.get_layers_in_document(): | ||
layer_data = photoshop.read(layer) | ||
|
||
# Skip layers without metadata. | ||
if layer_data is None: | ||
continue | ||
|
||
# Skip containers. | ||
if "container" in layer_data["id"]: | ||
continue | ||
|
||
child_layers = [*layer.Layers] | ||
if not child_layers: | ||
self.log.info("%s skipped, it was empty." % layer.Name) | ||
continue | ||
|
||
instance = context.create_instance(layer.Name) | ||
instance.append(layer) | ||
instance.data.update(layer_data) | ||
instance.data["families"] = self.families_mapping[ | ||
layer_data["family"] | ||
] | ||
instance.data["publish"] = layer.Visible | ||
|
||
# Produce diagnostic message for any graphical | ||
# user interface interested in visualising it. | ||
self.log.info("Found: \"%s\" " % instance.data["name"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import pyblish.api | ||
import os | ||
|
||
|
||
class CollectWorkfile(pyblish.api.ContextPlugin): | ||
"""Collect current script for publish.""" | ||
|
||
order = pyblish.api.CollectorOrder + 0.1 | ||
label = "Collect Workfile" | ||
hosts = ["photoshop"] | ||
|
||
def process(self, context): | ||
family = "workfile" | ||
task = os.getenv("AVALON_TASK", None) | ||
subset = family + task.capitalize() | ||
|
||
file_path = context.data["currentFile"] | ||
staging_dir = os.path.dirname(file_path) | ||
base_name = os.path.basename(file_path) | ||
|
||
# Create instance | ||
instance = context.create_instance(subset) | ||
instance.data.update({ | ||
"subset": subset, | ||
"label": base_name, | ||
"name": base_name, | ||
"family": family, | ||
"families": [], | ||
"representations": [], | ||
"asset": os.environ["AVALON_ASSET"] | ||
}) | ||
|
||
# creating representation | ||
instance.data["representations"].append({ | ||
"name": "psd", | ||
"ext": "psd", | ||
"files": base_name, | ||
"stagingDir": staging_dir, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import os | ||
|
||
import pype.api | ||
from avalon import photoshop | ||
|
||
|
||
class ExtractImage(pype.api.Extractor): | ||
"""Produce a flattened image file from instance | ||
This plug-in takes into account only the layers in the group. | ||
""" | ||
|
||
label = "Extract Image" | ||
hosts = ["photoshop"] | ||
families = ["image"] | ||
|
||
def process(self, instance): | ||
|
||
staging_dir = self.staging_dir(instance) | ||
self.log.info("Outputting image to {}".format(staging_dir)) | ||
|
||
# Perform extraction | ||
files = {} | ||
with photoshop.maintained_selection(): | ||
self.log.info("Extracting %s" % str(list(instance))) | ||
with photoshop.maintained_visibility(): | ||
# Hide all other layers. | ||
extract_ids = [ | ||
x.id for x in photoshop.get_layers_in_layers([instance[0]]) | ||
] | ||
for layer in photoshop.get_layers_in_document(): | ||
if layer.id not in extract_ids: | ||
layer.Visible = False | ||
|
||
save_options = { | ||
"png": photoshop.com_objects.PNGSaveOptions(), | ||
"jpg": photoshop.com_objects.JPEGSaveOptions() | ||
} | ||
|
||
for extension, save_option in save_options.items(): | ||
photoshop.app().ActiveDocument.SaveAs( | ||
staging_dir, save_option, True | ||
) | ||
files[extension] = "{} copy.{}".format( | ||
os.path.splitext( | ||
photoshop.app().ActiveDocument.Name | ||
)[0], | ||
extension | ||
) | ||
|
||
representations = [] | ||
for extension, filename in files.items(): | ||
representations.append({ | ||
"name": extension, | ||
"ext": extension, | ||
"files": filename, | ||
"stagingDir": staging_dir | ||
}) | ||
instance.data["representations"] = representations | ||
instance.data["stagingDir"] = staging_dir | ||
|
||
self.log.info(f"Extracted {instance} to {staging_dir}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import pype.api | ||
from avalon import photoshop | ||
|
||
|
||
class ExtractSaveScene(pype.api.Extractor): | ||
"""Save scene before extraction.""" | ||
|
||
order = pype.api.Extractor.order - 0.49 | ||
label = "Extract Save Scene" | ||
hosts = ["photoshop"] | ||
families = ["workfile"] | ||
|
||
def process(self, instance): | ||
photoshop.app().ActiveDocument.Save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import os | ||
|
||
import pyblish.api | ||
import pype.api | ||
from avalon import photoshop | ||
|
||
|
||
class ValidateInstanceAssetRepair(pyblish.api.Action): | ||
"""Repair the instance asset.""" | ||
|
||
label = "Repair" | ||
icon = "wrench" | ||
on = "failed" | ||
|
||
def process(self, context, plugin): | ||
|
||
# Get the errored instances | ||
failed = [] | ||
for result in context.data["results"]: | ||
if (result["error"] is not None and result["instance"] is not None | ||
and result["instance"] not in failed): | ||
failed.append(result["instance"]) | ||
|
||
# Apply pyblish.logic to get the instances for the plug-in | ||
instances = pyblish.api.instances_by_plugin(failed, plugin) | ||
|
||
for instance in instances: | ||
data = photoshop.read(instance[0]) | ||
data["asset"] = os.environ["AVALON_ASSET"] | ||
photoshop.imprint(instance[0], data) | ||
|
||
|
||
class ValidateInstanceAsset(pyblish.api.InstancePlugin): | ||
"""Validate the instance asset is the current asset.""" | ||
|
||
label = "Validate Instance Asset" | ||
hosts = ["photoshop"] | ||
actions = [ValidateInstanceAssetRepair] | ||
order = pype.api.ValidateContentsOrder | ||
|
||
def process(self, instance): | ||
instance_asset = instance.data["asset"] | ||
current_asset = os.environ["AVALON_ASSET"] | ||
msg = ( | ||
"Instance asset is not the same as current asset:" | ||
f"\nInstance: {instance_asset}\nCurrent: {current_asset}" | ||
) | ||
assert instance_asset == current_asset, msg |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.