DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

保存バージョン以外のInDesignで開くのを警告したい

はじめに

繁忙期も佳境になり、仕事に忙殺されております。
しかしだからこそ、スクリプトという享楽に打ち込んでしまうのもまた必然…。

それはさておき、できそうだなと思って取り組んでこなかったスクリプトができてしまったので紹介したいと思います。
以前東京のDTP勉強会(2017年10月21日開催回)で登壇させていただいたときに紹介した、保存バージョンをチェックするスクリプトがありました。ご存知ない方はこちらで↓。
スライド(PDF)
配布資料(PDF)
そのスクリプトは、ファイルを開いた際に、ファイルを保存したときに記録されたバージョン表記と、今現在実際に動作させているInDesignのバージョンを比較し、それが一致しなければその旨の警告を出すというものでした。これは警告を出すものの、ファイル自体は開きます。
というか、ファイルを開くという動作の間にファイル情報を調べる処理を仕込んだだけで、実際にはアプリケーションの動作に何も手を挟みません。

また、こういった「保存バージョンを確認して開く」手助けをしてくれるアプリケーションが実はもうあります。Macであればものかのさんの「Glee」、Winであればお〜まちさんの「open_the_indd」があります。どちらも拡張子の関連付けをおこない、Finder(エクスプローラ)上でダブルクリックするだけで、保存されたInDesignのバージョンでファイルを開くことができるという素晴らしいアプリケーションです。

で、これから紹介するスクリプトは、あくまでInDesignで動作するスクリプトです。なのでFinderでダブルクリックしてもバージョンを選んで開いてくれたりはしません。
その代わり、これらのアプリケーションを介さない方法でファイルを開いても(InDesignにファイルをドラッグ、もしくは右クリックから開くInDesignを指定など)、水際で開くバージョンを確認することができます。
挙動としては、一旦「違うバージョンのInDesignで開こうとしているけど、本当に開いていいんだよね?」という確認をします。それでも「いいよ、開いて!」とゴーサインを出してから初めて開くようにするものです。

動作画面

まずは百聞は一見に如かずということで、動作をGIFにしましたのでご覧ください。
f:id:uske_S:20180317034217g:plain ここで「はい」(InDesignのバージョンによってはYes)を選択するとファイル開き、「いいえ」(もしくはNo)を選択するとファイルを開く動作を中断します。要するにファイルを開きません。
見かけの動作としては本当にこれだけなので、派手さはまったくありませんw

コード

#targetengine versionChecker2

app.addEventListener ("beforeOpen", function (e){
    
    //XMPメタデータを読み書きするライブラリ
    //このXMPtoolライブラリについては、Ten A先生の記事
    //https://goo.gl/oEg2QE
    //より拝借しました。詳細はこちらの記事をご参照ください。
    var XMPtool = {
       ns : "hoge",
       prefix : "fuga:",//custom metada
       f : new Object(),
       read : function(prop){//read exist custom metadata.
       if(xmpLib==undefined) var xmpLib = new ExternalObject('lib:AdobeXMPScript');
          var xmpFile = new XMPFile(this.f.fsName, XMPConst.UNKNOWN, 
          XMPConst.OPEN_FOR_READ);
          var xmpPackets = xmpFile.getXMP();
          var xmp = new XMPMeta(xmpPackets.serialize());
          return xmp.getProperty(this.ns, prop).toString();
       },
       write : function(prop, val){ 
       //argumetns{prop:String/property of custom metadata, val1:String/value} 
         if(xmpLib==undefined) var xmpLib = 
            new ExternalObject('lib:AdobeXMPScript');
          var xmpFile = new XMPFile(this.f.fsName, 
              XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
          var xmp = xmpFile.getXMP();
          var mt = new XMPMeta(xmp.serialize());
          XMPMeta.registerNamespace(this.ns, this.prefix);
          mt.setProperty(this.ns, prop, val);
          if (xmpFile.canPutXMP(xmp)) xmpFile.putXMP(mt);
          xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
          }
       }
    XMPtool.ns = "http://ns.adobe.com/xap/1.0/"; //XMP name space
    XMPtool.f = File(e.fullName);
    var creatorTool = XMPtool.read("CreatorTool"); //read "CreatorTool" from XMPfile

    //取得したCreatorToolから必要な部分を正規表現で抽出
    var createdVer = creatorTool.match(/((CC( [0-9\.]+)*)|(CS)?[0-9\.]{1,3})/)[1];
    
    //保存バージョンを[表示バージョン名, メジャーバージョン数値]に変換する
    var myVerLib;
    switch (createdVer){
        case "3.0": myVerLib = ["CS", 3]; break;
        case "4.0": myVerLib = ["CS2", 4]; break;
        case "5.0": myVerLib = ["CS3", 5]; break;
        case "6.0": myVerLib = ["CS4", 6]; break;
        case "7.0": myVerLib = ["CS5", 7]; break;
        case "7.5": myVerLib = ["CS5.5", 7.5]; break;
        case "CS6": myVerLib = ["CS6", 8]; break;
        case "CC": myVerLib = ["CC", 9]; break;
        case "CC 2014": myVerLib = ["CC2014", 10]; break;
        case "CC 2015": myVerLib = ["CC2015", 11]; break;
        case "CC 2017": myVerLib = ["CC2017", 12]; break;
        case "CC 13.0": myVerLib = ["CC2018", 13]; break;
        default: myVerLib = ["判別できないバージョン", 0];
        }
    
    //現在開いているInDesignのバージョンのメジャーバージョン(CS5.5は7.5とする)
    var appVer = (parseFloat(app.version) === 7.5)? 7.5: parseInt(app.version, 10);
    
    //メジャーバージョンチェック
    if (myVerLib[1] !== appVer){
        if (!confirm (myVerLib[0]+"で保存されたデータです。開いてよろしいですか?")){
            e.preventDefault();
            return;
            }
        }
    });

そこそこ長いのでjsxファイルを末尾に用意してあります。コピペではなくダウンロードしたい方はそちらをご利用ください。

説明など

勉強会のときのスクリプトと話が行ったり来たりで申し訳ないのですが、勉強会で紹介したスクリプトafterOpenイベントを利用していました。つまり、ファイルを開いた後でスクリプトを実行し、開いているDocumentオブジェクトからメタデータを読み込むという手法でした。
ですが今回は開く前に確認ダイアログを出したかったので、beforeOpenイベントを使いました。
ここで最初のつまづきがあったのですが、イベントの引数にDocumentオブジェクトが入ってこないのです。

app.addEventListener ("beforeOpen", function (e){

冒頭にあるイベントリスナーを定義する部分ですが、このeにイベントのトリガーとなったものが入ってくるのがイベントスクリプトの仕組みです。勉強会のときのスクリプトafterOpenイベントだったので、この引数にはDocumentオブジェクトやLayoutWindowオブジェクトが入っていました。
ですが今回の引数のe.targetを調べてみたところ、Applicationオブジェクトだったのです。
これから開こうとしているファイルをどのように取得すればいいやら…と思って、Adobe自動化総合フォーラムにこのことを書き込んでみました。

forums.adobe.com

で、やっぱりTen A先生にご教示いただきましたw
そう、e.fullNameでファイルパスが取れる!
そこからFileオブジェクトで実際のファイルを特定できた!

というところまでは良かったのです…。
勉強会のスクリプトは、DocumentオブジェクトからmetadataPreferencesプロパティにアクセスして保存バージョンを取得しました。今回はFileオブジェクトからメタデータにアクセスしなくてはならなかったのです(FileオブジェクトにmetadataPreferencesプロパティはありません)。
仕方なく、

for (key in fileObj) $.writeln(key + ": " + fileObj[key]);

とかってやってプロパティを調べようと思ったんですけど、結果は




何もコンソールに取得できない…。久しぶりに絶望を味わった瞬間…。
気を取り直して、Fileオブジェクトのメタデータ、つまりXMPにアクセスする方法を調べると、あったのです。それも超便利なライブラリとして。

goo.gl

またかよ! またTen A先生かよ!www
ってまじで思いました。本当にありがとうございます。冒頭のXMPtoolの部分は記事からほとんどそのまま拝借しています。
ということで、僕のコードはその下からです。

XMPtool.ns = "http://ns.adobe.com/xap/1.0/"; //XMP name space
XMPtool.f = File(e.fullName);
var creatorTool = XMPtool.read("CreatorTool"); //read "CreatorTool" from XMPfile

XMPにアクセスするにはname spaceの指定が必要なのでそれを与えます。続いてイベントの引数からファイルを特定してFileオブジェクトとします。これをもとにXMPからCreatorToolの部分を読み込みます。簡単すぎて笑っちゃいますね。これで保存バージョンを取得できました。
あとは勉強会のときのスクリプトとほとんど変わりません。

//取得したCreatorToolから必要な部分を正規表現で抽出
var createdVer = creatorTool.match(/((CC( [0-9\.]+)*)|(CS)?[0-9\.]{1,3})/)[1];

正規表現で必要な部分だけを抽出します。この正規表現も、InDesignのバージョン表記に合わせて適宜書き換えていく必要がありますので注意してください。この正規表現はCS3〜CC2018(13.x)まで対応しています。

//保存バージョンを[表示バージョン名, メジャーバージョン数値]に変換する
var myVerLib;
switch (createdVer){
    case "3.0": myVerLib = ["CS", 3]; break;
    case "4.0": myVerLib = ["CS2", 4]; break;
    case "5.0": myVerLib = ["CS3", 5]; break;
    case "6.0": myVerLib = ["CS4", 6]; break;
    case "7.0": myVerLib = ["CS5", 7]; break;
    case "7.5": myVerLib = ["CS5.5", 7.5]; break;
    case "CS6": myVerLib = ["CS6", 8]; break;
    case "CC": myVerLib = ["CC", 9]; break;
    case "CC 2014": myVerLib = ["CC2014", 10]; break;
    case "CC 2015": myVerLib = ["CC2015", 11]; break;
    case "CC 2017": myVerLib = ["CC2017", 12]; break;
    case "CC 13.0": myVerLib = ["CC2018", 13]; break;
    default: myVerLib = ["判別できないバージョン", 0];
    }

ここでswitch文を使って、XMPから得られた保存バージョン情報の部分をふるいにかけています。ただCS2以下はもう面倒くさいので「判別できないバージョン」として一括りにしてしまいました^^;;

//現在開いているInDesignのバージョンのメジャーバージョン(CS5.5は7.5とする)
var appVer = (parseFloat(app.version) === 7.5)? 7.5: parseInt(app.version, 10);

現在動作しているInDesignのバージョンを取得しています。CS5.5なんて中途半端なのがいなければ、

parseInt(app.version, 10);

だけで済んだのですよ?

//メジャーバージョンチェック
if (myVerLib[1] !== appVer){
    if (!confirm (myVerLib[0]+"で保存されたデータです。開いてよろしいですか?")){
        e.preventDefault();
        return;
        }
    }

最後にそれぞれのバージョンを比較し、バージョンが違う場合はダイアログを出して確認します。その上でやっぱりやめた! ということであれば、

e.preventDefault();

このメソッドを使ってファイルを開こうとする動作を終了させます。このメソッド自体は、勉強会のスクリプトの3つめ、PDF書き出し前チェックリスト表示でも紹介したものです。
こうして、無事に「保存バージョンをチェックして、開く前に確認し、開きたくなければそのまま開かない」ってスクリプトができあがりました。

ダウンロード

このスクリプトファイルはこちらからどうぞ。

www.dropbox.com

startup scriptの使い方がわからない方は、記事先頭の勉強会のスライドを見てください^^/
そんなこんなでTen A先生に大変お世話になったスクリプトですが、こんなこともできるInDesignスクリプトは最高に面白いですね。