<% require 'index' %> =begin head =end # $Id: memo.txt,v 1.49 2005/11/12 02:44:07 hs9587 Exp $ # $Name: $ =begin =(())で(())10 ((:
:)) (()) 2003/1/1-, 2005/4/10- ((:
:)) ((<"rdソース(memo.txt)"|URL:./memo.txt>)) with (()) ruby -r erb -e 'ERB.new($stdin.read).run' < memo.txt | ruby "C:\Program Files\ruby-1.8\bin\rd2.rb" -r rd/rd2html-ext-lib --native-inline --ref-extension --headline-title --head-element --with-part=head:head --with-css=hs9587.css > memo.html =end ruby "C:\Program Files\ruby-1.8\bin\rd2.rb" -r rd/rd2html-ext-lib --native-inline --ref-extension --headline-title --with-css=hs9587.css memo.txt > memo.html ruby -r erb -e 'ERB.new($stdin.read).run' < memo.txt > tmp ruby "C:\Program Files\ruby-1.8\bin\rd2.rb" -r rd/rd2html-ext-smr-lib --native-inline --ref-extension --headline-title --head-element --with-part=head:head --with-css=hs9587.css tmp > memo.html xcopy index.rb index.rb.txt /D /FL /Y del tmp === アピアランス === 縁取りされた文字 * アウトラインを取ってその線幅を太くする * アピアランスに線と塗りを追加する === その物のクラス 何かオブジェクトがあったとき、そのもののクラスはなんだろうか、そしてどんなメソッドが呼べるんだろうか。 例えば Document.Selection配列の個々の要素について、その物の (Illustratorオブジェクトとしての) クラスは? メソッドのリストは? obj.class #=> WIN32LE... obj.ole_obj_help.name (()) === オブジェクトの回転、中心指定 === オブジェクトの同心円配置 === テキスト(文字(間))のカーニング(Kerning) kerning は GUIと百分だが、trackingは儘の値。 == 2005/12/3 === カーニングとトラッキング =begin == 2005/11/6 === ちょっと音を鳴らす また、Illustrator ではない話。 Windows環境で、ちょっと音を鳴らすにはどうしたら良いだろうか。 Illustrator の自動処理が終わったら、その時にちょっとチャイムを鳴らすなど。 コマンドラインや VBScriptで音を鳴らせるなら、Ruby からもそれを呼べばいいわけだ。 WIN32OLE.new('WScript.Shell').Run('sndrec32 /play /close "C:\WINNT\Media\ding.wav"', 0, true) この辺りでは、大概 require済みと思うので、require 'win32ole' の行は省略。 ==== sndrec32 とその呼び出しの解説 スクリプトからの音声起鳴は何処でも気に掛かるようです、マイクロソフトの 「((<"Hey, Scripting Guy!"|URL:http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/default.mspx>))」 にそういう QandA が挙がっていました。 * ((<スクリプトでサウンドを再生することはできますか|URL:http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/nov04/hey1103.mspx>)) * (()) あとは個々の記述について * wavファイルのパス名は適当です、適宜自分の環境の値で読み替えて下さい。 * WINNTフォルダは、XP から WINDOWS という名称になってます、気をつけて。 * 「"%SystemRoot%\Media\ding.wav"」でも良いかもしれないです、或いは %WIDNIR% * フルパス名では空白文字が入る事も多くなります、"" で囲うのが良いでしょう。 * サウンドレコーダー (sndrec32) は %SystemRoot%\system32 にあるでしょう、 きっとパスも通っているので、コマンド名だけで呼べる筈です。 * /play で再生を始め、/close で再生終了後アプリケーションも閉じます。 * 他にどんなコマンドオプションがあるのかは調べがつきませんでした。 * サウンドレコーダーコマンドは (()) で起動しました。 * 第2引数「0」で、サウンドレコーダーのウィンドウを非表示にします。 * 最小化する「2 (または 6, 7)」でも良いかも知れません。 * 第3引数「true」で再生終了を待ちます。 * この場合は終了コードが返る筈ですが、 wavファイルが見付からないとかいう程度のエラーではその値は変わりませんでした。 * 「false」或いは第3引数省略の場合は再生終了を待たず、 すぐに Ruby に制御が戻ります。 * サウンドレコーダーのウィンドウが出るのを気にしなければ、 sysytem() や `バッククォート` などでの実行も良いです。 system('sndrec32 /play /close "C:\WINNT\Media\ding.wav"') `sndrec32 /play /close "C:\\WINNT\\Media\\ding.wav"` * その時は「¥」文字のエスケープにも気を付けましょう。 * また、「%SystemRoot%」の展開も行われません、ご注意下さい。 ==== midi とか mp3 とか Scripting Guy の説明にもありましたが、 wavファイルより一般の音声ファイルにサウンドレコーダーは対応していません。 ウィンドウズメディアプレイヤー mplayer, mplayer2, wmplayer 等を探しましょう。 * メディアプレイヤーは、"%ProgramFiles%\Windows Media Player\" にあるでしょう。 * パスは通っていないと思います。 プレイヤー名はフルパス名で指定する事になるでしょう。 空白文字対策には、"" で囲っておくのが基本です。 * コマンドラインオプションは良く分かりません。 取り敢えず /play /close はエラーになりません。 * mplayer2 は、WshShell.Run の起動で第2引数の「0」が上手く行きません。 ウィンドウを最小化する「2 (または 6, 7)」の方が良いかもしれません。 * (()) より * 0 ウィンドウを非表示にし、別のウィンドウをアクティブにします。 * 2 ウィンドウをアクティブにし、最小化ウィンドウとして表示します。 * 6 指定したウィンドウを最小化し、Z オーダー上で次に上位となるウィンドウをアクティブにします。 * 7 ウィンドウを最小化ウィンドウとして表示します。アクティブなウィンドウは切り替わりません。 * 最小化された mplayer2ウィンドウと、起動元や Rubyスクリプトと、 どの辺のウィンドウをアィティブにするかの違いです。 * これでフォーカスをどうこうするより、 第3引数で制御ごと返してもらった方が良いかも知れませんね。 * wmplayer は、WshShell.Run の起動での第2引数「0」によるウィンドウの非表示は有効です、 * しかし、アプリケーションを終了しません。 * /close が効いていないのでしょう、 コマンドラインオプションを教えてください。 * メディアプレイヤーは OLEオブジェクトしても呼べるようです。 そちらで操作するのが良いのかもしれません。 * WIN32OLE.new('MediaPlayer.MediaPlayer.1') とか? === このメモの項目の一覧 <%= contents_index('memo.txt','項目一覧') %> == 2005/7/2 === InputBox (VBS) その2 前回 (()) によって入力ダイアローグを出すことを考えたが、その続き。 相変わらず Illustrator ではない話。というか Ruby の話ですらないかもしれない。 * Ruby: Tempfile * WSH: cscript オプション * WSH: WshScriptExec ==== Tempfile 一時作成する .vbsファイルの取り扱い、やっぱり Tempfile を使おう。 そうすれば既存チェックとか File.Delete とか余計な心配しなくていいし。 require 'tempfile' default = 'qwertyuiop' vbsbasename = 'vbsinputbox' tmpvbs = Tempfile.new(vbsbasename) tmpvbs.puts %Q[WScript.Echo InputBox("message", "title", "#{default}")] tmpvbs.close(false) input = `cscript #{tmpvbs.path} //E:VBScript //nologo` tmpvbs.close(true) require 'win32ole' WIN32OLE.new('WScript.Shell').Popup(input.to_s) * 最後の Win32OLE ポップアップは別に何でもいい、実際に入力値を使うところ * Tempfile の使い方はこんな感じ、closeの引数に注意 * cscript (wscript) は通常拡張子を見てスクリプトエンジンを判断する * Tempfileオブジェクトのファイル拡張子を指定する・変更することは出来ない(難しい) * スクリプトエンジンを指定するオプションがあった。 * //E:VBScript 大文字小文字の区別はあまりない、エンジン指定子下記 * RubyScript * VBScript * JScript * WSHバージョン表示などのロゴ表示はない方が入力の取り回しが楽 * //nologo * WScript.exe および CScript.exe のオプション * (()) * InputBox でのキャンセル釦押下はその仕様上、 入力なしで空文字列が返ってきたのと区別できない。 何れにせよ空文字列が(は)返る。 * InputBox の後ろに黒いDos窓が開いてるのが無様。(儘) ==== (()) 前段ではバッククォート(``)で実行したが、 (())オブジェクト で実行するとその部分はこのようになる。 exec = wsh.Exec("cscript #{tmpvbs.path} //E:VBScript //nologo") sleep 0.1 while exec.Status == 0 input = exec.StdOut.ReadAll() 同期実行のためには、その (())プロパティ を見ていてやればいい。 結果の標準出力は (())プロパティ から。 ==== 後ろのコマンドプロンプト窓 これを消すのは難しい。 (()) なら Window最小化の指定は出来るが値を返す手段がない。 その IntWindowStyle にしたところで、 2、6 とか指定したとき、 cscript窓(コマンドプロンプト窓)だけじゃなくて所要の InputBoxダイアローグまで最小化してしまう。 もう諦めるしかないのか。 : IntWindowStyle 内容 * 2: ウィンドウをアクティブにし、最小化ウィンドウとして表示します。 * 6: 指定したウィンドウを最小化し、Z オーダー上で次に上位となるウィンドウをアクティブにします。 == 2005/6/26 === InputBox (VBS) さて、メッセージボックスを出すことは ((<出来|メッセージボックス (再び)>))る ((<よう|メッセージボックス>))に ((<なった|メッセージボックスアイコン>))。 Yes/No/Cancel やその他の選択の返り値も得ることが出来る。 ということで、簡単なテキストの入力ダイアローグが欲しい。 勿論、前述の (()) でも、他の GUIツールキットでも、いろいろ出来るわけだが、 そこまで真面目なことをしなくてもなんとかならないだろうか。 VBScript には (()) というのがあるので、それでなんとか。 default = 'qwertyuiop' vbsfname = 'inputbox.vbs' raise "A file '#{vbsfname}' already exists." if FileTest.exist?(vbsfname) File.open(vbsfname, 'w'){ |f| f.puts %Q[WScript.Echo InputBox("message", "title", "#{default}")] } value = `cscript #{vbsfname}` File.delete(vbsfname) # input = value.split("\n")[3].to_s input = /\n\n/.match(value).post_match require 'win32ole' WIN32OLE.new('WScript.Shell').Popup(input) * (()) は VBScript で定義されてる1行テキスト入力ダイアローグ * 無様ではあるが入力値を取ってくるように出来た * ファイルの既存チェックはもう少し真面目にやるべき * tempfile を使いたいところだが、拡張子を「.vbs」にしないといけないので難しい * 後片付け (File.delete) ももっと真面目に * 最後のポップアップは別に何でもいい、実際に入力値を使うところ * 取り敢えずバッククオートで呼んだ。 * WIN32OLE.new('WScript.Shell').(()) や同じく ((<.Exec|URL:http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/script56/html/wslrfexecmethod.asp>))メソッド で実行することも考えたが、同期実行の問題や、値を返せないことなどから ちょっと実用的でない。 * InputBox の後ろに黒いDos窓が開いてるのが無様。 * 値を返してもらうからには、InputBoxダイアローグで「キャンセル」釦の時の対処も必要 * 仕様上その時は空文字列を返す、本当に空文字列を入力してた時との 区別は出来ない * 上記ではあまり何もしてない。 (inputが配列範囲外になって nil になるので、一応 .to_s しておいた) * WScript((<.Echo|URL:http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/script56/html/wsmthecho.asp>)) は wscriptで実行するとGUIダイローグを出すが、cscriptで実行するとコンソールに出力する * cscriptバッククオート実行値は下記。何かでずれるようなら調整して下さい (0) 0行目: WSH(WindowsScriptHost) のバージョン表示 (1) 1行目: Microsoftのコピーライト表示 (2) 2行目: 区切りの空白行 (3) 3行目(以降): WScript.Echo の出力 (()) 「鈴木さんを囲む会 2005-05-14 (土)」(二次会) の項にも同内容を書いています、ご参考まで。 === メッセージボックス (再び) 前にも((<メッセージボックス>))の事は書いた。 (()) (VisualuRuby) を使うのであった。 実は、WSH(WindowsScriptHost) の WScript.Shell オブジェクトの Popup メソッドでも同じことが出来る。 require 'win32ole' wsh = WIN32OLE.new('WScript.Shell') yes_no = wsh.Popup('メッセージ', 0, 'Title', 4 + 32 + 0x40000) case yes_no when 6 wsh.Popup('Yes', 0, 'Title', 0 + 64 + 0x40000) when 7 wsh.Popup('No' , 0, 'Title', 0 + 16 + 0x40000) end # case yes_no 引数と返り値、アイコンなどについては、 既述 (())、((<アイコンと規定値>)) と同じ。 この辺りでは大概において Win32OLEライブラリは require済みと思うので、 メッセージダイアログを出すだけなら、 そして WScript.Shellオブジェクトを使い捨てにするなら、 次行程度いでも良いかもしれない。 WIN32OLE.new('WScript.Shell').Popup('メッセージ', 0, 'Title', 0 + 48 + 0x40000) ==== JavaScript の alertメソッド 更に、DoJavaScript を使って JavaScript の alertメソッドを呼ぶという手もある。 まあ、alert自体の返り値がないのは不便なので、 わざわざこちらを使うケースは少ないでしょう。 # illu は llustrator の Applicationオブジェクト本体 illu.DoJavaScript('alert("メッセージ");') ((<既報|Rubyist Magazine 0006号>))、 「(()) 0006号」 にも同じことをまとめています。ご参考まで。 *「Win32OLE 活用法 第 4 回 Adobe Illustrator」問い合わせメッセージボックス * (()) == 2005/6/18 === GroupItem の解除 このあいだ、(()) については書いた、 今度はそのグループアイテムを解除することを考えよう。 ただ残念なことに、 オブジェクト - メニュー の [グループ解除(U) Ctrl + Shift + G] に相当するものはない。 グループの構成要素をチマチマ一つずつ操作していかねばならない。 # grp はなんか GroupItem grp.PageItems.Count.downto(1) do |i| grp.PageItems.item(i).MoveToBeginning(grp.Layer) end 或いは、 grp.PageItems.item(1).MoveToEnd(grp.Layer) while grp.PageItems.Count>0 ただ、グループ解除後の居場所を考えると前者の方が良い様に思う ==== PageItem そのグループ (GroupItem) にどんなものが入っているかは分からないので、 描画オブジェクトを統一的に取り扱う PageItem のコレクションを使う。 PageItemがもっと多態的だと使い出があるのに。 まあ今は MoveTo云々があるので善しとしよう。 ==== 逆順 .item() でのインデックス指定は重なりの上からで、 変更があった場合はその場で繰り上がったり下がったりする。 WIN32OLEオブジェクトの提供する each での実行中にも番号がつけ変わってくので、 コレクション.each でこの作業を実行すると変なことになる。 奇数番目だけ消えて、偶数番目が残る。 each が別にインデックスエラーにならないのは、ちゃんと動的に Count をかぞえてる訳だが、 エラーが起こらないだけになんとも変な感じに思えたりする。 そういうわけなので、逆順に実行するか、それとも最初の要素をずっと見続けるようにする。 ==== 重なり順の保存 重なり順を保存するため、逆順なら MoveToBeginning を使う。 最初の要素だけ見るというのなら、MoveToEnd を使うことになる。 いずれにせよ、レイヤーの先頭か末尾かに移動してしまう。 他の描画オブジェクトとの関係で言えば、 重なり順のその場でグループ解除できるわけではない。 また、その際の行き先レイヤーだが、 上記では該当グループ自体の所属するレイヤーとした。 これはアクティヴレイヤー (doc.ActiveLayer) 宛てとしても良いかもしれない。 ==== 重なり順とインデックス 先にも少し言及したが、それぞれのコレクションでの、 添数付けは、描画オブジェクトの重なり順になっている。 一番上にあるのが .item(1)、一番下になるのが .item(…Items.Count)、 例えばレイヤーなら。 (1) doc.Layers.item(1) (2) doc.Layers.item(2) (3) …… (4) doc.Layers.item(doc.Layers.Index(doc.ActiveLayer)) (5) …… (6) doc.Layers.item(doc.Layers.Count) == 2005/5/13 === Rubyist Magazine 0006号 Ruby のウェブマガジン「(()) 0006号」 (()) に、記事を書かせてもらいました。 * 「Win32OLE 活用法 第 4 回 Adobe Illustrator」 * (()) * Win32OLE の利用方法を紹介する連載の第 4 回。今回は Adobe Illustrator を Win32OLE で操作する方法をご紹介します。(難易度:絵が) よければ見てやって下さい。 =end =begin == 2005/4/10 === ご挨拶 (2005-04-10) しばらく更新すべき内容が無かったのですが、またいくつかの事例に出会ったので、少し案件を追加します。 その間に、 (()) は CS版にバージョンアップしましたが、僕は 10.0.3 の儘です。 このメモでは Illustrator 10 のまま話を続けます。 一方、(())は ((<1.8|URL:http://www.ruby-lang.org/ja/20041225.html>)) になりました。こちらは (()) を使っていて、1.8にバージョンアップしています。とはいっても、 Ruby自体に関わるような記述は余り多くないので、さほど気にする事は無いでしょう。 さらに、Illustratorの自動化という話題も世上に散見されるようになりました。 嬉しいことです。 : (()) : 古籏 一浩 (著); 毎日コミュニケーションズ ; ISBN: 4839913544 ; (2004/01) 紙の本です、書店の本棚でこれを見つけたときは感動しました。 : (()) : (()) そのCS版、出版はされないそうです。 同サイトには、Photoshop, InDesign の自動化の話などもあります : ((<イラレで便利 for Adobe Illustrator|URL:http://park17.wakwak.com/~ddpp/6ot/js_ill/index.html>)) : (()) イラストレーターのクラタさんのところです。JavaScript の公開もしています、 イラストレーションの実践で鍛えられた事柄群です。 === GroupItem への集積 各種グラフィックItemをグループ化して GroupItem を得る事を考えよう。 * GroupItems.Add は GroupItem自体を増やすのであって、 GroupItemそのものに何かを追加するのではない。 * その GroupItemに、新たなグラフィックItemを作るのなら、 その属性の <何とか>Itemsコレクションに Addすればよい。 * .PathItems.Add, .TextArtItems.Add, .CroupItems.Add, ... 等 * 既存のグラフィックItemをその GroupItemに追加するにはどうしたら良いのだろうか? ==== Cut (Copy) & Paste * Itemオブジェクトには Cut (Copy)メソッドがあり、自身をクリップボードに持って行く事が出来る。 * GroupItemオブジェクトの Pasteメソッドはクリップボードからそれを持ってくることが出来る。 どうだろうか。これで良いようなものだが、 Illustrator自体の編集メニューの「カット(コピー)」、「ペースト」(Ctrl+X,C,V) と同じで、自分の位置を忘れてしまうのが不便だ。 スクリプトなんだから事前に Positionメソッドで対象の位置を憶えておけば良い訳だが、 それもなんか迂遠だ。 # doc はなんかIllustrator.Documentオブジェクト grp = doc.GroupItems.Add path = doc.PathItems.item(1) pos = path.Position path.Cut grp.Paste pasted_path = grp.PathItems.item(1) pasted_path.Position = pos ==== MoveToBeginning, MoveToEnd Illustrator編集メニューの「前面へペースト」「背面へペースト」(Ctrl+F,B)に 相当するのが両メソッドである。 + PathItem : MoveToBeginning(Document/Layer/GroupItem) : Nothing Move the PathItem to the front of a container. : MoveToEnd(Document/Layer/GroupItem) : Nothing Move the PathItem to the end of a container. 他にも個々のグラフィックItemにはこのメソッドがある。 場所がその儘なのは非常に良い。 前記のように一度座標にしておいて代入し直すのと違い、原理的に全く同じ場所なのは非常に良い。 ただ、カット&ペーストしか出来ない(もとのを残せない) のがちょっと限界かな。 # doc はなんかIllustrator.Documentオブジェクト grp = doc.GroupItems.Add path = doc.PathItems.item(1) path.MoveToBegining(grp) =end =begin == 2003/10/18 === ドーナツ型に中を抜く ドーナツ型、というか Pierced disk 型に、真中が抜けていて回りに帯状にものがある状態。 或は、額縁上のオブジェクト。 それには、 Illustrator の使い方として、 パスファイダパレットの「前面オブジェクトで型抜き」 を用いる。 それをアクションに登録しておいて DoScriptで呼び出す。 出来あがりは複合パス CompoundPathItem になるので、扱いには注意が必要。 == 2003/10/11 === PathPoint.Selected の値 他の多くのオブジェクトの Selectedプロパティとは違って、 PathPointの Selectedプロパティは真偽値ではなく、AiPathPointSelection enumeration という 専用の値になっていて、端点(アンカーポイント と コントロール ポイント)の選択の様子を表す。 + PathPoint Properties : Selected : AiPathPointSelection enumeration Are points of this path point selected? If so, which one(s)?. : AiPathPointSelection Which points, if any, of a path point are selected? ====enumerarion (alphabetical oreder) aiAnchorPoint : 2 aiLeftDirection : 3 aiLeftRightPoint : 5 aiNoSelection : 1 aiRightDirection : 4 ====enumerarion (valuation oreder) aiNoSelection : 1 aiAnchorPoint : 2 aiLeftDirection : 3 aiRightDirection : 4 aiLeftRightPoint : 5 選択の状況は名前の通りで、 非選択、 アンカーポイントのみ選択、 アンカーポイントに加えて左右のコントロール(片方or双方)も選択、 という状態を示す。 コントロールポイントだけの選択状態がないのは、もともとの Illustrator の動作を反映している。 == 2003/10/5 === DoScript と Selection Illustrator での作業では、下記 ((<矢印を引く>))、((<パスファインダで交点を求める>)) の様に application.DoScript でアクション(メニュー)を呼んでやらないといけないことがいろいろ出てきそうだ。 その際には、アクション類は選択されたオブジェクトに作用する事も多いので、 アクティブドキュメントの Selectionプロパティとのやり取りも重要になってくるだろう。 (1) ((<選択オブジェクトの整理>)) (1) 関係無いオブジェクトの選択を解除し (2) 所要のオブジェクトを選択する (2) (()) (3) ((<終るのを待って>))、 (4) また((<選択オブジェクトの整理>)) ==== 終るのを待って アクションの実行には結構時間がかかる事があるので、ここできちんと待たないと 期待する動作をしないことになる。 アクションの実行が終る前に必要なオブジェクトの選択を解除してしまってはいけない。 それには application.ActionIsRunning でチェックする。 sleep 0.23 while illu.ActionIsRunning +Application Properties : ActionIsRunning : R/O Boolean Is an action still running? ==== 選択オブジェクトの整理 (()) に書いた。 要はアクティブドキュメントの Selectionプロパティを空配列にする。 To deselect all objects in the current document, simply set the selection to Empty ( Array.new() を代入する。nilの代入で済む事もある ) ==== DoScript でアクションを実行 application.DoScript でアクションを実行する。 DoScript(action As String, from As String, [dialogs As Boolean]) Plays an action from the Actions palette. ((<矢印を引く>))、((<パスファインダで交点を求める>)) など参照。 そういえば、((<矢印を引く>)) の時のサンプルの動作が不安定だったのは、 この注意事項を気にしていなかったせいかもしれない。 == 2003/10/1 === document.Selection と application.Selection application.Selection は、アクティブドキュメントの選択オブジェクトだとという事だが、 その document.Selection とは、少し挙動が違う。選択解除するのに nil の代入が効かない。 require 'win32ole' $illu = WIN32OLE.connect('Illustrator.Application') $doc = $illu::Documents.Add(AiEnum::AiDocumentCMYKColor) $path = $doc.PathItems.Add # def testSelection(str) obj = eval(str) if obj puts(str + '.size = ' + obj.size.to_s) else puts(str + ' is false.') end end # def testSelection(str) def run(str) eval(str) ; puts str end # def run(str) puts "\nnil\n" # => nil testSelection('$illu.Selection') # => $illu.Selection is false. testSelection('$doc.Selection') # => $doc.Selection is false. puts "\napplication.Selection" # => application.Selection run('$path.Selected = true') # => $path.Selected = true testSelection('$illu.Selection') # => $illu.Selection.size = 1 run('$illu.Selection = nil') # => $illu.Selection = nil # nil testSelection('$illu.Selection') # => $illu.Selection.size = 1 # but not nil testSelection('$doc.Selection') # => $doc.Selection.size = 1 puts "\ndocument.Selection" # => document.Selection run('$path.Selected = true') # => $path.Selected = true testSelection('$doc.Selection') # => $doc.Selection.size = 1 run('$doc.Selection = nil') # => $doc.Selection = nil testSelection('$doc.Selection') # => $doc.Selection is false. puts "\nArray.new()\n" # => Array.new() testSelection('$illu.Selection') # => $illu.Selection is false. testSelection('$doc.Selection') # => $doc.Selection is false. puts "\napplication.Selection" # => application.Selection run('$path.Selected = true') # => $path.Selected = true testSelection('$illu.Selection') # => $illu.Selection.size = 1 run('$illu.Selection = Array.new()') # => $illu.Selection = Array.new() testSelection('$illu.Selection') # => $illu.Selection is false. puts "\ndocument.Selection" # => document.Selection run('$path.Selected = true') # => $path.Selected = true testSelection('$doc.Selection') # => $doc.Selection.size = 1 run('$doc.Selection = Array.new()') # => $doc.Selection = Array.new() testSelection('$doc.Selection') # => $doc.Selection is false. カレントのドキュメント ActiveDocument の全ての選択を解除しようとするとき、 application.Selection へ nil を代入しても選択解除なされないが、 document.Selection への nil の代入では選択解除となる。 何れにせよ、空Array を代入すれば選択解除できる。 application.ActiveDocument.Selection を使うなり、 いつでも Array.new() を代入するようにしたりが無難。 + Application Properties : Selection : Variant Array (of objects) All of the currently selected objects in the active (frontmost) document. See note for more information. : (()) == 2003/9/15 === Document.Selection の挙動 Document.Selection は全ての選択されたオブジェクトの配列とされる。 + Document Properties : Selection : Variant Array (of objects) The array of references to the objects in this document's current selection. それで、何も選択されていない時は何も返らない (nilが返る) 事に注意。 Document.Selection の呼出し自体には成功するが、size 零の配列では無くて nil が結果となる。 require 'win32ole' require 'vr/vruby' title = 'IllustRuby' illu = WIN32OLE.connect('Illustrator.Application') begin doc = illu.ActiveDocument #rescue WIN32OLERuntimeError => err rescue => err VRLocalScreen.newform.messageBox(err,title, 0 + 48 + 0x40000) # MB_OK = 0, MB_ICONWARNING = 48, MB_TOPMOST = 0x40000 abort end selected = doc.Selection if selected then num = selected.size msghead = (num==1)?'One item is':"#{num} items are" else msghead = "#{selected.type} are" # NilClass end # if selected then msg = "#{msghead} selected \nin the document `#{doc.Name}'." VRLocalScreen.newform.messageBox(msg,title, 0 + 64 + 0x40000) # MB_OK = 0, MB_ICONINFORMATION = 64, MB_TOPMOST = 0x40000 =end =begin == 2003/9/12 === Matrixの作用 なんかマトリックスの作用が最初思っててた感じと違って、でもやってみれば当たり前の様な感じでもある。 ちゃんとまとめてないし、サンプルソースも用意できないけど様子だけ標語的に述べる。 * Tranformationマトリックスの作用は座標 (0, 0) を原点とした作用ではない。 * Tranformationマトリックスの作用は、対象オブジェクト(図形)の中心を原点として作用する。 * 対象オブジェクト(図形)の中心とは GeometricBounds の中心。 図形の重心 (や 5心(あるとは限らないけど) のどれか) とは必ずしも一致しない。 * 併進はどうせ作用の原点の場所に依存しないので、回転と反転のときには注意せよ。 * 考えてみれば当たり前の話で、普通にマウスでドラッグして回転させるときの中心を原点にするわけだ。 * そういうわけで、回転と反転だけのときや、併進だけのときは兎も角、 回転反転と併進を連続して交互に行ったりすると、作用の合成の途中で原点が変わる可能性もあるので大変だ。 * 例えば …‥・ =end === Matrixの作用 なんか Tranformationマトリックスの作用が変な感じなので、どういうものなのか確かめて試る。 座標(0,0) 中心の作用ではなく、対象オブジェクトの中心 ( geometric bounds の中点) を原点として作用する。 =begin == 2003/9/7 === 矢印を引く 矢印を引きたい、しかしそんなオブジェクト、メソッドはスクリプトにはない、 ((<パスファインダで交点を求める>)) の時と同じ様に、アクションを定義しておいて Application.DoScript 。 ==== 矢印をひく そもそも Illustrator で矢印を引くこと自体 FAQ な らしい。 (1) 線を引く、直線ツールでも何でもいいが閉パスは駄目、必ずオープンパス (2) 線を書いた直後はそのパスと端点はみんな選択状態になってる * だから、既存のパスを矢印にするときは選択ツールで選択する (3) [フィルタ]メニュー - [スタイライズ] - [矢印にする] を実行 (4) 「矢印にする」ダイアローグが開くので、始点終点の矢のかたちを 27種類のなかから選び、 拡大・縮小の割合を入力して「OK」 (5) パスはグループになり、その中には最初のパスと矢先(元)(鏃矢柄)図形のパスがある (6) 矢印の先端は最初のパスの端点より先になるのには注意する事、 始めにパスを描く時はその分を見込んでおかなくてはならない。 ==== アクションの定義 (1) 線を引いて選択状態にしておく (2) 適当なアクションのセットで「 新規にアクションを作成」 * 英字(所謂半角文字)で名前をつけておく方がスクリプト側からアクセスし易い、 「myArrow」くらい (3) ((<上記|矢印をひく>))のようにして矢印をひく (4) 「再生/記録を中止」 (5) アクションメニューからアクションの保存をしたほうが良いでしょう。 ==== スクリプトからの呼出 path = doc.PathItems.Add a = path.PathPoints.Add b = path.PathPoints.Add a.Anchor = [100, 400] a.LeftDirection = a.Anchor a.RightDirection = a.Anchor a.Selected = false b.Anchor = [240, 300] b.LeftDirection = b.Anchor b.RightDirection = b.Anchor b.Selected = true # 各頂点(始終点)も選択しとかないといけない # 終点(アクションではこっちに矢印をつける様に定義した)だけ選択しといても良いみたい # まあ、両端(と途中の点)を選択しておくのが無難 path.Closed = false path.Selected = true illu.DoScript('myArrow', 'myActions') doc.Selection.each do |item| item.Selected = false end # doc.Selection.each do |item| 最後のブロックは、作った矢印グループを選択解除する為のもの。 ここでなにか変数に代入しておけば今作った矢印をあとから参照できる。 ちなみに、端点を Select しておかないと、 “オブジェクト「矢印にする」は現在使用できません” ダイアローグがでて矢印がひけなかったりする事がある。 またそのダイアローグでキャンセルしたりすると、 アクションパレットにへんなアクションの残骸が残ったりする。 ==2003/7/31, /8/28 ===Colorオブジェクトの生成と代入 ((<直接生成すべきオブジェクト>))として挙げたものの中の Color系オブジェクトは、 では実際どのように生成し、代入すべきなのだろうか。 ++ AiColor enumeration aiColorNone = 0 aiColorCMYK = 1 aiColorGray = 2 aiColorRGB = 3 aiColorSpot = 4 aiColorPattern = 5 aiColorGradient = 6 ++ AiDocumentColorSpace aiDocumentRGBColor = 1 aiDocumentCMYKColor = 2 ====試行 + それでは Color を作ろう require 'win32ole' # color = WIN32OLE.new('Illustrator::Color') # 'new': Unknown OLE server : `Illustrator::Color' (WIN32OLERuntimeError) color = WIN32OLE.new('Illustrator.Color') puts "N: color.Color = #{color.Color}" # 0 # aiColorNone 作成されただけの Colorオブジェクトの色型は無名 aiColorNone である。 ++ win32ole('::') そういえば、win32ole的には、'::'は使えないんだね、'.'でないと。( 無効なクラス文字列です。) + .Color に直接代入する事は出来ない begin color.Color = 2 rescue WIN32OLERuntimeError =begin in 'method_missing': (WIN32OLERuntimeError) OLE error code:0 in HRESULT error code:0x8002000e パラメータの数が無効です。 =end ensure puts "N|2: color.Color = #{color.Color}" # 0 # aiColorNone end Colorオブジェクトの Colorプロパティは R/O ( ((*R*))ead ((*O*))nly ) なので、直接代入する事は出来ない。 WIN32OLERuntimeError になってしまう。 + .Color ではないプロパティへのアクセス .Color ではないプロパティへのアクセスも難しい。 相当する色空間プロパティに、別途作った CMYKColor や GrayColor を代入する事で item のカラーを設定する。 代入、設定されていない色系プロパティへのアクセスは失敗する。(初めは不定だが、Documentの色空間や Grayを期待しても良かろう) +そして CMYKDocumentを用意する illu = WIN32OLE.connect('Illustrator.Application') module AiEnum; end WIN32OLE::const_load(illu, AiEnum) doc = illu::Documents.Add(AiEnum::AiDocumentCMYKColor) path = doc.PathItems.Add +Gray gray = WIN32OLE.new('Illustrator.GrayColor') gray.Gray = 40 # 40% color.Gray = gray path.StrokeColor = color 成功 パスはグレーになる、 +CMYK cmyk = WIN32OLE.new('Illustrator.CMYKColor') cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black = 0,30,0,0 # 薄桃色 color.CMYK = cmyk path.FillColor = color 成功 Fill は CMYK(薄桃色)に満たされる。 +RGB rgb = WIN32OLE.new('Illustrator.CMYKColor') rgb.Red, rgb.Green, rgb.Blue = 0,0,40 # 淡青色 color.RGB = rgb path.StrokeColor = color 失敗 -> なんかCMYK(不定色)になってる もともとの Dobumentの色空間に反するものは出来ないようである。 しかし、Grayだったものは自分の色空間の天然色にはなるようだ、そして、色値は不定値になる。 ====整理(推定) * Document の DocumentColorSpace と整合性のない色様式は正常に代入できない。 ( Documents.Add([DocumentColorSpace As AiDocumentColorSpace]) の時に指定したもの) * 灰色は何時でも大丈夫だろう。 * カラー化は Documentの色系と同系に強制される、その際色値は不定値になる。 * 他の色 (Gradient, Pattern, Spot)の unmatch は良く解らない(確かめてない)。 (それを言えば、RGBでのも試行はしてない) =end だからそうできないから苦労してんだって! ((<" .Color ではないプロパティへのアクセス>")) ==== 03/9/5追記 上記試行では、Colorオブジェクトを作成して (CMYKなどをセットした上で) パス類の Color系プロパティに代入した。 いちいち Colorオブジェクト作成を経由しなくても、対象の Color系プロパティの所要のプロパティに 希望する色型をセットするのでも良い筈。 ( Color系プロパティの CMYKプロパティに別途作成した CMYKColorオブジェクトをセットしたり) =begin =end =begin * ==2003/6/27 ===GetScaleMatrix([scaleX As Single], [scaleY As Single]) この倍率も百分率? ((*Matrix関係試行必要。*)) ===Colorオブジェクトを別に作るとして、代入とかどうなるの? ((*試行必要*)) =end =begin ==2003/6/15 ===外部ファイル 余所の画像ファイルを持ってくるにはどうしたら良いのだろうか。 :GroupItems.CreateFromFile(imageFile As String) GroupItem objecr, Places an external vector art file as a GroupItem in the document. :PlacedItem.File String, The file containing the placed object. PlacedItems work only with embedded vector files: EPS, PDF, SVG and embedded AI. :RasterItem.File String, The file containing the RasterItem, if it is stored externally. と言う事だ、各 Fileプロパティに所要の画像ファイル名を代入してしまえば良い。 require 'win32ole' illu = WIN32OLE.connect('Illustrator.Application') doc = illu.Documents.Add raster = doc.RasterItems.Add # raster.File = "C:\ruby\illustrator\fromfile\door.jpg" # \のエスケープが難しいので raster.File = 'C:\ruby\illustrator\fromfile\door.jpg' # "文字列ではなく、'文字列が楽 raster.Resize(13,13) # 100% # RasterItem.Resize は 100%が基準の百分率値 raster.Position = [200,500] # Resize、Rotate、Transform(transformationMatrix) は兎も角、 # 移動は Translate するより Positionを直接弄る方が見易い (他のオプションが必要無い時は)。 ベクトル系の画像は PlacedItemとして、そうでない画像は RasterItemとして取り込めば良さそうだ。 ファイル名の指定には、\のエスケープが大変なので、"文字列" ではなくて '文字列' の方が分かり易い。 ====外部ファイルの埋込み このようにして呼んで来た画像をファイルに埋込むのかどうかは、この呼出の時に設定する物ではない。 saveas なり何なりで全体を保存するときに指定するのである。 :Document.SaveAs([saveIn As String], [options As EPSSaveOptions/IllustratorSaveOptions/PDFSaveOptions]) Nothing, Saves the document in the specified file as an Illustrator, EPS, or PDF file. :IllustraorSaveOptions.EmbedLinkedFiles Boolean, Are linked image files to be included in the saved document. Only valid for SaveOptions that specify an Illustrator compatibility of version 7 or later. ===Colorオブジェクト他 各種 Colorオブジェクトやオプション類などで、Illustrator.Applicationから生成するのではなく、 直接生成すべきオブジェクト。 マニュアルの中ほど、オブジェクトの生成に関する注意書きの所にその様な記述があった。 (()) ====直接生成すべきオブジェクト *CMYKColor *Color *EPSSaveOptions *GradientColor *GrayColor *IllustratorSaveOptions *Matrix *PDFSaveOptions *PatternColor *RGBColor *SpotColor *ExportOptionsGIF *ExportOptionsJPEG *ExportOptionsPhotoshop *ExportOptionsPNG8 *ExportOptionsPNG24 *ExportOptionsSVG *OpenOptionsPDF 例えば require 'win32ole' color = WIN32OLE.new('Illustrator.RGBColor') color.Red, color.Green, color.Blue = 255,0,0 # 真っ赤 Illustrator起動中とはいえ 其々のオブジェクトは個別には稼動しているわけではないので、 (()) ではなくて new で生成する。 Illustrator起動中で無いとIllustreatorの起動をはじめて (WIN32OLERuntimeError) HRESULT error code:0x80080005 サーバーの実行に失敗しました。 とエラーになるのは、(())と同様。 ===メッセージボックスアイコン 相変わらず Illustrator ではない話。 ====アイコンと規定値 ((<前述|メッセージボックス>))の様にすればメッセージボックスを表示出来た。 その際、メッセージ本文の左に、 丸く赤い所に白抜き×、黄色い三角にビックリ、青いはてな、青いiの字 といったアイコンを出したい。 また、 「YES」「NO」「CANCEL」とか釦が複数出るときは、デフォルトで選択状態になってる釦を指定してやりたい。 +アイコン MB_ICONERROR = 16 # 丸く赤い所に白抜き× MB_ICONSTOP = 16 # 同上 MB_ICONHAND = 16 # 同上 MB_ICONQUESTION = 32 # 白い吹出しの中に青い ? MB_ICONEXCLAMATION = 48 # 黄色い三角の中に ! MB_ICONWARNING = 0x30 # 同上 MB_ICONINFORMATION = 64 # 白い吹出しの中に青く i の字 MB_ICONASTERISK = 64 # 同上 MB_USERICON = 128 # (ユーザアイコンの指定法不明) +デフォルト選択 MB_DEFBUTTON1 = 0 MB_DEFBUTTON2 = 256 MB_DEFBUTTON3 = 512 MB_DEFBUTTON4 = 0x300 # 768 +MB_TOPMOST MB_TOPMOST = 0x40000 # 262144 例えば VRLocalScreen.newform.messageBox('message', 'title', 3 + 32 + 512) # 3 = WConst::MB_YESNOCANCEL # 32 = WConst::MB_ICONQUESTION # 512 = WConst::MB_WConst::MB_ こうすると、はてなアイコンが付いて、3番目の釦(キャンセル)が最初にフォーカスしている。 更に、MB_TOPMOST を加算しておくと、ボックスは常に最前面に表示されるようになる。 他にも contrib/msgboxconst.rb な値はあるので、いろいろ機能があるのでしょう。 その辺は Windows のダイアローグの説明をみれば色々わかるのだと思います。 ==2003/6/6 ===メッセージボックス ((<スクリプトメニューから_2 [DOS窓のない呼出]>)) とすると、 今度はメッセージダイアローグを出したくなる。 それには (()) ( (()) には最初から入っている) を使う事が出来る。 ==== (())でメッセージボックス この節は Illustrator ではなくて vruby (VisualuRuby計画(仮称)) のことになります。 しかも、余り(到底)正当ではない使い方です。 +最小限のスクリプト require 'vr/vruby' VRLocalScreen.newform.messageBox('message', 'title', 0) # 0 = WConst::MB_OK 第1項 'message' を表示するダイアローグである、第2項 'title' は Windowタイトルになる。 本来 (({VRLocalScreen.newform})) は新たにフォームオブジェクトを作成するので、 それに各種 Widget を配置して行くのが普通の流れだろう。 それらの Widget の機能と操作によっては Windows のメッセージボックスを呼び出す事もあるわけだ、 その メッセージボックス だけを用いる。 +YesNoで動作を変える require 'win32ole' require 'vr/vruby' frm = VRLocalScreen.newform msg = "Hello, rubyillustrator is here.\nDo you create a hello document ?" res = frm.messageBox(msg, 'ruby illustrator', 4) # 4 = WConst::MB_YESNO case res when 6 # YES->6, NO->7 illu = WIN32OLE.connect('Illustrator.Application') doc = illu.Documents.Add hello = doc.TextArtItems.Add hello.Contents = 'Hello rubyillustrator world!' hello.Position = [230, 700] hello.Resize(300, 300) when 7 # YES->6, NO->7 frm.messageBox('adieu', 'ruby illustrator', 0) # 0 = WConst::MB_OK else raise end # case res messageBox引数の第3項には、require 'vr/contrib/msgboxconst' に一覧のある WConst定数の値を指定するとメッセージボックスの表象が変る。 そして、そのダイアローグの釦押下の結果が返ってくる。 +WConstの値と返り値 MB_OK = 0 # OK->1 MB_OKCANCEL = 1 # OK->1, CANCEL->2 MB_ABORTRETRYIGNORE = 2 # ABORT->3, RETRY->4, IGNORE->5 MB_YESNOCANCEL = 3 # YES->6, NO->7, CANCEL->2 MB_YESNO = 4 # YES->6, NO->7 MB_RETRYCANCEL = 5 # RETRY->4, CANCEL->2 ==2003/6/1 ===スクリプトメニューから_2 [DOS窓のない呼出] そうは言っても、(({.vbs}))からの呼出の度に DOS窓が現れるのを煩わしく感じる場合も在ろう。 その時は WshShell.Run( "WScript.exe """" ") とすれば良いのだろう。'""' な '"' のエスケープや、フルパス名が安心である。 ==2003/5/31 ===スクリプトメニューからの実行 今まで書いてきた rubyスクリプトは Illustratorの外から実行していた。 Illustratorのスクリプトメニューからの呼出しも出来るようにしたい。 しかし、Illustratorは、(({.vbs})), (({.js})), (({.exe})) しか認識しない。 その為、(({WScript.Shell.Run})), (({WScript.Shell.Exec})) によって rubyスクリプトを呼び出すだけの VBScriptを書く。 Dim WshShell, oExec Set WshShell = CreateObject("WScript.Shell") Set oExec = WshShell.Exec( ) または Dim WshShell Set WshShell = CreateObject("WScript.Shell") WshShell.Run( ) 標準入出力などと相互作用出来る Execメソッドは、新しい(XP以降?) WSH にしか無い様なので、 その時は Runメソッドを使用する。 或は (()) によって (({.exe}))実行ファイルにしてやってもよい。 [ファイル]-[スクリプト]-[参照] メニューでの初めに参照するフォルダは (標準的なインストールでは) C:\Program Files\Adobe\Illustrator 10.0.3\Support Files\Contents\Windows\ になるので、その辺に入れれば良いだろう。 このフォルダには、(({.vbs})), (({.js})), (({.exe})) へのショートカット を入れても参照される。 また、[ファイル]-[スクリプト]-メニューから直接呼び出せるようにするには、 C:\Program Files\Adobe\Illustrator 10.0.3\プリセット\スクリプト\ に所要のファイルを置くと良い。ここにはショートカットを置いても参照されない。 実際にこのメニューに登録するには、Illustyratorを再起動する必要があることに注意。 =end =begin ==2003/3/29 ===テキスト内改行 テキスト文字列内で改行するには "\r" を挿む、"\n" ではないのに注意。 一文字毎に "\r" を挿めば縦書きもどきにもなる。 (縦書き文字ツールの名前がわからない) ==2003/3/16 ===テキスト位置_2 (V|G|C)Bounds を表す Fixed rectangle の指定するのが、左上座標と右下座標(この順)であるということを 実感していなかった(なんとなく左下点を思い描いてたりした)のが混乱の要因だった様だ。 もう一度状況を整理する。 (1)Layer等の TextArtItems から、TextArtItem を取り(作り)出す。最初は Addメソッドで作ることになろう。 (2)書きたい文字はそのオブジェクトで TextArtItem.Contents に代入すればよい。 (3)その際 TextArtItem.Kindプロパティには AiTextType enumeration を設定できる筈だが、 AiPointText (Default?)を明示的にセットしよう。 *AiPathText, AiAreaTextをセットしても効果がはっきりしない *TextArtItem.TextPaths や TextArtItem.TextPath_PathItems (どちらも ReadOnlyプロパティ) など、 関係するパスはどうなってるんだろうね? (4)そして、VisibleBoundsである。これは FixedRectangleとして、左上点と右下点を代表する。 visibles = text.VisibleBounds vw = (visibles[2] - visibles[0]).abs vh = (visibles[3] - visibles[1]).abs そういう意味では下記にすれば .absは要らない筈なわけだ、 vw = (visibles[2] - visibles[0]) vh = (visibles[1] - visibles[3]) (5)この幅を基準に移動すれば所要位置にテキスト text.Position = [ center[0] + @left - vw/2, center[1] + @bottom + vh/2 ] # 此れが所要の筈なんだ、pointが左上なんで -vw +vh と符号がずれる(2003/3/16) centerがテキストの中心になる様に移動したつもり。 (6)上下余白(英文)や右裾流れの為に厳密に中心が合うわけではないが、概ねこんな感じ。 (7)回転のことは未だ詳しく検討してない。一応回転 text.Rotate(direction) してても大丈夫だったんだけど、 Boundsの具体的な辺りとか、ちゃんと検討していない。 :まとめ AiPointTextとして、Boundsが与えるのが左上右下である事をきちんと注意すれば、 テキスト位置は調整出来る様だ。 ====Fixed rectangle (Coordinates - Scripting Illustrator, IllustratorScriptingGuide.pdf) To work with rectangular coordinates where there are a pair of x and y values, Illustrator uses the special class called a fixed rectangle. This class is comprised of a list with four items in AppleScript and a variant array with four elements in Visual Basic. The coordinates of a .xed rectangle in order are: left, top, right, bottom. ====AiTextType enumeration :AiTextType *aiAreaText *aiPathText *aiPointText ==2003/2/25 ===テキスト位置 どうも上下方向で下にずれるような感じ。 TextArea は左上をpointするのでなく、左下をポイントするのか? というより、pathテキストか、pointテキストか、エリアテキストかをきちんとすべきであった :pointテキスト 左上 ってことになるようだ(正対配置の場合) pathテキストは駄目みたい。pointテキストをちゃんと指定しよう。そしてそれでも、上下的には中央ではない。 ベースラインと上端の中央にくる感じ。(VigibleBoundsってどういう意味?、こんなことなの?) ===DoScriptパスファインダー アウトラインの線色 Application.DoScript で予め作っておいた「パスファインダー アウトライン」アクションを実行する。 得られたアウトライン線のパスStrokeColor.Color は Gray になる傾向がある。 いっぱい出来るうち最後のパスだけは Documentと同じAiColorCMYKになるが、あとはAiColorGrayになってしまう。 ===ColorObjectの振る舞い Color.Color が該当する Color Enumeration 値でないとき、そもそもそのカラープロパティは((*無い*))(nill) 上記のようにGrayになっちゃてるとき、CMYK属性はそもそも存在せず、ましてや CMYK.Cyan なんて nil はそんなメソッド(プロパティ)持って無いといわれる。 ===アクションの登録と保存 保存、読み込み、置き換え アクション表示ウィンドウのオプションメニューからアクションの保存ファイル操作。 「置き換え」をすると、デフォルト(初期設定)アクションなども含めて置換されてしまい、 ファイルの保存されていたアクションしかなくなってしまうのに注意。 ==2003/2/23 ===Color Document.DefaultColor なり、各オブジェクトの StrokeColor とか FillColor とかの Colorオブジェクトについて、 その Colorプロパティの AiColor Enumeration に従ったプロパティ(CMYK,...)の色値を設定する。 ==2003/2/11 ===テキストを書く Layer.TextArtItems からテキストを書く。 TextArtItem.Kind を設定すれば、point text、path text、area text、を選べる訳だが、取敢えず point系。 title = lay.TextArtItems.Add title.Contents = <文字列> title.ReSize( , ) title.Position = [ , ] (1)Layer等の TextArtItems から、TextArtItem を取り(作り)出す、 (2)TextArtItem.Contents に書くべき文字列を代入し、 (3)デフォルトの大きさから適当にサイズを調節(百分率)し、 (4)描くべき場所に配置する(左上端指定)。 *「the top left corner」を Array[ , ] と指定するので混乱しないように。 配置位置の計算には、Heigt, Width (どちらも GemotericBounds を基に計算する)を使って微調整出来るだろう。 より詳しくは、VisibleBounds, (GeometricBounds, ControlBounds) を使う事になる。 ====TextArtItem.Kind :TextArtItem.Kind *AiTextType enumeration *The type of text art displayed by this object. :AiTextType *aiAreaText *aiPathText *aiPointText ===テキストのフォント TextArtItem の TextRangeメソッドで、適用すべきテキストの範囲を選び(設定し)、 その TextRangeオブジェクトの、Fontプロパティに、所要の TextFace オブジェクト値を設定する。 TextFaceオブジェクトを探すのは大変(TextFace, TextFaces の exampleなど参照) TextFaces.item(itemKey) itemKey は フォント名称でいいのかな? 未確認 TextFacesコレクションを eachで回して(Count個)、各 TextFace.Name をフォント名にマッチさせる とかすればなんとかなるか? TextFaces[i] は効くのかな? ====TextArtItem.TextRange :TextRange([rangeStart As Long], [rangeEnd As Long]) *TextRange object *Returns a text range object referencing a substring of the current text range, where rangeStart is the beginning character position and rangeEnd is the ending position. The first character position is one. If omitted, rangeStart defaults to 1. If omitted, rangeEnd defaults to the last character of the range. ==2003/2/9 ===パスファインダで交点を求める 線と線(パスとパス)の交点を求めるのに、パスファインダ-アウトライン を使う事が出来る(GUI)。 しかし、スクリプトからは直接これを操作するやり方が解らないので、 あらかじめアクションを定義しておいて、Application.DoScript でアクションを呼ぶ事にする。 DoScript(action As String, from As String, [dialogs As Boolean]) Plays an action from the Actions palette. (1)アクションを定義(本体)しておく (1)直線 2本をセレクト (2)「新規にセットを作成 - 新規にアクションを作成」 *英字(所謂半角文字)で名前をつけておく方がスクリプト側からアクセスし易い (3)「パスファインダ-アウトライン」を実行 (4)線の色が消え、太さも細くなるのでその辺を調整。 *その際は必要なら終端の形状、角の形状も調整する。 (5)「再生/記録を中止」 (6)アクションメニューからアクションの保存をしたほうが良いでしょう。 (2)Application.DoScript(<アクションの名前>, <アクションの属するセットの名前>) (1)適宜パスを選択 * PathItem.Selected = true (2)illu.DoScript(<アクションの名前>, <そのセットの名前>) (3)結構時間が掛かるので、Application.ActionIsRunning でチェック * sleep 1 while illu.ActionIsRunning (3)GroupItem になってる。 (1)Layer.GroupItems.item(((*1*))) (1よりもっと大きいかも知れないけど) (2)GroupItem.PathItems.item( 1..(GroupItem.PathItems.Count) ) (3)その PathItem.PathPoints.item( 1..(PathItem.PathPoints.Count) ).Anchor をみると、グループ内での分割された線分の順番とか、交点は線分のどっち端とか、基準が良く解らない。 交点の座標が必要なら、これらの頂点(両端点)をすべて比べて同じものを抜き出す事になる。 全点座標を比較検討して交点座標(と交点)を抜き出したり、 適宜グループの名前や分割された線分の名前を設定するメソッドも必要でしょう ====パスファインダ-オプション このオプションはスクリプトから操作出来るような感じがしないので、設定値には十分注意する事。 rubyスクリプト実行前に所要の値になっているかどうか、GUIで確認すべき。 +精度 十分小さい値にする事。初期設定値 (({0.028})) でも良さそうだけど、(({0.01})) くらいにしようか。 +分割とアウトラインで塗りのないアートワークを削除 今の場合、塗りの無い線の交点を求めるのが目的なので、これは((*チェックしない*))。 +余分なポイントを削除 こっちのほうは目立った影響はないみたい。 ==2003/2/8 ===Document.PageOrigin :PageOrigin The zero-point of the page in the document without margins, relative to the overall height and width. 「プリント可能範囲 」(か「用紙の端」?) の左下端。 描画の基準点では((*ない*))。 ==2003/2/6 ===PathItem.SetEntirePath 不調 SetEntirePath(pathSpecification As Variant Array of Variant Array of 2 Singles) を使うと直接直線が引ける筈だがうまく行かない。 pathA = lay.PathItems.Add pathA.setEntirePath( Array[ Array[0,0], Array[100,100] ] ) でエラーになる。 blend.rb:56:in `method_missing': setEntirePath (WIN32OLERuntimeError) OLE error code:80070057 in the argument is not valid HRESULT error code:0x80020009 例外が発生しました。 from blend.rb:56 だからって、引数を Array,Array にしたり、0,0,100,100 にしても (({HRESULT error code:0x8002000e パラメータの数が無効です。})) が起こる。 ==2003/1/26 ===PathItems.item(1) PathItems コレクションの要素の item を取り出すメソッド PathItems.item(itemKey) itemKey は整数で良かったが、((*1*)) から始まる。rubyな 0 始まりで無いのに注意! 恐らく他のコレクションもみんな ((*1*)) 始まりだろう。要注意。 ==2003/1/12 ===Polygon(云々).Rotate(角度). ずれる。微妙に、1pt程度のズレかも知れないが((*ずれる*))。 傾いた多角形も自由頂点指定多頂点閉パスとして作成しないと、まさに思った位置には描画できない。 ==2003/1/11 ===角っコ(2) と言う訳でやってみた ((:./strokeCJ.rb.txt:)) doc.DefaultStrokeCap = Illu::AiButtEndCap doc.DefaultStrokeJoin = Illu::AiMiterEndJoin doc.DefaultStrokeMiterLimit = 5 としておいて((*下から*))順に、 (1)そのデフォルト値 (2)デフォルト値だが PointType = Illu::AiSmooth (3)デフォルト値だが2本のパスで引いてみた (4)StrokeJoin = AiBevelEndJoin (5)StrokeJoin = AiMiterEndJoin (6)StrokeJoin = AiRoundEndJoin PointTypeは関係無いみたい。 2本のパスで曳くと谷になっちゃう辺り見難かったかな、ちょっと拡大 ((:./strokeCJ.rb.txt:)) ===角っコと端っコ ====線の端っコを :パスの終わりで断ち切る PathItem.StrokeCap = AiButtEndCap : 1 :パスの終わりから StrokeWidth(の半分)だけ四角く終端する PathItem.StrokeCap = AiProjectingEndCap : 3 :パスの終わりで丸めて終端する PathItem.StrokeCap = AiRoundEndCap : 2 ====折線の交点を :パスの交点の所で断ち切る(わずかにはみでる) PathItem.StrokeJoin = AiBevelEndJoin : 3 :パスの交点の先まで StrokeWidth幅の線の延長に尖らす PathItem.StrokeJoin = AiMiterEndJoin : 1 :パスの交点の所で丸める PathItem.StrokeJoin = AiRoundEndJoin : 2 何れも丸めるときの半径はStrokeWidthの半分。 AiMiterEndJoin のとき、PathItem.StrokeMiterLimit が十分大きくないと Bevelのように断ち切られる。 ===StrokeCap, StrokeJoin StrokeCap: The type of line capping for a path stroke. *BUTTENDCAP *PROJECTINGENDCAP *ROUNDENDCAP StrokeJoin: The type of joints for a path stroke. *BEVELENDJOIN *MITERENDJOIN *ROUNDENDJOIN (()) より、 ってわけで AiStrokeCap AiButtEndCap : 1 AiProjectingEndCap : 3 AiRoundEndCap : 2 AiStrokeJoin AiBevelEndJoin : 3 AiMiterEndJoin : 1 AiRoundEndJoin : 2 ==2003/1/10 ===角っコ 折線の交点の尖り具合の制御はどうなってるんだろう。 ちょっと尖り過ぎてて、線の向こうに飛び出てしまう。 :StrokeCap :AiStrokeCap enumeration The type of line capping. :StrokeJoin :AiStrokeJoin enumeration Type of joints for the path. :StrokeMiterLimit :Single Are joins mitered (pointed) or beveled (squared-off)? AiStrokeCap, AiStrokeJoin ってなんだろう。 ==2003/1/5 ===線の幅 doc = illu.Documents.Add(Illu::AiDocumentCMYKColor, A5::WidthPt, A5::HeightPt) doc.DefaultStroked = true doc.DefaultStrokeWidth = 0.03 document単位でのパスを引く時の線の幅の指定。 *DefaultStroked は defaultで true なんだけどね。 *DefaultStrokeWidth でその線の幅を指定。default は 1point。それではちょっと太い。 正直、線幅 0.03point というのは細くし過ぎで、0.1より小さい値では、印字線幅に違いは無い様に見える (Canon BJ F200、それほど解像度の高くない非PSプリンタ)。まあ、0.1未満にしとけばいいのだろう。 ===閉じたパス PathItem.Closed = true Closed Path を作るとき。 PathItem.PathPoints.Add で頂点を付加え、適宜 Anchor座標(とDirection)を指定した後で、 単に PathItem.Closed を true にすれば良い。 たとえば自由頂点の多角形はそうやって作る。 ==2003/1/3 ===メソッドの値 結構値を返してくれないメソッドやプロパティ代入(ruby的にはこれもメソッド)が多くてストレスが溜まる。 (これはOLEなら仕方ない事だっけ、それとも Illustrator だけの事?) *例1 そういうわけで、直線を引く時 Anchor と Left[Right]Direstion は同座標、 point.LeftDirection = point.ReightDirection = point.Anchor = [, ] ではエラーになる point.Anchor = [, ] point.LeftDirection = point.Anchor point.ReightDirection = point.Anchor としないといけない。 *例2 paths.Polygon(云々).Rotate(角度).Name = 云々 は駄目で、 gon = paths.Polygon(云々) gon.Name = 云々 gon.Rotate(角度) としないといけない。 paths.Polygon(云々).Rotate(角度) は効く。 ===PathItem.Rotate(角度) PathItem.Rotate(角度) は度(degree) Rotate(Angle As Single, [changePositions As Boolean], [changeFillPatterns As Boolean], [changeFillGradients As Boolean], [changeStrokePattern As Boolean], [rotateAbout As AiTransformation]) ===PolygonのAnchorのDirection PathItems.Polygon で得られた PathItem の PathPoints の各点の Left[Right]Direction は自身だった。 pol = paths.Polygon(A5::WidthPt/2, A5::HeightPt/2, size/2, 5) pol.name = 'Hishi' pps = pol.PathPoints puts "\nPolygon" pps.Count.times do |i| pt = pps.item(i+1) puts "#{pt.PointType}:#{pt.Anchor[0]},#{pt.Anchor[1]}; L:#{pt.LeftDirection[0]},#{pt.LeftDirection[1]}; R:#{pt.RightDirection[0]},#{pt.RightDirection[1]}" end # 是に拠ると Polygon の各頂点の Left[Right]Direction は自身、PointType は勿論 AiCorner 出力 Polygon 2:184.7851563,55.14160156; L:184.7851563,55.14160156; R:184.7851563,55.14160156 2:115.0371094,269.8037109; L:115.0371094,269.8037109; R:115.0371094,269.8037109 2:297.6401367,402.4726563; L:297.6401367,402.4726563; R:297.6401367,402.4726563 2:480.2431641,269.8037109; L:480.2431641,269.8037109; R:480.2431641,269.8037109 2:410.4951172,55.14160156; L:410.4951172,55.14160156; R:410.4951172,55.14160156 ===PathItems.Polygon の作る正多角形だけど、 PathItems.Polygon の作る正多角形だけど、 作ったあとで回転させるとき、回転中心は、geometric(visible ?) bouds長方形の中心である。 Polygon定義のときに指定した外接円中心ではないのでちょっと混乱した。 また、そういう訳だから、偶数角形のときは大丈夫。 ==2003/1/2 ===RectangleのAnchorのDirection PathItems.Rectangle で得られた PathItem の PathPoints の各点の Left[Right]Direction は自身だった。 rec = paths.Rectangle(left_top[1], left_top[0], size, size) pps = rec.PathPoints pps.Count.times do |i| pt = pps.item(i+1) puts "#{pt.PointType}:#{pt.Anchor[0]},#{pt.Anchor[1]}; L:#{pt.LeftDirection[0]},#{pt.LeftDirection[1]}; R:#{pt.RightDirection[0]},#{pt.RightDirection[1]}" end # 是に拠ると Rectangle の各頂点の Left[Right]Direction は自身、PointType は勿論 AiCorner 出力 2:105.6401367,18.47265625; L:105.6401367,18.47265625; R:105.6401367,18.47265625 2:105.6401367,402.4726563; L:105.6401367,402.4726563; R:105.6401367,402.4726563 2:489.6396484,402.4726563; L:489.6396484,402.4726563; R:489.6396484,402.4726563 2:489.6396484,18.47265625; L:489.6396484,18.47265625; R:489.6396484,18.47265625 AiCorner : 2 AiSmooth : 1 ===PathIems.Ellipse の左上指定 ====PathIems.Ellipse も左上指定は、上、左 の順。混乱しそう。 Ellipse([top As Single], [left As Single], [Width As Single], [Height As Single], [reversed As Boolean], [inscribed As Boolean]) ===PathItems.Polygon ====PathItems.Polygon は正対した正多角形(外接円中心と外接円半径を指定)のみ Polygon([centerX As Single], [centerY As Single], [radius As Single], [sides As Long], [reversed As Boolean]) ==2003/1/1 ===PathItems.Rectangle の左上指定 ====PathItems.Rectangle の左上指定が、上、左 の順 Rectangle([top As Single], [left As Single], [Width As Single], [Height As Single], [reversed As Boolean]) X,Y順が直観と反するので凄く混乱した ===座標の単位 centimeters 28.346 points = 1 centimeter inches 72 points = 1 inch millimeters 2.834645 points = 1 millimeter picas 12 points = 1 pica Qs 0.709 point = 1 Q (1 Q equals 0.23 millimeter) (()) ===AdobeIllustrator Constants Ai constants は (())参照 ===Illustratorの起動とOLEオブジェクトの作成 こうやって require 'win32ole' #illu = WIN32OLE.new('Illustrator.Application') illu = WIN32OLE.connect('Illustrator.Application') module Illu; end WIN32OLE::const_load(illu, Illu) 作るわけだが、Illustratorは既に起動していないと起動できずに(起動中(終盤)に初期設定の読込みの辺りで)エラーになる。 (.new('Illustrator.Application') の場合) Illustrator が起動していれば、new で OLEオブジェクトを作る事が出来る。 というわけで、どうせ Illustrator が起動中でないといけないのなら、connect で OLEオブジェクトを作る事にしよう。 (Windows98SE 4.10.2222A, ActiveScriptRuby 1.6.8.0, Ruby1.6.8, Win32OLE 0.5.2) (Adobe Illustrator 10.0.3 Win版) ==きっかけ Illustrator で図を書かねばならない事情が出来た。しかし、マウスで書くのは性に合わず、得意でない。 図は同じ様なものを幾つもいくつも書く必要がある。というわけでスクリプトによる自動処理がしたい。 近くに Mac で AppleScript で自動処理をしている人がいるので可能ではあろう。 是を機会に MacOSX も用意して BSDな人 になるのも一案ではあった。 しかし、調べてみると Visual Basic によるスクリプティングの解説が Adobe自身にあった( (()) AppleScript含む。別に JavaScriptのもある)。 Visual Basic で出来て、VBScript で出来て、JavaScript で出来る: com である。 Windows Active Script なら Illustrator を操作できるわけだ。 そういうわけで「(()) で Illustrator 10 」。 ===メモ ここに書いて行くのは、上記に際して出会った事情のメモである。取敢えずの備忘録を兼ねたメモである。 機会があったら将来また見やすくまとめるかもしれないが、現状では単なる事象の順不同な羅列に過ぎない。 ((:
:)) ((:
:)) (()) 2003/1/1- ((:
:))