📜 ⬆️ ⬇️

The story of one obsession, or as I wrote a calendar script for Photoshop


This article is about how I wrote a script for creating calendars in Photoshop, from the very beginning to the very end, with bugs and easter eggs. A lot of text, some code and a bit of illustrations.

At the beginning


It all started with an idea schematically drawn on a tiny piece of paper. I wanted to write a script that could create a calendar for a given year right in Photoshop. Initially, it was necessary to obtain an annual calendar of 6 by 2 months. However, in the process of developing, Wishlist grew, and as a result, the list of desired settings became such that the user could specify:


I also wanted to have a function that is similar in action to “Preview” - a test month was created that would clearly reflect the result of the settings.

Why is it important for me to do this in Photoshop? I just want to create colorful calendars with photos or illustrations, making as little effort as possible and, if possible, working in this program. Perhaps someone also wants.
')

Tools


So, there is a plan, it's time to choose the necessary tools.

Tongue. Photoshop supports the following scripting languages: AppleScript, VBScript, and JavaScript. I think everyone here understands that the first is suitable for MacOS, the second is for Windows, the third is for both. JS was chosen, because some time ago I studied its basics, and the development of such a script could thus serve as a good practice (and served, I must say).

Text editor. I wrote the first hundred lines in a regular notepad, but it could not last that long. I remembered Sublime Text with its delightful for me function of the multiple cursor, which, by the way, saved me many times in the process of work.

Script tools from XBYTOR. In fact, I used only one of his tools, ActionToJavascript.jsx, but it was very useful. This script works like this - the recorded operation in Photoshop is set at the input (this is similar to macros in MS Office, only the closed format), and the output is a file with the extension * .jsx, in which a function is written that performs the same things with the help of low-level commands as the original operation.

Scripting Listener for Photoshop. The official plugin from Adobe. Performs, in essence, the same thing as the tool above, but it works on a slightly different principle - it follows the user's actions in the program window and writes them into two text files on the desktop. The first file is JavaScript, the second is VBS or AppleScript, depending on the OS. And, yes, he always writes, you need to delete it or turn it off before launching the program, adding a tilde ( ~ ) at the beginning of the plugin name.

Adobe ExtendScript Toolkit. This tool is, in fact, a native solution for writing scripts for Adobe programs, but I used it only at the end of my work. With it, you can close the source code from outsiders. The output is a working script with unreadable content.

Documentation. Without it, writing something harder than the pop-up window “Hello word!” Will be quite problematic. At the end of the article you can find some links.

Optimization


I had to optimize the work right in the process of writing the script. The first brakes began when the script could already create three months. Initially, I wanted to do all the work in one Photoshop document. But it turned out that after the first month the speed began to sag heavily - and if January was formed, then with each new month the creation time increased. It took one and a half minutes for February, and three for March. It was explained simply - as each date, each inscription is a separate text layer, it took more and more time to create and move a new layer in the growing stack of layers. Therefore, reluctantly the first time, I transferred the creation of each month to a new document, and the result was simply copied to the main document. Thus, the problem of increasing the time of creation of months was solved - now every month on average it was created for the same amount of time.

The next surprise happened when I needed to find out how large each of the months had been in order to arrange them correctly from each other (the user can set different intervals). Quickly writing a simple function that was supposed to return the values ​​of the heights and widths of the months, I launched it. Photoshop is frozen. After giving him a generous ten minutes, after which he never reanimated, the process had to be killed. I guess that one day he would still have finished, but ten minutes is too much in itself. The case again turned out to be in the number of layers in the document - there were too many of them to immediately get the necessary numbers. And again, reluctantly, I transferred the calculation of dimensions to the stage where I was created every month. Now the created month was immediately determined by size and readings were recorded in an array for later use. It sounds easy, but in fact it took me quite a lot of time.

Errors


Here, first of all, I want to say a big thank you to my testers, without them I would have left even more shortcomings in the code than there are now.

Error with rendering. This is a tip for those who write scripts with a user interface and when drawing uses a complicated recalculation of the size of elements (buttons, for example) - check the work of your script in Windows and MacOS. I had a case that in one place the script was hanging on the MacOS system. I had been looking for a reason for a long time and it lay in the following: the calculation of the size of one of the buttons had to be adjusted in relation to the other upwards, and this operation was driven by me into a cycle (I agree, a controversial decision). On Windows, on all versions of Photoshop, this worked out perfectly, since the customized button was always less than the main button. But on MacOS, it turned out the other way around - the main button was less adjustable by one or two pixels, and the script went into an infinite loop. Now I have corrected it, and the only conclusion that can be made is not to use dubious decisions when recalculating interface elements (your Cap).

Another couple of depressing moments is that different versions of Photoshop draw windows differently, especially elements with transparency, because of which I had to redraw these buttons already with the background (although, it seems to me, it was possible to be confused and come up with something else ).


Fans of Sir Terry Pratchett may have paid attention to the “Holi WIZZARD” button. I like such things, I don’t know if it’s an easter egg or not (by the way, about them below), I saw something similar in one antivirus - the scanner is called Luke Filewalker (Luke Sky Filelower).

Internal errors. Rarely, but there are errors that are very difficult to explain. In my case, this problem turned out to be the task of setting the width (and, possibly, height) of block text. Let me explain: there are two types of text in Photoshop - Point Text (short) and Paragraph Text (block). The first has no boundaries, unlike the second.


So, the following has happened to me - I have set the size of the width of this block text at 800 pixels. At the exit I got a width of 3333 pixels. I could not believe my eyes and began to check the code. There was no error. It was evening, and I sinned on my tired head, so I began to check with special care with a piece of paper in my hands. The error did not come across to eyes.

Half an hour later, when I was desperate to understand what was happening, I had a link with a similar problem. It turns out that if the resolution of the document is more than 72 dpi, then Photoshop exposes some value of its own. It is solved this way: we take the resolution of our document (I had it equal to 300), divide the standard 72 by our resolution and multiply the result by the required width of the text block. As a result, to get a block of 800 pixels for a document with 300 dpi, you need to set the size to 800 * 72/300 = 192 pixels. That's how simple it is.

Bug with weeks. Another point in which I was very stupid was in the calculation of the numbers of weeks. According to my ignorance, I did numbering the weeks, based on the absolute certainty that the first week starts on the first of January. I was so sure of it that I didn’t even bother to check in advance, but immediately began to implement it. Only when I finished, I decided to check whether it’s right to start numbering from the 1st of January. It turned out not.

Surely many (or all) who read this article know that there is an ISO 8601 standard for date and time format. And according to him, the week starts on Monday, and the first week is the one that falls on the first Thursday of January. And the first week can begin not at all on the 1st of January, but, for example, from the 2nd or even the 4th (as in this 2016). So this part of the code also had to be completely rewritten.

Error with ... array? This is where I don’t know what was the matter, but the decision turned out to be interesting.

Here is the code that creates seven drop-down menus with font names:

 for (var i=0; i<7; i++){ fontGroup.nameOfFont = fontGroup.add('dropdownlist', undefined, arrFonts); fontGroup.nameOfFont.selection = fontIndex[i]; } /* fontGroup –  «»   «» arrFonts –     fontIndex –             */ 

At the first generation of the window, everything went well and without problems. But if the user loads the save, the window will be closed and reopened with the new fontIndex value. When recreating a window with loaded settings, Photoshop crashed if the font had a name (in my case) Aarcover (Plain): 001.001 . The rest of the fonts were normal, but this one crashed the whole program.

It would seem, and all right, the probability is extremely small (in fact, not), but it puffed at me very much. The first solution was:

 alert(arrFonts); for (var i=0; i<7; i++){ fontGroup.nameOfFont = fontGroup.add('dropdownlist', undefined, arrFonts); fontGroup.nameOfFont.selection = fontIndex[i]; } 

That is, if before this cycle you simply call a warning window in which all the elements of the arrFonts array are listed (and this window turned out to be full screen and you could not even see the OK button), then the script window will be generated normally, as it should. Other "alerts" with empty lines and incoherent text did not help, only with an array of fonts.

After some time, a second solution appeared that works, but I don’t understand why.

 var tempArrFont = arrFonts.slice(); for (var i=0; i<7; i++){ fontGroup.nameOfFont = fontGroup.add('dropdownlist', undefined, tempArrFont); fontGroup.nameOfFont.selection = fontIndex[i]; } 

So, we make a copy of the “problem” array using the slice method, and use this copy instead of the original. It worked and is used now. I will be glad to see the answer in the comments, why this is happening and whether it is possible to somehow fix it.

Useful break


Somewhere in early December 2015, I paused to write the script. But I did not stop because I was tired or lost interest. I digress from the script to write another script. I will not dwell on this thing, I will only say that during the development of this script I found that creating a text layer using low-level commands was an order of magnitude faster than using my function using standard methods from the manual. Yes, the new function had a lot more lines of code than in the function that I originally wrote - and yet it worked faster. One could guess that our low level is everything, but at that moment I was completely stupid and checked it only in the middle.

For greater clarity, I will give a comparative tablet:

Time spent creating 600 text layers containing the text "01"
(WELL - low-level creation, SM - creation by standard methods)
Photoshop versionStationary
computer (tth)
Notebook (tth)
CS5Well: 0 min 47 sec
SM: 3 min 43 sec
Well: 2 min. 28 sec.
CM: 9 min 49 sec
CC 2015Well: 1 min 18 sec.
CM: 10 min 42 sec
Well: 3 min 12 sec.
SM: 42 min 36 sec

Seeing such indicators (pay attention to CS5 - bypassing the new CC in speed, the rogue) I was overwhelmed by the feeling of disappointment - after all, my old function of creating text in the “calendar” script was already organically written into its structure. And I really didn't want to redo everything. But, thinking that after all, in fact, everything is not so bad, you just need to very carefully and carefully replace one function with another. Then test, correct all the shortcomings that have appeared and fully switch to the new method. Moreover, by reducing the time to create a calendar, I will win.

So, first you had to get rid of unnecessary lines of code in the resulting element.

Raw function code
 //   (    ), //   XBYTOR' cTID = function(s) { return app.charIDToTypeID(s); }; sTID = function(s) { return app.stringIDToTypeID(s); }; //   ,       //     "TEXT TEXT",  Verdana,   9,32 ,   function step1() { var desc1 = new ActionDescriptor(); var ref1 = new ActionReference(); ref1.putClass(cTID('TxLr')); desc1.putReference(cTID('null'), ref1); var desc2 = new ActionDescriptor(); desc2.putString(cTID('Txt '), "TEXT TEXT"); var desc3 = new ActionDescriptor(); desc3.putEnumerated(sTID("warpStyle"), sTID("warpStyle"), sTID("warpNone")); desc3.putDouble(sTID("warpValue"), 0); desc3.putDouble(sTID("warpPerspective"), 0); desc3.putDouble(sTID("warpPerspectiveOther"), 0); desc3.putEnumerated(sTID("warpRotate"), cTID('Ornt'), cTID('Hrzn')); desc2.putObject(cTID('warp'), cTID('warp'), desc3); var desc4 = new ActionDescriptor(); desc4.putUnitDouble(cTID('Hrzn'), cTID('#Prc'), 35.5820105820106); desc4.putUnitDouble(cTID('Vrtc'), cTID('#Prc'), 48.2254697286012); desc2.putObject(cTID('TxtC'), cTID('Pnt '), desc4); desc2.putEnumerated(sTID("textGridding"), sTID("textGridding"), cTID('None')); desc2.putEnumerated(cTID('Ornt'), cTID('Ornt'), cTID('Hrzn')); desc2.putEnumerated(cTID('AntA'), cTID('Annt'), cTID('AnCr')); var desc5 = new ActionDescriptor(); desc5.putUnitDouble(cTID('Left'), cTID('#Pnt'), 0); desc5.putUnitDouble(cTID('Top '), cTID('#Pnt'), -8.04805660247803); desc5.putUnitDouble(cTID('Rght'), cTID('#Pnt'), 50.8121795654297); desc5.putUnitDouble(cTID('Btom'), cTID('#Pnt'), 2.8260350227356); desc2.putObject(sTID("bounds"), sTID("bounds"), desc5); var desc6 = new ActionDescriptor(); desc6.putUnitDouble(cTID('Left'), cTID('#Pnt'), 0); desc6.putUnitDouble(cTID('Top '), cTID('#Pnt'), -7); desc6.putUnitDouble(cTID('Rght'), cTID('#Pnt'), 52.0618438720703); desc6.putUnitDouble(cTID('Btom'), cTID('#Pnt'), 0); desc2.putObject(sTID("boundingBox"), sTID("boundingBox"), desc6); var list1 = new ActionList(); var desc7 = new ActionDescriptor(); desc7.putEnumerated(sTID("textType"), sTID("textType"), cTID('Pnt ')); desc7.putEnumerated(cTID('Ornt'), cTID('Ornt'), cTID('Hrzn')); var desc8 = new ActionDescriptor(); desc8.putDouble(sTID("xx"), 1); desc8.putDouble(sTID("xy"), 0); desc8.putDouble(sTID("yx"), 0); desc8.putDouble(sTID("yy"), 1); desc8.putDouble(sTID("tx"), 0); desc8.putDouble(sTID("ty"), 0); desc7.putObject(cTID('Trnf'), cTID('Trnf'), desc8); desc7.putInteger(sTID("rowCount"), 1); desc7.putInteger(sTID("columnCount"), 1); desc7.putBoolean(sTID("rowMajorOrder"), true); desc7.putUnitDouble(sTID("rowGutter"), cTID('#Pnt'), 0); desc7.putUnitDouble(sTID("columnGutter"), cTID('#Pnt'), 0); desc7.putUnitDouble(cTID('Spcn'), cTID('#Pnt'), 0); desc7.putEnumerated(sTID("frameBaselineAlignment"), sTID("frameBaselineAlignment"), sTID("alignByAscent")); desc7.putUnitDouble(sTID("firstBaselineMinimum"), cTID('#Pnt'), 0); var desc9 = new ActionDescriptor(); desc9.putDouble(cTID('Hrzn'), 0); desc9.putDouble(cTID('Vrtc'), 0); desc7.putObject(cTID('base'), cTID('Pnt '), desc9); list1.putObject(sTID("textShape"), desc7); desc2.putList(sTID("textShape"), list1); var list2 = new ActionList(); var desc10 = new ActionDescriptor(); desc10.putInteger(cTID('From'), 0); desc10.putInteger(cTID('T '), 10); var desc11 = new ActionDescriptor(); desc11.putBoolean(sTID("styleSheetHasParent"), true); desc11.putString(sTID("fontPostScriptName"), "Verdana"); desc11.putString(cTID('FntN'), "Verdana"); desc11.putString(cTID('FntS'), "Regular"); desc11.putInteger(cTID('Scrp'), 0); desc11.putInteger(cTID('FntT'), 1); desc11.putUnitDouble(cTID('Sz '), cTID('#Pnt'), 9.31999969482422); desc11.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("defaultDigits")); desc11.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pnt'), 5.76000165939331); desc11.putEnumerated(sTID("textLanguage"), sTID("textLanguage"), sTID("russianLanguage")); var desc12 = new ActionDescriptor(); desc12.putString(sTID("fontPostScriptName"), "MyriadPro-Regular"); desc12.putString(cTID('FntN'), "Myriad Pro"); desc12.putString(cTID('FntS'), "Regular"); desc12.putInteger(cTID('Scrp'), 0); desc12.putInteger(cTID('FntT'), 0); desc12.putUnitDouble(cTID('Sz '), cTID('#Pnt'), 12); desc12.putDouble(cTID('HrzS'), 100); desc12.putDouble(cTID('VrtS'), 100); desc12.putBoolean(sTID("syntheticBold"), false); desc12.putBoolean(sTID("syntheticItalic"), false); desc12.putBoolean(sTID("autoLeading"), true); desc12.putInteger(cTID('Trck'), 0); desc12.putUnitDouble(cTID('Bsln'), cTID('#Pnt'), 0); desc12.putDouble(sTID("characterRotation"), 0); desc12.putEnumerated(cTID('AtKr'), cTID('AtKr'), sTID("metricsKern")); desc12.putEnumerated(sTID("fontCaps"), sTID("fontCaps"), cTID('Nrml')); desc12.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("defaultDigits")); desc12.putEnumerated(sTID("dirOverride"), sTID("dirOverride"), sTID("dirOverrideDefault")); desc12.putEnumerated(sTID("kashidas"), sTID("kashidas"), sTID("kashidaDefault")); desc12.putEnumerated(sTID("diacVPos"), sTID("diacVPos"), sTID("diacVPosOpenType")); desc12.putUnitDouble(sTID("diacXOffset"), cTID('#Pnt'), 0); desc12.putUnitDouble(sTID("diacYOffset"), cTID('#Pnt'), 0); desc12.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pnt'), 100); desc12.putEnumerated(sTID("baseline"), sTID("baseline"), cTID('Nrml')); desc12.putEnumerated(sTID("otbaseline"), sTID("otbaseline"), cTID('Nrml')); desc12.putEnumerated(sTID("strikethrough"), sTID("strikethrough"), sTID("strikethroughOff")); desc12.putEnumerated(cTID('Undl'), cTID('Undl'), sTID("underlineOff")); desc12.putUnitDouble(sTID("underlineOffset"), cTID('#Pnt'), 0); desc12.putBoolean(sTID("ligature"), true); desc12.putBoolean(sTID("altligature"), false); desc12.putBoolean(sTID("contextualLigatures"), false); desc12.putBoolean(sTID("alternateLigatures"), false); desc12.putBoolean(sTID("oldStyle"), false); desc12.putBoolean(sTID("fractions"), false); desc12.putBoolean(sTID("ordinals"), false); desc12.putBoolean(sTID("swash"), false); desc12.putBoolean(sTID("titling"), false); desc12.putBoolean(sTID("connectionForms"), false); desc12.putBoolean(sTID("stylisticAlternates"), false); desc12.putBoolean(sTID("ornaments"), false); desc12.putBoolean(sTID("justificationAlternates"), false); desc12.putEnumerated(sTID("figureStyle"), sTID("figureStyle"), cTID('Nrml')); desc12.putBoolean(sTID("proportionalMetrics"), false); desc12.putBoolean(cTID('kana'), false); desc12.putBoolean(sTID("italics"), false); desc12.putBoolean(cTID('ruby'), false); desc12.putEnumerated(sTID("baselineDirection"), sTID("baselineDirection"), sTID("rotated")); desc12.putEnumerated(sTID("textLanguage"), sTID("textLanguage"), sTID("englishLanguage")); desc12.putEnumerated(sTID("japaneseAlternate"), sTID("japaneseAlternate"), sTID("defaultForm")); desc12.putDouble(sTID("mojiZume"), 0); desc12.putEnumerated(sTID("gridAlignment"), sTID("gridAlignment"), sTID("roman")); desc12.putBoolean(sTID("enableWariChu"), false); desc12.putInteger(sTID("wariChuCount"), 2); desc12.putInteger(sTID("wariChuLineGap"), 0); desc12.putDouble(sTID("wariChuScale"), 0.5); desc12.putInteger(sTID("wariChuWidow"), 2); desc12.putInteger(sTID("wariChuOrphan"), 2); desc12.putEnumerated(sTID("wariChuJustification"), sTID("wariChuJustification"), sTID("wariChuAutoJustify")); desc12.putInteger(sTID("tcyUpDown"), 0); desc12.putInteger(sTID("tcyLeftRight"), 0); desc12.putDouble(sTID("leftAki"), -1); desc12.putDouble(sTID("rightAki"), -1); desc12.putInteger(sTID("jiDori"), 0); desc12.putBoolean(sTID("noBreak"), false); var desc13 = new ActionDescriptor(); desc13.putDouble(cTID('Rd '), 0); desc13.putDouble(cTID('Grn '), 0); desc13.putDouble(cTID('Bl '), 0); desc12.putObject(cTID('Clr '), sTID("RGBColor"), desc13); var desc14 = new ActionDescriptor(); desc14.putDouble(cTID('Rd '), 0); desc14.putDouble(cTID('Grn '), 0); desc14.putDouble(cTID('Bl '), 0); desc12.putObject(sTID("strokeColor"), sTID("RGBColor"), desc14); desc12.putBoolean(cTID('Fl '), true); desc12.putBoolean(cTID('Strk'), false); desc12.putBoolean(sTID("fillFirst"), true); desc12.putBoolean(sTID("fillOverPrint"), false); desc12.putBoolean(sTID("strokeOverPrint"), false); desc12.putEnumerated(sTID("lineCap"), sTID("lineCap"), sTID("buttCap")); desc12.putEnumerated(sTID("lineJoin"), sTID("lineJoin"), sTID("miterJoin")); desc12.putUnitDouble(sTID("lineWidth"), cTID('#Pnt'), 1); desc12.putUnitDouble(sTID("miterLimit"), cTID('#Pnt'), 4); desc12.putDouble(sTID("lineDashOffset"), 0); desc11.putObject(sTID("baseParentStyle"), cTID('TxtS'), desc12); desc10.putObject(cTID('TxtS'), cTID('TxtS'), desc11); list2.putObject(cTID('Txtt'), desc10); desc2.putList(cTID('Txtt'), list2); var list3 = new ActionList(); var desc15 = new ActionDescriptor(); desc15.putInteger(cTID('From'), 0); desc15.putInteger(cTID('T '), 10); var desc16 = new ActionDescriptor(); desc16.putBoolean(sTID("styleSheetHasParent"), true); desc16.putEnumerated(cTID('Algn'), cTID('Alg '), cTID('Left')); desc16.putUnitDouble(sTID("firstLineIndent"), cTID('#Pnt'), 0); desc16.putUnitDouble(sTID("startIndent"), cTID('#Pnt'), 0); desc16.putUnitDouble(sTID("endIndent"), cTID('#Pnt'), 0); desc16.putUnitDouble(sTID("spaceBefore"), cTID('#Pnt'), 0); desc16.putUnitDouble(sTID("spaceAfter"), cTID('#Pnt'), 0); desc16.putInteger(sTID("dropCapMultiplier"), 1); desc16.putDouble(sTID("autoLeadingPercentage"), 1.20000004768372); desc16.putEnumerated(sTID("leadingType"), sTID("leadingType"), sTID("leadingBelow")); desc16.putEnumerated(sTID("directionType"), sTID("directionType"), sTID("dirLeftToRight")); desc16.putEnumerated(sTID("kashidaWidthType"), sTID("kashidaWidthType"), sTID("kashidaWidthMedium")); desc16.putEnumerated(sTID("justificationMethodType"), sTID("justificationMethodType"), sTID("justifMethodAutomatic")); desc16.putBoolean(sTID("hyphenate"), true); desc16.putInteger(sTID("hyphenateWordSize"), 6); desc16.putInteger(sTID("hyphenatePreLength"), 2); desc16.putInteger(sTID("hyphenatePostLength"), 2); desc16.putInteger(sTID("hyphenateLimit"), 0); desc16.putDouble(sTID("hyphenationZone"), 36); desc16.putBoolean(sTID("hyphenateCapitalized"), true); desc16.putDouble(sTID("hyphenationPreference"), 0.5); desc16.putDouble(sTID("justificationWordMinimum"), 0.80000001192093); desc16.putDouble(sTID("justificationWordDesired"), 1); desc16.putDouble(sTID("justificationWordMaximum"), 1.33000004291534); desc16.putDouble(sTID("justificationLetterMinimum"), 0); desc16.putDouble(sTID("justificationLetterDesired"), 0); desc16.putDouble(sTID("justificationLetterMaximum"), 0); desc16.putDouble(sTID("justificationGlyphMinimum"), 1); desc16.putDouble(sTID("justificationGlyphDesired"), 1); desc16.putDouble(sTID("justificationGlyphMaximum"), 1); desc16.putEnumerated(sTID("singleWordJustification"), cTID('Alg '), cTID('JstA')); desc16.putBoolean(sTID("hangingRoman"), false); desc16.putInteger(sTID("autoTCY"), 0); desc16.putBoolean(sTID("keepTogether"), true); desc16.putEnumerated(sTID("burasagari"), sTID("burasagari"), sTID("burasagariNone")); desc16.putEnumerated(sTID("preferredKinsokuOrder"), sTID("preferredKinsokuOrder"), sTID("pushIn")); desc16.putBoolean(sTID("kurikaeshiMojiShori"), false); desc16.putBoolean(sTID("textEveryLineComposer"), false); desc16.putDouble(sTID("defaultTabWidth"), 36); var desc17 = new ActionDescriptor(); desc17.putString(sTID("fontPostScriptName"), "MyriadPro-Regular"); desc17.putString(cTID('FntN'), "Myriad Pro"); desc17.putString(cTID('FntS'), "Regular"); desc17.putInteger(cTID('Scrp'), 0); desc17.putInteger(cTID('FntT'), 0); desc17.putUnitDouble(cTID('Sz '), cTID('#Pnt'), 12); desc17.putDouble(cTID('HrzS'), 100); desc17.putDouble(cTID('VrtS'), 100); desc17.putBoolean(sTID("syntheticBold"), false); desc17.putBoolean(sTID("syntheticItalic"), false); desc17.putBoolean(sTID("autoLeading"), true); desc17.putInteger(cTID('Trck'), 0); desc17.putUnitDouble(cTID('Bsln'), cTID('#Pnt'), 0); desc17.putDouble(sTID("characterRotation"), 0); desc17.putEnumerated(cTID('AtKr'), cTID('AtKr'), sTID("metricsKern")); desc17.putEnumerated(sTID("fontCaps"), sTID("fontCaps"), cTID('Nrml')); desc17.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("arabicDigits")); desc17.putEnumerated(sTID("kashidas"), sTID("kashidas"), sTID("kashidaDefault")); desc17.putEnumerated(sTID("diacVPos"), sTID("diacVPos"), sTID("diacVPosOpenType")); desc17.putUnitDouble(sTID("diacXOffset"), cTID('#Pnt'), 0); desc17.putUnitDouble(sTID("diacYOffset"), cTID('#Pnt'), 0); desc17.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pnt'), 0); desc17.putEnumerated(sTID("baseline"), sTID("baseline"), cTID('Nrml')); desc17.putEnumerated(sTID("strikethrough"), sTID("strikethrough"), sTID("strikethroughOff")); desc17.putEnumerated(cTID('Undl'), cTID('Undl'), sTID("underlineOff")); desc17.putBoolean(sTID("ligature"), true); desc17.putBoolean(sTID("altligature"), false); desc17.putBoolean(sTID("contextualLigatures"), true); desc17.putBoolean(sTID("alternateLigatures"), false); desc17.putBoolean(sTID("oldStyle"), false); desc17.putBoolean(sTID("fractions"), false); desc17.putBoolean(sTID("ordinals"), false); desc17.putBoolean(sTID("swash"), false); desc17.putBoolean(sTID("titling"), false); desc17.putBoolean(sTID("connectionForms"), false); desc17.putBoolean(sTID("stylisticAlternates"), false); desc17.putBoolean(sTID("ornaments"), false); desc17.putEnumerated(sTID("figureStyle"), sTID("figureStyle"), cTID('Nrml')); desc17.putEnumerated(sTID("baselineDirection"), sTID("baselineDirection"), sTID("withStream")); desc17.putEnumerated(sTID("textLanguage"), sTID("textLanguage"), sTID("englishLanguage")); var desc18 = new ActionDescriptor(); desc18.putDouble(cTID('Rd '), 0); desc18.putDouble(cTID('Grn '), 0); desc18.putDouble(cTID('Bl '), 0); desc17.putObject(cTID('Clr '), sTID("RGBColor"), desc18); var desc19 = new ActionDescriptor(); desc19.putDouble(cTID('Rd '), 0); desc19.putDouble(cTID('Grn '), 0); desc19.putDouble(cTID('Bl '), 0); desc17.putObject(sTID("strokeColor"), sTID("RGBColor"), desc19); desc16.putObject(sTID("defaultStyle"), cTID('TxtS'), desc17); desc15.putObject(sTID("paragraphStyle"), sTID("paragraphStyle"), desc16); list3.putObject(sTID("paragraphStyleRange"), desc15); desc2.putList(sTID("paragraphStyleRange"), list3); var list4 = new ActionList(); desc2.putList(sTID("kerningRange"), list4); desc1.putObject(cTID('Usng'), cTID('TxLr'), desc2); executeAction(cTID('Mk '), desc1, DialogModes.NO); }; 


. , : , , , , , , . , – . , , , .

, , – - , . , - , – , . , . .

 // ,        var sizeTestParam = { text:   fontName:   (postcript), fontSize:  , color:  () } newTextLayer(sizeTestParam, 'Left'); // .        //    function newTextLayer() { var paramset = arguments[0]; var justific = arguments[1]; if (justific===undefined) {justific = 'Cntr'} //   var text = paramset.text + ""||"<empty>"; var textLength = text.length; var fontName = paramset.fontName||"TimesNewRomanPS-BoldMT"; var fontSize = paramset.fontSize||5; var colorR = paramset.color.rgb.red||0; var colorG = paramset.color.rgb.green||0; var colorB = paramset.color.rgb.blue||0; var desc1 = new ActionDescriptor(); var ref1 = new ActionReference(); ref1.putClass(cTID('TxLr')); desc1.putReference(cTID('null'), ref1); var desc2 = new ActionDescriptor(); desc2.putString(cTID('Txt '), text); //   (  ) var desc4 = new ActionDescriptor(); desc4.putUnitDouble(cTID('Hrzn'), cTID('#Prc'), 5); desc4.putUnitDouble(cTID('Vrtc'), cTID('#Prc'), 5); desc2.putObject(cTID('TxtC'), cTID('Pnt '), desc4); desc2.putEnumerated(sTID("textGridding"), sTID("textGridding"), cTID('None')); desc2.putEnumerated(cTID('Ornt'), cTID('Ornt'), cTID('Hrzn')); desc2.putEnumerated(cTID('AntA'), cTID('Annt'), cTID('AnCr')); var list1 = new ActionList(); var desc7 = new ActionDescriptor(); desc7.putEnumerated(sTID("textType"), sTID("textType"), cTID('Pnt ')); desc7.putEnumerated(cTID('Ornt'), cTID('Ornt'), cTID('Hrzn')); desc7.putInteger(sTID("rowCount"), 1); desc7.putInteger(sTID("columnCount"), 1); desc7.putBoolean(sTID("rowMajorOrder"), true); desc7.putUnitDouble(sTID("rowGutter"), cTID('#Pxl'), 0); desc7.putUnitDouble(sTID("columnGutter"), cTID('#Pxl'), 0); desc7.putUnitDouble(cTID('Spcn'), cTID('#Pxl'), 0); desc7.putEnumerated(sTID("frameBaselineAlignment"), sTID("frameBaselineAlignment"), sTID("alignByAscent")); desc7.putUnitDouble(sTID("firstBaselineMinimum"), cTID('#Pxl'), 0); var desc9 = new ActionDescriptor(); desc9.putDouble(cTID('Hrzn'), 0); desc9.putDouble(cTID('Vrtc'), 0); desc7.putObject(cTID('base'), cTID('Pnt '), desc9); list1.putObject(sTID("textShape"), desc7); desc2.putList(sTID("textShape"), list1); var list2 = new ActionList(); var desc10 = new ActionDescriptor(); desc10.putInteger(cTID('From'), 0); //     (  -) desc10.putInteger(cTID('T '), textLength); var desc11 = new ActionDescriptor(); desc11.putBoolean(sTID("styleSheetHasParent"), true); //  desc11.putString(sTID("fontPostScriptName"), fontName); desc11.putInteger(cTID('Scrp'), 0); desc11.putInteger(cTID('FntT'), 1); //   desc11.putUnitDouble(cTID('Sz '), cTID('#Pnt'), fontSize); desc11.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("defaultDigits")); desc11.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pxl'), 100); //   var colorDesc = new ActionDescriptor(); colorDesc.putDouble(cTID('Rd '), colorR); colorDesc.putDouble(cTID('Grn '), colorG); colorDesc.putDouble(cTID('Bl '), colorB); desc11.putObject(cTID('Clr '), sTID("RGBColor"), colorDesc); var desc13 = new ActionDescriptor(); desc13.putString(sTID("fontPostScriptName"), "MyriadPro-Regular"); desc13.putString(cTID('FntN'), "Myriad Pro"); desc13.putString(cTID('FntS'), "Regular"); desc13.putInteger(cTID('Scrp'), 0); desc13.putInteger(cTID('FntT'), 0); desc13.putUnitDouble(cTID('Sz '), cTID('#Pxl'), 12); desc13.putDouble(cTID('HrzS'), 100); desc13.putDouble(cTID('VrtS'), 100); desc13.putBoolean(sTID("syntheticBold"), false); desc13.putBoolean(sTID("syntheticItalic"), false); desc13.putBoolean(sTID("autoLeading"), true); desc13.putInteger(cTID('Trck'), 0); desc13.putUnitDouble(cTID('Bsln'), cTID('#Pxl'), 0); desc13.putEnumerated(cTID('AtKr'), cTID('AtKr'), sTID("metricsKern")); desc13.putEnumerated(sTID("fontCaps"), sTID("fontCaps"), cTID('Nrml')); desc13.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("defaultDigits")); desc13.putEnumerated(sTID("dirOverride"), sTID("dirOverride"), sTID("dirOverrideDefault")); desc13.putEnumerated(sTID("kashidas"), sTID("kashidas"), sTID("kashidaDefault")); desc13.putEnumerated(sTID("diacVPos"), sTID("diacVPos"), sTID("diacVPosOpenType")); desc13.putUnitDouble(sTID("diacXOffset"), cTID('#Pxl'), 0); desc13.putUnitDouble(sTID("diacYOffset"), cTID('#Pxl'), 0); desc13.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pxl'), 100); desc13.putEnumerated(sTID("baseline"), sTID("baseline"), cTID('Nrml')); desc13.putEnumerated(sTID("otbaseline"), sTID("otbaseline"), cTID('Nrml')); desc13.putEnumerated(sTID("strikethrough"), sTID("strikethrough"), sTID("strikethroughOff")); desc13.putEnumerated(cTID('Undl'), cTID('Undl'), sTID("underlineOff")); desc13.putUnitDouble(sTID("underlineOffset"), cTID('#Pxl'), 0); desc13.putBoolean(sTID("ligature"), true); desc13.putBoolean(sTID("altligature"), false); desc13.putBoolean(sTID("contextualLigatures"), false); desc13.putBoolean(sTID("alternateLigatures"), false); desc13.putBoolean(sTID("oldStyle"), false); desc13.putBoolean(sTID("fractions"), false); desc13.putBoolean(sTID("ordinals"), false); desc13.putBoolean(sTID("swash"), false); desc13.putBoolean(sTID("titling"), false); desc13.putBoolean(sTID("connectionForms"), false); desc13.putBoolean(sTID("stylisticAlternates"), false); desc13.putBoolean(sTID("ornaments"), false); desc13.putBoolean(sTID("justificationAlternates"), false); desc13.putEnumerated(sTID("figureStyle"), sTID("figureStyle"), cTID('Nrml')); desc13.putBoolean(sTID("proportionalMetrics"), false); desc13.putBoolean(cTID('kana'), false); desc13.putBoolean(sTID("italics"), false); desc13.putBoolean(cTID('ruby'), false); desc13.putEnumerated(sTID("baselineDirection"), sTID("baselineDirection"), sTID("rotated")); desc13.putEnumerated(sTID("textLanguage"), sTID("textLanguage"), sTID("englishLanguage")); desc13.putEnumerated(sTID("japaneseAlternate"), sTID("japaneseAlternate"), sTID("defaultForm")); desc13.putDouble(sTID("mojiZume"), 0); desc13.putEnumerated(sTID("gridAlignment"), sTID("gridAlignment"), sTID("roman")); desc13.putBoolean(sTID("enableWariChu"), false); desc13.putInteger(sTID("wariChuCount"), 2); desc13.putInteger(sTID("wariChuLineGap"), 0); desc13.putDouble(sTID("wariChuScale"), 0.5); desc13.putInteger(sTID("wariChuWidow"), 2); desc13.putInteger(sTID("wariChuOrphan"), 2); desc13.putEnumerated(sTID("wariChuJustification"), sTID("wariChuJustification"), sTID("wariChuAutoJustify")); desc13.putInteger(sTID("tcyUpDown"), 0); desc13.putInteger(sTID("tcyLeftRight"), 0); desc13.putDouble(sTID("leftAki"), -1); desc13.putDouble(sTID("rightAki"), -1); desc13.putInteger(sTID("jiDori"), 0); desc13.putBoolean(sTID("noBreak"), false); desc13.putEnumerated(sTID("lineCap"), sTID("lineCap"), sTID("buttCap")); desc13.putEnumerated(sTID("lineJoin"), sTID("lineJoin"), sTID("miterJoin")); desc13.putUnitDouble(sTID("lineWidth"), cTID('#Pxl'), 1); desc13.putUnitDouble(sTID("miterLimit"), cTID('#Pxl'), 4); desc13.putDouble(sTID("lineDashOffset"), 0); desc11.putObject(sTID("baseParentStyle"), cTID('TxtS'), desc13); desc10.putObject(cTID('TxtS'), cTID('TxtS'), desc11); list2.putObject(cTID('Txtt'), desc10); desc2.putList(cTID('Txtt'), list2); var list3 = new ActionList(); var desc16 = new ActionDescriptor(); desc16.putInteger(cTID('From'), 0); desc16.putInteger(cTID('T '), 16); var desc17 = new ActionDescriptor(); desc17.putBoolean(sTID("styleSheetHasParent"), true); //  desc17.putEnumerated(cTID('Algn'), cTID('Alg '), cTID(justific)); desc17.putUnitDouble(sTID("firstLineIndent"), cTID('#Pxl'), 0); desc17.putUnitDouble(sTID("startIndent"), cTID('#Pxl'), 0); desc17.putUnitDouble(sTID("endIndent"), cTID('#Pxl'), 0); desc17.putUnitDouble(sTID("spaceBefore"), cTID('#Pxl'), 0); desc17.putUnitDouble(sTID("spaceAfter"), cTID('#Pxl'), 0); desc17.putInteger(sTID("dropCapMultiplier"), 1); desc17.putDouble(sTID("autoLeadingPercentage"), 1.20000004768372); desc17.putEnumerated(sTID("leadingType"), sTID("leadingType"), sTID("leadingBelow")); desc17.putEnumerated(sTID("directionType"), sTID("directionType"), sTID("dirLeftToRight")); desc17.putEnumerated(sTID("kashidaWidthType"), sTID("kashidaWidthType"), sTID("kashidaWidthMedium")); desc17.putEnumerated(sTID("justificationMethodType"), sTID("justificationMethodType"), sTID("justifMethodAutomatic")); desc17.putBoolean(sTID("hyphenate"), true); desc17.putInteger(sTID("hyphenateWordSize"), 6); desc17.putInteger(sTID("hyphenatePreLength"), 2); desc17.putInteger(sTID("hyphenatePostLength"), 2); desc17.putInteger(sTID("hyphenateLimit"), 0); desc17.putDouble(sTID("hyphenationZone"), 36); desc17.putBoolean(sTID("hyphenateCapitalized"), true); desc17.putDouble(sTID("hyphenationPreference"), 0.5); desc17.putDouble(sTID("justificationWordMinimum"), 0.80000001192093); desc17.putDouble(sTID("justificationWordDesired"), 1); desc17.putDouble(sTID("justificationWordMaximum"), 1.33000004291534); desc17.putDouble(sTID("justificationLetterMinimum"), 0); desc17.putDouble(sTID("justificationLetterDesired"), 0); desc17.putDouble(sTID("justificationLetterMaximum"), 0); desc17.putDouble(sTID("justificationGlyphMinimum"), 1); desc17.putDouble(sTID("justificationGlyphDesired"), 1); desc17.putDouble(sTID("justificationGlyphMaximum"), 1); desc17.putEnumerated(sTID("singleWordJustification"), cTID('Alg '), cTID('JstA')); desc17.putBoolean(sTID("hangingRoman"), false); desc17.putInteger(sTID("autoTCY"), 0); desc17.putBoolean(sTID("keepTogether"), true); desc17.putEnumerated(sTID("burasagari"), sTID("burasagari"), sTID("burasagariNone")); desc17.putEnumerated(sTID("preferredKinsokuOrder"), sTID("preferredKinsokuOrder"), sTID("pushIn")); desc17.putBoolean(sTID("kurikaeshiMojiShori"), false); desc17.putBoolean(sTID("textEveryLineComposer"), false); desc17.putDouble(sTID("defaultTabWidth"), 36); var desc18 = new ActionDescriptor(); desc18.putString(sTID("fontPostScriptName"), "MyriadPro-Regular"); desc18.putString(cTID('FntN'), "Myriad Pro"); desc18.putString(cTID('FntS'), "Regular"); desc18.putInteger(cTID('Scrp'), 0); desc18.putInteger(cTID('FntT'), 0); desc18.putUnitDouble(cTID('Sz '), cTID('#Pxl'), 12); desc18.putDouble(cTID('HrzS'), 100); desc18.putDouble(cTID('VrtS'), 100); desc18.putBoolean(sTID("syntheticBold"), false); desc18.putBoolean(sTID("syntheticItalic"), false); desc18.putBoolean(sTID("autoLeading"), true); desc18.putInteger(cTID('Trck'), 0); desc18.putUnitDouble(cTID('Bsln'), cTID('#Pxl'), 0); desc18.putDouble(sTID("characterRotation"), 0); desc18.putEnumerated(cTID('AtKr'), cTID('AtKr'), sTID("metricsKern")); desc18.putEnumerated(sTID("fontCaps"), sTID("fontCaps"), cTID('Nrml')); desc18.putEnumerated(sTID("digitSet"), sTID("digitSet"), sTID("arabicDigits")); desc18.putEnumerated(sTID("kashidas"), sTID("kashidas"), sTID("kashidaDefault")); desc18.putEnumerated(sTID("diacVPos"), sTID("diacVPos"), sTID("diacVPosOpenType")); desc18.putUnitDouble(sTID("diacXOffset"), cTID('#Pxl'), 0); desc18.putUnitDouble(sTID("diacYOffset"), cTID('#Pxl'), 0); desc18.putUnitDouble(sTID("markYDistFromBaseline"), cTID('#Pxl'), 0); desc18.putEnumerated(sTID("baseline"), sTID("baseline"), cTID('Nrml')); desc18.putEnumerated(sTID("strikethrough"), sTID("strikethrough"), sTID("strikethroughOff")); desc18.putEnumerated(cTID('Undl'), cTID('Undl'), sTID("underlineOff")); desc18.putBoolean(sTID("ligature"), true); desc18.putBoolean(sTID("altligature"), false); desc18.putBoolean(sTID("contextualLigatures"), true); desc18.putBoolean(sTID("alternateLigatures"), false); desc18.putBoolean(sTID("oldStyle"), false); desc18.putBoolean(sTID("fractions"), false); desc18.putBoolean(sTID("ordinals"), false); desc18.putBoolean(sTID("swash"), false); desc18.putBoolean(sTID("titling"), false); desc18.putBoolean(sTID("connectionForms"), false); desc18.putBoolean(sTID("stylisticAlternates"), false); desc18.putBoolean(sTID("ornaments"), false); desc18.putEnumerated(sTID("figureStyle"), sTID("figureStyle"), cTID('Nrml')); desc18.putEnumerated(sTID("baselineDirection"), sTID("baselineDirection"), sTID("withStream")); desc18.putEnumerated(sTID("textLanguage"), sTID("textLanguage"), sTID("englishLanguage")); var desc19 = new ActionDescriptor(); desc19.putDouble(cTID('Rd '), 0); desc19.putDouble(cTID('Grn '), 0); desc19.putDouble(cTID('Bl '), 0); desc18.putObject(cTID('Clr '), sTID("RGBColor"), desc19); var desc20 = new ActionDescriptor(); desc20.putDouble(cTID('Rd '), 0); desc20.putDouble(cTID('Grn '), 0); desc20.putDouble(cTID('Bl '), 0); desc18.putObject(sTID("strokeColor"), sTID("RGBColor"), desc20); desc17.putObject(sTID("defaultStyle"), cTID('TxtS'), desc18); desc16.putObject(sTID("paragraphStyle"), sTID("paragraphStyle"), desc17); list3.putObject(sTID("paragraphStyleRange"), desc16); desc2.putList(sTID("paragraphStyleRange"), list3); var list4 = new ActionList(); desc2.putList(sTID("kerningRange"), list4); desc1.putObject(cTID('Usng'), cTID('TxLr'), desc2); executeAction(cTID('Mk '), desc1, DialogModes.NO); }; 

- . , — , X Y . .


. , (, fireStarter). , . , .

3 . Simple Mode , ( , ) .
« !». info, — , Warcraft III .
. , . , - . , , , «egg», . , , . — , — , .




, , , . , , . , (IMHO) . , , .

, . 10-12 , .

. «Google ».

, «Examples» . , — .



, . , — , . , , Google ( , ).


« , ?»
, , - . , , , — , .

In the end


, , 2015 28 2016. — , , , , — . — , — . , — ?

. Relax. , , . , , , . , , , . .

, — , . — ? «». «», , , , , . , … , , .

, , , .
, – . , - .

PS , (~ 4 Mb).

:


» Adobe Photoshop — CS5 ( ) CS2 ( UI)
» Scripting Listener — Photoshop CC Adobe Windows MacOS
» Adobe ExtendScript Toolkit — CS3-CS5

Source: https://habr.com/ru/post/311390/


All Articles