Hatena::ブログ(Diary)

名もないテクノ手 このページをアンテナに追加 RSSフィード

EPUB版『InDesign者のための正規表現入門』

InDesignのTips一覧

2011-09-29

[][][][] はじめてのReVIEW〜InDesignへの取り込み

たいへん遅ればせながらReVIEWを導入しました。著者や編集者が簡易に編集可能なReVIEW記法*1を基に、XHTMLやEPUB、XMLTeX、PDFなどを自動生成するフレームワークです。

昨年発行された『電子書籍で生き残る技術−紙との差、規格の差を乗り越える−』を読んでからReVIEWに大きな関心を持ちました。先月、海上忍さんのコラム「1つのソースでEPUBとPDFを生成できる「ReVIEW」を試す」を拝見して、ヤラねば! と思いつつずっと宿題だったんです。先日たまたま「ReVIEW の使い方 - A Day in Serenity @ Kenji」を読んでようやく重い腰をあげることとなりました。<重すぎるだろ...

でだ。「ReVIEWクイックスタートガイド」と前述のリンクなどを参考にしてちょろっとやってみたら、簡単すぎて拍子抜けしました。もう、書くことない。


(インストール上で注意点があるとすれば)Mac OS Xの環境ですと、rubyは1.8系なので、gemがそもそも入っていないはずです*2TeXやPDFを生成するためには、TeX環境が必要です。TeXやPDFを生成しないなら、TeX環境はいりません。

海上忍さんのコラム中で紹介されている達人出版会の高橋征義さんがご用意くださっているサンプルを使って、実際にEPUBを作ってみます。

$ review-epubmaker config.yml

これだけで、ディレクトリ内にEPUBが生成されました。これをAdobe Digital Editionsで見ると、こんな感じです。

f:id:seuzo:20110929141220p:image



自前で作ってみた

あんまりあっけないので、簡単なものをひとつ自前で作ってみました。ディレクトリ階層はこんな感じです。

f:id:seuzo:20110929142607p:image

gingatetsudono_yoru.zip 直

ファイル・フォルダ名説明
_cover.htmlEPUB用のカバーHTML
base.cssCSS(EPUBやHTMLに付加するスタイルシート)
ch01.re〜ch09.re章分けしたReVIEWファイル(ソースコンテンツ)
CHAPS章構成を記述したファイル(名前は固定)
config.ymlEPUBやPDFを生成する時の設定YAML
images画像用ディレクトリ(名前は固定)
 ch01-fig01.jpg〜ch09-fig09.jpg画像ファイル(ファイル名には章ファイルと同じプレフィックスが必要)
 cover.jpgカバー用画像
styPDFやTeX生成時のマクロ
 jumoline.styTeXマクロ
 samplemacro.styTeXマクロ

EPUBに書き出してみると、こんな感じです。gingatetsudono_yoru.epub 直

f:id:seuzo:20110929151507p:image

iPhoneiBooksで見ると、こんな感じ。*3

f:id:seuzo:20110929151508p:image f:id:seuzo:20110929151509p:image f:id:seuzo:20110929151510p:image f:id:seuzo:20110929151511p:image


ReVIEWフォーマット自体は、いくら簡易フォーマットとはいえ人間がタイプするものですから、当然タイプミスが含まれてしまいます。HTMLでさくっと確認できればより正確ですね*4

$ review-compile --target html ch02.re > ch02.html

f:id:seuzo:20110929152953p:image

確認するだけならこれでも悪くないんですが、デフォルトでは見出しにセクション番号が付いてしまいます。番号が不要ならば「--level=0」を指定しましょう。また、特定のスタイルシートを適用したいなら、「--stylesheet=hoge.css」を付けます。他のオプションの説明は「--help」で表示されます。

$ review-compile --target html --stylesheet=base.css --level=0 ch02.re > ch02.html

とすればこうなりました。

f:id:seuzo:20110929152954p:image


InDesignへの取り込み

ReVIEWファイルからは、XMLを生成できます。XMLを生成すれは、InDesignへの取り込みはごく簡単なことでしょう。

$ review-compile --target idgxml --level=0 ch01.re > ch01.xml

とすると、xmlが生成されます。

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:aid="http://ns.adobe.com/AdobeInDesign/4.0/"><title aid:pstyle="h2">一 午後の授業</title><?dtp level="2" section="一 午後の授業"?>
<p>「ではみなさん、さういふふうに川だと云はれたり、乳の流れたあとだと云はれたりしてゐた、このぼんやりと白いものが何かご承知ですか。」</p>
<p> 先生は、黒板に吊した大きな黒い星座の圖の、上から下へ白くけぶつた銀河帶のやうなところを指しながら、みんなに問ひをかけました。</p>
 ...(中略)
<p> そして教室中はしばらく机の蓋をあけたりしめたり本を重ねたりする音がいつぱいでしたが、まもなくみんなはきちんと立つて禮をすると教室を出ました。</p>
<img>
<Image href="file://images/ch01-fig01.jpg"  />
</img>
</doc>

ここで注目したいのは、このXMLInDesignに流し込むことを前提としていることです。それはxmlnsを見てもわかりますし、InDesign特有の改行の扱いが最適化されています。余計なインデントもありません。実際にInDesignに流し込んでみると、こんな感じになります。

f:id:seuzo:20110929165102p:image

たまたま縦書きなので、写真も回転してくれちゃっています。これはXML読み込みの仕様、後処理はスクリプトで。

f:id:seuzo:20110929165103p:image


この流し込み例はXMLを利用したものですが、ReVIEWフォーマットからInDesignタグに直接マッピングしてもいいかもしれません。事実、ぼくはReVIEWフォーマットの前身にあたるASCIIのEWBフォーマットで何度も原稿をいただいて、InDesignタグ(あるいはXPressタグ)に変換していました。


まとめ

ReVIEWフォーマットを利用する利点を3つ上げます。

  • コンテンツをテキストベースで保持・管理できる
  • 書き出されたタグそのものがきれい
  • フリー!

コンテンツの保持者は著者であり、出版社の編集者です。書籍の改版時や部分的な転用時、あるいは電子出版への展開などに、コンテンツの持ち主が扱いやすいテキストであることはとても重要なことです。コンテンツをInDesignドキュメントとして持っていたらどうでしょう? ほとんどの著者や編集者ではInDesignを扱えません。組版の専業者に別途ご相談ということになります。たいてい、InDesignドキュメントはコンテンツと組み指定が分ち難く一体になっています。電子出版のために、それを分離するには多大な手間と時間とコストがかかっています。

また、InDesignが書出すEPUBやHTMLは人が読める形になっていません。通常、構造化もされていません。InDesign CS5.5からは新たにアーティクルやタグなどの概念が持ち込まれましたが、それはオッカムの剃刀です。InDesignドキュメントでコンテンツを保持するのは、InDesignのアプリケーションやバージョンに縛られる結果になります。このへんのことは以前「InDesignは電子書籍の中間ファイルたりうるか?」に書かせていただきました。現在、InDesignのアップグレードは1年と短くなっており、完全にイノベーションのジレンマに陥っています。InDesignはコンテンツのハブではなく、商業印刷物のための入れ物デバイスだと考えます。

そして、ReVIEWはオープンソースフレームワークです。誰もが無償でこの環境を享受できます。よくわかんない権利関係に悩まされることもありません。操作同様、シンプルに選択できる選択肢です。


最後に、ReVIEW開発者のみなさまと、使用方法などをレポートしてくださったみなさまに感謝いたします。ぼくの初めてのサンプルはいろいろ間違いがあるかもしれませんが、ご指摘いただければ修正させていただきます。

*1:ReVIEWフォーマットは ASCIIのEWBを基本としながら、一部に RD や各種 Wiki の文法をとりいれて簡素化したものです。詳しくはhttps://github.com/kmuto/review/blob/master/doc/format.rdoc を参照

*2:ぼくは現在、ruby 1.9.2p136を使っているので、デフォルト環境ってものがよくわかっていないんですが... 1.9系ならふつーにgem install reviewだけでいけちゃいます

*3:ちょっと書き方が悪いせいかiBooksでは章の最初にゴミが出てしまったので、Sigilで保存し直しました。

*4:実運用上では、とても重要なことです。所詮、人間がタイプするものなどハナから間違いが存在してあたりまえです。正しい記法でなければ、正しく処理できません。ほら、hatena記法にも「確認する」ホタンが付いているでしょ

2010-09-22

[][][][][][]TSVからInDesignXML流し込み

昨日のエントリ「TSV(タブ区切りテキスト)からXMLを簡易生成」を実際にInDesign上で使ってみます。

CSVTSVを指定して、内部的にXMLに変換し、ノードごとにInDesignXML流し込みを行います。動画で見るとこんな感じ:

D

とりあえず、CS4でもCS5でも動作しました。テストしてみたい方はテストキットを用意しました。

data_tsv2xml.zip 直

////////////////////////////////////////////エラー終了
function my_error(mess) {
	if (mess !== "") {alert (mess)}
	exit();
}

////////////////////////////////////////////ファイル・フォルダ選択ダイアログ。ファイルオブジェクトを返す。
function chooseF(my_prompt, my_kind) {
	var my_path;
	if (my_kind === "Folder") {
		my_path = Folder.selectDialog (my_prompt);
	} else {
		var my_regex = new RegExp('\\' + my_kind + '$');
		my_path =  File.openDialog (my_prompt, function(file){return(file.name.match(my_regex) || file instanceof Folder) ? true : false}, false );
	}
	return my_path
}

////////////////////////////////////////////ファイルの内容を読み込んで返す 
function read_file(my_read_file_path) {
	var my_file_obj = new File(my_read_file_path);
	if (!(my_file_obj.exists)) {my_error("ファイルがありません\n" + my_read_file_path)};
	if(my_file_obj.open("r")) {
		var tmp_str = my_file_obj.read();
		my_file_obj.close();
	} else {
		my_error("ファイルが開けません\n" + my_read_file_path);
	}
	 tmp_str = tmp_str.replace(/[\r\n]+$/, '');//最後の行末の改行を削除
	return tmp_str;
}

////////////////////////////////////////////データをファイルに書き込む 。書き込んだファイルオブジェクトを返す
function write_file(my_write_file_path, my_data) {
	var my_file_obj = new File(my_write_file_path);
	my_file_obj.encoding = "UTF-8";//★この行がないとShift-JISで書き出される
	//if (!(my_file_obj.exists)) {myerror("ファイルがありません\n" + my_write_file_path)};
	if(my_file_obj.open("w")) {
		my_file_obj.write(my_data);
		my_file_obj.close();
		return my_file_obj;
	} else {
		my_error("ファイルが開けません\n" + my_write_file_path);
	}
}

////////////////////////////////////////////TSVから簡易XMLを生成 
function tsv2xml(my_tsv) {
	//XMLのノード名とアイテム名
	var my_nodeName = "record";//ノード名
	var my_imteName = "item"//item名(追番がつきます)
	
	//XMLの生成
	var my_data = my_tsv.split("\n");//文字列を行ごとに分割
	var my_xml = new XML("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n</root>");//XMLのrootオブジェクトの生成
	for (var i in my_data) {//行ごと
		my_xml.appendChild(<{my_nodeName}></{my_nodeName}>);//ノードの作成
		var tmp_line = my_data[i].replace(/[\r\n]+$/, '');//行末改行の削除
		var tmp_items = tmp_line.split("\t");//tabで分割
		for (var ii in tmp_items) {//カラムごとの処理
			my_xml[my_nodeName][i].appendChild(<{my_imteName}{ii}>{tmp_items[ii]}</{my_imteName}{ii}>);
		}
	}
	return my_xml;
}

////////////////////////////////////////////XMLコンテンツの修正 
function modify_xml(my_xml, my_ext) {
	for (var i in my_xml.record) {
		my_xml.record[i].item2[0] = my_xml.record[i].item2[0].toString() + "円";//item2の文字列に「円」を加える
		my_xml.record[i].appendChild(<item0img />);//画像用の空要素をひとつ作る
		var tmp_str = my_xml.record[i].item0[0].toString();//item0の文字列を取り出しておく
		my_xml.record[i].item0img[0].@href = "file:///" +  tmp_str + my_ext;//画像のフルパスを生成して属性値にする
	}
	return my_xml;
}

////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////メイン 
function main(){
var my_filepath = chooseF("TSV(タブ区切りテキスト)ファイルを選んでください", ".tsv");
var my_template_indd = chooseF("ひな形のInDesignファイルを選んでください", ".indd");
var my_img_folder = chooseF("画像フォルダを選んでください", "Folder");//

var my_data = read_file(my_filepath);//ファイルの読み込み
var my_xml = tsv2xml(my_data);//TSVからXMLへ変換
my_xml = modify_xml(my_xml, ".psd");//XMLコンテンツの修正

//以下InDesign内の処理
app.open(my_template_indd);//ひな形のドキュメントを開く
for (var i in my_xml.record) {
	var my_doc = app.documents[0];
	var tmp_xml_path = write_file('' + my_img_folder + "/tmp.xml", my_xml.record[i].toXMLString());//レコードをファイルに書き込み##ああ、importXML()はなんでXMLを直接読まないかね?
	my_doc.importXML(tmp_xml_path);
	var tmp_save_path = new File('' + my_template_indd.parent + '/' + my_xml.record[i].item0[0].toString() + '.indd');
	my_doc.save(tmp_save_path);//別名で保存
}
my_doc.close();//ドキュメントを閉じる
File('' + my_img_folder + "/tmp.xml").remove();//tmp.xmlを削除
}
main();

まあ、これだけだったら、データ結合でもいいんだが...<みもふたもない^^

2010-09-21

[][][]TSV(タブ区切りテキスト)からXMLを簡易生成

TSVからXMLを生成するアプリケーションはたくさんありますけれど、JavaScript内で完結させるために書いてみました。メモ。

こんなTSVがあったとします。

f:id:seuzo:20100919140828p:image

JavaScript内からこのファイルを読み込んで、内部的にXMLオブジェクトを生成します(エラー処理の関係でInDesignで使用するのを前提にしています)。

////////////////////////////////////////////エラー終了
function my_error(mess) {
	if (mess !== "") {alert (mess)}
	exit();
}

////////////////////////////////////////////ファイル・フォルダ選択ダイアログ。パス文字列を返す。
function chooseF(my_prompt, my_kind) {
	var my_path = '';
	if (my_kind === "Folder") {
		my_path = my_path + Folder.selectDialog (my_prompt);
	} else {
		var my_regex = new RegExp('\\' + my_kind + '$');
		my_path = my_path + File.openDialog (my_prompt, function(file){return(file.name.match(my_regex) || file instanceof Folder) ? true : false}, false );
	}
	return my_path
}

////////////////////////////////////////////ファイルの内容を読み込んで返す 
function read_file(my_read_file_path) {
	var my_file_obj = new File(my_read_file_path);
	if (!(my_file_obj.exists)) {myerror("ファイルがありません\n" + my_read_file_path)};
	if(my_file_obj.open("r")) {
		var tmp_str = my_file_obj.read();
		my_file_obj.close();
	} else {
		myerror("ファイルが開けません\n" + my_read_file_path);
	}
	 tmp_str = tmp_str.replace(/[\r\n]+$/, '');//最後の行末の改行を削除
	return tmp_str;
}

////////////////////////////////////////////TSVから簡易XMLを生成 
function tsv2xml(my_tsv) {
	//XMLのノード名とアイテム名
	var my_nodeName = "record";//ノード名
	var my_imteName = "item"//item名(追番がつきます)
	
	//XMLの生成
	var my_data = my_tsv.split("\n");//文字列を行ごとに分割
	var my_xml = new XML("<root>\n</root>");//XMLのrootオブジェクトの生成
	for (var i in my_data) {//行ごと
		my_xml.appendChild(<{my_nodeName}></{my_nodeName}>);//ノードの作成
		var tmp_line = my_data[i].replace(/[\r\n]+$/, '');//行末改行の削除
		var tmp_items = tmp_line.split("\t");//tabで分割
		for (var ii in tmp_items) {//カラムごとの処理
			my_xml[my_nodeName][i].appendChild(<{my_imteName}{ii}>{tmp_items[ii]}</{my_imteName}{ii}>);
		}
	}
	return my_xml;
}


////////////////////////////////////////////メイン 
var my_filepath = chooseF("TSV(タブ区切りテキスト)ファイルを選んでください", ".tsv");
var my_data = read_file(my_filepath);//ファイルの読み込み
var my_xml = tsv2xml(my_data);//TSVからXMLへ変換

my_xml.toXMLString();

XMLはこんな感じになっています。あとはお好きに...

f:id:seuzo:20100919140829p:image

2010-09-18

[][][]ファイルを書き出すときはFile.encodingを指定しないとShift-JISになる

下記のようなXMLがあったとします。

f:id:seuzo:20100918172520p:image

このXMLをJavaScriptで読み込んで、ごにょごにょして新しいXMLファイルに書き出そうと思いました。元ファイルはXML宣言も付いてるし、何も考えずに書き出しました。そしたらShift-JISになってんの。

f:id:seuzo:20100918172521p:image

で、これをそのままInDesignのドキュメントに喰わそうとするとエラーになります。XML宣言でencoding指定のないXMLはISO10646と解釈されるからじゃないかな? たぶん。っていうか、InDesignはどこまでS-JIS大好きなんだよ、Shift-JIS爆発しろ!

てなわけで、ファイルを書き出す時はちゃんとFile.encoding指定をしないと、無用な失望を味わったりします。

XMLに限らず通常のテキストでも同じですね*1XML世界でもJavaScript世界でもUnicodeなんで、つい自分が日本人であることを忘れてしまいます(それはない)。ご興味のある方はこんな感じでテストしてみてください。

////////////////////////////////////////////ファイルの内容を読み込んで返す 
function read_file(my_file) {
	var tmp_str = "";
	if (my_file.reflect.name == "String") {my_file = new File(my_file)};//ファイルパス文字列だった
	if (fh = my_file.open("r")) {//ファイルを読み込みモードで開く
		tmp_str = my_file.read();
		my_file.close();
	}
	return tmp_str;
}

////////////////////////////////////////////データをファイルに書き込む 。書き込んだファイルオブジェクトを返す
function write_file(my_write_file_path, my_data) {
	var my_file_obj = new File(my_write_file_path);
	my_file_obj.encoding = "UTF-8";//★この行がないとShift-JISで書き出される
	//if (!(my_file_obj.exists)) {myerror("ファイルがありません\n" + my_write_file_path)};
	if(my_file_obj.open("w")) {
		my_file_obj.write(my_data);
		my_file_obj.close();
		return my_file_obj;
	} else {
		myerror("ファイルが開けません\n" + my_write_file_path);
	}
}

var my_file = File.openDialog("XMLファイルを指定してください");
var my_folder = my_file.parent;
var tmp_str = read_file(my_file);//ファイルの読み込み
var my_xml = new XML(tmp_str);//XMLオブジェクトの生成
//このへんでごにょごにょする
write_file('' + my_folder + '/new.xml', my_xml.toXMLString());//ファイル書き込み

*1:だけどInDesignはいまだにUTF-8のテキストが読めません

2009-09-28

[][][]選択したテキストをタグ付けする

InDesign上でXMLタグを付ける意味*1がなんだかいまひとつよくわかっていないんですけれど^^ 勉強部屋に書いたのでメモ。よくわかっていないので、storyじゃなくてもいいのか、とか、重複していても不都合はないか、とか、まるで検証していません。

選択したテキストにxmlタグ - InD-Board

var my_doc = app.activeDocument;
var my_textFrame = my_doc.selection[0].parentTextFrames[0];
var my_txt = my_doc.selection[0];

var my_root = my_doc.xmlElements[0];//Root要素

var my_textFrame_element = my_textFrame.associatedXMLElement;
if (my_textFrame_element === null) {
	my_textFrame_element = my_root.xmlElements.add("textFrame");
	my_textFrame_element.markup(my_textFrame);
}

var my_txt_element = my_txt.associatedXMLElements[1];
my_txt_element = my_textFrame_element.xmlElements.add("item");
my_txt_element.markup(my_txt);

*1:たくさんあるのならなんらかのシステマチックな方法が必要だし、ちょっとならタグパネルからやってもたいして手間は変わらないし...