• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Kerning script

Community Beginner ,
Jul 06, 2024 Jul 06, 2024

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 

enperror_0-1720260183795.png

 

TOPICS
Actions and scripting , Windows

Views

523

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Jul 21, 2024 Jul 21, 2024

Screenshot 2024-07-22 at 08.05.58.pngScreenshot 2024-07-22 at 08.06.10.png

// 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 (
...

Votes

Translate

Translate
Adobe
Community Expert ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

Where did you get the code from?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

gpt and plus I tried

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

Chat GPT is getting better, but it can often make stuff up to be "helpful".

 

https://theiviaxx.github.io/photoshop-docs/Photoshop/TextItem.html

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

Thank you! But now I'm confused, as I understood, manual kerning can only be done on the whole text, but not on certain characters?
https://theiviaxx.github.io/photoshop-docs/Photoshop/AutoKernType/MANUAL.html#autokerntype-manual

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

DOM code is limited in what it can do. Scripting text isn't fun.

 

If what you want to accomplish is even possible, it will likely require advanced Action Manager coding, which is beyond my knowledge and capabilities.

 

Search the Photoshop forum and make sure that the topic is for Photoshop and not Illustrator or InDesign etc.

 

Or look into the new UXP/BatchPlay scripting instead of legacy ExtendScript.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

 

quote

as I understood, manual kerning can only be done on the whole text, but not on certain characters?

By @enperror

 


Kerning is only for a pair of characters. Tracking is for a range of characters.

https://helpx.adobe.com/indesign/using/kerning-tracking.html

 

Jane

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

I misspoke, just below clarified what I was getting at.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 06, 2024 Jul 06, 2024

Copy link to clipboard

Copied

More precisely, it triggers on the first pair of letters, but how to specify the right one - no idea.

enperror_0-1720266047344.png

enperror_1-1720266058757.png

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

How important is this? 

Do you have to perform this task multiple times every day? 

 

As @Stephen_A_Marsh mentioned, the AM-code that could be used to achieve this is not exactly »easy«. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

Since I have to do it in photoshop, it takes me quite a bit of time.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

Please clarify what »quite a bit of time« actually means. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

I letterer comics/manga, it takes me a couple hours to lettering, let's say, one chapter. of those couple hours, at least 10-15 minutes are spent compensating for punctuation with kerning. Automating this function would help save a lot of time.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

 

Since I have to do it in photoshop, it takes me quite a bit of time.

By @enperror

 

Yes, you should expect that trying to work with text in Photoshop will take significantly more time than it does in InDesign. InDesign has excellent type controls and Illustrator has good text controls. Photoshop's main focus is images so it has limited text controls.

 

When I started using PS, text was pixels on the current layer. Kerning meant selecting all the letter to the right and using the Move tool. Tracking meant repeating the process for the other letters.

 

Photoshop's type controls have come a long way since then, but it is not expected that it will ever duplicate those in InDesign. I know you said you can't use InDesign for this project, so unfortunately you will have to deal with Photoshop's limitations. If a script won't work, then expect it to take a long time and hope that you don't need to make edits later.

 

Jane

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

This seems tricky me indeed. 

I have provided Scripts for changing the color of words in the past, but that happens in the textStyleRange, changing the kerning would necessitate splitting the kerningRange at the indices of the character (the question mark in this case). 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

I tried writing new code, it triggers, but instead of executing the function, I have a kerning 0 applied to all the text

if (app.documents.length > 0) {
    var doc = app.activeDocument; 
    
    for (var i = 0; i < doc.artLayers.length; i++) {
        var layer = doc.artLayers[i];
        
        if (layer.kind === LayerKind.TEXT) {
            var textItem = layer.textItem;
            
            textItem.autoKerning = AutoKernType.MANUAL;
            
            for (var j = 0; j < textItem.contents.length; j++) {
                if (textItem.contents[j] === "?") {
                    textItem.kerning = 220;
                }
            }
        }
    }
    alert("yep.");
} else {
    alert("nope.");
}

yonens_0-1720366831226.pngyonens_1-1720366852065.png

Most likely, as @Stephen_A_Marsh wrote to me earlier, UXP is required

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 07, 2024 Jul 07, 2024

Copy link to clipboard

Copied

quote

Most likely, as @Stephen_A_Marsh wrote to me earlier, UXP is required

While UXP code may be better at handling it AM code can handle the task, too, DOM code is the useless one in this case. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 21, 2024 Jul 21, 2024

Copy link to clipboard

Copied

Edit: The Script is kind of a proof-of-concept (based on some old scripts, so it contains superfluous lines) and applies to the selected Type Layer. 

Screenshot 2024-07-21 at 12.41.26.pngScreenshot 2024-07-21 at 13.03.17.png

 

 

// apply properties like fonts, size, … to letters of words in selected type layer;
// kerning in this case;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
    var theRegExp = /\?/gi;
	changeWordProperties (theRegExp, -500)
};
//////////////////
////// change word properties //////
function changeWordProperties (theRegExp, newKerning) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
//////////////////
try {
var theFonts = new Array;
var theStyleRanges = new Array;
var theStyleRanges2 = 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'));
// get indices for string;
var indicesCount = 0;
var theIndices = new Array;
while ((result = theRegExp.exec(theText))!=null) {
    theIndices.push([result.index, result.index+result[0].length])
};
//var shapeList = textDesc.getList(stringIDToTypeID('textShape'));
var paragraphRangeList = textDesc.getList(stringIDToTypeID('paragraphStyleRange'));
var kernRange = textDesc.getList(stringIDToTypeID('kerningRange'));
var rangeList = textDesc.getList(stringIDToTypeID('textStyleRange'));
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" );
// change text;
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 kerningRanges = new ActionList;
var theCounter = 0;
if (kernRange.count > 0) {var thisKerningRange = kernRange.getObjectValue(theCounter)};
// kernRange
for (var m = 0; m < theText.length; m++) {
// check for relevant existing kerning range;
if (kernRange.count > 0) {
    if (thisKerningRange.getInteger(idFrom) == m) {
        kerningRanges.putObject( stringIDToTypeID( "kerningRange"),  thisKerningRange);
        theCounter++;
        if (theCounter < kernRange.count) {
            var thisKerningRange = kernRange.getObjectValue(theCounter)
        }
    };
};
// check for regexp;
if (theText[m].match(theRegExp) != null) {
var desc15 = new ActionDescriptor();
desc15.putInteger( idFrom, m - 1 );
desc15.putInteger( idT, m );
desc15.putInteger( stringIDToTypeID("kerning"), newKerning );
kerningRanges.putObject( stringIDToTypeID( "kerningRange"),  desc15);
};
};
//////////////////////////////////////////////////////
//desc7.putList( idTxtt, list2 );
desc7.putList( idTxtt, rangeList );
desc7.putList( stringIDToTypeID( "kerningRange"), kerningRanges);
//////////////////////////////////////////////////////
desc6.putObject( idT, idTxLr, desc7 );
executeAction( idsetd, desc6, DialogModes.NO );
}
}
}
catch (e) {};
app.preferences.rulerUnits = originalRulerUnits;
};

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 21, 2024 Jul 21, 2024

Copy link to clipboard

Copied

Screenshot 2024-07-22 at 08.05.58.pngScreenshot 2024-07-22 at 08.06.10.png

// 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 (theId, theRegExp, newKerning) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
//////////////////
try {
// get font of active layer;
var ref = new ActionReference();
ref.putIdentifier( charIDToTypeID("Lyr "), theId ); 
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) {
var hasText = layerDesc.hasKey(stringIDToTypeID("textKey"));
if (hasText == true) {
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID('textKey'));
//var shapeList = textDesc.getList(stringIDToTypeID('textShape'));
var kernRange = textDesc.getList(stringIDToTypeID('kerningRange'));
var rangeList = textDesc.getList(stringIDToTypeID('textStyleRange'));
var idTxtt = charIDToTypeID( "Txtt" );
var idFrom = charIDToTypeID( "From" );
var idT = charIDToTypeID( "T   " );
var idTxLr = charIDToTypeID( "TxLr" );
var idTxt = charIDToTypeID( "Txt " );
var idsetd = charIDToTypeID( "setd" );
// change text;
var desc6 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
    var ref1 = new ActionReference();
    ref1.putIdentifier( idTxLr, theId );
desc6.putReference( idnull, ref1 );
    var desc7 = new ActionDescriptor();
    desc7.putString( idTxt, theText );
//////////////////////////////////////////////////////
var kerningRanges = new ActionList;
var theCounter = 0;
if (kernRange.count > 0) {var thisKerningRange = kernRange.getObjectValue(theCounter)};
// kernRange
for (var m = 0; m < theText.length; m++) {
// check for relevant existing kerning range;
if (kernRange.count > 0) {
    if (thisKerningRange.getInteger(idFrom) == m) {
        kerningRanges.putObject( stringIDToTypeID( "kerningRange"),  thisKerningRange);
        theCounter++;
        if (theCounter < kernRange.count) {
            var thisKerningRange = kernRange.getObjectValue(theCounter)
        }
    };
};
// check for regexp;
if (theText[m].match(theRegExp) != null) {
var desc15 = new ActionDescriptor();
desc15.putInteger( idFrom, m - 1 );
desc15.putInteger( idT, m );
desc15.putInteger( stringIDToTypeID("kerning"), newKerning );
kerningRanges.putObject( stringIDToTypeID( "kerningRange"),  desc15);
};
};
//////////////////////////////////////////////////////
desc7.putList( idTxtt, rangeList );
desc7.putList( stringIDToTypeID( "kerningRange"), kerningRanges);
//////////////////////////////////////////////////////
desc6.putObject( idT, idTxLr, desc7 );
executeAction( idsetd, desc6, DialogModes.NO );
}
}
}
catch (e) {};
app.preferences.rulerUnits = originalRulerUnits;
};
////// collect type layers from active document //////
function collectTypeLayers () {
// 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'));
theLayers.push([theName, theID, visible])
};
}
catch (e) {};
};
return theLayers
};

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 23, 2024 Jul 23, 2024

Copy link to clipboard

Copied

LATEST

@enperror , have you tested the Script yet? 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines