add/create_textflow 関数の mark インラインオプションを使って、テキストフロー内の適切な位置にマークをします。fit_textflow 関数の returnatmark オプションを使って mark インラインオプションが指定された値により定義されたテキストの位置で改行します。この改行は、_mark# 文字列を対象としています(# には適切にマークされた値です)。マークのついた文字列は、常に一つのフィットボックス内に収まります。
/*
* 行のまとまり :
* 一つのテキストフロー内に出力する行のまとまりを指定します。
*
* add/create_textflow 関数の mark インラインオプションを使って、テキスト
* フロー内の適切な位置にマークをします。fit_textflow 関数の returnatmark
* オプションを使って mark インラインオプションが指定された値により定義さ
* れたテキストの位置で改行されます。この改行は、_mark# 文字列を対象として
* います(# には適切にマークされた値です)。マークのついた文字列は、常に一つ
* のフィットボックス内に収まります。
*
* 必要な製品 : PDFlib/PDFlib+PDI/PPS 10
* 必要なデータ : 無し
*/
package com.pdflib.cookbook.pdflib.textflow;
import com.pdflib.pdflib;
import com.pdflib.PDFlibException;
public class keep_lines_together
{
public static void main (String argv[])
{
/* 必要に応じてデータファイルがあるフォルダのパスを指定する */
String searchpath = "../input";
String outfile = "keep_lines_together.pdf";
String title = "Keep Lines Together";
pdflib p = null;
int tf = -1;
int exitcode = 0;
final int ystart = 700;
final int boxwidth = 210, boxheight = 110;
final int offset = 10;
final int xleft = 10;
final int xright = xleft + boxwidth + 80;
String result, optlist;
int lastmark = 0;
int y = ystart;
try {
p = new pdflib();
p.set_option("searchpath={" + searchpath + "}");
/* load_font() 等の戻り値を確認する */
p.set_option("errorpolicy=return");
/* 出力文書名を指定して、出力文書を開く */
if (p.begin_document(outfile, "") == -1)
throw new Exception("Error: " + p.get_errmsg());
p.set_info("Creator", "PDFlib Cookbook");
p.set_info("Title", title);
/* テキストを作成する。
* ページ上にテキストを配置する。ソフトハイフンは文字参照""で表す。
* (文字参照はcharrefオプションで有効となる)
* インラインオプション "mark"は分割されてはいけないテキスト。
* 1つのはめ込み枠において、奇数のマークまでテキストは保持される。
*/
final String text =
"<mark=0>Have a look at our new paper plane models!" +
"<mark=1>" +
"<mark=2><nextline fillcolor={rgb 0.5 0.0 0.0}>Long Distance Glider:<nextline>" +
"With this paper rocket you can send all your messages even when " +
"sitting in a hall or in the cinema pretty near the back." +
"<mark=3>" +
"<mark=4><nextline fillcolor={rgb 0.0 0.5 0.0}>Giant Wing:<nextline>" +
"An unbelievable sailplane! It is amazingly robust and can " +
"even do aerobatics. But it best suited to gliding." +
"<mark=5>" +
"<mark=6><nextline fillcolor={rgb 0.8 0.4 0.1}>Cone Head Rocket:<nextline>" +
"This paper arrow can be thrown with big swing. We launched it " +
"from the roof of a hotel. It stayed in the air a long time and " +
"covered a considerable distance." +
"<mark=7>" +
"<mark=8><nextline fillcolor={rgb 0.0 0.5 0.5}>Super Dart:<nextline>" +
"The super dart can fly giant loops with a radius of 4 or 5 " +
"metres and cover very long distances. Its heavy cone point is " +
"slightly bowed upwards to get the lift required for loops." +
"<mark=9>" +
"<mark=10><nextline fillcolor={rgb 0.0 0.0 0.5}>German Bi-Plane:<nextline>" +
"Brand-new and ready for take-off. If you have lessons in the " +
"history of aviation you can show your interest by letting it " +
"land on your teacher's desk.<mark=11>";
/* テキストフローで定義されるマークの最大値 */
int maxmark = 11;
p.begin_page_ext(0, 0, "width=a4.width height=a4.height");
/* 説明用のテキストを出力 */
String topts = "fontname=NotoSerif-Bold fontsize=14 ";
p.fit_textline("Fit Textflow without considering",
xleft, y + 30, topts);
p.fit_textline("marks", xleft, y + 15, topts);
p.fit_textline("Fit Textflow using \"returnatmark\"", xright, y + 30,
topts);
p.fit_textline("to keep lines together", xright, y + 15, topts);
/* テキストフローで使用するオプションリストを作成する。
* "avoidemptybegin" はめ込み枠の先頭行の空白を削除
* "charref" 数値・文字参照とグリフ名参照の置き換えを有効にする。
* (ソフトハイフンのための文字参照"&-"など)
*/
optlist = "fontname=NotoSerif-Regular fontsize=12 " +
"alignment=justify leading=120% charref avoidemptybegin";
/* ------------------------------------------------------------------
* マークは使用せず(テキストのまとまりを考慮せずに)出力する
* ------------------------------------------------------------------
*/
/* テキストフローを作成する */
tf = p.create_textflow(text, optlist);
if (tf == -1)
throw new Exception("Error: " + p.get_errmsg());
do
{
/* テキストフローのはめ込み枠の境界線("showborder")の線の幅を指定する */
p.setlinewidth(0.3);
/* テキストフローよりテキストを出力する */
result = p.fit_textflow(tf, xleft, y, xleft + boxwidth,
y - boxheight, "showborder");
y -= boxheight + offset;
/* "_stop" はテキストフローの全テキストの処理が完了したことを示す */
} while (!result.equals("_stop") &&
!result.equals("_boxempty"));
/* -------------------------------------------------------------------
* マークを使用して、テキストのまとまりを維持したまま出力する
* -------------------------------------------------------------------
*/
/* 再び、テキストフローを作成する */
tf = p.create_textflow(text, optlist);
if (tf == -1)
throw new Exception("Error: " + p.get_errmsg());
/* はめ込み枠のy座標を指定する */
y = ystart;
/* 配置すべきテキストがなくなるまで、フィットボックスを生成しテキストを
* 配置する
*/
do
{
/* テキストフローのはめ込み枠の境界線の幅を指定する。境界線は
* "showborder" で設定
*/
p.setlinewidth(0.3);
/* テキストフローのためのオプションリスト
* "showborder" は、はめ込み枠の境界線を表示する
* "blind"はブラインドモードではめ込む
* "blind" is used to fit the Textflow in "blind" mode. All
* ここでは、計算のみで、テキストフローは実際に配置されることはない。
*/
optlist = "showborder blind";
/* テキストフローにおいて、どのマークまで、はめ込み枠にテキストを
* 配置することができるか知るために、ブラインドモードを使用する
*/
result = p.fit_textflow(tf, xright, y, xright + boxwidth,
y - boxheight, optlist);
lastmark = (int) p.info_textflow(tf, "lastmark");
/* マークの番号はテキストセクションの開始を示しており、テキストセクションの
* 終わりを示す最後の奇数のマークの番号まで、テキストは保持され、その後リセッ
* トされる
*/
if (lastmark%2 == 0) {
--lastmark;
}
/* テキストフローを配置する。"rewind=-1" で、テキストフローを最初に呼び出した
* ときの前の状態に戻す。
*/
optlist = "showborder returnatmark=" + lastmark + " rewind=-1";
result = p.fit_textflow(tf, xright, y, xright + boxwidth,
y - boxheight, optlist);
y -= boxheight + offset;
/* _stop はテキストフローの全テキストの処理が完了したことを示す
* _mark#(# は上記で設定した"maxmark"の値)は、テキストフローで定義された最大マーク
* 値に達したことを示す
*/
} while (!result.equals("_stop") &&
!result.equals("_boxempty") &&
!result.equals("_mark" + maxmark));
/* "_boxempty" は、はめ込み枠が小さすぎて、テキストが全く入っていない場合 */
if (result.equals( "_boxempty")) {
throw new Exception ("Error: Textflow box too small");
}
p.end_page_ext("");
p.delete_textflow(tf);
p.end_document("");
} catch (PDFlibException e){
System.err.println("PDFlib exception occurred:");
System.err.println("[" + e.get_errnum() + "] " + e.get_apiname()
+ ": " + e.get_errmsg());
exitcode = 1;
} catch (Exception e) {
System.err.println(e);
exitcode = 1;
} finally {
if (p != null) {
p.delete();
}
System.exit(exitcode);
}
}
}