2008年12月21日日曜日

Illustrator CS3でScriptUIするときはBridgeTalkしなくちゃいけない?


ScriptUIを使っていてハマったのでメモ。
以下のスクリプト。


parette = new Window("palette","ScriptUI TEST");
parette.orientation = 'row';
parette.btn = parette.add('button', undefined, '選択したものの数は?');

parette.btn.onClick = function() {
parette.close();
var obj=app.activeDocument.selection;
alert(obj.length);
}
parette.show();
これをIllustratorで動かしてクリックしても、反応しない。
ちなみに、InDesignで動かせばちゃんと選択項目の数を教えてくれる。
parette = new Window("palette","ScriptUI TEST");
parette.orientation = 'row';
parette.btn = parette.add('button', undefined, '選択したものの数は?');

parette.btn.onClick = function() {
parette.close();
var bt=new BridgeTalk();
bt.target = "Illustrator";
bt.body ="alert(app.activeDocument.selection.length)";
bt.send();
}
parette.show();
これなら動く。
どうも、Illustrator CS3でScriptUIを使う場合は、BridgeTalkで話しかけないと反応しないみたい。
うーん…。

2008年12月20日土曜日

InDesignスクリプトのArrayを拡張してみる

選択範囲の大きさを求める関数を、InDesignのArrayに拡張してみるテスト。
Arrayのprototypeに関数を設定してしまえばよい。
Array.prototype.visibleBounds=function(){
var ary=this[0].visibleBounds;
if(ary){
for(i=1;i<this.length;i++){
var follow=this[i].visibleBounds;
if(ary[0]>follow[0]) ary[0]=follow[0];
if(ary[1]>follow[1]) ary[1]=follow[1];
if(ary[2]<follow[2]) ary[2]=follow[2];
if(ary[3]<follow[3]) ary[3]=follow[3];
}
}
return ary;
};

Array.prototype.geometricBounds=function(){
var ary=this[0].geometricBounds;
if(ary){
for(i=1;i<this.length;i++){
var follow=this[i].geometricBounds;
if(ary[0]>follow[0]) ary[0]=follow[0];
if(ary[1]>follow[1]) ary[1]=follow[1];
if(ary[2]<follow[2]) ary[2]=follow[2];
if(ary[3]<follow[3]) ary[3]=follow[3];
}
}
return ary;
};

選択したもの全体の大きさを出したいときは、選択して
var objs=app.activeDocument.selection;
$.writeln(objs.visibleBounds());
$.writeln(objs.geometricBounds());

で、visibleBounds,geometricBoundsの形でとれる。
JavaScriptは不思議だー。

2008年12月14日日曜日

Illustratorで、選択オブジェクトの持つプロパティと値をコンソールに書き出す

InDesignはオブジェクトの値をtoSource()で見られるけれど、Illustratorでは見られない。
いちいちJavaScriptリファレンスで確認するのも大変だし、どうするかなーと思ってた。

JavaScript の配列と連想配列の違い - IT戦記
配列は素直に for
連想配列には for in

あ、そうか。JavaScriptのオブジェクトは全て連想配列だから…
第一章 JavaScriptにおけるオブジェクトの基本的性質を知る
var obj=app.activeDocument.selection[0];

for (var i in obj) {
$.write(i+":");
try{
$.writeln(obj[i])
}catch(e){
$.writeln(e.toString())
}
};

やっぱりJavaScriptはきちんと勉強しないとだめだね。

091216追記:ワンライナー、変数がかぶってるところにも使えるようにfunctionに。
var o=app.activeDocument.selection[0];
(function(o){for(var i in o){try{i+=':'+o[i]}catch(e){i+=':'+e}$.writeln(i)}})(o);

2008年12月12日金曜日

Antenna House Formatter の説明会に行ってきました

表題の通り、名古屋駅前で開催されたアンテナハウス主催「CSSによる文書レイアウト指定セミナー」へ行ってきました。

小さな会議室で、集まったのは自分を含め10人。これは多いのか、少ないのか。
名古屋という土地柄から見れば多いのかも……。
内容は、アンテナハウスのXSL-Formatterの新バージョン「Antenna House Formatter v5」の紹介と、CSSによる組版の説明。あとWord2DITAという、WORDでDITAを作成するためのプラグイン製品の紹介。

AH Formatter、なかなか印象的でした。

まず料金体系。今回、フル機能版に加えてLite版を用意して、用途に会わせて6製品にわけ、Lite版の方はかなり戦略的な価格に設定してきました。
手元にある説明会資料によると、単機能のLiteでスタンドアロンならば4万。
ニュースリリース参照。
ちょっと奮発すれば個人でも買ってみようかと思える値段。
ただし、Lite版は1文書300ページ以内とか、PDF/XやPDF/A出力機能がない等の制限あり。もっともAcrobatを持っていれば、標準の書き出しを使う必要はないでしょう。

それで、今回の一番の目玉、CSS組版。
セミナー自体は淡々と進みましたが、これはちょっと衝撃でした。

アンテナハウスのサイトで配布しているHTML+CSSのサンプルを、そのままFirefoxで開けてみると、CSS3やAH拡張部分以外は普通に見れてしまうんです。HTMLだから当然ですが。
これをAH Formatterに通すと、きちんとページ組みされて出てくる。CSSをきちんと作ってさえいれば、もう自動組みする必要さえない。完全なワンソース。
あれ?でもそうなると、普通のブラウザが全てCSS3に対応するようになったらどうなるんだろう…。

アンテナの司会の方がぽろっと一言。
「まあ、今はFormatterが他の3、4年先を行っているだけで、3年ぐらいたつとブラウザに追いつかれるかもしれないんですよ〜…」

そう、CSS3は標準化される予定のフォーマットなわけで、そうなれば当然ブラウザに搭載されるわけです。そうなればblogもwikiも最初からページ組を意識して作られるようになります。WEBで見た物が、何も手を加えることなく、そのまま、普通に、タダで組版されて出てくる時代が近いうちに来る。長文組版、大学の紀要やマニュアルなんかのDTPの仕事は確実になくなりそう。
だからこそアンテナハウスは真っ先にCSS組版を作ったのだろうし、これから先はブラウザに比べてどう付加価値をつけるか、日本語組版や多国語をどこまできれいに出力できるかで勝負するつもりなのだろうと思います。
自分らの仕事は、CSS3を駆使していかに上手く組版するかがポイントになるでしょう。機能が多い分使いがいはありそうですが、そうなるとWEB系の人らとガチ勝負になるなー。

セミナーで出た話だと、W3Cの慣例だと実装が2つ揃ったところで勧告になるそうで、たぶんCSS3勧告は2011年頃までかかるだろうとの事。でも3年なんてすぐですもんね。組版の未来を占う上でも、AH Formatterは注目です。

他に出た話。
  • 現状ではCSS組版はFO組版よりだいぶ遅い。分厚いマニュアルや高度なサーバ処理にはFOを進めるとの事。
  • CSS,FOを混在させて組版することはできない。
  • AHの独自拡張部分は、他の仕様と区別するためベンダープレフィックスをつけて欲しい(なしでも出るらしい)。
  • サイズプロパティに入れられるB5,B4の指定はISOの標準なので、日本のB4,B5版はJIS-B4,JIS-B5と入れる。AH独自仕様。
  • スタンドアロン版にはJAVAインターフェイス等の開発環境は含まれない(以前同様)。
  • FOとCSSの機能の差については、体験版をダウンロードした中にあるオンラインマニュアルに対応表がある。

あと、Word2DITAについて。
Darwin Information Typing Architecture - Wikipedia
DITAは技術情報を配布するために策定されたXML仕様。DITAで検索するとアンテナハウス関連のページばかりかかるので、アンテナハウスが押している仕様なのはわかります。
Word2DITAはそれをWORDを使って簡単に作成できるというもの。ウィザード形式に画面の進めていくとテンプレートが生成されて、その内容を埋めることでDITAを書き出せる。再利用性を考えた仕様なので、トピックごとの小さなXMLになり、最終的にマップに取り込んで一つの文書になるらしいです。

なんというか、Wordで作成できる以前に、なぜDITAが便利なのかの理解が進みませんでした。
必要を感じなければ誰も興味を持たないわけで、たぶん流行らないだろうなぁ。。。

2008年12月4日木曜日

GroovyからJPEG画像をRGB→CMYK変換

imageio を使った jpeg の rgb, cmyk 相互変換 - 夜の Discovery
Java Programming [Archive] - HELP!!! URGENT!!!! convert a jpg CMYK to jpg RGB
上記ページのJava→Groovy翻訳に挑戦。自分の力ではこれ以上コード削れなかった…。

import java.awt.image.*;
import java.awt.color.*;
import java.awt.event.*;
import java.awt.*;
import com.sun.image.codec.jpeg.*;

String USAGE = "groovy CMYKSave <cmykProfile> <rgbJPEGFile> <cmykJPEGFile> <invert=yes|no>"

//引数が4つ未満ならUSAGEを表示して終了
if(args.length<4){
println(USAGE)
System.exit(0)
}

//引数それぞれの割当て
String cmykProfile = args[0]
String rgbJPEGFile = args[1]
String cmykJPEGFile = args[2]
boolean invert = "true".equalsIgnoreCase(args[3])

//元イメージを読み込む
def decoder = JPEGCodec.createJPEGDecoder(new FileInputStream(rgbJPEGFile))
def rgbImage = decoder.decodeAsBufferedImage();

//CMYKプロファイルからCMYKカラースペースを作成
def p = ICC_Profile.getInstance(new FileInputStream(cmykProfile))
def cmykCS = new ICC_ColorSpace(p);

def out = new FileOutputStream(cmykJPEGFile)

//RGBイメージからCMYKへのコンバート
def rgbCS = rgbImage.getColorModel().getColorSpace()
def rgbToCmyk = new ColorConvertOp(rgbCS, cmykCS, null)

//変換先CMYKイメージのカラーモデル作成
def cmykModel = new ComponentColorModel(cmykCS,[8, 8, 8, 8] as int[],
false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE)
def cmykRaster =
cmykModel.createCompatibleWritableRaster(rgbImage.getWidth(),rgbImage.getHeight())

//ここでCMYKにコンバートする
rgbToCmyk.filter(rgbImage.getRaster(), cmykRaster)

//trueなら階調反転
if(invert){
println("CMYKの階調を反転します")
def swap = new byte[256]
for(i in 0..<swap.length){
swap[i] = (byte)(255-i)
}
def lookup = new ByteLookupTable(0, [swap, swap, swap, swap] as byte[][] )
def luop = new LookupOp(lookup, null)
cmykRaster = luop.filter(cmykRaster, cmykRaster.createCompatibleWritableRaster())
}

//最後にCMYK画像を保存する
def encoder = JPEGCodec.createJPEGEncoder(out)
def param = encoder.getDefaultJPEGEncodeParam(cmykRaster, JPEGDecodeParam.COLOR_ID_CMYK)
param.setQuality(1, false)
encoder.encode(cmykRaster, param)
out.close()
println("イメージ${cmykJPEGFile}を保存しました。")

動作確認は
$ groovy CMYKSave.groovy JapanColor2001Coated.icc test.jpg test_out.jpg true

って感じです。