2008年5月30日金曜日

Illustratorで文字あふれしたテキストフレームを全選択する

Illustratorで、文字あふれしているテキストフレームだけををすべて選択するスクリプトです。
...


#target Illustrator

Application.active

//まず選択解除
app.activeDocument.selection = null;

doc = app.activeDocument;
Frs = doc.textFrames;
visibleText = "";

for(Fr=0; Fr < Frs.length; Fr++){

//あふれ部分含む全テキスト抽出
allText = Frs[Fr].contents;

//改行をすべて取る
allText = allText.replace(/\r/g, "");

//あふれていないテキスト部分だけを抽出する
for(i=0; i < Frs[Fr].lines.length; i++) {
visibleText = visibleText + Frs[Fr].lines[i].contents;
}

if(allText != visibleText) {
Frs[Fr].selected = true;
}
}

alert("文字あふれは" + doc.selection.length + "個所");


textFrameのlinesプロパティでは表示されているテキストだけが取得されることを利用して、フレーム内の全テキストと表示テキストの文字列が違った場合に、文字あふれしていると判断します。
なぜこんな処理をするかというと、テキストフレームにオーバーフローのプロパティがない(らしい)からです(あったら教えて…)。

表示テキストを取得する際に、linesプロパティでは改行コードが取り出せません。表示テキストには改行がなくて、全テキストには改行があるということでは両者を正しく比較できないので改行を戻してやる必要がある…ところが、linesプロパティで取り出されるのは段落ではなく、あくまで見かけの行なので、lineの後ろに必ず改行が入るわけではありません。すると、ちょっと面倒な処理になりそうです。
考えた結果、押してだめなら引いてみな、ということで全テキストの方から改行をすべて取る処理

allText = allText.replace(/\r/g, "");

をしています。
「/\r/g」は、「すべての改行(キャリッジリターン)」という意味です。よくわからない方は「正規表現」でググってください。Illustratorでの改行コードは、Windows版でも「\r」のみで扱われているようなので、このままでOKです(つーかWin版でしか動作確認してない)。

2008年5月29日木曜日

【InDesign】【VBS】スクリプト未対応の操作を呼出すには?(文字あふれの検索)/解説編

前エントリーの解説です。
VBSで作ったInDesign CS2のスクリプト。Windows版専用です。

※当ブログのスクリプトを実行した結果、データが壊れたとか、パソコンが壊れたとか、なんかおかしくなったとか、あらゆる損害にたいする苦情等は受け付けられません。すべて自己責任でご利用ください。

【動作内容】
文字あふれしたテキストフレームを探し出し、そのフレームを画面中央に表示、あふれている内容をダイアログで確認できるスクリプトです。改行は「¶」として表現します。でないと改行だけであふれている場合にわかりにくいからね。
文字あふれがあったらその場で修正したいこともあるでしょうから、他の文字あふれフレームも続けて表示するかどうか問いかけます。
表示しないことを選択した場合も文字あふれフレームの検索は(裏で)行い、最終的な文字あふれフレーム数をダイアログで表示して終わります。
...
※連結されているフレームからあふれた内容を取得するのはメンドクサイ&長くなりそう、という理由で未対応です(検索自体はできます。また、内容を取得できませんという表示はしています)。

※[オブジェクト全体を表示]のショートカットキー([Alt]+[Ctrl]+[-])を変更していると、予測不能の結果になります。

【スクリプト未対応の操作とは】
InDesignのスクリプトでは、あるフレームを画面に表示するというメソッドが用意されていません(少なくともCS2で私が調べた範囲では。あったらショック)。
そこで私はWindows Script Hostを利用し、ショートカットキーが押されたという情報を直接InDesignに送り込むという荒業を考えました。InDesign上のJavaScriptでWindows Script Hostを利用する方法がわからなかったので、Windows専用スクリプトとなってしまうVBSです(つーかJSで作れたところで使う機能がWin専用だけど)。MacならAppleScriptでなんとかしてアプリにショートカットを送信できれば、同じようなことができるかもしれませんね。どうかな?
しかしあまり褒められたやり方ではないと思いますが・・・まあ、この世は結果がすべてということで。

・2,3行目(Windows Script Hostの利用準備)
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")

・24行目(ショートカットキー送信)
WshShell.SendKeys "%^-"

これで[オブジェクト全体を表示]コマンドのショートカットキー([Alt]+[Ctrl]+[-])がInDesignに送信されます。他にも、スクリプトでは実行不可能な機能に対してショートカットキーを割り当てられれば、この方法で何とかなるのではないでしょうか。
ちなみに、ショートカットキーを送ってからすぐに次の処理を始めると、InDesignの画面切り替え処理が追いつかないため、次の25行目で無駄な処理を行うslp関数を呼び出しています。この無駄がないと、文字あふれ発見ダイアログが画面の切り替えより早く出てしまい、文字あふれフレームの表示がうまくいきません。ダイアログを閉じた後で表示されるとか(これでスゲー悩んだ・・・)。このまま実行してもうまく[オブジェクト全体を表示]が働かない場合はslp関数に渡す数値を増やしてみてください。サンプルでは10000としていますが、当方Core2 Duo 1.8GHz(メモリ1GB)のマシンでいい感じに動いています。

【InDesign】【VBS】スクリプト未対応の操作を呼出すには?(文字あふれの検索)

文字あふれしたテキストフレームを探し出し、そのフレームを画面中央に表示、あふれている内容をダイアログで確認できるスクリプトです。
長いので説明は次のエントリーを参照。
...

Dim app
Set app = CreateObject("InDesign.Application.CS2_J")
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")

Dim pageObj
Dim cont, flag, all_len,show_len,all_text,show_text,over_text
Dim i,j,BtnCode, eachTMP

cnt = 0
flag = true

Set pageObj = app.activeDocument.AllPageItems

for each eachTMP in pageObj

if typename(eachTMP) = "TextFrame" then
if (eachTMP.overflows) then 'あふれているかどうか?

cnt = cnt+1 '文字あふれをカウント

if (flag) then 'フレームを表示するか?
eachTMP.select() 'フレームの選択
WshShell.SendKeys "%^-" 'ショートカットキーの送信
call slp(10000) '表示切替待ち

all_len = len(eachTMP.ParentStory.contents) '全文字数を取得
show_len = len(eachTMP.contents) '表示されている文字数を取得
all_text = eachTMP.parentStory.contents '全テキスト内容を取得
over_text = mid(all_text, show_len+1, (all_len-show_len+1)) 'あふれている部分を取得
over_text = ReplaceText(over_text, chr(13), "¶"& chr(13)) '改行マークを追加

if eachTMP.Id <> eachTMP.PreviousTextFrame.Id then
over_text = "【!】連結フレームの場合はあふれた内容を表示できません"
end if

BtnCode = WshShell.Popup("【あふれた内容】" & chr(13) & chr(13) & over_text & chr(13) & chr(13) & chr(13) & chr(13) & "【次の文字あふれフレームを表示しますか?】",0,"文字あふれ発見",4+32+4096)

if BtnCode = 7 then flag = false

end if
end if
end if
next

if (cnt = 0) then
BtnCode = WshShell.Popup("文字あふれはありません", 0, "ドキュメント全体の検索完了" , 0+64+4096)
else
BtnCode = WshShell.Popup("全部で " & cnt & " 個の文字あふれフレームが存在します", 0, "ドキュメント全体の検索完了" , 0+64+4096)
end if


Function ReplaceText(str1, patrn, replStr)
Dim regEx
Set regEx = New RegExp ' 正規表現を作成
regEx.Pattern = patrn ' パターンを設定
regEx.IgnoreCase = True ' 大文字と小文字を区別しないように設定
regEx.Global = True ' 文字列全体を検索
ReplaceText = regEx.Replace(str1, replStr) ' 置換
End Function


sub slp(cnt)
for j=1 to cnt
j = j
next
end sub

2008年5月26日月曜日

【InDesign】テキストフレームを全選択

スプレッド内のテキストフレームだけを全選択するスクリプトです。
どんな場面で使用するかはわかりませんが。
...
InDesign CS2で動作確認。他のバージョンは知りません。CSやCS3でも多分動く・・・と思う。
JAVASriptなのでMac、Win両対応だと思います。Winでしか確認してないけど。

グループ化されているオブジェクトの処理に、関数「groupCheck」を作りました。もっといいやり方があるかもしれない。

InDesignスクリプトでは、グループ化されているオブジェクト群が1つのオブジェクトとされるため、グループ化されているテキストフレームがあると、そのフレームはactiveSpread.textFramesで取り出すことができません。したがってスプレッド内にグループが存在すれば、グループ毎に処理を行います。さらに多重グループ化されていたら・・・なので、グループが発見されるたびにgroupCheckを再帰的に呼び出しています。




#target InDesign

app.activeDocument.selection = null;

if (app.layoutWindows[0].activeSpread.textFrames.length > 0)
{
textITM = app.layoutWindows[0].activeSpread.textFrames;
selectFrames(textITM);
}

if (app.layoutWindows[0].activeSpread.groups.length > 0) groupCheck(app.layoutWindows[0].activeSpread.groups);


function selectFrames(itemLST)
{
var i;
for(i = 0; i < itemLST.length; i++)
{
hkITM = itemLST[i].select(SelectionOptions.addTo);
}
}


function groupCheck(itemLST)
{
var i;
for(i=0; i < itemLST.length; i++)
{
if (itemLST[i].textFrames.length > 0) selectFrames(itemLST[i].textFrames);
if (itemLST[i].groups.length > 0) groupCheck(itemLST[i].groups);
}
}


2008年5月23日金曜日

【InDesign】同じスウォッチを使用しているオブジェクトを選択

Illustratorでは同じ塗りや線色のオブジェクトをまとめて選択するコマンドがありますが、InDesignでも同じことをやれるスクリプトです。
...
【使い方】
1つだけフレームを選択してスクリプトを実行すると、そのフレームと同じ塗り色&同じ線色のフレームをすべて選択状態にします。
※「同じ色」というのはスウォッチ名で判断しているので、スウォッチ登録していない色では反応しません。
※シェード(濃淡)の違いは判断しません。同じスウォッチ名なら薄いのも濃いのも同じ色として判断します。
※作業中のスプレッドが対象です。ドキュメント全体ではありません。

ちなみにInDesign CS2で確認しています。他のバージョンは動くかどうかわかりません。
そして、JAVASriptです。Mac、Win両対応だと思います。Winでしか確認してないけど。

一応、このスクリプトのミソはselectFillAndStrokeColor関数です。引数として渡されたオブジェクトのfillColorを調べて判断するのですが、引数としてグループ化されたオブジェクトが渡されている可能性もあります。なぜかというとpageItemsプロパティでは、グループも1つのオブジェクトとなっているからです。fillColorプロパティを見ようとしたとき、これがグループであるとエラーになります。そこでエラーメッセージをキャッチして、グループだと判断した場合はグループのpageItemsプロパティを取り出し、自身を再帰呼び出ししています。再帰呼び出ししているので、多重グループ化されているオブジェクトでも問題なく処理できます。




// 選択-スウォッチの塗りと線色.jsx
// For InDesign CS2
// (c)Gyoniso
// 2008/5/23 v1.0

#target InDesign

chkFillColor = "";
chkStrokeColor = "";

baseITM = app.selection;
if (baseITM.length == 1)
{
typeArray = new Array("Oval", "Rectangle", "Polygon", "GraphicLine", "TextFrame")
for (i=0; i < typeArray.length; i++)
{
worktype = typeArray[i];
if (worktype.indexOf(baseITM[0].constructor.name) >= 0)
{
chkFillColor = baseITM[0].fillColor;
chkStrokeColor = baseITM[0].strokeColor;
}
}
}

if ((chkFillColor != "") & (chkStrokeColor != ""))
{
allITM = app.layoutWindows[0].activeSpread.pageItems;
selectFillAndStrokeColor(chkFillColor, chkStrokeColor, allITM);
} else {
alert("有効なオブジェクトを1つだけ選択してください");
}

function selectFillAndStrokeColor(fCol, sCol, itemLST)
{
var i, chkITM
for(i = 0; i < itemLST.length; i++)
{
chkITM = itemLST[i];
try
{
if ((chkITM.fillColor == fCol) & (chkITM.strokeColor == sCol))
{
chkITM.select(SelectionOptions.addTo);
}
}
catch(e)
{
if (e == "Error: このオブジェクトのコンテンツは、この画像属性の値を複数有しています。")
{
selectFillAndStrokeColor(fCol, sCol, chkITM.allPageItems);
}
}
}
}