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

Changing color of text found with regex

Explorer ,
Sep 26, 2017 Sep 26, 2017

Hi,

I have multiple text layers in the document. I would like to filter through the contents of each text layer with regex and change the color of the found result.

In the example below I would like to find all the hastags in the text layer and change the color to blue.

Example:

This is a really long piece of text copy and #hashtag more copy here #anotherhastag #hashtagNo3

I've written a few scripts for indesign that involve GREP(regex) and it's fairly simple to change the color of the found results. I can't seem to find a solution for this in photoshop.

Thanks

TOPICS
Actions and scripting
7.9K
Translate
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
Adobe
Community Expert ,
Sep 26, 2017 Sep 26, 2017

I recommend abandoning the idea to do this in Photoshop, Indesign is oriented towards sophisticated text editing, so better to do it there.

In Photoshop changing parts of text within a Type Layer necessitates using AM code that can become quite unwieldy in my experience.

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

Thanks for the quick response.Unfortunately, I have to use photoshop for this job. So I'm stuck with photoshop. By "AM code" do you mean action manager? Any pointers in that direction will be very helpful.

Unfortunately, I can only use photoshop for this job. So I'm stuck with photoshop. By "AM code" do you mean action manager? Any pointers in that direction will be very helpful.

Thanks

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

Yes, I meant Action Manager code.

Try recording changing the color of one word in a larger text in a Type Layer with ScriptingListener.plugin and see how well manageable the resulting code seems to you.

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

I forgot to add: If there is any possibility that some parts within the type layer vary at all with regard to type properties (size, leading, font etc.) do include some such varying elements in your test.

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

Will give that a shot. Thank you.

One thing I am stumbling upon in my tests is finding a word with regex and affecting just those results. Any tips on how I would go about that? For example, in a regex search like this "foundText" ends up as just plain text. I can't seem to affect the properties of that "foundText". Like color size etc. Is this the right approach? Is there a better way?

var foundText = textLayer.match(new RegExp("#hashtag", "i"))

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

The foundText (the result of the match) is a String, it is not part of the actual Type Layer.

Translate
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
Guide ,
Sep 26, 2017 Sep 26, 2017

Here is an example changing text when the text layer is selected. Changing colour of a section of text has been done in the past by xbytor

and he might chip in, but I would not attempt it!

if(activeDocument.activeLayer.kind == LayerKind.TEXT){

var textContent = activeDocument.activeLayer.textItem.contents;

activeDocument.activeLayer.textItem.contents = textContent.replace(/mine/ig,"his");

}

Translate
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
Advisor ,
Sep 26, 2017 Sep 26, 2017

Somebody mention me?

SourceForge is acting up so you will need to download xtools:

SourceForge

The files of interest are xtools/xlib/Text.jsx  and xtools/xlib/TextTest.jsx. It can be done but it requires a bit of work.

Here is the relevant code from TextTest.jsx that shows you how it's done.

var layer = doc.layers[layerName];
  doc.activeLayer = layer;
  var opts = new TextOptions(layer.textItem);
  opts.contents = "123567875688\radsfasfasdfasdfasdf\n(&#^&^#$";

  // construct the styles
  var s1 = new TextStyle("ArialMT");
  var s2 = new TextStyle("Courier-Bold", 30, Text.toRGBColor(0, 255, 0));

  // this style will use the default font...
  var s3 = new TextStyle(undefined, 42, Text.toRGBColor(255, 0, 0));

  // superscript test
  var s0 = new TextStyle(s1);
  s0.baseline = PSString.superScript;

  // Now create the set of ranges to apply the styles over
  var ranges = new TextStyleRanges();
  ranges.add(new TextStyleRange(0, 1, s0));
  ranges.add(new TextStyleRange(1, opts.contents.length, s1));
  ranges.add(new TextStyleRange(5, 10, s2));
  ranges.add(new TextStyleRange(7, 15, s3));
  ranges.add(new TextStyleRange(25, undefined, s2));

  opts.ranges = ranges;
  Text.modifyTextLayer(doc, opts, doc.layers[layerName]);

As somebody said before, InDesign is a more appropriate tool.

Translate
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 ,
Sep 27, 2017 Sep 27, 2017

Wow. Thanks for sharing these scripts. They are incredibly helpful. Very much appreciated.

Translate
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 ,
Sep 27, 2017 Sep 27, 2017

Question: What is the best way for me to get the text ranges from the text layer with a regex search. My current solution returns a string which isn't very helpful. Is regex the right approach or is there a better way?

Example:

Below are the contents of the text layer and I want to find all the hashtags.

This is a really long piece of text copy and #hashtag more copy here #anotherhastag #hashtagNo3

var foundText = textLayer.match(new RegExp("\S*#(?:\[[^\]]+\]|\S+)", "i")) 

Translate
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 ,
Sep 27, 2017 Sep 27, 2017

I would use something like "IndexOf" but this will be more than 1 line of code.

Translate
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
Guide ,
Sep 27, 2017 Sep 27, 2017

Something like...

var s = activeDocument.activeLayer.textItem.contents;

var re = /(?:^|\W)#(\w+)(?!\w)/g, match, matches = [];

while (match = re.exec(s)) {

  matches.push([[match[0].replace(/^\s+|\s+$/g,'')],[match.index+1],[match[0].replace(/^\s+|\s+$/g,'').length]]);

}

for(var a in matches){

    $.writeln("Word found = " + matches[0] + " start = " + matches[1] + " length = " +matches[2]);

    }

Translate
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 ,
Sep 27, 2017 Sep 27, 2017

Thank you!

Translate
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 ,
Oct 09, 2017 Oct 09, 2017

Hi xbytor2

Thank you for sharing all those scripts. I've been looking through the code and they've been a huge learning resource.

I tried to implement the TextTest.jsx script into my own version but I've been running into an issue.

When I run the below script I get this error: "Error: General Photoshop error occurred. This functionality may not be available in this version of Photoshop."

Is it something to do with this line in the script?

Text.modifyTextLayer(doc, opts, doc.layers[layerName]);

Here's the whole script.

//

// HashtagColor_v1.jsx

//

//============================================================================

//@includepath "~/Documents/xtools"

//

//@include "xlib/PSConstants.js"

//@include "xlib/stdlib.js"

//@include "xlib/Text.jsx"

//@include "xlib/Action.js"

//@include "xlib/xml/atn2xml.jsx"

//

function colorHashtag(doc) {

  var layerName = "Test Layer";

  var layer = doc.layers[layerName];

  doc.activeLayer = layer;

  var opts = new TextOptions(layer.textItem);

  opts.contents = layer.textItem.contents;

  //opts.contents = "123567875688\radsfasfasdfasdfasdf\n(&#^&^#$";

  // construct the styles

  var s1 = new TextStyle("ArialMT");

  var s2 = new TextStyle("Courier-Bold", 30, Text.toRGBColor(0, 255, 0));

  // this style will use the default font...

  var s3 = new TextStyle(undefined, 42, Text.toRGBColor(255, 0, 0));

  // superscript test

  var s0 = new TextStyle(s1);

  s0.baseline = PSString.superScript;

  // Now create the set of ranges to apply the styles over

  var ranges = new TextStyleRanges();

  ranges.add(new TextStyleRange(0, 1, s0));

  ranges.add(new TextStyleRange(1, opts.contents.length, s1));

  ranges.add(new TextStyleRange(5, 10, s2));

  ranges.add(new TextStyleRange(7, 15, s3));

  ranges.add(new TextStyleRange(25, undefined, s2));

  opts.ranges = ranges;

  Text.modifyTextLayer(doc, opts, doc.layers[layerName]);

}

Text.test = function(doc) {

  var doc;

  if (app.documents.length) {

    doc = app.activeDocument

  }

  colorHashtag(doc);

}

Text.test();

"HashtagColor_v1.jsx";

Translate
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 ,
Oct 09, 2017 Oct 09, 2017

Upon further trial and error, I noticed that the "modifyTextLayer" function runs without issues on a text layer created by the script, but has issues with existing text layers created directly in the photoshop document.

So in your TextTest.jsx file, the newTextLayerDemo function creates a text layer. The rest of the script works when working with that text later. But in my version of the script, I am trying to work with an existing text layer in photoshop (ideally, the currently selected text layer), and I get that error.

Any thoughts or how to solve this?

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

So do you want to do something like Font Remaping script here: Magic scripts for Photoshop  but with searched text and colors instead font family?

I agree with others. This can be very difficult.

You need to:

1) read whole text layer action descriptor

2) find all your strings and position where they start and where is end of string

3) if text layer has multiple styles, there is list of these styles and index where they start and where they end. So you need to read this descriptor, make copy and change color and position indexes and then put this descriptors into list and this list replace in original layer descritor

4) finaly you can use "set descriptor" action manager code and change the layer.

Like this:

2017-09-26_184756.jpg

Before:

2017-09-26_183731.jpg

After:

2017-09-26_183925.jpg

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

Wow. This is very helpful. Thank you. I'm going to give it a crack and see where I end up.
Clearly, this looks like a "long walk for a ham sandwich". But it'll be worth the learning experience. I guess??

I'll hit you up with questions as I go along.

Jarda, what app/plugin did you use in your images? It looks incredibly helpful. Where can i get that?

Thanks again, c.pfaffenbichler,  SuperMerlinand Jarda Bereza.

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

It's my own tool. Not public yet, but maybe it could be public soon.

It's based on this code: GitHub - JavierAroche/descriptor-info: JSX module to recursively get all the properties in an Action...

And this code:

descriptor to JSON is already buil-in in Photoshop · Issue #10 · JavierAroche/descriptor-info · GitH...

So this should help you. You also can explore my script with align to baseline and text columns. I am getting here descriptor, changing it and then setting back. Magic scripts for Photoshop

Translate
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 ,
Sep 26, 2017 Sep 26, 2017

Great. Thanks much,

Those are some great scripts. Congrats.

Translate
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
Contributor ,
Sep 26, 2017 Sep 26, 2017

I have a TODO line to implement low level text manipulation in my extension. But, as my collegues suggested, the AM structure is a  bedrock layer under the swamp guarded by hydras. I don't have enough patience and passion and not smart enough to get to the lowest layers.

I wish Adobe would start the whole PS source code from scratch again and implement it a way which is allowing us to properly script the app.

Thanks xbytor2 for the .jsx code, ill try it!

Translate
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 ,
Oct 09, 2017 Oct 09, 2017

I will tell you secret.

You can:

0) read layer actionDescriptor

1) use native function for converting actionDescriptor into JSON

2) use eval() on JSON string and create javascript object

3) modify regular JS object with well known object opertions. You need to do same thing as in my screenshot.

4) convert JS object into JSON string with ".toSource()" method

5) convert JSON string into ActionDescriptor with native function

6) and finally you can put modified descriptor into "executeAction"

I think I will create small library for this workflow.

Translate
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 ,
Oct 10, 2017 Oct 10, 2017

Thanks Jarda. This is way above my punching weight, but I'm going to give it a shot. I have managed to get up to step 4. But I am struggling with the step 5 and 6. At the moment I'm keeping it pretty basic: change the color of the entire text to red. Once I get the core functionality working I'll jump into figuring out how to change text ranges to a different color.

Bear in mind that I've written the script referencing different sources across the forms. So it's probably not the cleanest and most efficient way to do it.

Any help on how I can get steps 5 and 6 working would be great.

Thanks

#include "./helpers/JSON.jsx"

// 0) read layer actionDescriptor

var ref = new ActionReference();

ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));

var desc = executeActionGet(ref)

var convertDesc = new ActionDescriptor();

convertDesc.putObject(stringIDToTypeID("object"), stringIDToTypeID("object"), desc);

var jsonDesc = executeAction(stringIDToTypeID("convertJSONdescriptor"), convertDesc, DialogModes.NO);

// 1) use native function for converting actionDescriptor into JSON

jsonDesc.getString(stringIDToTypeID("json"));

// 2) use eval() on JSON string and create javascript object

var obj = JSON.parse(jsonDesc.getString(stringIDToTypeID("json")));

// 3) modify regular JS object with well known object opertions. You need to do same thing as in my screenshot.

obj["textKey"]["textStyleRange"][0]["textStyle"]["baseParentStyle"]["color"]["red"] = 255;

// 4) convert JS object into JSON string with ".toSource()" method

var objToStr = JSON.stringify(obj);

alert(objToStr);

// 5) convert JSON string into ActionDescriptor with native function

// 6) and finally you can put modified descriptor into "executeAction"

Translate
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 ,
Oct 10, 2017 Oct 10, 2017

Here is first version of my tool:

GitHub - jardicc/ActionManagerHumanizer: This tool will reveal for you occult mystery of Photoshop A...

Works good for me. You probably will need CC 2015.5 and higher

Keep in mind that pure AM will be faster something about 10-30ms per conversion into JS object and back.

Translate
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 ,
Oct 10, 2017 Oct 10, 2017

Wow! Thank you. I'll play with it now.

Much appreciated.

Translate
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