PSD Importer for Godot
Speed up your import workflow
An artisanally made PSD Importer for Godot 3.5, written in Rust.
PSD Importer is a tool for speeding up your import workflow using Photoshop's PSD files. If you use a different program but export to PSD it should also work. You can use this tool to mass-export all of your layers as seperate assets or as single files depending on import settings.
If you have a developer on your team that can write code, you can write custom import code per-file so you can make your import specific to your needs!
Getting started
This repo contains the code for the project, but you'll need to be at the release repository to download addon for Godot. I'll try and have an addon available for easy download inside of Godoteasy download inside of Godot.
Download from AssetLib
Unfortunately this option isn't available yet. Stay tuned!
download the zip
Clone this repository /- Extract the repository in a folder of your choice.
- Run
cargo build
in the folder. (More details on compilation here)- Really sorry it works like this for now, will automate a 100% ready release soon!
- Import the project in Godot.
- Run the scene to get a taste of the PSD Importer!
- Move the addons folder to your Godot project.
- Enable the plugin in your Project Settings.
- Setup the importer using the documentation or tutorial!
Roadmap
There are a few things I want to tackle before calling a v1:
- Releasing the addon on the AssetLib
- Make a release repository
- Make an automated Github Actions that cross-compiles
- Write compilation instructions for the Rust aspect of the repository
- A mascot for the page and project
- Resolve problems with
get_node
function and path formatting.- Currently there are small nuances that can cause certain paths to not behave in a manner the user wants.
- Add more sensible defaults for the default import script.
- Try to eliminate all of the
unwrap
calls or replace them withexpect
. - Try to eliminate all
unsafe
code or properly document it.
Feature requests
If for whatever reason the importer doesn't 100% fit your needs, feel free to reach out to me, but make sure you can't easily script this functionality using the custom script option.
Getting Help
There are several places you can get help with PSD Importer for Godot & stay up to date with developments:
- Reach out on Mastodon or Twitter
- Open an issue on Github
- Email bram [at] dingelstad.works for more indepth questions or inqueries for consultancy. (You can also hire me for all your Godot needs)
License
PSD Importer is available under the MIT License. This means that you can use it in any commercial or noncommercial project. The only requirement is that you need to include attribution in your game's docs. A credit would be very, very nice, too, but isn't required. If you'd like to know more about what this license lets you do, tldrlegal.com have a very nice write up about the MIT license that you might find useful.
Made by Bram Dingelstad & Placeholder Gameworks
PSD Importer was originally made for a game called CraftCraft, but we found it nice to share this technology with the broader world
Support Placeholder Gameworks by buying our games.
Originally written by Bram Dingelstad.
Tutorial
Using the standard addon is quite simple. Simply enable the plugin after installing, and you should see *.psd
files pop up in Godot's file explorer. Click on any of them and uncheck the "Dont import" option in the import tab. By default, the importer puts the files in the same directory as the import itself, so perhaps move it to a place where you want your final files to be.
Writing a custom importer
Made a GDScript .gd
file and start by extending PsdImportScript
. PsdImportScript
has one method which is import
. It has a few arguments:
plugin
which is a reference to the EditorPlugin instance, used to skipping framesimporter
which is a pre-setupPsdImporter
instance with your PSD file pre-loaded.options
which is a Dictionary holding different import options set by the user.base_directory
which is a path String where the PSD file is situated.
You can navigate the PSD by calling methods on the importer
and its resulting PsdNode
children, an example below is exporting all of the layers on the root of PSD that start with the letter A.
extends PsdImportScript
func import(plugin, importer, options, base_directory):
# Go through all the children in the root of the PSD
for child in importer.get_children():
match child.node_type:
'Layer':
var name = child.name
# When it the name of the layer doesn't start with A or a, skip this (continue)
if not name.to_lower().starts_with('a'):
continue
var image_path = '%s%s.png' % [base_directory, name]
# Wait a frame every
yield(plugin.get_tree(), 'idle_frame')
# Get the image
child.get_image()
var image = yield(child, 'image') # And await its result
if image:
image.save_png(image_path)
print('Imported "%s" to "%s"' % [name, image_path])
else:
printerr('Tried saving image to "%s" but something went wrong' % image_path)
return OK
Another example, which is default import script, can be found here. It features a recursive exporter, which will go into groups and export sublayers.
Documentation
PsdImporter
Inherits from Object
Object for all interaction with PSD Importer.
Description
This the main importer class that is the entry point for the importer code. You'll use this class to get access to the different layers and groups inside of the PSD. Usually, most users should not have to interact with this class however.
Make sure that you load
valid PSD data before resuming with other methods.
Methods
Return value | Method name |
---|---|
void | load( PoolByteArray psd_bytes ) |
void | print_tree ( ) |
PsdNode | get_node ( String path ) |
Array | get_children ( ) |
Array | get_layers ( ) |
Array | get_groups ( ) |
Method Descriptions
-
void load ( PoolByteArray psd_bytes )
Loads in the PSD data into the class to do operations on. You can get
psd_bytes
by reading from a file usingFile
. -
void print_tree ( )
Will print an entire tree of the PSD with layers and groups into Godot's stdout (including your debug console). It can help you track down issues in your code or confirm if your file has been loaded correctly during debugging.
An example of how that looks:
[G] Group name [G] Another sub-group [L] A sub-sub layer (you get the idea) [L] Layer that is a child of "Group name" above [L] Another Layer [L] Layer on the root
-
PsdNode get_node ( String path )
Get a single
PsdNode
(either a Layer or a Group) and return it. Works similarly toNode.get_node
, should be familiar for most Godot programmers. -
Array get_children ( )
Gets all direct children as
PsdNode
s (either Layer or a Group) of the Root of the PSD file. -
Array get_layers ( )
Gets all direct children as
PsdNode
s of the Root of the PSD file, guaranteed to be Layers. -
Array get_groups ( )
Gets all direct children as
PsdNode
s of the Root of the PSD file, guaranteed to be Groups.
PsdNode
Inherits from Reference
A generic node representing either a Layer or a Group in a PSD file.
Description
The result of any get_node
call, either on PsdImporter
or PsdNode
. You can
Properties
Type | Property | Default value |
---|---|---|
String | name | Name of layer / group |
String | path | The path of the layer / group relative from the root |
String | node_type | The type of node either "Layer" or "Group" can be used to differentiate (e.g in match statements) |
Dictionary | properties | Properties of the Layer if node_type is of type "Layer" . |
Methods
Return value | Method name |
---|---|
PsdNode | get_node ( String path ) |
Array | get_children ( ) |
Array | get_layers ( ) |
Array | get_groups ( ) |
void | get_image ( ) |
Signals
-
image ( Image image )
Emitted when the node is done rendering an image after executing
get_image
Property Descriptions
-
String name
The name of the layer or group, as saved in the PSD file.
-
String path
The path to the layer or group, relative from the root of the PSD file.
-
String node_type
The type of the
PsdNode
, can either be"Layer"
or"Group"
. You can use this to guarantee the type in your code.An example, to make sure that you can execute
get_image
:var psd_node = importer.get_node('/Path/to/arbitrary/node') var image match psd_node.node_type: "Layer": psd_node.get_image() image = yield(psd_node, 'image') _: printerr("not a layer containing an image")
-
Dictionary properties
A dictionary containing information of the node in case
node_type
has the value of"Layer"
. If thenode_type
has the value of"Group"
, this property will benull
.It has the following values:
{ visible: bool, pub opacity: int, pub width: int, pub height: int }
Method Descriptions
-
PsdNode get_node ( String path )
Get a single
PsdNode
(either a Layer or a Group) and return it. Works similarly toNode.get_node
, should be familiar for most Godot programmers. -
Array get_children ( )
Gets all direct children as
PsdNode
s (either Layer or a Group) of the Root of the PSD file. -
Array get_layers ( )
Gets all direct children as
PsdNode
s of the Root of the PSD file, guaranteed to be Layers. -
Array get_groups ( )
Gets all direct children as
PsdNode
s of the Root of the PSD file, guaranteed to be Groups. -
void get_image ( )
Starts converting the Layer into an
Image
, will only work ifnode_type
is of type"Layer"
. Result of this function is captured using theimage
signal.An example of how to get an image:
var bytes = ... # PoolByteArray with PSD data # Create an importer var importer = PsdImporter.new() importer.load(bytes) # Get the psd node, which we assume to be of `node_type` "Layer" var psd_node = importer.get_node('/Path/to/a/Layer') # Start image rendering process psd_node.get_image() # Wait until it's done var image = yield(psd_node, 'image')