主にInDesignによる新聞組版Tips中心です。Mac使いですが業務はWin多め。Win DTP Tipsを増やしたい

テキストを選択順に書き出し【InDesign】EDICOLOR機能を再現(5)

InDesignのテキスト書き出しは、基本ストーリー単位・1つずつしかできません。

一括書き出しはスクリプトで可能ですが、単純に抜き出すとページも順序もバラバラ(※story ID順)、出したくないマスターやレイヤー上も対象、またページを跨ぐストーリーをは分断され、何故か他のストーリーと繋がってしま(った記憶)うなどそのままでは不都合だらけなのです。


以下、確かいき親分作(ネタ元は確かBBS)

flag = confirm("ドキュメント全テキストを順不同でUTF-8書き出し\r\r※欄外の不要テキストフレームは削除しておいて下さい¥r※色々ゴミが付くので、必ずエディタで後処理を。");
if (flag == true){
    var myObj = new File ("~/Desktop/_export.txt");
    var flagA = myObj.open ("w");
    myObj.encoding="UTF-8"; //エンコードは必ず付けよう

    if (flagA == true){
        var mytext = app.documents[0].stories.everyItem().contents;
        myObj.writeln (mytext);
        myObj.close();
        }else{
            alert ("書き込むためのファイルが開けません");
                }
        alert ("書き出しました");
        }else{
        alert("処理を中止しました");
            }

InDesignサンプルスクリプトExportAllStories.jsxを使えばストーリー切断は解消できますが、非出力レイヤーの制御やストーリー順の問題は解決できず、更にエンコーディングは前回利用時に依存し、コントロールができません。

スクリプトパネル→ アプリケーション→ Samples→ JavaScript→ ExportAllStories.jsx

というわけで、以下。ページ内に沢山のストーリーがある物、例えば漫画フキダシ等の書き出しに便利です。

InDesignCS5から選択順の認識が可能になり、実現できました(つまりCS4以下は不可)。

2013年頃原型を鯵ぼんさんに作って頂き、長らく自分だけで便利に使っていました。しかし検索すると解決できてる所は意外と見つけられず、これは需要があるのか?と考え、世のため多少のブラシュアップを加え公開する事に。こういうの幾つかあるんですよね… 自分で使っているものを公開しようという発想がありませんでした←


選択フレームのContentsをforと+=で変数の後ろに加算していき、新規作成するInDesignドキュメントのテキストフレームに配置。更にInDesignで新規*.txtを作成保存し、それに先のInDesignドキュメントの内容を書き込む。基本的には最初のいき親分の進化系ですね。

それに最低限の記号類の整理(検索と置換)と、テキストフレーム以外を選択した時のエラー処理を追加しました。普段は検索置換をもっと増やして、親フォルダ名を追加したりしています。

  • Desktopに「myText」フォルダーを作り、保存。連番は「01,02....」
  • インラインオブジェクトやアンカーはゲタに置き換え、表組み非対応
  • 当然スプレッド単位
  • UTF-16/BOMなし
  • LineFeed(改行コード)は指定しない方が良さげ(組み合わせ次第では文字化けする)
  • 検索置換部分は、市川せうぞー大先生の丸パクリ


テキストを選択順に書き出し

//DESCRIPTION:テキストフレームを選択順に書き出し(らーで閣下)
//インラインやミッシンググリフ、インデント分割系の処理だけは入れた

var mySel = app.selection;
if (mySel.length < 1)
{ alert ("何も選択されていません"); exit(); }
else {
    //activeDocumentのテキストを整形 ////////////////////////////////////////////////////////
    //文字列を16進数にエスケープして、「\x{hex}」という形で返す。    
        function my_escape(str) {
            tmp_str = escape(str);
            return tmp_str.replace(/\%u([0-9A-F]+)/i, "\\x{$1}")
            }
        //正規表現検索でカタカナを16進に変換--------------------------------------
        function katakana2hex() {
            var find_str = app.findGrepPreferences.findWhat;
            while (/([ァ-ヴ])/.exec(find_str)) {
                find_str = find_str.replace(/([ァ-ヴ])/, my_escape(RegExp.$1));
                }
            app.findGrepPreferences.findWhat = find_str;//検索文字の設定
            }
        //実行:その1(Grep)--------------------------------------------------------------
        function my_RegexFindChange(my_range, my_find, my_change) {
            //検索の初期化
            app.findGrepPreferences = NothingEnum.nothing;
            app.changeGrepPreferences = NothingEnum.nothing;
            //検索オプション
            app.findChangeGrepOptions.includeLockedLayersForFind = false;//ロックされたレイヤーをふくめるかどうか
            app.findChangeGrepOptions.includeLockedStoriesForFind = true;//ロックされたストーリーを含めるかどうか
            app.findChangeGrepOptions.includeHiddenLayers = false;//非表示レイヤーを含めるかどうか
            app.findChangeGrepOptions.includeMasterPages = true;//マスターページを含めるかどうか
            app.findChangeGrepOptions.includeFootnotes = true;//脚注を含めるかどうか
            app.findChangeGrepOptions.kanaSensitive = true;//カナを区別するかどうか
            app.findChangeGrepOptions.widthSensitive = true;//全角半角を区別するかどうか

            app.findGrepPreferences.properties = my_find;//検索の設定
            app.changeGrepPreferences.properties = my_change;//置換の設定
            my_range.changeGrep(); //検索置換を実行
            }
        var my_doc = app.documents[0]; //範囲
        var my_find_obj = {findWhat:"[\uFFFC\uFFFD\u001A]"};
        //replacmentObject(インライン)・replacmentCharacter(置き換えられた文字)・substitute(ミッシンググリフ等)
        var my_change_obj = {changeTo:"〓"};
        my_RegexFindChange(my_doc, my_find_obj, my_change_obj);
    //実行:その2(Grep)--------------------------------------------------------------
    function my_RegexFindChange(my_range, my_find, my_change) {
        //検索の初期化
        app.findGrepPreferences = NothingEnum.nothing;
        app.changeGrepPreferences = NothingEnum.nothing;
        app.findGrepPreferences.properties = my_find;//検索の設定
        app.changeGrepPreferences.properties = my_change;//置換の設定
        my_range.changeGrep(); //検索置換を実行
        }
    var  my_doc = app.documents[0]; //範囲
    var my_find_obj = {findWhat:"[\u2011\u0007\u0008\u000A\u000B\u0003\u200C\u00A0\u202F\u2008\u2007\u2028\u2029\u2001\u200B\u0019\u00A7]"};
    //分散禁止ハイフン・ここまでインデント・右インデントタブ・LF・垂直タブ・先頭文字スタイルの終了(EOT)・結合なし・分散禁止スペース・分散禁止スペース固定幅・句読点等の間隔・数字の間隔・行区切り文字・段落区切り文字・フラッシュスペース・任意の改行(強制改行)・セクションマーカー・セクション記号
    var my_change_obj = {changeTo:""};
    my_RegexFindChange(my_doc, my_find_obj, my_change_obj);
    //検索置換の終了 ///////////////////////////////////////////////////////////////////////////////////////////

//main ////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (i=0; i<mySel.length; i++)
if (mySel[i].constructor.name != "TextFrame")
{
    alert ("テキストフレーム以外を選択しています(グループも不可)\r\r処理を中断します");
    app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
    var rvt = app.documents[0].revert();
    app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL; 
    exit(); }
else
{
    var myContents = "";
    for (j=0; j<mySel.length; j++)
    {
        myContents += mySel[j].parentStory.contents; //(+=)加算
        if (j<mySel.length -1)
        myContents = myContents + "\r\r"; //フレーム間を改行で区切る
    }
}
    //New Documentを作成・myContentsを書き込んで*.txt保存---------------------
    myFolder = new Folder("~/Desktop" + "/" + "myText" );
    myFolder.create();
    var newDoc = app.documents.add();
    var tf = newDoc.textFrames.add();
    tf.contents = myContents;
    var fileList = myFolder.getFiles(); //doc名に連番を振る為のList
    var myFileList = fileList.length;
    var myFile = new File(myFolder + "/" + "0" + (myFileList+1) + ".txt");
    myFile.open("w");
    myFile.encoding="UTF-16"; //UTF-8
    //myFile.lineFeed = "windows"; //macintosh
    myFile.write(myContents); //*.txtにmyContentsを書き込む
    app.documents[0].close(SaveOptions.no); //用済みnewDocを保存せず閉じる
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//処理前=最後の上書きまで復帰(確認アラートを出さない)
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
var rvt = app.documents[0].revert();
app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL; 
alert ("デスクトップの「myText」フォルダーに保存しました");
}

改行がバラバラなのは勘弁してね(

確実に選択したか認識するために、こちら選択数を表示パレットを併用下さい。

表組みとインラインは… まず中へ潜りContents取得、行列数やインラインの場所・位置を記録してその位置へペースト…などかなり面倒で← 表テキスト保存はセルID順にひたすらタブで繋げられ、素では行で折り返されないのです。そういうトコが、腕の見せ所だろうに

因みにサンプルスクリプトExportAllStories.jsxは、不要レイヤーの削除とドキュメントの見開き保存、からのPDF Exportなどを書き足し、顧客への納品に使ったりしています。


余談ですが、私は前処理としてグループを解除する場合に、あるふぁ(仮)さんによる「入れ子のないグループ」の下に、改めてグループ解除を付け足して運用しています。

// 入れ子グループをまとめる-------------------------------------------
app.doScript(main,ScriptLanguage.JAVASCRIPT,[],UndoModes.FAST_ENTIRE_SCRIPT);
function main(){
    var myDocu=app.activeDocument;
    var Sel=myDocu.selection;
    if (Sel.length==1 && Sel[0].constructor.name=="Group"){
    IrekoGroupKaijo(Sel[0]);
} else if (Sel.length>1) {
    SelGroup=myDocu.groups.add(Sel);
    IrekoGroupKaijo(SelGroup);
    SelGroup.select();
    }
}
function IrekoGroupKaijo(GObj){
    while(GObj.groups.length>0){
    //グループを破壊するのでダルマ落とし的に次のグループがgroups[0]に
    GObj.groups[0].ungroup();
    }
}
    //-----------------------------------------------------------------------
    var myDoc = app.activeDocument;
    var mySel = myDoc.selection;
    //myDoc.preferences.GeneralPreference. //環境設定→ 一般 → オブジェクトの編集→ロックされたオブジェクトの選択を防ぐ = false

    for (i=0; i<mySel.length; i++){
    if (mySel[i].constructor.name == "Group")
    mySel[i].ungroup();
    }