Skip to main content
Participating Frequently
January 22, 2018
Answered

Script to Select and Raster similar text-layer (font-family + font weight)

  • January 22, 2018
  • 3 replies
  • 4669 views

Though this is not a usual use case, I am stuck with the scripting part. Really need help!!!

My use case :

I want to select text layer of my choice (for eg. CircularStd-Medium) out of several hundred text-layers while designing a UI, I may not know the no. of exact text layers which has that specific font-family or font-weight i.e CircularStd-Medium. It would quite hectic to do such things manually, clearly, need a script to resolve such issue. So I just want my script to select the text-layers which I want to target and rasterize them, without affecting other text-layer.

Problem with my script :

I got partial success to select & raster similar text-layers with specific font-family or font-weight i.e CircularStd-Medium. The only issue is that the script is not working with layer-group, nested-layers, artboards. It would be great if someone can enlighten me.

SCRIPT.jsx

var refPSD = new ActionReference();

function arrayUnique(a) {

    var temp = []

    i = a.length;

    // ExtendScript has no indexOf function

    while (i--) {

        var found = false,

            n = temp.length;

        while (n--) {

            if (a === temp) {

                found = true;

            }

        }

        if (!found) {

            temp.push(a);

        }

    }

    return temp;

}

function findFonts() {

    refPSD.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));

    // Get layers from PSD

    var countLayers = executeActionGet(refPSD).getInteger(charIDToTypeID('NmbL')) + 1,

        fonts = [];

    // Loop through each layer

    while (countLayers--) {

        var refLayer = new ActionReference(),

            descLayer,

            layerStyles,

            countStyles;

        refLayer.putIndex(charIDToTypeID('Lyr '), countLayers);

        // Catch error when no backgroundLayer is present

        try {

            descLayer = executeActionGet(refLayer);

        } catch (e) {

            continue;

        }

        // Only proceed if text layer

        if (!descLayer.hasKey(stringIDToTypeID('textKey'))) continue;

        // Get list of styles (in case of multiple fonts in a text layer)

        layerStyles = descLayer.getObjectValue(stringIDToTypeID('textKey')).getList(stringIDToTypeID('textStyleRange'));

        countStyles = layerStyles.count;

        // Loop through each style and get the font name

        while (countStyles--) {

            try {

                var fontName = layerStyles.getObjectValue(countStyles).getObjectValue(stringIDToTypeID('textStyle')).getString(stringIDToTypeID('fontPostScriptName'));

                fonts.push(fontName);

            } catch (e) {

                continue;

            }

        }

    }

    // Return a unique and sorted array of font names

    return arrayUnique(fonts).sort();

}

if (documents.length) {

    var fontsFound = findFonts();

    alert(fontsFound.length + ' fonts found \n' + fontsFound.join('\n'));

} else {

    alert('No fonts found \nOpen a PSD before running this script', );

}

var fontToRaster = prompt("Which font would you like to Raster?", "\(PostScript font name\)", "Raster Font");

var doc = app.activeDocument;

function RasterFont(target) {

    var layers = target.layers;

    for (var i = 0; i < layers.length; i++) {

        if (layers.kind == LayerKind.TEXT) {

            if (layers.textItem.font == fontToRaster) {

                layers.rasterize(RasterizeType.TEXTCONTENTS);

            };

        };

    };

};

RasterFont(doc);

Regards

This topic has been closed for replies.
Correct answer Kukurykus

Indeed, I ran that again and my script didn't work with layer sets. When I tried it earlier there had to be specific combination of them. Anyway I abandoned that attempt and I rewritten your script to modifiy it in some important parts using AM only.

I have to note that your script doesn't do its job after all. In its first part it searches for styles to see how many different fonts are in range of each single text layer. When you choose a font you want layers that contain it were rasterized second part is ran. Here it fails, because using layers.textItem.font == fontToRaster, checks only font of first character in each text layer. From first part of script and that you said the point is to raster all text layers that have certain font, so if for example you had 10 text layers and you chose them to be rasterized as they contain some interesting for you font, but that font is not seen by DOM textItem.font (as like I said only first used is recognised), any of those TEN layers will not be changed to normal layer.

I wrote new script that do exactly you wanted PLUS works 90 times faster than yours! If you didn't disappear yet, use it!

function sTT(v) {return stringIDToTypeID(v)} $.level = 0, fnts = [], object = {}

function par(v1, v2, v3) {

     eval("(" + v1 + " = new ActionReference()).putEnumerated\

     (sTT('" + v2 + "'), sTT('ordinal'), sTT('targetEnum'))")

     if (v3) return executeActionGet(eval(v1)).getInteger(sTT('numberOf' + v3

     + 's')); (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

}

function srchng() {

     (l = par('ref1', 'document', 'Layer') + 1); while(--l) {

          (ref2 = new ActionReference()).putIndex(sTT('layer'), l)

          if (!(get = executeActionGet(ref2)).hasKey(sTT('textKey'))) continue;

          c = (lS = get.getObjectValue(sTT('textKey')).getList(sTT('textStyleRange'))).count

          object = []; while(c--) {

               if (!RegExp(fnt = lS.getObjectValue(c).getObjectValue

               (sTT('textStyle')).getString(sTT('fontPostScriptName')))

               .test(String(fnts))) {fnts.push(fnt)} object.push(fnt)

          }

     }

     return fnts.sort()

}

if (par('ref0', 'application', 'Document') && len = (fF = srchng()).length) {

     alert(len + ' fnts found:\n\n' + fF.join('\n'))

     fTR = RegExp(prompt('Choose font to Raster?', fnts.join(', '), 'Raster Font'))

     par('ref1', 'layer'), executeAction(sTT('selectNoLayers'), dsc1, DialogModes.NO)

     for(i in object) if (fTR.test(String(object))) {

          (ref1 = new ActionReference()).putIndex(sTT('layer'), i);

          (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

          dsc1.putEnumerated(sTT(sM = 'selectionModifier'),

          sTT(sM + 'Type'), sTT('addToSelection'))

          executeAction(sTT('select'), dsc1, DialogModes.NO)

     }

     par('ref1', 'layer'), executeAction(sTT('rasterizeLayer'), dsc1, DialogModes.NO)

}

else{alert('No documents / fonts found. Open a PSD with text layers.')}

Just in case: when you copy above code do not forget later to delete extra space at end of line 4, or it won't be working!

3 replies

Kukurykus
Legend
January 23, 2018

I'm still very waak at Action Manager code, but this one I just wrote should do job, if you know how to apply it to your script. Anyway that I wrote takes 'Arial-BoldMT' as example, just to test it rasterizes only text layers having this font - and it does

function sTT(v) {return stringIDToTypeID(v)} (ref = new ActionReference())

.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum'))

i = (c = executeActionGet(ref).getInteger(sTT('numberOfLayers'))) - c

while(i < c) {

     (ref = new ActionReference()).putIndex(sTT('layer'), ++i)

     if ((get = executeActionGet(ref)).hasKey(sTT('textKey')) &&

          activeDocument.layers.getByName(get.getString(sTT('name')))

          .textItem.font == 'Arial-BoldMT') {

          (dsc = new ActionDescriptor()).putReference(sTT('null'), ref)

          executeAction(sTT('rasterizeLayer'), dsc, DialogModes.NO)

     }

}

Participating Frequently
January 23, 2018

Kukurykus: your script looks promising to me and looks compact to me, but it didn't work, may b some minor tweakings required.

thanks

Legend
January 27, 2018

par('ref1', 'layer'), executeAction(sTT('selectNoLayers'), dsc1, DialogModes.NO)

is used to unselect all selected layers before script selects all text layers with a font+weight chosen by user. If I did not use that in script and user had selected one or more layers at the time of running script then all selected originally layers would be rasterized as well (what somone of course didn't want that to happen).

Regarding tests. I did them exactly with new document settings you say it doesn't work. I tested it till it hurts, so with all two selected layers, or without, with just 1 and then choosing either Arial or TimesNewRoman to be rasterized or in other order with all possible variations. Still with/out backround and layers un-visibility. I did everything reading each time your words, and I did all in CS6 Extended (13.0.1) x64 with Windows 10. It didn't fail even once I really would like to see it didn't work so I could fix it, but maybe there is something more you didn't say I could set for testings?

What about font 12, I heard and experienced with other scripts that there is bug when it's not rechoosen or switched to any other quantity. But it's only about text editing, so here that doesn't affect anything. Still maybe you can change 12 to 13 or something and see again. If you have that bug again then I really don't know why I can't reproduce it :/

Anyone else got it too, maybe together we can find why that happens for some of us?


I tried to rasterize both fonts at once. Is this unacceptable?

Jarda Bereza
Inspiring
January 22, 2018

This could be complex problem because you can have multiple fonts in single layer. So you couldn't use DOM scripting because DOM contains simplified data and you would use Action Manager code.

Legend
January 22, 2018

I did not check, but try using this version of your function (one new line is added)

function RasterFont(target) { 

    var layers = target.layers; 

    for (var i = 0; i < layers.length; i++) { 

 

        if (layers.kind == undefined) RasterFont(layers);

 

        if (layers.kind == LayerKind.TEXT) { 

            if (layers.textItem.font == fontToRaster) { 

                layers.rasterize(RasterizeType.TEXTCONTENTS); 

            }; 

        }; 

    }; 

}; 

Participating Frequently
January 23, 2018

Thanks @ r-bin for the script . Will check this too and let you know.