PhotoshopScriptが糞でTextLayerのfont sizeが正しく取れないのでどうにかした件


Photoshopは、自分でScriptを書くことでいろいろなことが自動で出来ることは皆さんご存知ですよね?
結構便利ではあるのですが、糞のような仕様が紛れ込んでいたりします。
今回はそのうちの一つ、設定しているFont sizeが正しく取れないというバグ(仕様?)を紹介します。

Referenceを見ると、TextItemにsizeというフィールドが存在し、これを使うとFontSizeが取れそうと思いますよね?

if(layer.kind == LayerKind.TEXT) {
    var fontSize = layer.textItem.size.as("pt");
}

ところがどっこい、Photoshop上で表示されている値と違った値を返すことが多々発生し、全く使えません。
どういう時に発生するかというと、

  • Textを20ptで作成(フォント、文章はなんでも良い)
  • Transformして、2倍位の大きさに
  • Photoshop上での表示は40ptに変化
  • textItem.sizeを見ると20ptのまま(本当は40ptを返して欲しい)

つまり、textItem.sizeは常に初期に設定されたTransform前の値を返す仕様となっているようです。(ちなみに、ArtLayerのboundsから近似の値はとれますが、正確では無いです)
それじゃ、どうすれば良いかというと、

用意されているAPIでは、正しい値を取得すること出来ません。

はい、クソです。
とはいえどうにかしないと行けなかったので、どうにかしました。
PhotoshopScriptの中にはUIの操作を模倣できる機能があるので、それを利用してUI操作を模倣しUI上の値を取って来ることになります。そのコードが↓になります。

    /**
     * textItem.sizeで取れる値は初期設定値で、
     * LayerをScaleした場合、その情報が反映されていない。
     * そのため、正しい値を取得するにはActionReferenceを使用する必要がある
     */
    function getFontSize(layer /* ArtLayer */ ){

        selectLayer(layer);
        // read font size
        var ref = new ActionReference();  
        ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );   
        var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID('textKey'));  
        var textSize =  desc.getList(stringIDToTypeID('textStyleRange')).getObjectValue(0).getObjectValue(stringIDToTypeID('textStyle')).getDouble (stringIDToTypeID('size'));  
        if (desc.hasKey(stringIDToTypeID('transform'))) {  
            var mFactor = desc.getObjectValue(stringIDToTypeID('transform')).getUnitDoubleValue (stringIDToTypeID("yy") );  
            textSize = (textSize* mFactor).toFixed(2);  
        }  
        return textSize;
    }
    /**
     * Layer選択をする
     */
    function selectLayer(layer){

        var idslct = charIDToTypeID( "slct" );
        var desc = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
        var ref = new ActionReference();
        var idLyr = charIDToTypeID( "Lyr " );
        ref.putName( idLyr, layer.name ); // Pass layer name
        desc.putReference( idnull, ref );
        var idMkVs = charIDToTypeID( "MkVs" );
        desc.putBoolean( idMkVs, false );
        var idLyrI = charIDToTypeID( "LyrI" );
        var list = new ActionList();
        list.putInteger( layer.id );
        desc.putList( idLyrI, list ); // Pass layer id
        executeAction( idslct, desc, DialogModes.NO );
    }

何やっているコードかわかりませんよね?私もわかりません。Photoshopには、UI操作をScriptコードとして記録してくれるScriptingListenerと呼ばれる機能があり、そこに出てきたログをコピペしただけです。
ScriptingListenerを有効にする方法

次回、フィールドアクセスだけで例外(気が向いたら)