To setup the development environment for this project, you will need to obtain the ZXPSignCmd tool provided by Adobe.
Once you have logged in using your existing Adobe user account, download the CC Extensions Signing Toolkit, which will provide you with the necessary executable.
If you are developing on a Mac, please set all necessary variables in dev/env.mk.
If you are developing on Windows, please set all necessary variables in dev\env.cmd
This is what the env file should look like:
TARGET_VERSION=1.1.3 # Make sure this matches the tk-framework-adobe version you will be releasing
TKCORE_VERSION=0.19.19 # This core version is expected to exist in your bundle cache
ZXP_SIGN_TOOL=/path/to/bin/ZXPSignCmd
CERTIFICATE_FILE=/path/to/file/location/cert.p12
CERTIFICATE_PASS=<Make up your own secure password>
CERT_COUNTRY=<Two Character Country Code>
CERT_STATE=<Two Character State or Province Code>
CERT_ORG=Autodesk
CERT_CN=SGTK
Follow this link
to find out where your bundle cache is located.
To install the CEP extension for testing without signing:
cd path/to/tk-adobe-framework
cd dev
make test
To sign the CEP extension
cd path/to/tk-adobe-framework
cd dev
make sign
To create a certificate for use when signing the CEP extension
cd path/to/tk-adobe-framework
cd dev
make create_certificate
Note: In the case where the configured CERTIFICATE_FILE does not exist, the create_certificate command will be automatically run as part of the sign target.
To remove the latest signed zxp file
cd path/to/tk-adobe-framework
cd dev
make clean
Notes on editing the env files (env.mk and env.cmd)
Changes to the env files (env.mk and env.cmd) will typically not be tracked in git. The information contained in these files is specific to a particular development environment, so tracking changes to that data in git is undesirable.
If you need to make changes to these files, you can use the following commands:
Please be aware that these files contain potentially-sensitive information, such as a certificate password. When making changes to these files and pushing them to a git repository, be sure that you've removed any data that might be considered confidential.
I'm not able to use Shotgun integration in both After Effects and Photoshop on mac.
Here is the console output from Photoshop CC 2019 (it is the same win_32_api error in AE) PhotoshopErrorMac.txt
We should do a pass on the various environment variables to ensure they are in the right place. I am seeing a lot of stuff on the engine level that looks like it likely belongs at the framework level and in some cases it is defined in both the engine and the framework, which is bad.
The goal: Get as many of the environment variables into the framework as possible. Update the documentation to reflect the new state (wiki + sphinx, adobe fw, AE engine, PS engine).
Examples of duplicate definitions
It looks like the SHOTGUN_ADOBE_NETWORK_DEBUG environment is defined both in the engine and in the framework - we should refactor this to be less leaky. I think we should drop the network_debug flag and the only way to control the debug state is through the SHOTGUN_ADOBE_NETWORK_DEBUG env var, which is only accessed from the fw.
I am seeing a similar situation for SHOTGUN_ADOBE_PYTHON.
We need to get parity with other frameworks and define a strict interface for the adobe framework modules inside __init__.py - for alignment with other patterns in tk, but more importantly to ensure there is a clear public interface which will allow for refactoring in the future.
Framework interfaces should only expose the minimum public interface that we commit to officially support.
Documentation
Note how the docs for the shotgun utils are generated to look like this:
Currently, the docs for the adobe fw look like this:
As part of this work, we want them to align in structure with how the shotgun utils ones above look, e.g it should just say adobe_bridge.AdobeBridge.
Invoking the Photoshop API with engine.adobe can cause the AdobeBridge websocket communication to be interrupted. This only seems to happen during long, blocking operations that cause a progress bar in Photoshop to appear such as saving and loading large files from network storage, or saving files with high compression settings.
Note that the original operation (File Save, File Open, etc.) does complete successfully, but because it's immediately followed up by an error that crashes the plugin, you can't do anything else afterwards.
Impact
This bug causes the SGTK plugin to fail during vital operations such as saving and loading files. It can often become a blocking issue that prevents artists from publishing work.
Traceback
Note: line numbers will be slightly off: I've inserted a lot of logging messages to my local files for debugging.
[49446 ERROR sgtk.env.project.tk-photoshopcc] Traceback (most recent call last):
File ".../tk_multi_pythonconsole/1.3.0._build1/5322/a/ext/python/app/input_widget.py", line 246, in execute
exec(python_code, self._locals, self._locals)
File "python input", line 13, in <module>
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/proxy.py", line 232, in __call__
parent=self._parent,
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/communicator.py", line 300, in rpc_call
wrapper_class=ProxyWrapper,
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/communicator.py", line 760, in __run_rpc_command
results = self._wait_for_response(payload["id"])
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/adobe_bridge.py", line 44, in wrapper
result = func(*args, **kwargs)
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/adobe_bridge.py", line 440, in _wait_for_response
return super(AdobeBridge, self)._wait_for_response(uid)
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/communicator.py", line 655, in _wait_for_response
self.wait(single_loop=True, process_events=False)
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/communicator.py", line 523, in wait
process_events=process_events,
File ".../tk_framework_adobe/1.1.7/411f/a/ext/python/tk_framework_adobe/rpc/communicator.py", line 245, in process_new_messages
self._io._process_packets()
File ".../tk_framework_adobe/1.1.7/411f/a/ext/pkgs/socketIO_client_nexus/__init__.py", line 276, in _process_packets
for engineIO_packet in self._transport.recv_packet():
File ".../tk_framework_adobe/1.1.7/411f/a/ext/pkgs/socketIO_client_nexus/transports.py", line 158, in recv_packet
packet_text)
File ".../tk_framework_adobe/1.1.7/411f/a/ext/pkgs/socketIO_client_nexus/parsers.py", line 96, in parse_packet_text
packet_type = int(get_character(packet_text, 0))
File ".../tk_framework_adobe/1.1.7/411f/a/ext/pkgs/socketIO_client_nexus/symmetries.py", line 33, in get_character
return chr(get_byte(x, index))
File ".../tk_framework_adobe/1.1.7/411f/a/ext/pkgs/socketIO_client_nexus/symmetries.py", line 29, in get_byte
return indexbytes(x, index)
IndexError: index out of range
Video
Here is a video of me saving a PNG file with the maximum compression settings.
video.mp4
Steps to reproduce
Reproducing the error can be tricky. I can reliably reproduce the error on MacOS, but not on Windows. Furthermore, not all large files produce the error. However, once I have a file that produces the error, it is consistently reproducible with the same steps.
Open a large PSD file that will take a long time to save. I have uploaded the file from the video above to Google Drive: test.psd
Open the ShotGrid Python Console
Use the Python API to save the file as a PNG with maximum compression settings. Example code:
frompathlibimportPathdst=Path.home() /"Desktop"/"save_test.png"# Save file to Desktoppng_file=engine.adobe.File(dst.as_posix())
png_options=engine.adobe.PNGSaveOptions()
png_options.interlaced=Falsepng_options.compression=9# Highest compression value, most likely to cause Photoshop to hangdocument=engine.adobe.get_active_document()
document.saveAs(png_file, png_options, True)
If you get an IndexError in the Python console, followed by the ShotGrid Adobe panel shutdown, you have reproduced the error successfully.
Environment
Toolkit environment:
tk-framework-adobe v1.1.7
tk-photoshopcc v1.9.4
tk-core v0.20.13
Python version:
Python 3.7.13
Photoshop version:
Photoshop 2022 (v23.5.4)
System information:
I have reproduced the error on both of the following systems:
MacBook Pro, Apple M1 Pro, macOS Monterey v12.6.3
MacBook Pro, Intel Core i9, macOS Ventura v13.2.1
What I've tried
I have read the ShotGrid community forum post for
Adobe engine crashing on long operations. While this issue feels related, and indeed presents some of the same symptoms, I could not get any of the solutions to work.
My understanding is that disabling the heartbeat should be the most "forceful" way of circumventing some of these issues. I have tried saving with the heartbeat_disabled context manager, but the issue persists:
I've tried to break down the steps in the websocket communication to understand where the error is coming from, and this is my best understanding of what happens when you call, for example, document.saveAs:
The Document.saveAs function is invoked on the document's FunctionWrapper
An rpc call is sent over the websocket in Communicator.__run_rpc_commandline 677
We start waiting for a response from the rpc call in Communicator._wait_for_responseline 611
Packet data is received in Websocket.recvlines 292-304
This part is important. From the packet, we receive an opcode, and some data bundle as a byte string. In the example above that produces the IndexError, we get the following values:
opcode==8data==b''
Ok, let's continue...
Next, that packet data is read in the socketIO-client-nexus WebsocketTransport.recv_packetlines 157-158
The text from the packet data is parsed in the parse_package_text function lines 95-98
This line emphasized here is why we get the IndexError. We are trying reading the first character from an empty byte string.
Alright, great. So that's one mystery solved. But why do we get an empty byte string, and what is the 8 opcode telling us? If we jump back to the websocket-client module, we can see the opcodes defined in _abnf.py lines 80-86:
The 8 opcode is a close event. Indeed if you keep tracking it down, you'll see that WebSocket.send_close (lines 362-373) is called immediately before the packet is received, which happens right before the IndexError.
If you add an except IndexError: ... block in tk-framework-adobe's Communicator.process_new_messages (lines 238-251), you can ignore the IndexError, but you immediately get another communication error, because the close signal has already been sent, and the socket communication is terminated.
And that's as far as I've been able to get. I do not know why the close signal is being sent. I don't know whether it's being deliberately called somewhere, or if it's a byproduct of some other error wrapped in a try/except clause. I dug around in the Adobe CEP plugin and couldn't find a smoking gun in there. I don't have a ton of familiarity with JavaScript, so I don't feel confident saying anything definitive one way or the other with regards to the plugin.
To circumvent the error for now, I have dialed down the compression settings that our publisher plugin uses to render PNGs. That makes the document.saveAs function complete more quickly, which doesn't produce the error. That is just a stopgap solution though. Sooner or later, I'm worried that an even more "troublesome" file will come along that we can't buy ourselves any more leeway on with the compression settings, and we'll be stuck unable to save it at all.
Any help investigating this, or suggestions on using the Python API to avoid the error, would be extremely welcome!
Looks like the log file is named after the framework rather than the engine which is currently being launched. We want the log file to be named tk-photoshopcc.log and tk-aftereffects.log depending on the DCC.
Publish failed in Photoshop CC when using if Begin File versioning is selected: (tested on Windows)
Steps:
Create a new project in Shotgun
Make sure you are using the updated after effects basic config
Select that project in Desktop and launch Photoshop
Open a file and do a publish. Make sure you select Begin File Versioning
= Publish fails
Traceback (most recent call last):
File "C:\Users\mathurf\AppData\Roaming\Shotgun\bundle_cache\app_store\tk-multi-publish2\v2.3.0\python\tk_multi_publish2\api\plugins\publish_plugin_instance.py", line 282, in _handle_plugin_error
yield
File "C:\Users\mathurf\AppData\Roaming\Shotgun\bundle_cache\app_store\tk-multi-publish2\v2.3.0\python\tk_multi_publish2\api\plugins\publish_plugin_instance.py", line 198, in run_publish
self._hook_instance.publish(settings, item)
File "C:\Users\mathurf\Documents\GitHub\tk-photoshopcc\hooks\tk-multi-publish2\basic\start_version_control.py", line 247, in publish
engine.save_to_path(document, version_path)
File "C:\Users\mathurf\Documents\GitHub\tk-photoshopcc\engine.py", line 522, in save_to_path
save_options.quality = 12
File "C:\Users\mathurf\Documents\GitHub\tk-framework-adobe\python\tk_adobe_basic\rpc\proxy.py", line 278, in __setattr__
remote_names = self.data["properties"] + self.data["methods"].keys()
KeyError: 'properties'
Move some of the photoshop logic into the photoshop engine. There could be a subclassed version of the Communicator inside the engine, which implements the various photoshop specific methods.