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

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

Explorer ,
Jan 22, 2018 Jan 22, 2018

Copy link to clipboard

Copied

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

TOPICS
Actions and scripting

Views

3.6K

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

LEGEND , Jan 25, 2018 Jan 25, 2018

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 seco

...

Votes

Translate

Translate
Adobe
People's Champ ,
Jan 22, 2018 Jan 22, 2018

Copy link to clipboard

Copied

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); 

            }; 

        }; 

    }; 

}; 

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
Explorer ,
Jan 22, 2018 Jan 22, 2018

Copy link to clipboard

Copied

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

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
Explorer ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

Thanks again r-bin for the script. It really worked hurray.

It worked on my PC, hopefully, it will work on Mac as well.

Regards

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
Enthusiast ,
Jan 22, 2018 Jan 22, 2018

Copy link to clipboard

Copied

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.

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
LEGEND ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

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)

     }

}

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
Enthusiast ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

I think this shouldn't work if multiple layers has same name. And selecting all layers before reading font should be a bit slow.

But r-bin code would not work with nested folders. There would be slow recursion.

Kukurykus: why are you writing so much condensed code? It's hard to read. Most people prefer a bit longer more understandable code instead short genial looking code. It saves our 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
LEGEND ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

Yes you are right, I forgot to mention about. This can works for layerSets too, but probably will fail when layers don't have unique names, the more if layer sets have same names like layers. Well I was aware of this, but Action Manage is hard for me and I didn't know how to check activeDocument.activelayer.textItem.font other way than by Document Object Model. Perhaps you know how to access 'font' (or however it's named) by Action Manager. It's how I wanted to do it to make code resitant for every occurance. The problem is lack of my knowledge. Anyone can give any example so we'll update my code?

Writing codes the way I do is just my style I love the same like writing scripts. If I didn't do it this way I was kind of unhappy.

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
People's Champ ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

https://forums.adobe.com/people/Jarda+Bereza  написал(а)

But r-bin code would not work with nested folders.

Have you checked? )

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
Enthusiast ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

r-bin: ah... now I see recursion

kukurykus: that's why I did Humanizer: GitHub - jardicc/ActionManagerHumanizer: This tool will reveal for you occult mystery of Photoshop A...

I am a bit unhappy that undestanding your code takes me 10x more time than code from somebody else. 😄

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
Explorer ,
Jan 23, 2018 Jan 23, 2018

Copy link to clipboard

Copied

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

thanks

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
LEGEND ,
Jan 25, 2018 Jan 25, 2018

Copy link to clipboard

Copied

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!

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
Explorer ,
Jan 26, 2018 Jan 26, 2018

Copy link to clipboard

Copied

Kukurykus  Awesome. NOt only you refine the script you make it efficient. Thanks a lot man

Regards

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
People's Champ ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

This does not work in the simplest case, when there are two simple text layers, but with different fonts. Something is wrong with selecting the layers. Laziness to understand.)

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
LEGEND ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

May you be more precise (however you are enough) about those two different text layers (other font for each)  that do not result as rasterization of chosen font+weights text layer(s). I tried few cases with two layers with/out background, layer sets etc and always it worked. So can you tell me exactly a case that didn't work so I'm going to update script it worked correctly.

Maybe you pressed just enter when script broke after finding fonts to show them, or else after separating chosen font to be restarized you kept space in front of font name, or delimiter at end?

The only case that may not working in (at least I thought so so far, but was too lazy to check this theory), is when unregular font name contained full name of regular font name. So for ex. there is some fictious font name like Fake, then the bold ver. would be for example Fake-Bold. If someone chose from found fonts to rasterize Fake, it would rasterize also all Fake-Bold fonts, as it contains full Fake word. It could happen as I I don't make a loop over found font names, but change that array to string and with regex I match only font name chosen by user. Solution is very simple, instead of matching full font name it's sufficient to use this regex: /(Fake,|$)/. So in the code that would be RegExp(fTR + (,|$)).test(String(object)), in place of fTR.test(String(object)). I didn't test it but it should work. I also checked is it worth to change code to this and I found on Arial font example that perhaps it's not. If scripting name for Arial was just Arial then that I wrote made sense, as it would match Arial word in all other weight Arial fonts, then rasterize them all. What is good core name for Arial is ArialMT. This way there never can be matched any other weighted Arial font, as their scripting namings are Arial-ItalicMT, ArialBoldMT, ArialBoldItalicMT and Arial-Black. If it is so with other kind of fonts, there is no worry to change script. But if not, then that siimple regex sample can be used to sort it out. The same method is used earlier in script to insert to array only unique font names. Well if any of them will be repeated we will see it in alert. That will be a proof changed regex must be aplied to fix it.

There is one adventage upon current method. If there are different weight of one font found (beside other fonts - weights - used an user has chance to be precise and rasterize only some font weigth (typing its full name) or rasterize all font weights in range of one font typing only common name for all of those fonts. To rasterize 1 of AialMT, Arial-ItalicMT, ArialBoldMT, ArialBoldItalicMT and Arial-Black​ there is need to use exact name of font weight name. But when you want to rasterize them all it's enough to type into blank only Arial word

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
People's Champ ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

New doc 1920x1080x72, RGB8, white background. One text layer with text 123, font Alrial 12pt. Another layer with text 123 with Times New Roman font. It does not matter which layer is active. The result is the deselecting of all layers. No rasterization.

If you comment line

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

only the current text layer is rasterized.if it was selected.

CS6 (13.0.1.1) x32 and x64 win7 x32 and x64

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
LEGEND ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

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?

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
People's Champ ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

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

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
LEGEND ,
Jan 27, 2018 Jan 27, 2018

Copy link to clipboard

Copied

LATEST

Yes it is. I didn't write completetly new script. I just wrote anoldasgupta​​​'s a new way. So mainly I kept original functionality. There is chance to add possibility of rasterizing more than only one font+weight, but personally I don't have point to mess with untill someone doesn't need it So reason it didn't work for you was you chose 2, not only 1 font to rasterize, right?

UPDATE TO SCRIPT IN LINE 28:

Okey, that wasn't your request but you may change in the script this line:

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

to this:

fTR = RegExp('^(' + prompt('Choose font to Raster?', fnts.join('|'))+ ')$')

Now it's acceptable to rasterzie more than one font+weight at once

For others: if you want to rasterize 1 font just keep its name in blank (without "|" characters surranding a font+weight name. If you want more to be rasterized then delete all others keeping only those you chosen with "|" characters between them!

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