Copy link to clipboard
Copied
I'm not happy with the hanging punctuation in photoshop, but I can't work in indesign, where this feature is much more elaborate. I want to make a script with manual kerning on punctuation marks, but I can't figure out what I'm doing wrong.
function adjustPunctuationKerning() {
var textLayer = app.activeDocument.activeLayer;
if (textLayer.kind !== LayerKind.TEXT) {
return;
}
var textItem = textLayer.textItem;
for (var i = 0; i < textItem.contents.length; i++) {
var currentCharacter = textItem.contents[i];
switch (currentCharacter) {
case '?':
textItem.characters[i+1].kerning = -300;
break;
case '!':
textItem.characters[i+1].kerning = -100;
break;
case '.':
textItem.characters[i+1].kerning = -100;
break;
}
}
}
adjustPunctuationKerning();
I don't know js well and i hope photoshop gives kerning manipulation in text layer
// apply properties like fonts, size, … to letters of words in selected type layer;
// kerning in this case and for all type layers in the document;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var theRegExp = /\?/gi;
var theTypeLayers = collectTypeLayers ();
for (var m = 0; m < theTypeLayers.length; m++) {
changeWordProperties (theTypeLayers[m][1], theRegExp, -500)
}
};
//////////////////
////// change word properties //////
function changeWordProperties (
...
Copy link to clipboard
Copied
The Script (from the post marked as »correct answer«) seems to insert the kerning before the question mark, as intended.
Copy link to clipboard
Copied
That's right, but the point doesn't change, look at the kerning before the “d”, it will be 0
where the kerning will be applied, it will be 0 before it
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Now I get it; if there is existing kerning (other than 0) one place before the intended kerning-change it is changed to 0.
I don’t know why this happens, though.
Photoshop Type Layers are kind of difficult to Script, I guess.
Copy link to clipboard
Copied
I did a test; even if I use code created with ScriptingListener.plugin that changes the kerning of two consecutive letters the first one’s is disregarded.
So it seems likely that this is a bug in Photoshop ESTK Scripting.
But as that is on »legacy status« as it is it doesn’t seem worth reporting as it seems unlikely to get fixed anyway.
Edit: It does seem like a bug, but it seems one can work around it.
Copy link to clipboard
Copied
Please try this, it seems going backwards instead of forwards works out:
// apply kerning before question mark;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
//executeAction( stringIDToTypeID( "revert" ), undefined, DialogModes.NO );
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var theRegExp = /\?/gi;
var theNewKerning = -500;
//////////////////
try {
var theFonts = new Array;
var theStyleRanges = new Array;
// get font of active layer;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
var hasText = layerDesc.hasKey(stringIDToTypeID("textKey"));
if (hasText == true) {
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID('textKey'));
var paragraphRangeList = textDesc.getList(stringIDToTypeID('paragraphStyleRange'));
var kernRange = textDesc.getList(stringIDToTypeID('kerningRange'));
var rangeList = textDesc.getList(stringIDToTypeID('textStyleRange'));
// process the list;
for (var o = 0; o < rangeList.count; o++) {
var thisList = rangeList.getObjectValue(o);
var theFrom = thisList.getInteger(stringIDToTypeID('from'));
var theTo = thisList.getInteger(stringIDToTypeID('to'));
var styleDesc = thisList.getObjectValue(stringIDToTypeID('textStyle'));
var aSize = styleDesc.getUnitDoubleValue(charIDToTypeID( "Sz " ));
// check for default font;
if (styleDesc.hasKey(stringIDToTypeID('fontPostScriptName')) == true) {var aFont = styleDesc.getString(stringIDToTypeID('fontPostScriptName'))}
else {
var theDefault = styleDesc.getObjectValue(stringIDToTypeID('baseParentStyle'));
var aFont = theDefault.getString(stringIDToTypeID('fontPostScriptName'));
};
if (styleDesc.hasKey(stringIDToTypeID('impliedFontSize')) == true) {var aFont = styleDesc.getString(stringIDToTypeID('fontPostScriptName'))}
// add to array;
theFonts.push([aFont, aSize, theFrom, theTo]);
theStyleRanges.push(thisList.getObjectValue(stringIDToTypeID('textStyle')));
}
}
};
// the change arrays;
var theColors = [[128,0,0], [128,128,0], [0,128,0],[0,128,128], [0,0,128], [128,0,128]];
var newFonts = ["MyriadPro-Regular", "MyriadPro-Bold", "Times-BoldItalic"];
var theBaselineShift = 10;
// change text;
// =======================================================
var idPxl = charIDToTypeID( "#Pxl" );
var idPnt = charIDToTypeID( "#Pnt" );
var idTxtt = charIDToTypeID( "Txtt" );
var idFrom = charIDToTypeID( "From" );
var idT = charIDToTypeID( "T " );
var idTxtS = charIDToTypeID( "TxtS" );
var idTxLr = charIDToTypeID( "TxLr" );
var idTxt = charIDToTypeID( "Txt " );
var idsetd = charIDToTypeID( "setd" );
var desc6 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref1 = new ActionReference();
ref1.putEnumerated( idTxLr, charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ));
desc6.putReference( idnull, ref1 );
var desc7 = new ActionDescriptor();
desc7.putString( idTxt, theText );
var list2 = new ActionList();
//////////////////
// define each letter individually;
var theIndex = 0;
var theRef = theStyleRanges[theIndex];
var theRef2 = theFonts[theIndex];
var theSize = theStyleRanges[theIndex].getUnitDoubleValue(charIDToTypeID( "Sz " ));
for (var m = 0; m < theText.length; m++) {
// check for relevant style range;
anIndex = Math.floor(Math.random() * (theColors.length))
if (m == theRef2[3]) {
theIndex++;
var theRef = theStyleRanges[theIndex];
var theRef2 = theFonts[theIndex];
var theSize = theStyleRanges[theIndex].getUnitDoubleValue(charIDToTypeID( "Sz " ));
};
var desc14 = new ActionDescriptor();
desc14.putInteger( idFrom, m );
desc14.putInteger( idT, m+1 );
var theStyle = theRef;
//////////////////
/*// color;
var desc21 = new ActionDescriptor();
desc21.putDouble( charIDToTypeID( "Rd " ), theColors[anIndex][0] );
desc21.putDouble( charIDToTypeID( "Grn " ), theColors[anIndex][1] );
desc21.putDouble( charIDToTypeID( "Bl " ), theColors[anIndex][2] );
theStyle.putObject( charIDToTypeID( "Clr " ), charIDToTypeID( "RGBC" ), desc21 );
// font;
var aRandomFont = newFonts[Math.floor(Math.random()*newFonts.length)];
theStyle.putString( stringIDToTypeID( "fontPostScriptName" ), aRandomFont);
// size;
var thisSize = theSize * (0.99 + Math.random() * 0.02);
theStyle.putUnitDouble( charIDToTypeID( "Sz " ), idPxl, thisSize );
theStyle.putUnitDouble( stringIDToTypeID( "impliedFontSize" ), idPxl, thisSize );
// baseline shift:
var thisShift = theBaselineShift * (0.5 - Math.random());
theStyle.putUnitDouble( charIDToTypeID( "Bsln" ), idPxl, thisShift );
theStyle.putUnitDouble( stringIDToTypeID( "impliedBaselineShift" ), idPxl, thisShift );*/
//////////////////
desc14.putObject( stringIDToTypeID('textStyle'), stringIDToTypeID('textStyle'), theStyle);
list2.putObject( charIDToTypeID( "Txtt" ), desc14);
};
// kerning range;
var list3 = new ActionList();
if (kernRange.count > 0) {
var kernIndex = kernRange.count-1;
var thisOne = kernRange.getObjectValue(kernIndex);
var theFrom = thisOne.getInteger(charIDToTypeID("From"));
var theTo = thisOne.getInteger(charIDToTypeID( "T " ));
var theKerning = thisOne.getInteger(stringIDToTypeID("kerning"));
} else {theFrom = undefined};
for (var m = theText.length-1; m >= 0; m--) {
if (m == theFrom) {
var desc15 = new ActionDescriptor();
desc15.putInteger( idFrom, m );
desc15.putInteger( idT, m+1 );
desc15.putInteger( charIDToTypeID( "Krng" ), theKerning);
list3.putObject( stringIDToTypeID( "kerningRange"), desc15);
kernIndex--;
if (kernIndex >= 0) {
var thisOne = kernRange.getObjectValue(kernIndex);
var theFrom = thisOne.getInteger(charIDToTypeID("From"));
var theTo = thisOne.getInteger(charIDToTypeID( "T " ));
var theKerning = thisOne.getInteger(stringIDToTypeID("kerning"));
}
};
if (theText[m].match(theRegExp) != null) {
var desc15 = new ActionDescriptor();
desc15.putInteger( idFrom, m-1 );
desc15.putInteger( idT, m );
desc15.putInteger( charIDToTypeID( "Krng" ), theNewKerning);
list3.putObject( stringIDToTypeID( "kerningRange"), desc15);
};
};
//////////////////
desc7.putList( idTxtt, list2 );
desc7.putList( stringIDToTypeID( "kerningRange"), list3);
//////////////////
desc6.putObject( idT, idTxLr, desc7 );
executeAction( idsetd, desc6, DialogModes.NO );
}
catch (e) {};
app.preferences.rulerUnits = originalRulerUnits;
};
edited 2024-12-03
Copy link to clipboard
Copied
What version of photoshop are you using? I tried to use the script, but on versions 2024 (25.12, 25.06, 25.03) I got one error 8800 and that the “revert” function is not available in the current version. I also tried on the latest version (26.1) and 2022 (23.1.0) but the error is the same. on pc
Copy link to clipboard
Copied
I updated the code, please try again.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now