Created
January 5, 2024 02:33
-
-
Save AdamStormhardtGH/6739cf548435ea64c012196ef0ed9479 to your computer and use it in GitHub Desktop.
Using python to write a new layer to a psd file
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
""" | |
Exmample of how to read a PSD in python, add a layer and write image data to it. | |
With this you can automate a bunch of PSD functionality | |
""" | |
import pytoshop | |
from pytoshop import layers | |
from pytoshop.enums import BlendMode | |
import numpy as np | |
import cv2 | |
# This is creative commons. Use it and be cool to one another. | |
# psd-tools needs this functionality and if you have time I'm sure a PR would be highly appreciated | |
# urls for images | |
my_image_url = "art/my_cool_image.png" | |
def create_rgba_data_for_image(image_url: str) -> np.ndarray: | |
""" | |
Reads in image and converts it to RGBA | |
:param image_url: The url of the image to be converted eg. art/my_image.png | |
:return: The image as a numpy array | |
""" | |
# do initial read | |
image = cv2.imread(image_url, 1) # reads using opencv and as rgb format | |
# Convert the image to RGBA | |
rgba_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGBA) # todo: see if we can do this in one step | |
return rgba_image # Return the numpy array directly | |
def insert_psd_layer(psd, image_data, layer_name="a new photoshop layer appears!", blending_mode=BlendMode.normal): | |
""" | |
Inserts a layer into a PSD | |
Expects a PSD to exist, but there are other methods which will create a PSD from scratch | |
:param psd: The PSD to insert the layer into. This is done using `psd = pytoshop.read(fd)` after you open the image as a read binary | |
:param image_data: The image data as a numpy array. Use the function `create_rgba_data_for_image` to convert an image to RGBA | |
:param layer_name: The name of the layer to be inserted | |
:param blending_mode: The blending mode of the layer to be inserted. Use `BlendMode.normal` for normal blending | |
""" | |
num_channels = image_data.shape[2] | |
channel_data = [layers.ChannelImageData(image=image_data[:, :, i], compression=1) for i in range(num_channels)] | |
layer_channels = { | |
-1: channel_data[3] if num_channels > 3 else None, # if no alpha channel, set to none | |
0: channel_data[0], | |
1: channel_data[1], | |
2: channel_data[2], | |
} | |
layer_channels = {k: v for k, v in layer_channels.items() if v is not None} | |
layer_record = layers.LayerRecord( | |
channels=layer_channels, | |
top=0, | |
bottom=image_data.shape[0], | |
left=0, | |
right=image_data.shape[1], | |
blend_mode=blending_mode, | |
name=layer_name, | |
opacity=255, | |
) | |
psd.layer_and_mask_info.layer_info.layer_records.append(layer_record) | |
return psd | |
########################################################## | |
# EXAMPLE TO READ AND WRITE A PSD WITH A FANCY NEW LAYER # | |
########################################################## | |
with open("example2.psd", "rb") as fd: | |
psd = pytoshop.read(fd) | |
# Get the RGBA image data | |
rgba_image_data = create_rgba_data_for_image(my_image_url) | |
# Insert the layer | |
insert_psd_layer(psd, rgba_image_data, "test layer name", BlendMode.normal) # Use string 'norm' for blending_mode | |
# Write the modified PSD to a new file | |
# Writing to the same open file is weird and can probably be done, but I can't be bothered dealing with it atm | |
with open("example1.psd", "wb") as fd2: | |
psd.write(fd2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
<3 to AuthorSultra for the example in his repo
https://github.com/AuthorSultra/Layer-PSD/blob/main/scripts/layer_divider_modules/mask_utils.py#L5
And of course to
psd-tools
andpytoshop
for building packages