使用Photoshop脚本更改选定文本图层的语言

4

虽然我已经成功地编写了一个功能脚本来更改选择层的词典语言,但它还不完全符合我的需求。

目前我正在检索所选层的索引,使用它们获取层名称——这是问题所在——然后根据自定义对话框中选择的选项来更改它们的语言。

使用层名称是一种非常笨拙的解决方案,我需要精度,我需要能够根据层ID或索引来更改语言。我的脚本不仅容易出现名称冲突,而且我也不知道选择的层将在哪里,是在文档的根部还是在5个层组堆栈中。

以下是我的当前代码:

主函数

function main() {
    // Create window with language selection and retrieve selected value
    var lang = createWindow();

   // Retrieve selected layers
   var selectedLayers = getSelectedLayersIdx();

   // Look at each entry and change language when possible
   for(var a in selectedLayers){
        try {
           setLangByIndex(Number( selectedLayers[a]), lang );
        } catch(err) {   }
   }
}

(createWindow返回一个lang值,跳过该内容)

迈克的get Idx

function  getSelectedLayersIdx(){
    var selectedLayers = new Array;
    var ref = new ActionReference();
    ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
    var desc = executeActionGet(ref);
    if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) {
        desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
        var c = desc.count
        var selectedLayers = new Array();
        for(var i=0;i<c;i++) {
            try{
                activeDocument.backgroundLayer;
                selectedLayers.push(  desc.getReference( i ).getIndex() );
            } catch(e) {
                selectedLayers.push(  desc.getReference( i ).getIndex()+1 );
            }
        }
    } else {
        var ref = new ActionReference();
        ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' ));
        ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
        try {
            activeDocument.backgroundLayer;
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ))-1);
        } catch(e) {
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' )));
        }
    }
    return selectedLayers;
}

设置语言的功能
function setLangByIndex(idx, lang){
    ref = new ActionReference();
    ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm  " ));
    ref.putIndex( charIDToTypeID( "Lyr " ), idx );
    var name = executeActionGet(ref).getString(charIDToTypeID( "Nm  " ));

    var el = activeDocument.layers.getByName( name );
    // Temp quick block; MUST UPDATE IN CASE OF NEW LANGUAGES
     if (lang == 'pt_br' )
        el.textItem.language = Language.BRAZILLIANPORTUGUESE;
    else if (lang == 'en_us' )
        el.textItem.language = Language.ENGLISHUSA;
    else
        el.textItem.language = Language.ENGLISHUK;
}

我尝试的低效解决方法:

  • 使用Adobe的脚本监听器和executeAction来更改语言,但无法使其正常工作。语言部分位于 ~4 个堆叠描述符(和一个列表!)中。我迷失了方向并不断出现错误8800。
  • 试图通过使用 idx 来获取对象引用。失败了。

没有一个示例PSD文件,调试起来有点困难。你能否上传一个非常简化的PhotoShop文档?如果你要上传,也可以同时上传这些脚本吗? - Tahir Ahmed
我今天早上又尝试了一次,成功了!我使用的 Script Listener 输出在这里可以找到:http://pastebin.com/U9fQKLvG这是我的当前脚本:http://pastebin.com/kZf8aeDY 我暂时不会将其发布为答案,只是想看看是否有更好的建议(我的编码能力很差!)。我使用完整的 set 操作,因为 Override 不接受 idx。PSD 示例(我认为不再需要,但…):http://goo.gl/C9SdNu 值得注意的是,我将在不同文件上使用此脚本,因此脚本不应仅针对此示例进行调整。 - Rhaenys
1个回答

0

在我注意到一些与段落样式相关的烦人故障后(这些故障是您可以在PS上定义为文本默认值的样式,而不是JS对象),我放弃了固执的想法,停止避免通过索引数组进行新循环以在完成后重新选择图层。

/*
   *  Based in Mike Hale's "getSelectedLayersIdx" script and Adobe's Scripting Listener dump.
      Based the panel on Davide Barranca's code: http://www.davidebarranca.com/2012/10/scriptui-window-in-photoshop-palette-vs-dialog/

      Useful Resources:
      Photoshop char list: http://www.pcpix.com/Photoshop/char.htm
      ActionDescriptor methods: http://jongware.mit.edu/pscs5js_html/psjscs5/pc_ActionDescriptor.html
      TextItem methods: http://jongware.mit.edu/pscs5js_html/psjscs5/pc_TextItem.html
      You can fish for language codes here: http://wingp.googlecode.com/svn/photogp/photoshopapi/photoshop/PIStringTerminology.h
*/

/* ______________________________ SCRIPT ______________________________ */
var scriptAlert = "Language Change says";

// MUST UPDATE IF YOU WANT TO CHANGE THE AVAILABLE LANGUAGES
// The available languages, as { text displayed on dialog window : codename }. See notes above for more language codes
var langs = {};
langs['Português (Brasil)'] = 'brazilianPortugueseLanguage';
langs['English (UK)'] = 'ukenglishLanguage';
langs['English (USA)'] = 'englishLanguage';

if(app.documents.length>0){ // the script will be executed  only if an active document exists.

    var imgName = activeDocument.name;
    var extreme= imgName.substr(imgName.length - 5, 5);
    var dot = extreme.lastIndexOf(".");

    if(dot == -1) { // Checks if the active document  was saved or not.
        alert("Please, save your document!", scriptAlert, false);
    } else {
        main(); // if the active document was saved, go ahead! 
    }
}


function createWindow() { // Creates a panel asking for input
        var isDone, win, windowResource, radio_group, cancel, rb, i;

        //sentinel variable
        isDone = false;
        cancel = false;

        // Build dialog radio buttons
        i = 0;
        for( var k in langs ) {
            if( i==0 )
                rb = "rb"+i+": RadioButton { text:  '"+k+"', value: 1 }, \ ";
            else
                rb += "rb"+i+": RadioButton { text:  '"+k+"' }, \ ";
            i++;
        }

        windowResource = "palette {  \
            orientation: 'column', \
            alignChildren: ['fill', 'top'],  \
            preferredSize:[300, 130], \
            text: 'Change Spell Check Language',  \
            margins:15, \
            \
            optPanel: Panel { \
                orientation: 'row', \
                alignChildren: 'left', \
                margins:15, \
                text: ' Select the desired dictionary language for the select text ', \ "+  rb + " \
                } \
            \
            bottomGroup: Group{ \
                cancelButton: Button { text: 'Cancel', properties:{name:'cancel'}, size: [120,24], alignment:['right', 'center'] }, \
                applyButton: Button { text: 'Ok', properties:{name:'ok'}, size: [120,24], alignment:['right', 'center'], active: true }, \
            }\
        }";
        win = new Window(windowResource);

        radio_group = win.optPanel; // set group

        // Match options with language
        function selected_rbutton (rbuttons)
        {
             for (var i = 0; i < rbuttons.children.length; i++)
                 if (rbuttons.children[i].value == true)
                    return langs[rbuttons.children[i].text];
         }

        win.bottomGroup.cancelButton.onClick = function() {
            win.close();
            return cancel = true;
        };      
        // Button listeners
        win.bottomGroup.applyButton.onClick = function() {
          return isDone = true;
        };             
        // don't forget this one!
        win.onClose = function() {
            return cancel = true;
        };

        win.addEventListener("keydown", function (k)
         {
             if (k.keyName == 'Enter')
                return isDone = true;
         });

        win.show();

        while (isDone === false) {
            try {
                app.refresh();
            } catch(err) { // Esc cancels without errors
                return false;
            }
        }

       return cancel ?  false : selected_rbutton (radio_group); // return value, or false if cancelled
}


function  getSelectedLayersIdx(){ // Gets array of indexes of selected layers
    var selectedLayers = new Array;
    var ref = new ActionReference();
    ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
    var desc = executeActionGet(ref);
    if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) {
        desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
        var c = desc.count
        var selectedLayers = new Array();
        for(var i=0;i<c;i++) {
            try{
                activeDocument.backgroundLayer;
                selectedLayers.push(  desc.getReference( i ).getIndex() );
            } catch(e) {
                selectedLayers.push(  desc.getReference( i ).getIndex()+1 );
            }
        }
    } else {
        var ref = new ActionReference();
        ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' ));
        ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
        try {
            activeDocument.backgroundLayer;
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ))-1);
        } catch(e) {
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' )));
        }
    }
    return selectedLayers;
}


function selectLayerByIndex( selectedLayers, add ){ // Selects layers by index. If fed an array + true add, selects them, otherwise provide a single value so it selects a single layer
    if (typeof(add)==='undefined') add = false;

    if ( add ) // If Add it's an array
        for(var a in selectedLayers){
            var desc = new ActionDescriptor();
                var ref = new ActionReference();
                ref.putIndex( charIDToTypeID( "Lyr " ), Number(selectedLayers[a]) );
            desc.putReference( charIDToTypeID( "null" ), ref );
            desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
            var idMkVs = charIDToTypeID( "MkVs" );
            desc.putBoolean( charIDToTypeID( "MkVs" ), false );

            executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
        }
    else // Else I just need to make this layer active, it's a number
    {
            var desc = new ActionDescriptor();
                var ref = new ActionReference();
                var idLyr = charIDToTypeID( "Lyr " );
                ref.putIndex( charIDToTypeID( "Lyr " ), selectedLayers );
            desc.putReference( charIDToTypeID( "null" ), ref );
            desc.putBoolean( charIDToTypeID( "MkVs" ), false );
        executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
    }
}


function setLangByIndex( idx, lang ){ // Sets the dictionary language for a text layer based on its index
// Make layer active
    selectLayerByIndex( idx );

// And do tiny override
    var textObj = new ActionDescriptor();
        var target = new ActionReference();
        target.putProperty( charIDToTypeID( "Prpr" ), charIDToTypeID( "TxtS" ) ); // desired property: text style
        target.putEnumerated( charIDToTypeID( "TxLr" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) ); // the active layer
    textObj.putReference( charIDToTypeID( "null" ), target );
        var textStyle = new ActionDescriptor();
        textStyle.putInteger( stringIDToTypeID( "textOverrideFeatureName" ), 808466225 );
        textStyle.putInteger( stringIDToTypeID( "typeStyleOperationType" ), 3 );
        textStyle.putEnumerated( stringIDToTypeID( "textLanguage" ), stringIDToTypeID( "textLanguage" ), stringIDToTypeID( lang ) );

    textObj.putObject( charIDToTypeID( "T   " ), charIDToTypeID( "TxtS" ), textStyle ); // to (end); text style, desc.
executeAction( charIDToTypeID( "setd" ), textObj, DialogModes.NO ); // execute
}


////////////////////////////////////
// Main function
function main() {
    // Create window with language selection and retrieve selected value
    var lang = createWindow();

    if ( !lang ) // If cancelled please stop
        return;

     // Retrieve selected layers
     var selectedLayers = getSelectedLayersIdx();

    // Look at each entry and change language when possible; otherwise skip to next item
    for(var k in selectedLayers){
       try {
            setLangByIndex(Number(selectedLayers[k]), lang);
        } catch(err) {
            continue;
        }
    }
    selectLayerByIndex( selectedLayers, true );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接