Skip to main content
This topic has been closed for replies.

7 replies

Kukurykus
KukurykusAuthor
Legend
January 2, 2017

First update was for suggestion of Jarda Bereza, who wanted  chars were displayed as strings.

Now the second update is for JavierAroche Noone needs anymore be Windows user to copy content of result to clipboard automaticly by script. I was using AHK script to this, but now it's possible it will happen irrespectively beeing on Mac or Pc.

Another part of this update was fixing empty strings which were effect of most filters conversion from chars to strings. I simply restricted such changes if a script detected a result will be an empty string. So what can't be converted it will stay as original char. For example I checked all Artistic, Blur filters and single Liquify. I found these charIDToTypeID "Avrg", "BeIn", "BeNu", "BeS6", "BkDi", "BkDp", "BkDs", "BkIb", "BkIc", "BkIr", "BkIs", "BkNa", "BkNm", "BkNt", "BkSb", "BkSt", "Bokh", "BtDi", "BtIs", "BtNt", "GEfc", "GEfk", "GEft", "LqFy", "VnPt" dont' have equivalent stringIDToTypeID. There are probably more of them but fortunately that wasn't needed search for them all to make script working properly if it finds their "buddies".

I found also that script brekes with Lens Correction in filters section. I'm not sure I want to fix it. It seems a code partially looked like taken from XML, while I didn't designed a script to find its characters. It's only single case so probably I won't use even try...catch statement to fix it.

Ah and probably I resign from description of that what happens in a script in every next line. There are more important scripts I do want to focus on. So if there won't be any serious bugs I recoginse this script as finished.

SuperMerlin
Inspiring
January 2, 2017

Just another option for Wndows users for get/set clipboard and a new version of system that returns the results is modified External Lib example in the bridge SDK

Bridge Developer Center | Adobe Developer Connection

BasicExternalObject

This modified code was written by Paul Riggott, shame to lose it.

#include "BasicExternalObject.h"

#include "SoSharedLibDefs.h"

#include <string>

#include <windows.h>

#include <stdio.h>

#include <iostream>

#if defined (_WINDOWS)

    #pragma warning(disable : 4996) // Turn off warning about deprecated strcpy on Win

#endif

/**

* \brief To allow string manipulation

*/

using namespace std;

/**

* \brief Utility function to handle strings and memory clean up

*

* \param s - The referenced string

*/

static char* getNewBuffer(string& s)

{

    // Dynamically allocate memory buffer to hold the string

    // to pass back to JavaScript

    char* buff = new char[1+s.length()];

   

    memset(buff, 0, s.length()+1);

    strcpy(buff, s.c_str());

    return buff;

}

extern "C" BASICEXTERNALOBJECT_API long systemCmd(TaggedData* argv, long argc, TaggedData* retval)

{

    // The returned value type

    retval->type = kTypeString;   

    // Accept 1 and only 1 argument

    if(argc != 1)

    {

        return kESErrBadArgumentList;

    }

    // The argument must be a string

    if(argv[0].type != kTypeString)

    {

        return kESErrBadArgumentList;

    }

char*  cmd = (argv[0].data.string);

    FILE* pipe = _popen(cmd, "r");

    if (!pipe) retval->data.string = "";

    char buffer[128];

    std::string result = "";

    while(!feof(pipe)) {

        if(fgets(buffer, 128, pipe) != NULL)

            result += buffer;

    }

    _pclose(pipe);

    retval->data.string = getNewBuffer(result);

    return kESErrOK;

}

extern "C" BASICEXTERNALOBJECT_API long getClipboard(TaggedData* argv, long argc, TaggedData* retval)

{

    // The returned value type

    retval->type = kTypeString;   

    HANDLE h;  

  if (!OpenClipboard(NULL)) return kESErrBadArgumentList; 

  h = GetClipboardData(CF_TEXT);

  CloseClipboard();

  if(h){

  string text;

    text = (char*)h;

    if(text.length() < 1) return kESErrBadArgumentList;

    retval->data.string = getNewBuffer(text);

  }else{

retval->data.string = "";

  }

    return kESErrOK;

}

extern "C" BASICEXTERNALOBJECT_API long clearClipboard(TaggedData* argv, long argc, TaggedData* retval)

{

    if (OpenClipboard(NULL)){

        EmptyClipboard();

        CloseClipboard();

    }

    return kESErrOK;

}

extern "C" BASICEXTERNALOBJECT_API long setClipboard(TaggedData* argv, long argc, TaggedData * retval)

{   

    // Accept 1 and only 1 argument

    if(argc != 1)

    {

        return kESErrBadArgumentList;

    }

    // The argument must be a string

    if(argv[0].type != kTypeString)

    {

        return kESErrBadArgumentList;

    }

string source = (argv[0].data.string);

int len = source.length() +1;

source = source.c_str();

if(OpenClipboard(NULL))

{

    HGLOBAL clipbuffer;

    char * buffer;

    EmptyClipboard();

    clipbuffer = GlobalAlloc(GMEM_DDESHARE, len);

    buffer = (char*)GlobalLock(clipbuffer);

    strcpy(buffer, LPCSTR(source.c_str()));

    GlobalUnlock(clipbuffer);

    SetClipboardData(CF_TEXT,clipbuffer);

    CloseClipboard();

}

    return kESErrOK;

}

/**

* \brief Free any string memory which has been returned as function result.

*

* \param *p Pointer to the string

*/

BASICEXTERNALOBJECT_API void ESFreeMem (void* p)

{

    delete(char*)(p);

}

/**

* \brief Returns the version number of the library

*

* ExtendScript publishes this number as the version property of the object

* created by new ExternalObject.

*/

BASICEXTERNALOBJECT_API long ESGetVersion()

{

    return 0x1;

}

/**

* \brief Initialize the library and return function signatures.

*

* These signatures have no effect on the arguments that can be passed to the functions.

* They are used by JavaScript to cast the arguments, and to populate the

* reflection interface.

*/

BASICEXTERNALOBJECT_API char* ESInitialize (const TaggedData ** argv, long argc)

{

    return "makeArray,getAverage,appendString_s,myScript_a,acceptBoolean_b";

}

/**

* \brief Terminate the library.

*

* Does any necessary clean up that is needed.

*/

BASICEXTERNALOBJECT_API void ESTerminate()

{

   

}

Kukurykus
KukurykusAuthor
Legend
January 3, 2017

Like I mentioned in some post of this topic I heard of this code of Paul Riggott. Unfortunately that was after he closed his site where were some libraries his code used. Probably it's the same code because I see there are include statements on top. I tried to run it but can't because it tries to include files they don't exists 😞
Could you please provide us with rest of your repositry regarding above script, thx!

Jarda Bereza
Inspiring
December 23, 2016

I don't know why, but Photoshop crashes everytime I am using this script from Extension Sctip Toolkit CC

Kukurykus
KukurykusAuthor
Legend
December 23, 2016

Yes that's fact, at least in case of ExtendScript provided with CS 5.1 and CS 6.0. I don't konw it's a same case with later Phosothop (CC) versions, I mean last Extensdscript, but what I know is:

You can't run this script without pointing Photoshop. Sole Extendscript doesn't suffice to read property of Photoshop, so those Char and String long codes. Trying it outside of Photoshop fails as it must connect to Ps "library" to use strictly coded methods (or how to name it) like char/stringIDToTypeID used by Photoshop. I believe it's question of something else so I mention this all just in case, as it's probably obvious for most of us. The same you can't make rotaion of anything ran in Extendscript if there's no for example #target photoshop at top of sheet in extendscript editor.

I'm sorry for that I didn't do everything else I described before about enhancing this script (for example making all systems compatibile for selecting, copying and pasting (with JavierAroche​ help ), other little stuff but meantime I started new project, and it's nice to say it's thanks to that one post of you which inspired me to that Jarda Bereza​. Because most time Mikaeru69 site is down and I couldn't at least check how work his script translating chars to strings so I wrote it last days myself. Probably today / tomorrow I post it and I'm happy to say it takes only 1 minue to get the same result you said it takes 5 minutes with Mirakeu script, and just 1,5 minute if you want to have progress bar (not only letters and numbers of course it sees). There is also stuff to break and close script, so if an ESC key was pressed by bad luck, you can continue a progress from place that was stopped, or quit.

Shortly I'll post it. I hope you compare it with Mirakeu script to tell me differences, as I really respect this guy for his work and I'm happy my abilities let me beat him in case of this one script by time factor or maybe his script does much more things and it's why it took longer time to fully finish its tasks.

Ps.1 regarding crashes, the current script I'm in last phase when broke (but previously been ran from Extendscript to be released in Photoshop) can't be continued. It highlights some codes for red. If you run it from Photoshop it's fine, you can choose a script to be stopped or continued. And it's not a question of lack of try...catch statement or $.levels = 0 put only for Extendscript use. If anyone can say how to avoid it, please tell us

Ps. 2 it's always good practise to put alerts in your script when you can't fastly realise where the bug is. You ran a script and check which alerts popped up. If some did not, you can narrow down your searching to that specific part if you still do not know what casued a crash. Then you can experiment changing values, removes some part of that code etc. At least it's what I would've done about it. If it's question of RegExp differently read by Extendscript than Photoshop then tell me what part the latest you could reach testing this way a script and I'll see what I can change to make it working for CC too.

Ps.3 I know where to download it but can I use Extendscript CC with CS 5.1 or 6.0 ?

Ps. 4 maybe one day I'll try vocajs, unfortunatelly I have so many programs to check on my list that present day I just focus on that I have to do or there is really something important I had to check immediatelly. But that's true, when someone uses simple Regex as little help to his codes then it's almost impossible to understand quickly what someobody wanted to "say" by his Regex, especially when you don't even know what it had to be used for. Personally I love narrowed codes, so I use Regex and eval quite much. It's my point to gather many information on short text but still I try to make it easy to read for those more experienced scripters. probably with some years of practise. btw I saw some dedicated RegEx sites. People are really crazy - they love Regex so much that learn it more than they can later use it and, it's more about sole regex than coding If I had time I would be in this group too probably, at least I'm happy I could practise al Regex exercises of different levels of hardness for few months in Javascripts on codewars.com. Another place where you can forgot what you started with coding for and you may get used enough of doing it on there that only one goal is trying to slove next somebody's scripts to be higher in ranking or playing with it to have fun like from solving crossword puzzles :/

Jarda Bereza
Inspiring
December 15, 2016

I seen mention about some JS library which has nice function for text operations: vocajs

 

Maybe this javasript could work also in Photoshop Script Engine.

 

Disadvantages of complex regex is that anybody except you can't read it easily and after half year or one year even you can't read it easily 🙂

Jarda Bereza
Inspiring
December 15, 2016

Thanks for string IDs.

List of all strings ID can be done with method known as brute-force attack. CharId has always four characters... so you are trying all combinations and you are checking if you got result. It took cca 5 minutes on realatively fast PC. Tonton (link above) has script for this.

Anyway I always have my PS runing.

Btw aren't regex usualy a bit slow?

Kukurykus
KukurykusAuthor
Legend
December 15, 2016

Haha I learnt much things thx to sharing my script with others:

- Jarda Bereza told me there is way to change all charsId's to stringsId's (I found later in Paul Riggott post how to do that)

- JavierAroche showed me how to not use external AHK scripts to select all & copy to clipboard as there is non-built-in method to do it even in older Photoshops

- some things I got to know from xbytor2 plus other little stuff and now I know what cca stands for ha ha, it's a circa (around, about), and what is brute-force attack

I want to say opensourse you share your scripts in is a good idea. You never know what's good you get back for. So far I haven't tried to ask of anything, but did myself even if I couldn't find an answer. Well, time to change attitude

Jarda Bereza, I'd like to answer yes or no, but I have no idea. I have no fundamental knowledge. Probably I wouldn't do much mistakes if I started off from zero my education with programming. When I didn't know something like RegEx (not only JavaScript's) exists I created loops in loops in loops ..... in loops ... ha ha and neverending Arrays... Well some of my scripts were so long that I couldnt get to know what and where is exactly inside and I even found most of them were something like beeing type of 'fake' regex. Then I removed all of them and started to learn RegEx for few months (and nothing else). Now I'm able to write everything I did before by 30 lines, maybe just in 3 short, or 1 long? I don't know what is alternative for RegEx, but if I had to use those loops and arrays again that would be step back. Only one thing I know for sure there are fast working regex and slow working. All is about your goal and text your looking thru. If it's short text there is no matter you use inside RegEx between other things: .* (so mark all), but the longer text the more often you must avoid .* as searching thru will take long minutes. So when you specify what you are looking for, or what you want to ommit, the same regex without .* but with some other even short 'command' make those minutes process change to ONE second, in fact. An example to proove it.

If in the code from my previous post, so:

while(lne = c.match(/(\w+) = ((s|c)TT\('#?[\w ]*'\))/)) {

  eval((slh = "c = c.replace(RegExp(lne[0].replace(/(?=\\()/, '\\\\').replace(/(?=\\))/, '\\\\')), '')")

  + ".replace(RegExp(lne[1] + '(?=,|\\\\))' + '\\\\b'), lne[2])")

}

you replace this part:

/(\w+) = ((s|c)TT\('#?[\w ]*'\))/

with this:

/(\w+) = ((s|c)TT(.*)\))/

or even worse:

/(\w+) = (.*)(\n|$)/

you would feel like you work on the computer from early '90 years! as that few second of searching through long code wouldn't take few secs but 10 or more minutes, however if your computer woulnd't explode meantime it'd finish its job.

If there is some other non RegEx method to use I'd like to be fully acquainted with - please let me get mastered the use of IT

Inspiring
December 13, 2016

I have a couple of scripts in xtools that tackle this kind of problem:

SLCFix.js

//

// SLCFix.js

// This script does some minor massaging of ScriptListener output

// primarily by substituting charIDToTypeID and stringIDToTypeID with

// cTID and sTID. In the process of doing this replacement, the

// 'var id##' style declarations are removed in the c/sTID calls

// placed inline. You'll need to copy the c/sTID definitions from

// this file into whatever file you decide to use the converted code.

//

// One other piece of corrective surgery is to canonicalize all

// filename strings to use '/' instead of '\' characters. I didn't bother

// messing with the drive names.

//

// The only thing left that I don't really have a solution for is Actions

/// that invoke scripts. For some reason, the return value of the script

// is placed in the action and gets output to the ScriptingListener log

// file as well. Search for 'jsMs' to see what I mean. Unforunately, in

// many case, the return value is effectively the last piece of textual

// code parsed, I think. There is not an easy way that I have found to

// remove this travesty after the fact, except to do it manually by replacing

// the code with an empty string, "". You can, however, remove it before

// the fact. Make the last line of your script files 'true;' or, like I do,

// the name of the script as a string, e.g. "SLCFix.js"; This has the nice

// added benefit of showing up in the debugger console if you are running

// the script from within the debugger.

//

// I've converted up to 20,000 lines of ScriptingListenerJS.log code in one

// pass with the only problems being the 'jsMs' garbage. That can, as I said

// before, be fixed manually.

// !!! This may gave been fixed!!!

//

// $Id$

// Copyright: (c)2005, xbytor

// License: http://www.opensource.org/licenses/bsd-license.php

// Contact: xbytor@gmail.com

 

This handles complete SL log files. There is also an option to use symbolic variables instead of cTID or sTID expressions.

 

There is also LastLogEntry.jsx which I use more frequently. Do something in PS, run this script, hit the Fix button and you get something that is a lot more readable and smaller. Remember, however, that not all actions in PS are recordable.

 

//

// LastLogEntry.js

// Get the last entry from a ScriptingListenerJS.log file.

//

// $Id$

// Copyright: (c)2005, xbytor

// License: http://www.opensource.org/licenses/bsd-license.php

// Contact: xbytor@gmail.com

//

 

Both of these 'include' other files (like stdlib.js). I you don't have xtools installed, substitute /xapps/ with /apps/ to get a self contained script. I tend to reuse/include previously written code which is why the /apps/ code is a lot thicker than it needs to be. But, then again, I only need to fix a bug or enhance a feature one place instead of five.

 

The scripts handle funky file path stuff and a few other odd things and has been used by Adobe for internal research stuff so I have to assume it is fairly stable in addition to be fairly old but continually refined.

 

It's good to see others do similar  (and more light weight) implementations.

Kukurykus
KukurykusAuthor
Legend
December 13, 2016

I fixed wrongly working RegExp, actually I replaced it with one of original parts I used during beta versions but later changed to new one during last phase, "the slimming". Unfortunatelly I found it failed so had to retype it to that worse looking one., (/(\.(0+\b|([0-9]{0,5}?)0+))(?=\))/, '$3') -> (/((\.0+\b|(\.[0-9]{0,5}?)0+))(?=\))/, '$3')

 

Now I'm going to list everything there happens in code. Blue for points seen in final result, and some other colour for those in process but needed all other "blue" steps could be executed.

 

 

I'm gald even Xbytor showed up, personally for me (just 1,5 year with scripting) one of greatest Gods who remembers "times before time", when there weren't many people you could ask for advice how to do something while the resources were cheap. Honestly if I had to do anything 15 years ago like Xbytor without practising at Codewars for example (where without beeing genius you can learn 2 years material just in few months) that wouldn't be fun but only hard work.

 

 

Ps. after I finished my code I looked into yours to see differences. But there were 20000 lines! so afer scrolling down and looking for those I needed and still not seeing them I gave up. It's good you showed now in your post link to its essence. I'll analyse that later to see differences. I'm not sure you did some newest version of it but where I looked for (xtools) your code didn't do so much (looking at sample from that PS CS1? times, nearly 15 years ago!), so after all I would write my own Anyway I believe I have enough time one day to browse everything you wrote, that will be one of best lessons I could ever had learning Photoshop scripting.

 

 

btw I made a test to see how huge can be reduction. In case of 2 lines you get of course only one but some simple 3 points Puppet Warp on some 3 letters reduced 3866 to 2141 lines of code, what's still not proportional, as there is many lines of numbers which stay unchanged. I cut them from both codes and left only changable code (2558 to 839). Still much, but it's only sample, noramlly I will use it to some regular, shoter actions I do. Ah and the time of this process was a little long, about 30 - 45 seconds! Fortunately mostly with other long codes you want to change for some reason it should be up 7 - 8 seconds.

 

 

After description I'm going to do that help maybe others I hope to have from them ideas how to enhance this code like for example changing CharID to StringID (Jarda Bereza idea), or replacing AHK script working on Windows only with part I had no idea it exists (JavierAroche told me). I'll check it later, maybe I do something wrong but I tested it in CS5.1 and CS6 and possibly stringIDToTypeID( "textToClipboard" ) wasn't yet implemented but only later in some CC?

 

Ps. I see in other posts that names of users are highlighted for blue and preceded by some blue icon, why it nover happens in my post when I mention other posters?

JavierAroche
Inspiring
December 13, 2016

Based on this forum post, it looks like the textToClipboard stringID was implemented in Photoshop 13.1. I'm not sure if that's accurate.

Photoshop JSX -- How do I copy arbitrary text to the clipboard? - Stack Overflow

If your Photoshop version doesn't support that stringID, you could always do it through a system command.

var thisOS = $.os,

    systemCommand;

   

var txt = 'hello world!';

// Analyze current OS and determine system command

if (thisOS.indexOf('Windows') !== -1) {

    systemCommand = 'clip';

} else if(thisOS.indexOf('Macintosh') !== -1) {

    systemCommand = 'pbcopy';

}

app.system('echo ' + txt + ' | ' + systemCommand);

Ps. I see in other posts that names of users are highlighted for blue and preceded by some blue icon, why it nover happens in my post when I mention other posters?

You need to add "@" before the name to tag them.

JavierAroche
Inspiring
December 13, 2016

Hey Kukurykus​, thanks for sharing! I see you're using an exe, does that mean this only works on Windows?

Kukurykus
KukurykusAuthor
Legend
December 13, 2016

Well, not exactly JavierAroche . Let me explain intention of using .exe. I have Photoshop 5.1 a home and 6 in work. They both use Flash while CC not anymore(?). So when I wanted to use a script with Photoshop (of course if a Flash was the reason) even when I marked in a code the result text was highlighted in dialog box it wasn't (for example in CS2 it was). Now it was highlighted only when I ran the script in from Extendscript. So I used that AHK script (I think you can't use it on Mac's) it was to highlight the text you couldn't as you see (I don't know how in CC though) by Photoshop script. Then it additionally (that .exe file) copies content of displayed dialog, and finally it presses enter (return), so the window is going to be closed. You have now simply converted code result in your Windows clipboard (memory). So you don't have manually to copy it and close the window. Now you can paste it anywhere you want.

But don't worry, as far as you use Mac that part of code won't be executed, so the same like that was in Extendscript. My script will finish its work on the part Final Dialog box with (unhighllighted) content will be popped out (I guess). Then you have manuualy to copy a content and close the window.

JavierAroche
Inspiring
December 13, 2016

Ah I see! I think there's a way to avoid these 2 external files then, and make it compatible with any OS.

 

You can copy something to the clipboard directly from ExtendScript, with this descriptor.

var txt = 'hello world!';

 

var desc = new ActionDescriptor();

    desc.putString( charIDToTypeID('TxtD'), txt );

   

executeAction( stringIDToTypeID( "textToClipboard" ), desc, DialogModes.NO );

 

By that point, you might not need to highlight your text in your dialog window anymore. But, if you still want to highlight it, you can do it by adding this line to your code:

ans.text.active = true;

 

 

Yes some CharIDs are messed up 🙂 Tonton has page on his site how to solve this this problem. He is looking into context. If "Grn " is inside something, then it means something. If "Grn " is inside something else, then it means something else 🙂

Jarda Bereza, this is a little explanation by Tom Ruark as to why stringIDToTypeID('grain') == stringIDToTypeID('green')

Determine layer color label from layer id?

Jarda Bereza
Inspiring
December 12, 2016

Thanks! It looks useful. It reduces code for creating text layer from 470 line to 174 lines 🙂 That's 63 % less lines of code.

 

Is there possibility use String ID instead of Char ID if possible? String IDs are more meaningfull. There should be code which can do that, but the web is not working right now. tonton-pixel

Kukurykus
KukurykusAuthor
Legend
December 13, 2016

Just think of 1000 line code generated with Puppet Warp for example. It would be about 350 lines, however duration of conversion would take probably more than 10 seconds (still better than doing it manually maybe 10 hours :D)

There were few exceptions before my code started to work with every result of Script Listener (I tested so far), but I hope even when someone find something it can't handle it won't be much work to look into by me again to make it for better.

That site you linked let you do probably do the same but with JSON. I knew it but never tried to use any code from that, and the web worked now, unfortunately I assume this guy run his site on home computer server, so it's available when his computer is launched at the moment. Mostly any time I try to visit his site it's down. Now at my polish morning I found there that CharId are possible to be presented as StringId. I wasn't aware of it, however I saw some problem with 'grain' case in the past what is obviously 'Grn ' (CharId), but wasn't so smart to get to know people are saying of StringID sample. So yes, it would be possible to change my code to change charID to StringID. Let me find the way it works and I implement it. Possibly it'll be an option, so for people who prefer it more.

And thank you for giving the credit. It's always nice when some mastered coder do so to that less experienced yet

Update: I found a bug as I tried my code first time with a lasso tool, and it gave strange result. I'll fix that later.

Jarda Bereza
Inspiring
December 13, 2016

Yes some CharIDs are messed up :-) Tonton has page on his site how to solve this this problem. He is looking into context. If "Grn " is inside something, then it means something. If "Grn " is inside something else, then it means something else :-)

The most crazy thing you can test is probably applying liquify on smart object. Because developers forgoten disable action recording in this action. (Usually can't record pating with brushes) and generated code has many thousand lines of code for single action :-D