Editable Text Layers#
Scope#
Create a
TextLayer_*bitStyle/format via high-level range helpers (
*_range,*_text,*_all)Use lower-level run APIs (
style_run(index),paragraph_run(index),set_style_run_*)Read attributes from layer-level and run-level APIs
Switch orientation between horizontal and vertical text
Switch between box text and point text (
TextLayercreation defaults to box text)Set character direction (LTR / RTL)
C++#
Create a layer:
using namespace NAMESPACE_PSAPI;
LayeredFile<bpp8_t> doc = { Enum::ColorMode::RGB, 1200u, 1800u };
auto layer = TextLayer<bpp8_t>::create(
"Caption",
"Hello\nWorld",
"ArialMT",
36.0,
{1.0, 0.0, 0.0, 0.0}, // [A, R, G, B]
120.0, 160.0,
600.0, 260.0
);
doc.add_layer(layer);
Style/format (high-level first)#
Use these first:
Character styles:
style_all(),style_text(needle, occurrence=0),style_range(start, end)Paragraph styles:
paragraph_all(),paragraph_text(needle, occurrence=0),paragraph_range(start, end)occurrencebehavior for*_text(...):0(default) = all matches,1= first match,2= second match, etc.
Note: start/end are UTF-16 code-unit indices.
// High-level range helpers
layer->style_all().set_font_size(36.0).set_fill_color({1.0, 0.0, 0.0, 0.0});
layer->style_text("World").set_underline(true); // occurrence omitted -> all matches
layer->style_text("World", 1).set_font("Arial-BoldMT").set_stroke_flag(true).set_outline_width(2.0); // first match
layer->style_range(0, 5).set_underline(true);
layer->style_all().set_character_direction(TextLayerEnum::CharacterDirection::RightToLeft); // RTL
layer->style_all().set_character_direction(TextLayerEnum::CharacterDirection::LeftToRight); // LTR
layer->paragraph_all().set_justification(TextLayerEnum::Justification::Center);
// Orientation: horizontal <-> vertical
layer->set_orientation(TextLayerEnum::WritingDirection::Vertical);
layer->set_orientation(TextLayerEnum::WritingDirection::Horizontal);
// Text frame type: box <-> point (create() defaults to box text)
layer->convert_to_point_text(); // box -> point
layer->convert_to_box_text(600.0, 260.0); // point -> box
Lower-level API (run-level control)#
When you need exact run control:
Discover runs with
style_run_lengths()/paragraph_run_lengths()Edit one run with
style_run(index)/paragraph_run(index)Or use direct setters:
set_style_run_*,set_paragraph_run_*
layer->split_style_run(0, 6);
layer->style_run(1).set_faux_bold(true);
layer->set_style_run_font_size(1, 42.0);
Get attributes:
auto text = layer->text();
auto [x, y] = layer->position();
auto box_w = layer->box_width();
auto box_h = layer->box_height();
auto orientation = layer->orientation();
if (auto lengths = layer->style_run_lengths(); lengths.has_value()) {
for (size_t i = 0; i < lengths->size(); ++i) {
auto font_idx = layer->style_run_font(i);
auto size = layer->style_run_font_size(i);
auto fill = layer->style_run_fill_color(i);
auto char_dir = layer->style_run_character_direction(i);
}
}
if (auto p_lengths = layer->paragraph_run_lengths(); p_lengths.has_value()) {
for (size_t i = 0; i < p_lengths->size(); ++i) {
auto just = layer->paragraph_run_justification(i);
}
}
Important when editing an existing PSD#
If you modify text on a PSD you read from disk, call invalidate_text_cache() on the
LayeredFile before writing. This triggers Photoshop’s text-update prompt on open.
Without this, text can appear invisible until Photoshop refreshes text internals.
doc.invalidate_text_cache();
doc.write("edited.psd");
Python#
Create a layer:
import photoshopapi as psapi
doc = psapi.LayeredFile_8bit(psapi.enum.ColorMode.rgb, 1200, 1800)
layer = psapi.TextLayer_8bit(
layer_name="Caption",
text="Hello\nWorld",
font="ArialMT", # PostScript font name
font_size=36.0,
fill_color=[1.0, 0.0, 0.0, 0.0], # [A, R, G, B]
position_x=120.0,
position_y=160.0,
box_width=600.0,
box_height=260.0,
)
doc.add_layer(layer)
Style/format (high-level first)#
Same high-level API semantics as C++ above (occurrence=0 means all matches).
# Character styling
layer.style_all().set_font_size(36.0).set_fill_color([1.0, 0.0, 0.0, 0.0])
layer.style_text("World", 1).set_font("Arial-BoldMT").set_stroke_flag(True).set_outline_width(2.0)
layer.style_range(0, 5).set_underline(True)
layer.style_all().set_character_direction(psapi.enum.CharacterDirection.RightToLeft) # RTL
layer.style_all().set_character_direction(psapi.enum.CharacterDirection.LeftToRight) # LTR
# Paragraph styling
layer.paragraph_all().set_justification(psapi.enum.Justification.Center)
# Orientation: horizontal <-> vertical
layer.set_orientation(psapi.enum.WritingDirection.Vertical)
layer.set_orientation(psapi.enum.WritingDirection.Horizontal)
# Text frame type: box <-> point (TextLayer_8bit(...) defaults to box text)
layer.convert_to_point_text() # box -> point
layer.convert_to_box_text(600.0, 260.0) # point -> box
Lower-level API (run-level control)#
Same run-control API as C++ above (style_run_lengths, paragraph_run_lengths,
style_run(index), paragraph_run(index), and direct set_* run setters).
layer.split_style_run(0, 6) # "Hello " | "World"
layer.style_run(1).set_faux_bold(True)
layer.style_run(1).set_fill_color([1.0, 1.0, 0.0, 0.0])
# equivalent direct setter
layer.set_style_run_font_size(1, 42.0)
Get attributes#
High-level layer reads:
text = layer.text
x, y = layer.position()
box_w = layer.box_width()
box_h = layer.box_height()
orientation = layer.orientation()
Run-level reads:
for i, run_len in enumerate(layer.style_run_lengths() or []):
font_idx = layer.style_run_font(i)
font_ps = layer.font_postscript_name(font_idx) if font_idx is not None else None
size = layer.style_run_font_size(i)
fill = layer.style_run_fill_color(i)
stroke = layer.style_run_stroke_color(i)
underline = layer.style_run_underline(i)
char_dir = layer.style_run_character_direction(i)
for i, run_len in enumerate(layer.paragraph_run_lengths() or []):
just = layer.paragraph_run_justification(i)
Proxy-style run reads:
run = layer.style_run(0)
size = run.font_size
fill = run.fill_color
outline_w = run.outline_width
When editing an existing PSD, call:
doc.invalidate_text_cache()
doc.write("edited.psd")