Skip to main content
Known Participant
July 31, 2024
Answered

Text inside path/shape into point text?

  • July 31, 2024
  • 3 replies
  • 2457 views

Thank to many helps from this forum that now I could improve all my works! Now I have a new trouble about typing inside the shape/path. As y'all know, the path text is very awesome for typing inside shapes, but it could never be turned into point text (or paragraph text, of course haha).

My first solution is: breaking lines of the text by continuing press end > enter until the last line, then copy the whole content into a new point text layer. However, there are so many text layers now, that I could not done by hand anymore! I tried auto keyboard but not very effective, now I need a solution as a script or action. Is it possible in photoshop? I've attached the sample file, thank you very much for taking an attention to this post!

This topic has been closed for replies.
Correct answer c.pfaffenbichler

oh... So that's because of my additional line break?


A crude approach: Insert this 

 

// remove carriage returns;
var thisOne = /\s?\r/i;
while (theText.match(thisOne) != null) {
theText = theText.replace(thisOne, " ")
};

 

before 

 

// insert linebreaks;
var theRegExp = /\s/;

 

3 replies

c.pfaffenbichler
Community Expert
Community Expert
August 1, 2024

Edit: code updated to move the Layer to top-align with original type layer 

 

// create point text from type in path layers with corresponding linebreaks;
// only one point is evaluated per subpathitem from the work path;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var theW = myDocument.width;
var theH = myDocument.height;
var theLayers = collectTypeInPathLayers ();
// process the layers;
for (var a = 0; a < theLayers.length; a++) {
try {
selectLayerByID(theLayers[a][1], false);
// try determining letters per line via work path;
createWorkPath ();
for (var x = 0; x < myDocument.pathItems.length; x++) {
if (myDocument.pathItems[x].kind == PathKind.WORKPATH) {var theWorkPath = getDOMPathInfo(myDocument.pathItems[x])};
};
var theNumbers = [1];
var horStart = theWorkPath[0][0];
for (var m = 1; m < theWorkPath.length; m++) {
if (theWorkPath[m][0] > horStart) {
horStart = theWorkPath[m][0];
theNumbers[theNumbers.length-1] = theNumbers[theNumbers.length-1] + 1
} else {
horStart = theWorkPath[m][0];
theNumbers.push(1)
};
};
// get type and bounds;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID('textKey'));
var x1 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("left"));
var x2 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("right"));
var y1 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("top"));
var y2 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("bottom"));
var theX = (x1 + (x2-x1) / 2)/theW*100;
var theY = (y1 + (y2-y1) / 2)/theH*100;
// insert linebreaks;
var theRegExp = /\s/;
var thisNumber = theNumbers[0];
var lineCounter = 0;
var lettersCounter = 0;
for (var n = 0; n < theText.length; n++) {
if (theText[n].match(theRegExp) == null) {
lettersCounter++
} else {
if (lettersCounter == thisNumber) {
theText = theText.slice(0,n) + "\r" + theText.slice(n+1);
lineCounter++;
lettersCounter = 0;
thisNumber = theNumbers[lineCounter];
}
}
};
// create point type layer; 
var desc180 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putClass( stringIDToTypeID( "textLayer" ) );
desc180.putReference( stringIDToTypeID( "null" ), ref2 );
textDesc.putString( stringIDToTypeID( "textKey" ), theText );
var desc183 = new ActionDescriptor();
desc183.putUnitDouble( stringIDToTypeID( "horizontal" ), stringIDToTypeID( "percentUnit" ), theX );
desc183.putUnitDouble( stringIDToTypeID( "vertical" ), stringIDToTypeID( "percentUnit" ), theY );
textDesc.putObject( stringIDToTypeID( "textClickPoint" ), stringIDToTypeID( "paint" ), desc183 );
var list2 = new ActionList();
var desc186 = new ActionDescriptor();
var idchar = stringIDToTypeID( "char" );
desc186.putEnumerated( idchar, idchar, stringIDToTypeID( "paint" ) );
var idorientation = stringIDToTypeID( "orientation" );
desc186.putEnumerated( idorientation, idorientation, stringIDToTypeID( "horizontal" ) );
var idtransform = stringIDToTypeID( "transform" );
var desc187 = new ActionDescriptor();
desc187.putDouble( stringIDToTypeID( "xx" ), 1.000000 );
desc187.putDouble( stringIDToTypeID( "xy" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "yx" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "yy" ), 1.000000 );
desc187.putDouble( stringIDToTypeID( "tx" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "ty" ), 0.000000 );
desc186.putObject( idtransform, idtransform, desc187 );
desc186.putInteger( stringIDToTypeID( "rowCount" ), 1 );
desc186.putInteger( stringIDToTypeID( "columnCount" ), 1 );
desc186.putBoolean( stringIDToTypeID( "rowMajorOrder" ), true );
desc186.putUnitDouble( stringIDToTypeID( "rowGutter" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
desc186.putUnitDouble( stringIDToTypeID( "columnGutter" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
desc186.putUnitDouble( stringIDToTypeID( "spacing" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
var idframeBaselineAlignment = stringIDToTypeID( "frameBaselineAlignment" );
desc186.putEnumerated( idframeBaselineAlignment, idframeBaselineAlignment, stringIDToTypeID( "alignByAscent" ) );
desc186.putUnitDouble( stringIDToTypeID( "firstBaselineMinimum" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
var desc188 = new ActionDescriptor();
desc188.putDouble( stringIDToTypeID( "horizontal" ), 0.000000 );
desc188.putDouble( stringIDToTypeID( "vertical" ), 0.000000 );
desc186.putObject( stringIDToTypeID( "base" ), stringIDToTypeID( "paint" ), desc188 );
list2.putObject( stringIDToTypeID( "textShape" ), desc186 );
textDesc.putList( stringIDToTypeID( "textShape" ), list2 );
desc180.putObject( stringIDToTypeID( "using" ), stringIDToTypeID( "textLayer" ), textDesc );
executeAction( stringIDToTypeID( "make" ), desc180, DialogModes.NO );
} catch (e) {};
// move layer;
moveLayer(null, 0, (y1 - myDocument.activeLayer.bounds[1]) * (-1));
};
app.preferences.rulerUnits = originalRulerUnits;
};
////// create work path from type layer //////
function createWorkPath () {
try {
var desc5 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putClass( stringIDToTypeID( "path" ) );
desc5.putReference( stringIDToTypeID( "null" ), ref1 );
var ref2 = new ActionReference();
ref2.putEnumerated( stringIDToTypeID( "textLayer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ) );
desc5.putReference( stringIDToTypeID( "from" ), ref2 );
executeAction( stringIDToTypeID( "make" ), desc5, DialogModes.NO );
} catch (e) {}
};
////// get path-array //////
function getDOMPathInfo (thePath) {
var lineSubPathArray = new Array;
for (var a = 0; a < thePath.subPathItems.length; a++) {
var extremeArray = [thePath.subPathItems[a].pathPoints[0].anchor[0], thePath.subPathItems[a].pathPoints[0].anchor[1], thePath.subPathItems[a].pathPoints[0].anchor[0], thePath.subPathItems[a].pathPoints[0].anchor[1]];
/*for (var b = 1; b < thePath.subPathItems[a].pathPoints.length; b++) {
var aPoint = thePath.subPathItems[a].pathPoints[b].anchor;
extremeArray[0] = Math.min(extremeArray[0], aPoint[0]);
extremeArray[1] = Math.min(extremeArray[1], aPoint[1]);
extremeArray[2] = Math.max(extremeArray[2], aPoint[0]);
extremeArray[3] = Math.max(extremeArray[3], aPoint[1]);
};*/
lineSubPathArray.push(extremeArray);
/*for (var b = 0; b < thePath.subPathItems[a].pathPoints.length; b++) {
var aPoint = thePath.subPathItems[a].pathPoints[b];
lineArray[b] = new PathPointInfo;
lineArray[b].kind = aPoint.kind;
lineArray[b].anchor = aPoint.anchor;
lineArray[b].leftDirection = aPoint.leftDirection;
lineArray[b].rightDirection = aPoint.rightDirection;
};
lineSubPathArray[a] = new SubPathInfo();
lineSubPathArray[a].operation = ShapeOperation.SHAPEXOR;
lineSubPathArray[a].closed = thePath.subPathItems[a].closed;
lineSubPathArray[a].entireSubPath = lineArray;*/
};
return lineSubPathArray
};
////// collect type in path layers //////
function collectTypeInPathLayers () {
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true && layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {
var visible = layerDesc.getBoolean(stringIDToTypeID("visible"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theShape = textDesc.getList(stringIDToTypeID('textShape')).getObjectValue(0);
if (theShape.hasKey(stringIDToTypeID('path')) == true) {theLayers.push([theName, theID, visible])}
};
}
catch (e) {};
};
return theLayers
};
////// based on code by mike hale, via paul riggott //////
function selectLayerByID(id,add){ 
add = undefined ? add = false:add 
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};
////// duplicate layer and move, rotate and scale it //////
function moveLayer (theID, theX, theY) {
if (theID != null) {selectLayerByID(theID,false)};
try{
var desc217 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated( stringIDToTypeID( "layer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ) );
desc217.putReference( stringIDToTypeID( "null" ), ref1 );
var desc218 = new ActionDescriptor();
var idpixelsUnit = stringIDToTypeID( "pixelsUnit" );
desc218.putUnitDouble( stringIDToTypeID( "horizontal" ), idpixelsUnit, theX );
desc218.putUnitDouble( stringIDToTypeID( "vertical" ), idpixelsUnit, theY );
desc217.putObject( stringIDToTypeID( "to" ), stringIDToTypeID( "offset" ), desc218 );
executeAction( stringIDToTypeID( "move" ), desc217, DialogModes.NO );
} catch (e) {}
};

 

 

Known Participant
August 2, 2024

Thank you so very much!!! You really save my whole life 😄

c.pfaffenbichler
Community Expert
Community Expert
July 31, 2024

I updated the previous code. 

Known Participant
July 31, 2024

Thank you very much!! The script worked exact what I need, although a bit slow (may due to my device XD) and only run one layer a time. I wonder if I do the 'converting text layer to path' step - separate with your script, will the script run faster?

c.pfaffenbichler
Community Expert
Community Expert
July 31, 2024

The speed-bump is the DOM-collection of the pathPoints. 

AM would run faster … but it would cause another problem because letters like »O« or »P« for example would be two elements. 

 

Edit: And »8« would even be three objects in most fonts … 

So to utilize AM code one would need a further check; for example one that compares the subPathItems and sorts out the ones the bounds of which are completely inside the bounds of another one – that could still get incorrect results, though, both false negatives (»i«, »!«, »%«, …) and false positives (strongly kerned »7.« possibly). 

c.pfaffenbichler
Community Expert
Community Expert
July 31, 2024

Why do you want to turn it into Point Text? 

For the top example (with the irregular shape) the alignment and line-breaks would get lost. 

Known Participant
July 31, 2024

Actually in my work, the alignment of the shape is not so important, we need the text just be at the center of the shape, most of them will be round or rectangular ( the top one I just drawn is a random one, but it was so distort haha, pls forget about it)

The Point text is one of our required task. When we haven't found out the Path text, we broke the line by feelings (it means keep pressing enter, and delete, and enter, delete until the text looks fine, that thing wasted almost time). I wished they would keep working with Path text, but they don't want to 😞

c.pfaffenbichler
Community Expert
Community Expert
July 31, 2024

I don’t understand what the point is. Could you please post screenshots to clarify? 

 

Does this help? (I colored some words to ascertain whether type settings are honored.) 

Edit: The Script works on the active Layer and does not include a check for Type-in-Path so far but depends on a fitting Layer to be selected. 

 

 

// 2024, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var theW = myDocument.width;
var theH = myDocument.height;
try {
// try determining letters per line via work path;
createWorkPath ();
for (var x = 0; x < myDocument.pathItems.length; x++) {
if (myDocument.pathItems[x].kind == PathKind.WORKPATH) {var theWorkPath = getDOMPathInfo(myDocument.pathItems[x])};
};
var theNumbers = [1];
var horStart = theWorkPath[0][0];
for (var m = 1; m < theWorkPath.length; m++) {
if (theWorkPath[m][0] > horStart) {
horStart = theWorkPath[m][0];
theNumbers[theNumbers.length-1] = theNumbers[theNumbers.length-1] + 1
} else {
horStart = theWorkPath[m][0];
theNumbers.push(1)
};
};
// get type and bounds;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID('textKey'));
var x1 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("left"));
var x2 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("right"));
var y1 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("top"));
var y2 = layerDesc.getObjectValue(stringIDToTypeID ("bounds")).getUnitDoubleValue(stringIDToTypeID("bottom"));
var theX = (x1 + (x2-x1) / 2)/theW*100;
var theY = (y1 + (y2-y1) / 2)/theH*100;
// insert linebreaks;
var theRegExp = /\s/;
var thisNumber = theNumbers[0];
var lineCounter = 0;
var lettersCounter = 0;
for (var n = 0; n < theText.length; n++) {
    if (theText[n].match(theRegExp) == null) {
        lettersCounter++
    } else {
        if (lettersCounter == thisNumber) {
            theText = theText.slice(0,n) + "\r" + theText.slice(n+1);
            lineCounter++;
            lettersCounter = 0;
            thisNumber = theNumbers[lineCounter];
        }
    }
};
// create point type layer; 
var desc180 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putClass( stringIDToTypeID( "textLayer" ) );
desc180.putReference( stringIDToTypeID( "null" ), ref2 );
textDesc.putString( stringIDToTypeID( "textKey" ), theText );
var desc183 = new ActionDescriptor();
desc183.putUnitDouble( stringIDToTypeID( "horizontal" ), stringIDToTypeID( "percentUnit" ), theX );
desc183.putUnitDouble( stringIDToTypeID( "vertical" ), stringIDToTypeID( "percentUnit" ), theY );
textDesc.putObject( stringIDToTypeID( "textClickPoint" ), stringIDToTypeID( "paint" ), desc183 );
var list2 = new ActionList();
var desc186 = new ActionDescriptor();
var idchar = stringIDToTypeID( "char" );
desc186.putEnumerated( idchar, idchar, stringIDToTypeID( "paint" ) );
var idorientation = stringIDToTypeID( "orientation" );
desc186.putEnumerated( idorientation, idorientation, stringIDToTypeID( "horizontal" ) );
var idtransform = stringIDToTypeID( "transform" );
var desc187 = new ActionDescriptor();
desc187.putDouble( stringIDToTypeID( "xx" ), 1.000000 );
desc187.putDouble( stringIDToTypeID( "xy" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "yx" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "yy" ), 1.000000 );
desc187.putDouble( stringIDToTypeID( "tx" ), 0.000000 );
desc187.putDouble( stringIDToTypeID( "ty" ), 0.000000 );
desc186.putObject( idtransform, idtransform, desc187 );
desc186.putInteger( stringIDToTypeID( "rowCount" ), 1 );
desc186.putInteger( stringIDToTypeID( "columnCount" ), 1 );
desc186.putBoolean( stringIDToTypeID( "rowMajorOrder" ), true );
desc186.putUnitDouble( stringIDToTypeID( "rowGutter" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
desc186.putUnitDouble( stringIDToTypeID( "columnGutter" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
desc186.putUnitDouble( stringIDToTypeID( "spacing" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
var idframeBaselineAlignment = stringIDToTypeID( "frameBaselineAlignment" );
desc186.putEnumerated( idframeBaselineAlignment, idframeBaselineAlignment, stringIDToTypeID( "alignByAscent" ) );
desc186.putUnitDouble( stringIDToTypeID( "firstBaselineMinimum" ), stringIDToTypeID( "pixelsUnit" ), 0.000000 );
var desc188 = new ActionDescriptor();
desc188.putDouble( stringIDToTypeID( "horizontal" ), 0.000000 );
desc188.putDouble( stringIDToTypeID( "vertical" ), 0.000000 );
desc186.putObject( stringIDToTypeID( "base" ), stringIDToTypeID( "paint" ), desc188 );
list2.putObject( stringIDToTypeID( "textShape" ), desc186 );
textDesc.putList( stringIDToTypeID( "textShape" ), list2 );
desc180.putObject( stringIDToTypeID( "using" ), stringIDToTypeID( "textLayer" ), textDesc );
executeAction( stringIDToTypeID( "make" ), desc180, DialogModes.NO );
} catch (e) {};
app.preferences.rulerUnits = originalRulerUnits;
};
////// create work path from type layer //////
function createWorkPath () {
try {
var desc5 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putClass( stringIDToTypeID( "path" ) );
desc5.putReference( stringIDToTypeID( "null" ), ref1 );
var ref2 = new ActionReference();
ref2.putEnumerated( stringIDToTypeID( "textLayer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ) );
desc5.putReference( stringIDToTypeID( "from" ), ref2 );
executeAction( stringIDToTypeID( "make" ), desc5, DialogModes.NO );
} catch (e) {}
};
////// get path-array //////
function getDOMPathInfo (thePath) {
var lineSubPathArray = new Array;
for (var a = 0; a < thePath.subPathItems.length; a++) {
var extremeArray = [thePath.subPathItems[a].pathPoints[0].anchor[0], thePath.subPathItems[a].pathPoints[0].anchor[1], thePath.subPathItems[a].pathPoints[0].anchor[0], thePath.subPathItems[a].pathPoints[0].anchor[1]];
for (var b = 1; b < thePath.subPathItems[a].pathPoints.length; b++) {
var aPoint = thePath.subPathItems[a].pathPoints[b].anchor;
extremeArray[0] = Math.min(extremeArray[0], aPoint[0]);
extremeArray[1] = Math.min(extremeArray[1], aPoint[1]);
extremeArray[2] = Math.max(extremeArray[2], aPoint[0]);
extremeArray[3] = Math.max(extremeArray[3], aPoint[1]);
};
lineSubPathArray.push(extremeArray);
/*for (var b = 0; b < thePath.subPathItems[a].pathPoints.length; b++) {
var aPoint = thePath.subPathItems[a].pathPoints[b];
lineArray[b] = new PathPointInfo;
lineArray[b].kind = aPoint.kind;
lineArray[b].anchor = aPoint.anchor;
lineArray[b].leftDirection = aPoint.leftDirection;
lineArray[b].rightDirection = aPoint.rightDirection;
};
lineSubPathArray[a] = new SubPathInfo();
lineSubPathArray[a].operation = ShapeOperation.SHAPEXOR;
lineSubPathArray[a].closed = thePath.subPathItems[a].closed;
lineSubPathArray[a].entireSubPath = lineArray;*/
};
return lineSubPathArray
};

 

edited