Image Magicの代替として使い始めたpsd-tools
PSDの編集はできないものの、情報の取得に特化していて便利です。
以下、詳しい内容です。
psd-toolsは、PythonでAdobe PhotoshopのPSDファイルを読み書きできるライブラリです。
PSDファイルの構造を解析し、レイヤー情報の取得や画像のエクスポート、さらにはファイルの編集まで可能にします。
主な特徴
- PSD/PSBファイルの低レベル構造の読み書き
- レイヤー画像のNumPy配列やPIL形式でのエクスポート
- 基本的なピクセルベースレイヤーの合成
- ベクターマスクのサポート
- レイヤー属性(名前、可視性、不透明度など)の編集
- レイヤーやグループの追加・削除
- ブレンドモードのサポート(dissolveを除く)
- コマンドラインツールの提供
インストール
基本インストール
pip install psd-tools高度な合成機能を使う場合
ベクターシェイプ、グラデーション、パターン塗り、レイヤーエフェクトなどの高度な合成機能を使用する場合は、compositeエクストラをインストールします。
pip install 'psd-tools[composite]'これにより、aggdraw、scipy、scikit-imageといった追加の依存関係がインストールされます。
基本的な合成はNumPyのみで動作しますが、高度な機能にはこれらのライブラリが必要です。
32bitファイルのサポート
32bit PSDファイルから画像を抽出する場合、PIL/PillowがLITTLECMSまたはLITTLECMS2サポート付きでビルドされている必要があります。
# Ubuntu/Debian
apt-get install liblcms2-2
# macOS
brew install little-cms2基本的な使い方
PSDファイルを開く
from psd_tools import PSDImage
# PSDファイルを開く
psd = PSDImage.open('example.psd')
# ファイル情報を表示
print(psd) # PSDImage(mode=RGB size=101x55 depth=8 channels=3)PSDファイル全体を画像としてエクスポート
# 全レイヤーを合成してPNG出力
image = psd.composite()
image.save('output.png')レイヤーを反復処理
# 全レイヤーをループ
for layer in psd:
print(f"レイヤー名: {layer.name}")
print(f"レイヤータイプ: {layer.kind}")
print(f"サイズ: {layer.width}x{layer.height}")
print(f"可視性: {layer.visible}")
print("---")イテレーション順序は背景から前景への順です(バージョン1.7.x以前とは逆)。
前景から背景へ反復するにはreversed(psd)を使用します。
インデックスでレイヤーにアクセス
# 最初のレイヤーを取得
first_layer = psd[0]
# ネストしたレイヤーにアクセス
nested_layer = psd[0][0]レイヤーの種類
PixelLayer(ピクセルレイヤー)
最も基本的なレイヤータイプで、ラスター画像を含みます。
# ピクセルレイヤーの確認
if layer.kind == 'pixel':
# レイヤーを画像として出力
layer_image = layer.composite()
layer_image.save(f'{layer.name}.png')
# NumPy配列として取得
pixels = layer.numpy()
print(pixels.shape) # (height, width, channels)
# PIL Imageとして取得
pil_image = layer.topil()Group(グループレイヤー)
複数のレイヤーをまとめるグループです。
# グループ内のレイヤーを反復処理
for layer in psd:
if layer.is_group():
print(f"グループ: {layer.name}")
for child in layer:
print(f" - {child.name}")TypeLayer(テキストレイヤー)
テキストとフォント情報を含むレイヤーです。
if layer.kind == 'type':
# テキスト内容を取得
print(f"テキスト: {layer.text}")
# スタイル情報(読み取り専用)
print(f"エンジン辞書: {layer.engine_dict}")
print(f"リソース辞書: {layer.resource_dict}")注意: テキスト情報は現在読み取り専用で、編集はサポートされていません。
ShapeLayer(シェイプレイヤー)
ベクターシェイプを描画するレイヤーです。
if layer.kind == 'shape':
# ベクターマスク情報
print(layer.vector_mask)
# ライブシェイププロパティ
for shape in layer.origination:
print(shape)SmartObjectLayer(スマートオブジェクトレイヤー)
外部ファイルを埋め込むまたはリンクするレイヤーです。
import io
from PIL import Image
if layer.kind == 'smartobject':
# スマートオブジェクトデータにアクセス
smart_obj = layer.smart_object
if smart_obj.filetype in ('jpg', 'png'):
image = Image.open(io.BytesIO(smart_obj.data))
image.save(f'{layer.name}_embedded.{smart_obj.filetype}')塗りつぶしレイヤー
塗りつぶしレイヤーは、マスクがない場合に領域全体を塗りつぶします。
# SolidColorFill(ベタ塗り)
# PatternFill(パターン)
# GradientFill(グラデーション)AdjustmentLayer(調整レイヤー)
合成画像に適用される調整レイヤーです。
レイヤー属性の取得と編集
基本属性
# レイヤー情報の取得
print(f"名前: {layer.name}")
print(f"可視性: {layer.visible}")
print(f"不透明度: {layer.opacity}") # 0-255
print(f"位置: ({layer.left}, {layer.top})")
print(f"サイズ: {layer.width}x{layer.height}")
print(f"バウンディングボックス: {layer.bbox}") # (left, top, right, bottom)
# レイヤー属性の編集(書き込み可能)
layer.name = "新しい名前"
layer.visible = False
layer.opacity = 128
layer.left = 100
layer.top = 50ブレンドモード
from psd_tools.constants import BlendMode
# ブレンドモードの確認
print(layer.blend_mode)
# ブレンドモードの変更
if layer.blend_mode == BlendMode.NORMAL:
layer.blend_mode = BlendMode.SCREENサポートされているブレンドモード(dissolveを除く):
- NORMAL, MULTIPLY, SCREEN, OVERLAY
- SOFT_LIGHT, HARD_LIGHT, COLOR_DODGE, COLOR_BURN
- DARKEN, LIGHTEN, DIFFERENCE, EXCLUSION
- HUE, SATURATION, COLOR, LUMINOSITY など
レイヤーのロック
from psd_tools.constants import ProtectedFlags
# レイヤーのピクセルと位置をロック
layer.lock(ProtectedFlags.COMPOSITE | ProtectedFlags.POSITION)マスク操作
# マスクの有無を確認
if layer.has_mask():
# マスクを取得
mask = layer.mask
# マスクを画像として出力
mask_image = mask.topil()
mask_image.save('mask.png')
# ベクターマスクの確認
if layer.has_vector_mask():
print(layer.vector_mask)レイヤーの階層操作
レイヤーの検索
# 名前でレイヤーを検索
def find_layer_by_name(psd, name):
for layer in psd.descendants():
if layer.name == name:
return layer
return None
target_layer = find_layer_by_name(psd, "背景")レイヤーの並び替え
# レイヤーを上に移動
layer.move_up()
# レイヤーを下に移動
layer.move_down()レイヤーの追加と削除
# レイヤーをグループに追加
group = psd[0]
group.append(layer)
# レイヤーを削除
layer.remove()
# グループをクリア
group.clear()新規PSDファイルの作成
ゼロから作成
from PIL import Image
from psd_tools import PSDImage
# 新しいPSDを作成
psd = PSDImage.new(mode='RGB', size=(640, 480), depth=8)
# PIL画像からレイヤーを作成
pil_image = Image.open('input.png')
layer = psd.create_pixel_layer(
pil_image,
name="Layer 1",
top=0,
left=0,
opacity=255
)
# グループを作成
group = psd.create_group(name="Group 1")
group.append(layer)
# 保存
psd.save('new_image.psd')
レイヤーリストからグループを作成
# 複数のレイヤーを新しいグループにまとめる
layer1 = psd[0]
layer2 = psd[1]
group = psd.create_group(
layer_list=[layer1, layer2],
name="New Group"
)画像エクスポート
全体を合成して出力
# PSD全体を合成
image = psd.composite()
image.save('output.png')
# 特定のビューポートで合成
viewport = (0, 0, 300, 300) # (x1, y1, x2, y2)
image = psd.composite(viewport=viewport)レイヤーフィルターを使用
# テキストレイヤーを除外して合成
image = psd.composite(
layer_filter=lambda layer: layer.is_visible() and layer.kind != 'type'
)レイヤーごとに出力
for layer in psd:
if layer.kind == 'pixel':
# レイヤーを合成して出力(マスクとクリッピングレイヤーを含む)
layer_image = layer.composite()
layer_image.save(f'{layer.name}.png')マスクなしで出力
# レイヤーとマスクを別々にエクスポート(合成なし)
layer_image = layer.topil()
layer_image.save('layer_no_mask.png')
if layer.has_mask():
mask_image = layer.mask.topil()
mask_image.save('mask.png')特定のチャンネルを取得
from psd_tools.constants import ChannelID
# RGB個別チャンネル
red = layer.topil(ChannelID.CHANNEL_0)
green = layer.topil(ChannelID.CHANNEL_1)
blue = layer.topil(ChannelID.CHANNEL_2)
# アルファチャンネル
alpha = layer.topil(ChannelID.TRANSPARENCY_MASK)NumPy配列として扱う
NumPy配列を使用することで、画像処理ライブラリ(OpenCV、scikit-imageなど)と組み合わせて高度な処理が可能になります。
import numpy as np
# PSD全体をNumPy配列として取得
array = psd.numpy()
print(array.shape) # (height, width, channels)
# レイヤーをNumPy配列として取得
layer_array = layer.numpy()
# 特定のチャンネルのみ取得
color_only = layer.numpy(channel='color')
alpha_only = layer.numpy(channel='alpha')
mask_only = layer.numpy(channel='mask')
shape_only = layer.numpy(channel='shape')
コマンドラインツール
psd-toolsはコマンドラインからも使用できます。
PSDファイルの内容を表示
psd-tools show example.psdPSDを画像として出力
# PSD全体をエクスポート
psd-tools export example.psd output.png
# 特定のレイヤーをエクスポート(インデックス指定)
psd-tools export example.psd[0] layer0.pngデバッグ情報の表示
psd-tools debug example.psd高度な機能
レイヤーエフェクト
# レイヤーエフェクトの有無を確認
if layer.has_effects():
# エフェクト情報にアクセス
effects = layer.effects注意: レイヤーエフェクトと調整レイヤーの多くは完全にはサポートされていません。合成結果がPhotoshopと異なる場合があります。
ベクターマスクとライブシェイプ
# ベクターマスク情報
if layer.has_vector_mask():
vector_mask = layer.vector_mask
print(vector_mask)
# ライブシェイププロパティ
if layer.has_origination():
for shape in layer.origination:
# Rectangle, RoundedRectangle, Ellipse, Line など
print(type(shape).__name__)クリッピングマスク
# クリッピングフラグ
print(layer.clipping)
layer.clipping = 1 # クリッピングマスクとして設定タグ付きブロック
低レベルのPSD設定にアクセスできます。
from psd_tools.constants import Tag
# タグ付きブロックにアクセス
tagged_blocks = layer.tagged_blocks
# 特定のタグの情報を取得
if Tag.LAYER_ID in tagged_blocks:
layer_id = tagged_blocks[Tag.LAYER_ID]バッチ処理の例
PSDファイルからすべてのレイヤーをエクスポート
from pathlib import Path
from psd_tools import PSDImage
def export_all_layers(psd_path, output_dir):
"""PSDファイルの全レイヤーを個別の画像ファイルとして出力"""
psd = PSDImage.open(psd_path)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
for i, layer in enumerate(psd.descendants()):
if layer.kind in ('pixel', 'shape'):
try:
image = layer.composite()
# ファイル名をサニタイズ
safe_name = "".join(c for c in layer.name if c.isalnum() or c in (' ', '-', '_'))
image.save(output_path / f"{i:03d}_{safe_name}.png")
print(f"Exported: {layer.name}")
except Exception as e:
print(f"Error exporting {layer.name}: {e}")
# 使用例
export_all_layers('example.psd', 'output_layers')レイヤー情報を抽出してJSON化
import json
from psd_tools import PSDImage
def extract_layer_info(psd_path):
"""レイヤー情報を辞書形式で抽出"""
psd = PSDImage.open(psd_path)
def layer_to_dict(layer):
info = {
'name': layer.name,
'kind': layer.kind,
'visible': layer.visible,
'opacity': layer.opacity,
'blend_mode': str(layer.blend_mode),
'bbox': layer.bbox,
'has_mask': layer.has_mask(),
}
if layer.is_group():
info['children'] = [layer_to_dict(child) for child in layer]
return info
result = {
'mode': psd.mode,
'size': (psd.width, psd.height),
'depth': psd.depth,
'layers': [layer_to_dict(layer) for layer in psd]
}
return result
# 使用例
info = extract_layer_info('example.psd')
print(json.dumps(info, indent=2, ensure_ascii=False))PSDファイルの一括変換
from pathlib import Path
from psd_tools import PSDImage
def batch_convert_psd_to_png(input_dir, output_dir):
"""ディレクトリ内の全PSDファイルをPNGに変換"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
for psd_file in input_path.glob('*.psd'):
try:
psd = PSDImage.open(psd_file)
image = psd.composite()
output_file = output_path / f"{psd_file.stem}.png"
image.save(output_file)
print(f"Converted: {psd_file.name} -> {output_file.name}")
except Exception as e:
print(f"Error converting {psd_file.name}: {e}")
# 使用例
batch_convert_psd_to_png('input_psds', 'output_pngs')制限事項と注意点
サポートされていない機能
以下の機能は現在サポートされていません:
- テキストレイヤーのテキスト編集
- タイプレイヤー、シェイプレイヤー、スマートオブジェクトなどの完全な編集
- 調整レイヤーの合成
- 多くのレイヤーエフェクトの合成
- フォントのレンダリング
合成の精度
- レイヤーの合成結果は、Photoshopでの表示と異なる場合があります
- dissolveブレンドモードはサポートされていません
- すべてのレイヤーエフェクトと調整レイヤーが完全にサポートされているわけではありません
PSD仕様の不完全性
Adobe Photoshop PSD file formatの仕様は完全ではなく、多くの未文書化された部分があります。
ドキュメントで必要な情報が見つからない場合は、低レベルのデータ構造を直接調査する必要があります。
# 低レベルデータ構造にアクセス
psd._record # 低レベルPSDレコードパフォーマンスの考慮事項
- 大きなPSDファイルの処理にはメモリと時間がかかります
- 高度な合成機能(composite extra)は処理が重い場合があります
- NumPy配列を使用することで処理を高速化できる場合があります
トラブルシューティング
ImportError: Advanced compositing features require optional dependencies
高度な合成機能を使用しようとした際にこのエラーが出る場合は、compositeエクストラをインストールしてください。
pip install 'psd-tools[composite]'32bit PSDファイルが読めない
PIL/PillowがLITTLECMSサポート付きでビルドされているか確認してください。
# Ubuntu/Debian
apt-get install liblcms2-2
# macOS
brew install little-cms2
# Pillowを再インストール
pip uninstall Pillow
pip install Pillowレイヤーが正しく合成されない
高度な合成機能が必要な場合があります。
compositeエクストラをインストールしているか確認してください。
また、一部のレイヤーエフェクトや調整レイヤーは完全にサポートされていません。
まとめ
psd-toolsは、PythonでPSDファイルを操作するための強力なライブラリです。
基本的な読み込みとエクスポートから、レイヤー属性の編集、新規PSDの作成まで幅広い機能を提供します。
主な用途:
- PSDファイルからの画像やレイヤーの一括エクスポート
- レイヤー情報の自動抽出と分析
- PSDファイルのバッチ処理
- PSDテンプレートからの自動生成
- 画像処理パイプラインへの統合
完全な機能はPhotoshopには及びませんが、自動化やバッチ処理には十分な機能を備えています。

