iPhone3GS的な

iPhone3GSから始まったブログ。今はiPhone8。ポケットコンピュータ的な活用法を探る!
このエントリーをはてなブックマークに追加

Illustratorで差し込み印刷をした。実はかなり優秀な機能だった。

年賀状の宛名印刷で、はじめてIllustratorでの差し込み印刷に挑戦した。

苦戦したが、結果的に希望通りの要件を満たす宛名印刷に成功した。

Illustratorの「データ駆動型グラフィックス」という機能を利用した。今回は宛名印刷だったが、不動産情報のチラシとか、複数パソコンのスペックを見比べるようなカタログ?とか、一定の書式の情報を羅列しつつも、物件の種類などによって異なるアクセントを付けたい印刷物の自動レイアウトに威力を発揮しそうな機能だとわかった。

はじめて「データ駆動型グラフィックス」を試してみる方はこちらのサイトの記事が大変素晴らしく参考になる。私もこちらの記事を突破口に、成功に漕ぎつけた。

ただし、シンプルな差し込み印刷は上のサイトの情報だけで実現できるが、「データ駆動型グラフィックス」機能の力を最大限に発揮するには、Illustratorの外部でスクリプト言語などを使って、「データ」の作成を自動化(単なる自動化ではなく、元データの内容によって判断を加えながら本機能用のデータを自動生成)する工夫が必要になる。本投稿では、その辺りのヒントを提供できればと思う。
※扱うデータ数が少なければ、Illustratorでデータを手入力しつつ、Illustratorで保存していくことで、Illustratorだけで完結できる。しかし大量のデータを元データとしてすでにデジタルデータで持っているなら本投稿の内容がヒントになるだろう。

経緯と要件


宛名印刷は、これまでAccessで作ったレポートを何年も使ってきたが、パソコンの故障でファイルを失ったため、再作成の必要に迫られた。

Accessは自分の思い通りの配置にするのが難しい(あらゆる意味でIllustratorみたいにレイアウトしたい)のと、レポートに配置した画像が綺麗に印刷できない(自分のやり方がマズイだけかもしれないが回避法がわからない)ので、宛名面もIllustratorでやることにした。

試行錯誤の結果、以下の要件を満たす差し込み印刷を実現できた。

●住所録の元データは嫁さんが管理するExcelファイル。
●宛名は最大で4人まで対応したい。「様」の表示・非表示も適切に制御。
●姓と名は別にして、それぞれ両端揃えにする。
●姓または名が一文字だと、Illustratorの両端揃えは先頭に配置されるが、センターにしたい。
●「喪中の人」や「年賀状のやりとりをしてない人」を印刷しない。

ただし、これを「Illustratorでやった」というと多少語弊がある。
他のテキストエディタの機能を使ったり、スクリプト言語(今回はPHP)によるちょっとした自作スクリプトも使用した。
なんらかの自動化の工夫をしないと、持っているデータの再入力(手入力)が必要になる。
(プログラム言語は使わずに、Excelの数式を使ってなんとかすることもできそうだ。)

Illustratorでの差し込み印刷の概要


Illustratorの「データ駆動型グラフィックス」という機能を利用したのだが、普通の差し込み印刷だけでなく、配置画像リンクやグラフの元データなども1件毎に差し替え可能で、かつ、1件毎にどのオブジェクトを表示し、どのオブジェクトを表示しないかをも指定できることで、使いようによってはかなり高度なレイアウト制御が可能な仕掛けとなっている。

そして、その仕掛けのキモとなるデータの保存・読込のためのファイルフォーマットにXMLが採用されている。
単純な表示文字列のリストでなく、「このオブジェクトはこういう文字列だよ」「このオブジェクトのリンク画像のパスはこれだよ」「このオブジェクトは表示するよ」「このオブジェクトは非表示だよ」と、オブジェクトの表示状態も保存するため、複雑な情報を保存しやすいXMLファイルが採用されているのだろう。

オブジェクトの表示・非常時情報も扱ってくれるお陰で、単に1件ごとに文字を差し替えるだけでなく、「名前2」が空白だったらその後の「様2」は表示しないということも指示できるわけだ。ただし、この判断はIllustratorは自動的にやってくれない。XMLファイルを作る際に、「この家は名前2、3、4が空白だから様2、3、4は非表示にしよう」と自分で判断してそのように作成してなければならない。なので、自分はその判断を自動化するためのPHPスクリプトを書いてXMLファイルを自動生成した。

こうしてプログラム言語を介在させることでこの方式は、さらに発展的な使い方もできる。マクロ言語みたいに直接オブジェクトのフォントサイズや色・文字間隔などを操作できなくても、あらかじめそういう細かい書式が異なった複数のオブジェクトを同じ位置に重ねて作成しておけば、表示・非表示の切替で、あたかも書式を操作したみたいに変化させることも可能だ。例えば、文字数の多い住所はフォント小さめで文字間隔狭め、文字数が少ない住所はフォント大きめで文字間隔広めで表示させるようなこともやれそうだ。(印刷し終わってから気が付いたので今回はやれなかった。)

このように「オブジェクトの表示状態」までデータとして保存・読込することでレイアウトを自在に操る仕組みが「データ駆動型グラフィックス」というものらしい。

XMLを採用したために素人は手を出しにくい機能になってしまっているが、その分プロには大変役立ちそうな機能となっている。(プロと言っても、プログラミングの経験のある人か、そういうパートナーが必要と思う)

ただ、Adobeとしては、この機能は外部ファイルを読み込むところから始まるものとしてでなく、Illustratorで入力したものを1件ずつデータセットとして保存していき、そうやって保存したものをまた読み込んで使う前提らしい。(Illustratorで入力してIllustratorで使用する限りは直接XMLファイルの中を見る必要はない)
少なくとも表向きはそうしておかないとサポートが大変になりすぎるのだろう。XMLファイルはノンプログラマーには簡単に扱えるものではない。逆にプログラマーなら、概要が分かってしまえば何をどうするべきかすぐにわかるだろう。

それでも本当に単純な差し込み印刷なら、使用するXMLファイルも単純で、ノンプログラマーでもExcelのセルを上手く使ってデータとデータの間にXMLタグを割り込ませてから一体化することで比較的容易に必要なXMLファイルを作成できる。(こちらのサイトの記事が大変素晴らしく参考になる。私の今回の挑戦も突破口はここだった。)
あるいは、VimなどのテキストエディタにExcelデータをコピペして、区切り文字のタブをXMLタグに一括置換してやる方法でもいい。(一発置換ではなく、数発置換のイメージだが)

ただ、上でも触れたが「オブジェクトの表示・非表示」までデータとして保存・読込することでレイアウトを自在に操る仕組みが「データ駆動型グラフィックス」なので、そこをフル活用するためにはやはり、なにかプログラム言語を使って、ソースデータ1件ごとの内容を吟味して表示・非表示を決定しつつXMLファイルを自動生成するようにしたいものだ。(いや、上のリンク先のExcel作戦でも、表示・非表示(true/false)を格納する列を増やし、直接true/falseを書き込むのではなく数式で他のセルを参照してtrue/falseを決めるようにすれば、プログラミングなしでもいけそうだ。プログラミングかExcelの数式かどちらかが得意ならなんとかなりそうだ。)

今回私はPHPスクリプト(コマンドプロンプトで使うタイプ)を作成したので、記事の末尾に添付しておく。(「ソースコードの書き方」のお手本にはならない雑なものだが、どういうことをしているかの参考にはなるだろう。)

Illustratorでの年賀状宛名差し込み印刷の手順


  • ●まず、印刷レイアウトを作成
    • ・葉書サイズのアートボードを作成
    • ・年賀状宛名面のスキャン(Photoshopなどで)
    • ・年賀状のスキャン画像を下敷き用レイヤーに正しく配置(本当に原寸で正しい位置か念入りに)
    • ・下敷きを参考に、上層のレイヤーに実際に印刷するテキストオブジェクトを配置
    • ・フィールド化するテキストオブジェクトには適切な内容(実際のデータの値やわかりやすいダミー値)を入力しておく
    • ・上記のものを含め動的に扱うオブジェクトは、レイヤーウインドウで、判別しやすい名前をつけておく

  • ●差し込み印刷のフィールドを作成(「変数」を作成して関連付けるとフィールドになる)
    • ・「動的に内容を変えるための変数」と「表示・非表示を設定するための変数」がある
    • ・フィールド化したいテキストオブジェクトや動的に表示・非表示を切り替えたいオブジェクトを選択し、「変数」ウインドウの下部のボタンをクリックすると変数が作成され、テキストオブジェクトと関連付けられる。
    • ・一通り変数を作成後「変数」ウインドウの「カメラのアイコン」をクリック。
      (「カメラアイコン」のクリックで、データセット(1件分のデータの組)が一つ確定する。その時の文字内容、表示・非表示の状態で確定される。この要領で実際のデータを全件入力していく方法もありえるが、1件分だけで「変数ライブラリを保存」で保存してしまい、生成されるXMLファイルを雛形として全件分のXMLファイルを好きなプログラム言語で自動生成して、それを読み込むほうが現実的である。)

  • ●雛形用に保存したXMLファイルと宛先csvファイルデータを元に、全件分のXMLファイルを好きなプログラム言語で自動生成(本記事の末尾にPHPの参考スクリプトあり)
  • ●生成されたXMLファイルをIllustratorに読み込む
  • ●1件ずつ順にオブジェクトに読み込ませてプレビュー的なことをできる。(この状態でデータ内容を修正することも可能。ただ、自分はここでデータの間違いに気付いた場合は元データを修正し、XMLファイルを再作成し、再読込させた。)
  • ●全データがOKならアクションを使って全件自動印刷開始!
    • ・新規セットを作成
    • ・新規アクションを作成
    • ・記録開始
    • ・1件分の印刷をして記録を中止(トレイの選択も明示的にしておく。じゃないと1枚ごとに聞かれたりする)
    • ・印刷ダイアログを表示しないようにしておかないと1枚ごとに印刷ダイアログが表示される
    • ・「バッチ」で「実行」の「セット」と「アクション」のところを先ほど作成したものにする。
      「ソース」のところは「データセット」になっていることを確認し、OKで印刷開始。(だったかな?)



<?php
//PHPで書いたが、WEBアプリではなく、コマンドプロンプトで利用するコンソールアプリ。
//結果を保存せず、echoしているので、コマンドプロンプトで「php thisScript.php > jusho.xml」のようにリダイレクトする必要有り。
//このスクリプト自身のエンコードはUTF-8にする。

//csvファイルの読み込み。Excelで保存して作成したcsvファイルではない。
//Excelからエディタにコピペして、タブをカンマに置換して作成した、単純なカンマ区切りテキスト。
$lines = file('jusho.csv', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

$num=0;//初期化
$datasets='';//初期化
$count = array(1,2,3,4);//ループ用カウンタ

//宛先1件ごとにループ
foreach ($lines as $eachLine){
list($add1,$add2,$z1,$z2,$familyNm,$person[1],$person[2],$person[3],$person[4],$flgActive)=explode(',',$eachLine);//カンマ区切りデータを変数に分解
//住所1、住所2、郵便番号1、郵便番号2、姓、名1、名2、名3、名4、喪中  の順でデータが並んでいる。住所2はマンション・アパート

if(($flgActive == "y") or ($flgActive == "×")){//「喪中」フィールドのチェック。「y」なら喪中。「年賀状やりとりなし」を意味する「×」も同フィールドに混在
continue;
}

if($add2 == ""){//$add2(住所2)が空白なら非表示(どうせ空白なので、非表示にする必要はないと思うが、なんとなくこうしてしまった。面倒なのでこのまま。)
$flgAdd2 = "false";
}else{//空白でなければ表示
$flgAdd2 = "true";
}

if($person[2] == ""){//2人目が空白なら、その項目と、その項目の後につく「様」も非表示(ここも、「様」の非表示は必要だが、空白になる項目自体はどうせ空白だから非表示にする必要がないと思う。)
$flgPerson2 = "false";
$flgSama2 = "false";
}else{
$flgPerson2 = "true";
$flgSama2 = "true";
}

if($person[3] == ""){//3人目
$flgPerson3 = "false";
$flgSama3 = "false";
}else{
$flgPerson3 = "true";
$flgSama3 = "true";
}

if($person[4] == ""){//4人目
$flgPerson4 = "false";
$flgSama4 = "false";
}else{
$flgPerson4 = "true";
$flgSama4 = "true";
}

if(preg_match('/^.$/u',$familyNm)){//姓が1文字だけだった場合
$familyNm = " " . $familyNm . " ";//全角スペースを前後に追加(中央揃えのようになるため)
}

foreach ($count as $curIdx){//名1から名4までループ処理
if(preg_match('/^.$/u',$person[$curIdx])){//名が1文字だった場合
$person[$curIdx] = " " . $person[$curIdx] . " ";//全角スペースを前後に追加
}
}

$num++;//「データセット 1」 とか「データセット 2」 とかになる数値

//1件ごとに異なる部分のテキストデータを生成し、$datasets変数に追記していく。
$datasets .= <<<_EOS_
<v:sampleDataSet dataSetName="データセット $num">
<変数1>
<p>$z1</p>
</変数1>
<変数2>
<p>$z2</p>
</変数2>
<変数3>
<p>$familyNm</p>
</変数3>
<変数4>
<p>$person[1]</p>
</変数4>
<変数5>true</変数5>
<変数6>
<p>$person[2]</p>
</変数6>
<変数7>$flgPerson2</変数7>
<変数8>$flgSama2</変数8>
<変数9>
<p>$add1</p>
</変数9>
<変数10>
<p>$add2</p>
</変数10>
<変数11>$flgAdd2</変数11>
<変数12>
<p>$person[3]</p>
</変数12>
<変数13>$flgPerson3</変数13>
<変数14>$flgSama3</変数14>
<変数15>
<p>$person[4]</p>
</変数15>
<変数16>$flgPerson4</変数16>
<変数17>$flgSama4</変数17>
</v:sampleDataSet>
_EOS_;
}//1件ごとのループの終端


//XMLファイルの全体部分。変数 $datasets のところに、1件ごとのデータを全件ぶん合わせた内容が展開される
$baseStr = '<?xml version="1.0" encoding="utf-8"?>';
$baseStr .= <<<_EOS_

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd" [
<!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
<!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
<!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
<!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
]>
<svg>
<variableSets xmlns="&ns_vars;">
<variableSet varSetName="binding1" locked="none">
<variables>
<variable trait="textcontent" category="&ns_flows;" varName="変数1"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数2"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数3"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数4"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数5"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数6"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数7"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数8"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数9"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数10"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数11"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数12"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数13"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数14"></variable>
<variable trait="textcontent" category="&ns_flows;" varName="変数15"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数16"></variable>
<variable trait="visibility" category="&ns_vars;" varName="変数17"></variable>
</variables>
<v:sampleDataSets xmlns:v="&ns_vars;" xmlns="&ns_custom;">
$datasets
</v:sampleDataSets>
</variableSet>
</variableSets>
</svg>
_EOS_;

echo $baseStr;//エコーしているだけで、ファイルに保存していないので、コマンドプロンプトで「php thisScript.php > jusho.xml」のようにリダイレクトする必要有り。
?>



以上!

   
関連記事
スポンサーサイト




<広告>

Comment

よしお says... "xmlファイルを作るエクセルを作りました!"
はじめまして、こんにちわ。
検索して、こちらの記事を見つけ、大変参考にさせていただきました。
便利に使わせていただいております。
ありがとうございました。

データのxmlファイルをパパッと生成するエクセルファイルを作りまして、ブログにて公開しております。
お使いいただければ幸いです。
2015.11.07 14:49 | URL | #- [edit]

Post comment

管理者にだけ表示を許可する

Trackback

trackbackURL:https://ti001.blog.fc2.com/tb.php/335-4021c443