Cíl lekce
Náplní této lekce je nalezení fontů ve všech vrstvách dokumentu. Skript je užitečný v případě, kdy uživatel dostane grafiku na upravení a potřebuje zjistit styly fontů, jakými jsou texty v dokumentu napsány. Skript prohledá všechny vrstvy zda-li obsahují fonty a uloží je do pole. Poté je prohledá, aby pole neobsahovalo duplicitní prvky a nakonec setřídít. V lekci využívám již znamý ActionDescriptor a ActionReference s konstantami.
Původní obrázek - obrázek 11.1
Výsledek - obrázek 11.2
Využité třídy v této lekci
- Application: pro práci s atributy dokumentu.
- Konstanty: konstanty typu event ID.
- Descriptor: pro popis prováděných akcí z rozhraní.
- Reference: pro zadání objektů do ActionDescriptoru.
Funkce na odstranění duplicit v poli
Jako první krok si vytvořím funkci, která bude mít účel výsledné pole s fonty projít a odstranit
duplicitní fonty.
K tomuto si vytvořím pomocné pole, které poté se poté bude vracet jako výsledné. Dále potřebuji dva cykly, jeden
k
procházení vstupního pole předaným parametrem a druhý pro procházení lokálního pole a zjišťování zda-li
pole již
tento prvek obsahuje. Použiji (for) cykly,
abych opět jako v předchozích lekcích mohl pracovat s indexy. Dále do této části již doplním známe
metody na získání event ID.
function getArrayWithoutDuplicits(array){
//pole
var temp = []
//projdi pole z parametru
for(var i = array.length; i >= 0;i--){
//projdi seřazené pole
var found = false;
for(j = temp.length; j >= 0;j--){
//zkontroluj duplicitu
if(array[i] == temp[j]) {
found = true;
}
}
//pokud ještě není v poli, přidej
if(!found) {
temp.push(array[i]);
}
}
return temp;
}
Konstanty v této lekci
V této lekci opět využívám již více konstant pro popis akce pro program Adobe Photoshop. Jako v předchozích lekcí je přehled konstant možné najít v rozšířených skriptovacích příručkách v dodatku nebo v github repozitáři zde. Vyvětlení konstant: Dcmn dokument třídy, Ordn druh výčtu, Trgt cíl, NmbL klíčové číslo vrstvy, Lyr třída vrstvy, textKey text jako klíč, textStyleRange seznam textů, textStyle textové styly, fontPostScriptName dané fonty PostScriptu.
Funkce pro vrácení fontů
Teď již mám vše připravené a mohu vytvořit hlavní funkci pro získání fontů z vrstev. Vytvořím si objekt
třídy ActionReference a následně do něj vložím konstanty pro procházení.
Celý objekt poté vložím do metody executeAction, kde ještě dodám, že chci vrátit číslo. Tedy
počet vrstev plus jedna, jelikož hodlám zahrnout i pozadí.
Počet si uložím do proměnné a zárověň si vytvořím pole pro získané fonty. Dále vytvořím první cyklus,
který má za úkol projít všechny vrstvy, cyklus jde od největšího po nulu a to z toho důvodu, že
maximální index má v programu Adobe Photoshop vždy první vrstva, tedy z většiny případů vrtsva pozadí.
V cyklu si vytvořím referenci, descriptor, seznam pro fonty. Do reference vložím aktuální
vrstvu, která je pro ActionDescriptor jako navrátová hodnota z metody executeAction pro
popsání objektu. Toto musím obalit do bloku
try {}catch(){}, abych ošetřil výjimku, že vrstva neosahuje fonty, v případě výjimky
jednoduše pokračuji dál. Poté se zeptám jestli ActionDescriptor obsahuje klíč pro font. V
případě že ne, přeskočím na další vrstvu.
Pokud obsahuje font, pomocí metody getObjectValue() získám seznam fontů. Ten v následujícím cyklu
procházím a jako při obyčejné práci s pole k němu přes
index přistupuji, stejnou metodou si vrátím font a ten poté vložím na konec pole. Nakonci již pouze
vrátím pole fontů, které ovšem může obsahovat i duplicitní prvky. Toto vše ilustruje kód níže.
function getFonts() {
var actionRef = new ActionReference();
actionRef.putEnumerated(charIDToTypeID('Dcmn'),charIDToTypeID('Ordn'),charIDToTypeID('Trgt'));
//získání počtu vrstev
var countLayers = executeActionGet(actionRef).getInteger(charIDToTypeID('NmbL'))+1,
fonts = [];
//procházení každé vrstvy
for(var i = countLayers; i >= 0; i--){
var reference = new ActionReference();
var descriptor;
var list;
//získání vrstvy do reference
reference.putIndex( charIDToTypeID( 'Lyr ' ), i );
// získání popisu
try {
descriptor = executeActionGet(reference);
} catch (e) {
continue;
}
// pokud popis obsahuje klíč fontu
if(!descriptor.hasKey(stringIDToTypeID( 'textKey' )))
continue;
//získání seznamu fontů
list = descriptor.getObjectValue(stringIDToTypeID('textKey'))
.getList(stringIDToTypeID('textStyleRange'));
if(!list) continue;
//prochází seznamu a vkládání fontu do pole
var countStyles = list.count;
while (countStyles--) {
var textStyle = list.getObjectValue(countStyles)
.getObjectValue(stringIDToTypeID('textStyle'));
//pokud neobsahuje proměnná fontPostScriptName, pokračuj
if(!textStyle || !textStyle.hasKey(stringIDToTypeID('fontPostScriptName'))) continue;
var n = textStyle.getString(stringIDToTypeID('fontPostScriptName'));
fonts.push(n);
}
}
//využití funkce pro eliminování duplicit a setřídění metodou sort()
return getArrayWithoutDuplicits(fonts).sort();
}
Vypsání fontů uživateli
V poslední části jen zbývá vypsat velikost pole a obsah pole uživateli, to provedu jednoduchou metodou alert(), v které zároveň použiji metodu join() pro spojování řetězců.
if (documents.length) {
var fonts = getFonts();
alert(" Nalezené fonty: \n'+fonts.join('\n')", "Počet fontů " + fonts.length);
}else{
alert("Žádný dokument není otevřený.", "Varování");
}
Závěr
Na závěr této lekce bych chtěl dodat upozornění k tomuto skriptu. Při psaní jsem objevil chybu, která může způsobit nepřesné provedení skriptu. Jedná se o případ kdy při čerstvě špuštěném Photoshopu může Photoshop špatně, či vůbec nastavit atribut textové vrstvy. Konkrétně postScriptName atribut. V případě změny fontů, se atribut přenastaví a problém nenastane. Ovšem při počátečních hodnatách se při prvním zadaní může tato chyba objevit. Je to chyba v programu a ani po dlouhém hledání na developerských fórech a příručkách, jsem nebyl schopný najít odpověď na tento nedostatek, ani najít způsob jak se mu vyvarovat. Proto bych v závěrem této lekce na tuto chybu upozornil a varoval tak uživatele, který skript použijí.
Výsledný zdrojový kód
if (documents.length) {
var fontsFound = getFonts();
alert('Nalezené fonty: \n' + fontsFound.join('\n'), "Počet fontů: " + fontsFound.length);
}
function getArrayWithoutDuplicits(array) {
//pole
var temp = []
//projdi pole z parametru
for (var i = array.length; i >= 0; i--) {
//projdi seřazené pole
var found = false;
for (j = temp.length; j >= 0; j--) {
//zkontroluj duplicitu
if (array[i] == temp[j]) {
found = true;
}
}
//pokud ještě není v poli, přidej
if (!found) {
temp.push(array[i]);
}
}
return temp;
}
function getFonts() {
var actionRef = new ActionReference();
actionRef.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
//získání počtu vrstev
var countLayers = executeActionGet(actionRef).getInteger(charIDToTypeID('NmbL')) + 1,
fonts = [];
//procházení každé vrstvy
for (var i = countLayers; i >= 0; i--) {
var reference = new ActionReference();
var descriptor;
var list;
//získání vrstvy do reference
reference.putIndex(charIDToTypeID('Lyr '), i);
// získání popisu
try {
descriptor = executeActionGet(reference);
} catch (e) {
continue;
}
// pokud popis obsahuje klíč fontu
if (!descriptor.hasKey(stringIDToTypeID('textKey')))
continue;
//získání seznamu fontů
list = descriptor.getObjectValue(stringIDToTypeID('textKey'))
.getList(stringIDToTypeID('textStyleRange'));
if (!list) continue;
//prchází seznamu a vkládání fontu do pole
var countStyles = list.count;
while (countStyles--) {
var textStyle = list.getObjectValue(countStyles)
.getObjectValue(stringIDToTypeID('textStyle'));
//pokud neobsahuje proměnná fontPostScriptName, pokračuj
if (!textStyle || !textStyle.hasKey(stringIDToTypeID('fontPostScriptName'))) continue;
//nalezení názvu fontu
var n = textStyle.getString(stringIDToTypeID('fontPostScriptName'));
//vložení fontu do pole
fonts.push(n);
}
}
//využití funkce pro eliminování duplicit a setřídění metodou sort()
return getArrayWithoutDuplicits(fonts).sort();
}