PDFファイルに、コマンドラインから、しおり（ブックマーク）情報を付与したい（C#とiTextを使って）


#やりたいこと

PDFファイルに、コマンドラインから、しおり（ブックマーク）情報を付与したい

#どうやる

・cpdf / Coherent PDF というツールを使う　
・iText なる　AGPLというライセンスで公開あるオープンソースを使う　

今回は、後者で、C#とiTextを使って、実施


#出来上がりはこちら

https://github.com/santarou6/iText_CSharp/blob/main/pack.zip
https://github.com/santarou6/iText_CSharp/blob/main/myChangeBookmarks_v1.cs

#実行方法

（コマンド　元PDF　先PDF　しおりの内容テキストファイル）

```
> myChangeBookmarks_v1.exe ./sample.pdf ./sample_out.pdf ./bookmark_list.txt
```

#準備：しおり（ブックマーク）

しおりの内容は、テキストに、UTF-8で、「内容」タブ「ページ番号」で準備

```text:bookmark_list.txt
あいうえお	1
かきくけこ	2
さしすせそ	3
```

#実施前と実施後のイメージ

↓処理前、しおり無し

![1before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/1c61b6cf-4f62-9d0b-d9af-d1377962d157.png)

↓処理後、しおり有り

![2after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107418/377a9f24-215a-4c55-25e1-d8a77485a22f.png)

#プログラム

```csharp:myChangeBookmarks_v1.cs
//c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:itext.kernel.dll;itext.io.dll;Common.Logging.dll;BouncyCastle.Crypto.dll myChangeBookmarks_v1.cs

using System;
using System.IO;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Navigation;

public class myChangeBookmarks {

public static string SRC_PDF = "";
public static string DEST_PDF = "";
public static string LIST_TXT = "";

/////
public static void Main(String[] args)
{

//---------------------
SRC_PDF = @"./" + args[0];
System.IO.FileInfo fi0 = new System.IO.FileInfo(SRC_PDF);
if(!fi0.Exists){
Console.WriteLine("File is not exists! {0}", SRC_PDF);
return;
}

//---------------------
DEST_PDF = @"./" + args[1];
System.IO.FileInfo fi1 = new FileInfo(DEST_PDF);
fi1.Directory.Create();

//---------------------
LIST_TXT = @"./" + args[2];
System.IO.FileInfo fi2 = new System.IO.FileInfo(LIST_TXT);
if(!fi2.Exists){
Console.WriteLine("File is not exists! {0}", LIST_TXT);
return;
}

PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC_PDF), new PdfWriter(DEST_PDF));
pdfDoc.GetOutlines(true).RemoveOutline();

using (System.IO.StreamReader sr = new System.IO.StreamReader(LIST_TXT, System.Text.Encoding.UTF8))
{
int line_cnt = 0;
string line = "";
while ((line = sr.ReadLine()) != null){
string[] p = line.Split('\t');
int i = int.Parse(p[1]);
PdfOutline outline = pdfDoc.GetOutlines(true).AddOutline(p[0],line_cnt);
outline.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(i)));
line_cnt++;
}
}

pdfDoc.Close();
Console.WriteLine("== Done ==");

}
/////

}
```

#別途、必要となるDLL
itext.kernel.dll;
itext.io.dll;
Common.Logging.dll;
Common.Logging.Core.dll;
BouncyCastle.Crypto.dll;

※入手方法は、後述「参考」をご参照



#参考

iText本家
https://itextpdf.com/ja

iText / AGPL（Affero General Public License）/ AGPLライセンス
https://itextpdf.com/ja/how-buy/agpl-license

itext7の、dotNet(C#)での利用はこちら
https://github.com/itext/itext7-dotnet

-> download the latest releases
https://github.com/itext/itext7-dotnet/releases/tag/7.1.17
https://github.com/itext/itext7-dotnet/releases/download/7.1.17/itext7.7.1.17.nupkg

※.nupkgは、.zipと拡張子を変えれば、中身の参照は可

iText / Bookmarks処理のサンプル
https://kb.itextpdf.com/home/it7kb/examples/bookmark-examples
https://github.com/itext/i7js-examples/blob/develop/src/main/resources/pdfs/bookmarks.pdf

iText / Bookmarks,Outline の削除のサンプル
https://kb.itextpdf.com/home/it7kb/examples/removing-items-from-a-pdf-s-outline-tree

-----

cpdf / Coherent PDF
https://community.coherentpdf.com/

※しおり追加処理
cpdf -add-bookmarks bookmarks.txt in.pdf -o out.pdf

-----

iTextを利用した「しおり」処理のサンプル

https://mitsugeek.net/entry/2020/09/26/C%23_%28dotnetcore%29_iText7%E3%81%A7%E3%82%B9%E3%82%AD%E3%83%A3%E3%83%B3%E3%81%97%E3%81%9F%E9%9B%BB%E5%AD%90%E6%9B%B8%E7%B1%8D%E3%81%AB%E7%9B%AE%E6%AC%A1%28%E3%81%97%E3%81%8A%E3%82%8A%29%E3%82%92%E3%81%A4

-----

Common.Logging.Core.dll
https://github.com/net-commons/common-logging

https://www.nuget.org/api/v2/package/Common.Logging/3.4.1
https://www.nuget.org/api/v2/package/Common.Logging.Core/3.4.1

-----

BouncyCastle.Crypto
BouncyCastle.Crypto.dll
https://www.bouncycastle.org/csharp/index.html

※使用した版は、1.8.9　（コンパイル時に、版の違いの指摘で判明）


-----

iTextで取得できるDLL

itext.barcodes.dll;
itext.forms.dll;
itext.io.dll;
itext.kernel.dll;
itext.layout.dll;
itext.pdfa.dll;
itext.sign.dll;
itext.styledxmlparser.dll;
itext.svg.dll;

-----

#追記、階層しおり

階層0,1,2
bookmark_list.txt
で
階層　タブ　しおり名　タブ　ページ数
で、指定する。

```csharp:myChangeBookmarks_v2.cs

using (System.IO.StreamReader sr = new System.IO.StreamReader(LIST_TXT, System.Text.Encoding.UTF8))
{
int line_cnt = 0;
string line = "";

PdfOutline outline = null;
PdfOutline ol1 = null;
PdfOutline ol2 = null;

while ((line = sr.ReadLine()) != null){
string[] p = line.Split('\t');

int d = int.Parse(p[0]);
int i = int.Parse(p[2]);


switch (d)
{
case 0:
outline = pdfDoc.GetOutlines(true).AddOutline(p[1],line_cnt);
outline.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(i)));
line_cnt++;
//Console.WriteLine("0");
break;
case 1:
ol1 = outline.AddOutline(p[1]);
ol1.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(i)));
//Console.WriteLine("1");
break;
case 2:
ol2 = ol1.AddOutline(p[1]);
ol2.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(i)));
//Console.WriteLine("2");
break;
default:
//Console.WriteLine("defaultが実行されました");
break;
}


}


}

pdfDoc.Close();
Console.WriteLine("== Done ==");

```


以上