adobe-ps-scripts-loreal/test/extract_internal_ids.jsx
DJP 4a192a8c97 Initial commit: Adobe Photoshop API text management scripts
Local and cloud-based workflows for extracting and updating
text layers in PSD files via ExtendScript and Adobe PS API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:46:52 -05:00

291 lines
No EOL
12 KiB
JavaScript

// Extract Internal Layer IDs from Photoshop Document
// This script extracts the actual internal IDs that Adobe's API uses
// to identify text layers in a PSD file.
#target photoshop
// Function to extract text layers with their internal IDs
function extractTextLayersWithInternalIDs() {
if (!app.documents.length) {
return {
error: "No document open"
};
}
var doc = app.activeDocument;
var result = {
documentName: doc.name,
psdPath: doc.fullName.fsName,
extractedAt: new Date().toString(),
dimensions: {
width: doc.width.as('px'),
height: doc.height.as('px')
},
textLayerCount: 0,
textLayers: []
};
// Utility function to traverse layers and extract info
function traverseLayers(layers, path) {
path = path || "";
for (var i = 0; i < layers.length; i++) {
var layer = layers[i];
if (layer.typename === "LayerSet") {
// This is a layer group, traverse its children
var groupPath = path ? path + "/" + layer.name : layer.name;
traverseLayers(layer.layers, groupPath);
} else if (layer.kind === LayerKind.TEXT) {
// This is a text layer, extract its information
extractTextLayerInfo(layer, path);
}
}
}
function extractTextLayerInfo(layer, path) {
try {
var layerPath = path ? path + "/" + layer.name : layer.name;
// Get the layer's ID directly from the layer object
var directID = layer.id;
// Get the layer's internal ID using ActionManager
var internalID = getInternalLayerID(layer);
// Extract text content
var text = layer.textItem.contents;
// Extract basic style information
var styleInfo = {
font: layer.textItem.font,
size: layer.textItem.size.value,
color: null, // Will be populated if available
alignment: getTextAlignment(layer)
};
// Try to extract text color
try {
if (layer.textItem.color.rgb) {
styleInfo.color = [
layer.textItem.color.rgb.red,
layer.textItem.color.rgb.green,
layer.textItem.color.rgb.blue
];
}
} catch (e) {
// Color not defined or error accessing it
}
// Extract detailed formatting info if available
var richTextInfo = extractRichTextInfo(layer);
if (richTextInfo && richTextInfo.styles && richTextInfo.styles.length > 0) {
styleInfo.styles = richTextInfo.styles;
var hasRichTextFormatting = richTextInfo.styles.length > 1;
} else {
styleInfo.styles = [];
var hasRichTextFormatting = false;
}
// Create layer info object with both direct and internal IDs
var layerInfo = {
id: directID, // The ID we normally use
internalID: internalID, // The ID Adobe API might use
name: layer.name,
path: layerPath,
text: text,
visible: layer.visible,
styleInfo: styleInfo,
hasRichTextFormatting: hasRichTextFormatting
};
// Add to results
result.textLayers.push(layerInfo);
result.textLayerCount++;
} catch (e) {
// Log error but continue processing other layers
$.writeln("Error processing layer '" + layer.name + "': " + e.message);
}
}
// Function to get internal layer ID using ActionManager
function getInternalLayerID(layer) {
try {
// Select the layer
var idslct = charIDToTypeID("slct");
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), layer.id);
desc.putReference(charIDToTypeID("null"), ref);
executeAction(idslct, desc, DialogModes.NO);
// Get the layer's item index
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var itemIndexDesc = executeActionGet(ref);
var itemIndex = itemIndexDesc.getInteger(charIDToTypeID("ItmI"));
// Get the layer's ID
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("layerID"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var layerDesc = executeActionGet(ref);
// Check if the layer has a layerID property
if (layerDesc.hasKey(stringIDToTypeID("layerID"))) {
return layerDesc.getInteger(stringIDToTypeID("layerID"));
} else {
// Fallback to another method of ID extraction
return layer.id; // Use direct ID as fallback
}
} catch (e) {
$.writeln("Error getting internal ID for layer '" + layer.name + "': " + e.message);
return layer.id; // Use direct ID if we can't get the internal ID
}
}
// Function to get text alignment
function getTextAlignment(layer) {
try {
var align = layer.textItem.justification;
if (align === Justification.LEFT) {
return "left";
} else if (align === Justification.CENTER) {
return "center";
} else if (align === Justification.RIGHT) {
return "right";
} else {
return "left"; // Default
}
} catch (e) {
return "left"; // Default if error
}
}
// Function to extract rich text information
function extractRichTextInfo(layer) {
try {
var styles = [];
// Get a reference to the layer
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), layer.id);
var desc = executeActionGet(ref);
// Check if textKey exists
if (desc.hasKey(stringIDToTypeID("textKey"))) {
var textKey = desc.getObjectValue(stringIDToTypeID("textKey"));
// Check if textStyleRange exists
if (textKey.hasKey(stringIDToTypeID("textStyleRange"))) {
var styleRanges = textKey.getList(stringIDToTypeID("textStyleRange"));
// Iterate through each style range
for (var i = 0; i < styleRanges.count; i++) {
var range = styleRanges.getObjectValue(i);
var from = range.getInteger(stringIDToTypeID("from"));
var to = range.getInteger(stringIDToTypeID("to"));
var styleRef = range.getObjectValue(stringIDToTypeID("textStyle"));
var rangeText = layer.textItem.contents.substring(from, to);
var fontName = layer.textItem.font;
var fontSize = layer.textItem.size.value;
var fontStyle = "Regular";
var fontColor = null;
// Extract font name
try {
if (styleRef.hasKey(stringIDToTypeID("fontName"))) {
fontName = styleRef.getString(stringIDToTypeID("fontName"));
}
} catch (e) {}
// Extract font style
try {
if (styleRef.hasKey(stringIDToTypeID("fontStyleName"))) {
fontStyle = styleRef.getString(stringIDToTypeID("fontStyleName"));
}
} catch (e) {}
// Extract font size
try {
if (styleRef.hasKey(stringIDToTypeID("size"))) {
fontSize = styleRef.getUnitDoubleValue(stringIDToTypeID("size"));
}
} catch (e) {}
// Extract color
try {
if (styleRef.hasKey(stringIDToTypeID("color"))) {
var colorObj = styleRef.getObjectValue(stringIDToTypeID("color"));
var colorValues = colorObj.getObjectValue(stringIDToTypeID("color"));
// Check color model
if (colorValues.hasKey(stringIDToTypeID("red"))) {
fontColor = [
Math.round(colorValues.getDouble(stringIDToTypeID("red"))),
Math.round(colorValues.getDouble(stringIDToTypeID("green"))),
Math.round(colorValues.getDouble(stringIDToTypeID("blue")))
];
}
}
} catch (e) {}
// Add style info to the array
styles.push({
start: from,
end: to,
text: rangeText,
font: fontName,
style: fontStyle,
size: fontSize,
color: fontColor
});
}
}
}
return { styles: styles };
} catch (e) {
$.writeln("Error extracting rich text info: " + e.message);
return { styles: [] };
}
}
// Start the layer traversal
traverseLayers(doc.layers);
return result;
}
// Main function
function main() {
try {
var result = extractTextLayersWithInternalIDs();
// Convert result to formatted JSON
var jsonString = JSON.stringify(result, null, 2);
// Save the result to a file
var docPath = app.activeDocument.path;
var fileName = app.activeDocument.name.replace(/\.[^\.]+$/, '') + "_internal_ids.json";
var outputFile = new File(docPath + "/" + fileName);
if (outputFile.open("w")) {
outputFile.write(jsonString);
outputFile.close();
alert("Layer ID information saved to:\n" + outputFile.fsName);
} else {
alert("Error saving output file");
}
// Also return the JSON string
return jsonString;
} catch (e) {
alert("Error: " + e.message);
return JSON.stringify({ error: e.message });
}
}
// Run the script
main();