PDFlib+PDI には「しおりをコピーする」機能はありませんが、PDFlib+PDI に内蔵されている pCOS インターフェースを使って既存の PDF ファイルからしおりを取得し、PDFlib の機能で新規 PDF ファイルにしおりを作成することで、しおりのコピーを実現します。
しおりには様々な機能がありますのが、今回対象とするしおりは以下の機能をもつものです。
またしおりの文書内の移動には、「ページ番号を使用」する方法と、「移動先を利用」する方法がありますが、今回はどちらも実装しています。
基本的な処理の流れは下記のとおりです。(今回は、Javaを使用して記述しています。)
/*
*しおりのコピー
*
*2019 Copyright (c) infoTek K.K. all rights reserved.
*
*必要な製品:PDFlib+PDI/PPS 9
*/
import java.util.HashMap;
import com.pdflib.PDFlibException;
import com.pdflib.pdflib;
class bookmark {
public static void main(String[] args) {
pdflib p = null;
String optlist;
try {
/* PDF オブジェクトを生成 */
p = new pdflib();
p.set_option("errorpolicy=return");
/* 新規PDF文書を開く */
if (p.begin_document("new_bookmark.pdf", "") == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* 文書情報を設定 */
p.set_info("Creator", "bookmark.java");
p.set_info("Author", "infoTek");
p.set_info("Title", "しおりのコピー");
/* 既存 PDF 文書を開く */
int doc = p.open_pdi_document("bookmark.pdf", "");
if (doc == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* 既存 PDF 文書のぺージ数を pCOS 関数で取得する */
int endpage = (int)p.pcos_get_number(doc, "length:pages");
/* 既存 PDF 文書が複数ページがある場合、必要分繰り返す */
for (int pageno = 1; pageno <= endpage; pageno++) {
/* 既存 PDF ページを開く */
int page = p.open_pdi_page(doc, pageno, "");
if (page == -1) {
throw new Exception("Error: " + p.get_errmsg());
}
/* 新規 PDF ページをダミーのページサイズで作成する。 */
p.begin_page_ext(10, 10, "");
/* 新規 PDF ページ上に既存 PDF ページをインポートし、サイズを調整する */
p.fit_pdi_page(page, 0, 0, "adjustpage");
/* 既存 PDF ページを終了する */
p.close_pdi_page(page);
/* 新規 PDF ページを終了する*/
p.end_page_ext("");
}
/* 全てのしおりをコピー */
copy_bookmarks(p, doc);
/* 既存 PDF 文書を終了する */
p.close_pdi_document(doc);
/* 新規 PDF 文書を終了する */
p.end_document("");
}
catch (PDFlibException e) {
System.err.println("PDFlib exception occurred in hello sample:");
System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() + ": " + e.get_errmsg());
}
catch (Exception e) {
System.err.println(e);
}
finally {
if (p != null) {
p.delete();
}
}
}
public static void copy_bookmarks(pdflib p, int doc) throws PDFlibException {
/*既存 PDF 文書内の「しおり」の数を pCOS 関数で取得する*/
int bookmarkcount = (int)p.pcos_get_number(doc, "length:bookmarks");
if (bookmarkcount == 0) {
System.out.println("No bookmarks found");
return;
}
/*既存 PDF 文書内の「移動先」の数を pCOS 関数で取得する*/
int destcount = (int)p.pcos_get_number(doc, "length:names/Dests");
/*pCOS ID としおりハンドルを紐づけるハッシュマップ*/
HashMap<Integer, Integer> shiori = new HashMap<Integer, Integer>();
/*既存 PDF 文書内の「しおり」が複数がある場合、必要分繰り返す*/
for (int i = 0; i < bookmarkcount; i++) {
String bookmark_path = "bookmarks[" + i + "]";
String optlist;
double y, zoom;
/*しおりの階層構造を作成する*/
int level = (int)p.pcos_get_number(doc, bookmark_path + "/level");
int parent_pcosid = (int)p.pcos_get_number(doc, "pcosid:" + bookmark_path + "/Parent");
int parent = 0;
if (level != 0 && shiori.containsKey(parent_pcosid)) {
parent = shiori.get(parent_pcosid);
}
/*「しおり」のページ移動の方法
/*①ページ番号を使用 or ②移動先を使用 ごとに処理を分ける*/
/*①:bookmarks 疑似オブジェクトのプロパティ /A/D の型が配列("array")*/
/*②:bookmarks 疑似オブジェクトのプロパティ /A/D の型が文字列("string")*/
switch (p.pcos_get_string(doc, "type:" + bookmark_path + "/A/D")) {
/*ページ番号を使用して移動先を設定する場合*/
case "array":
/*移動先のページ番号を取得*/
int dest_page = (int)p.pcos_get_number(doc, bookmark_path + "/destpage");
optlist = "open={true} parent={" + parent + "}";
/*
*・100%表示:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitR
*・ページレベルにズーム:names/Dests 疑似オブジェクトのプロパティ /D[1] → Fit
*・幅に合わせる:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitH
*・描画領域の幅に合わせる:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitBH
*・倍率を設定:names/Dests 疑似オブジェクトのプロパティ /D[1] → XYZ
*/
/*画面の表示方法によって、画面表示の y 座標を格納しているプロパティが異なり、
*また、destinationに設定する移動先オプションが異なるので、処理を分岐する*/
/*画面の表示方法を取得・分岐*/
switch (p.pcos_get_string(doc, bookmark_path + "/A/D[1]")) {
case "FitR":
y = p.pcos_get_number(doc, bookmark_path + "/A/D[5]");
if (y < 0) y = 0;
optlist += " destination={page={" + dest_page + "} top={" + y + "} zoom={1} type={fixed}}";
break;
case "Fit":
optlist += " destination={page={" + dest_page + "} type={fitwindow}}";
break;
case "FitH":
y = p.pcos_get_number(doc, bookmark_path + "/A/D[2]");
if (y < 0) y = 0;
optlist += " destination={page={" + dest_page + "} top={" + y + "} type={fitwidth}}";
break;
case "FitBH":
y = p.pcos_get_number(doc, bookmark_path + "/A/D[2]");
if (y < 0) y = 0;
optlist += " destination={page={" + dest_page + "} top={" + y + "} type={fitvisiblewidth}}";
break;
case "XYZ":
y = p.pcos_get_number(doc, bookmark_path + "/A/D[3]");
if (y < 0) y = 0;
zoom = p.pcos_get_number(doc, bookmark_path + "/A/D[4]");
optlist += " destination={page={" + dest_page + "} top={" + y + "} zoom={" + zoom + "} type={fixed}}";
break;
default:
optlist += " destination={page={" + dest_page + "} type={fitwindow}}";
}
break;
/*移動先を使用して移動先を設定する場合*/
case "string":
String destname;
String path = "";
/*移動先名と、該当の移動先情報を取得*/
destname = p.pcos_get_string(doc, bookmark_path + "/A/D");
for (int j = 0; j < destcount; j++) {
String names_key = p.pcos_get_string(doc, "names/Dests[" + j + "].key");
if (destname.equals(names_key)) {
path = "names/Dests[" + j + "]";
break;
}
}
/*
*・100%表示:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitR
*・ページレベルにズーム:names/Dests 疑似オブジェクトのプロパティ /D[1] → Fit
*・幅に合わせる:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitH
*・描画領域の幅に合わせる:names/Dests 疑似オブジェクトのプロパティ /D[1] → FitBH
*・倍率を設定:names/Dests 疑似オブジェクトのプロパティ /D[1] → XYZ
*/
/*画面の表示方法によって、画面表示の y 座標を格納しているプロパティが異なり、
*また、destinationに設定する移動先オプションが異なるので、処理を分岐する*/
/*ページ番号を取得する*/
dest_page = (int)p.pcos_get_number(doc, path + "/destpage");
optlist = "page={" + dest_page + "}";
/*画面の表示方法を取得・分岐*/
switch (p.pcos_get_string(doc, path + "/D[1]")) {
case "FitR":
y = p.pcos_get_number(doc, path + "/D[5]");
if (y < 0) y = 0;
optlist += " top={" + y + "} zoom={1} type={fixed}";
break;
case "Fit":
optlist += " type={fitwindow}";
break;
case "FitH":
y = p.pcos_get_number(doc, path + "/D[2]");
if (y < 0) y = 0;
optlist += " top={" + y + "} type={fitwidth}";
break;
case "FitBH":
y = p.pcos_get_number(doc, path + "/D[2]");
if (y < 0) y = 0;
optlist += " top={" + y + "} type={fitvisiblewidth}";
break;
case "XYZ":
y = p.pcos_get_number(doc, path + "/D[3]");
if (y < 0) y = 0;
zoom = p.pcos_get_number(doc, path + "/D[4]");
optlist += " top={" + y + "} zoom={" + zoom + "} type={fixed}";
break;
default:
optlist += " type={fitwindow}";
}
/*名前付き移動先を、新規 PDF 文書のページ上に作成する*/
p.add_nameddest(destname, optlist);
optlist = "destname={" + destname + "} open={true} parent={" + parent + "}";
break;
default:
dest_page = (int)p.pcos_get_number(doc, bookmark_path + "/destpage");
optlist = "destination={page={" + dest_page + "}} open={true} parent={" + parent + "}";
}
/*「しおり」のタイトルを取得する*/
String title = p.pcos_get_string(doc, bookmark_path + "/Title");
/*しおりの作成・しおりハンドルを pCOS ID と紐づけるため取得する*/
int handle = p.create_bookmark(title, optlist);
int pcosid = (int) p.pcos_get_number(doc, "pcosid:" + bookmark_path);
shiori.put(pcosid, handle);
}
}
}