入力PDFの内容を出力PDFにコピーして、コピーされた出力PDFにアノテーションを追加します。
// 入力PDFファイルを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
// 出力PDFを生成
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite);
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null);
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// コピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 最初のページをコピーして注釈を追加
Page outPage = CopyAndAddAnnotations(outDoc, inDoc.Pages[0], copyOptions);
// 出力ドキュメントのページリストにページを追加
outDoc.Pages.Add(outPage);
// 残りのページをコピーし、出力ドキュメントのページリストに追加
PageList inPages = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList outPages = PageList.Copy(outDoc, inPages, copyOptions);
outDoc.Pages.AddRange(outPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static Page CopyAndAddAnnotations(Document outDoc, Page inPage, PageCopyOptions copyOptions)
{
// ページを出力ドキュメントにコピー
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// RGB色空間作成
ColorSpace rgb = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// 注釈を配置するためのページサイズを取得
Size pageSize = outPage.Size;
// 注釈を追加するための出力ページの注釈リストを取得
AnnotationList annotations = outPage.Annotations;
// 付箋(sticky note)を作成し、出力ページの注釈に追加
Paint green = Paint.Create(outDoc, rgb, new double[] { 0, 1, 0 }, null);
Point stickyNoteTopLeft = new Point() { X = 10, Y = pageSize.Height - 10 };
StickyNote stickyNote = StickyNote.Create(outDoc, stickyNoteTopLeft, "Hello world!", green);
annotations.Add(stickyNote);
// 楕円を作成し、出力ページの注釈に追加
Paint blue = Paint.Create(outDoc, rgb, new double[] { 0, 0, 1 }, null);
Paint yellow = Paint.Create(outDoc, rgb, new double[] { 1, 1, 0 }, null);
Rectangle ellipseBox = new Rectangle() { Left = 10, Bottom = pageSize.Height - 60, Right = 70, Top = pageSize.Height - 20 };
EllipseAnnotation ellipse = EllipseAnnotation.Create(outDoc, ellipseBox, new Stroke(blue, 1.5), yellow);
annotations.Add(ellipse);
// フリーテキストを作成し、出力ページの注釈に追加
Paint yellowTransp = Paint.Create(outDoc, rgb, new double[] { 1, 1, 0 }, new Transparency(0.5));
Rectangle freeTextBox = new Rectangle() { Left = 10, Bottom = pageSize.Height - 170, Right = 120, Top = pageSize.Height - 70 };
FreeText freeText = FreeText.Create(outDoc, freeTextBox, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", yellowTransp);
annotations.Add(freeText);
// 既存のページコンテンツ要素にフィットするハイライトとウェブリンク
Highlight highlight = null;
WebLink webLink = null;
// 入力ページからコンテンツ要素を抽出
ContentExtractor extractor = new ContentExtractor(inPage.Content);
foreach (ContentElement element in extractor)
{
// 最初のテキスト要素を取得
if (highlight == null && element is TextElement textElement)
{
// このテキスト要素の矩形を取得
QuadrilateralList quadrilaterals = new QuadrilateralList();
foreach (TextFragment fragment in textElement.Text)
quadrilaterals.Add(fragment.Transform.TransformRectangle(fragment.BoundingBox));
// ハイライトを作成し、出力ページの注釈に追加
highlight = Highlight.CreateFromQuadrilaterals(outDoc, quadrilaterals, yellow);
annotations.Add(highlight);
}
// 最初の画像要素を取得
if (webLink == null && element is ImageElement)
{
// この画像の矩形を取得
QuadrilateralList quadrilaterals = new QuadrilateralList();
quadrilaterals.Add(element.Transform.TransformRectangle(element.BoundingBox));
// ウェブリンクを作成し、出力ページのリンクに追加
webLink = WebLink.CreateFromQuadrilaterals(outDoc, quadrilaterals, "https://www.pdf-tools.com");
Paint red = Paint.Create(outDoc, rgb, new double[] { 1, 0, 0 }, null);
webLink.BorderStyle = new Stroke(red, 1.5);
outPage.Links.Add(webLink);
}
// ハイライトとウェブリンクが作成された場合はループを終了
if (highlight != null && webLink != null)
break;
}
// 完成したページを戻す
return outPage;
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_and_add_annotations(out_doc: Document, in_page: Page, copy_options: PageCopyOptions):
# ページを出力ドキュメントにコピー
out_page = Page.copy(out_doc, in_page, copy_options)
# RGB色空間作成
rgb = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# 注釈を配置するためのページサイズを取得
page_size = out_page.size
# 注釈を追加するための出力ページの注釈リストを取得
annotations = out_page.annotations
# 付箋(sticky note)を作成し、出力ページの注釈に追加
green = Paint.create(out_doc, rgb, [0.0, 1.0, 0.0], None)
sticky_note_top_left = Point(x=10.0, y=page_size.height - 10.0)
sticky_note = StickyNote.create(out_doc, sticky_note_top_left, "Hello world!", green)
annotations.append(sticky_note)
# 楕円を作成し、出力ページの注釈に追加
blue = Paint.create(out_doc, rgb, [0.0, 0.0, 1.0], None)
yellow = Paint.create(out_doc, rgb, [1.0, 1.0, 0.0], None)
ellipse_box = Rectangle(left=10.0, bottom=page_size.height - 60.0, right=70.0, top=page_size.height - 20.0)
ellipse = EllipseAnnotation.create(out_doc, ellipse_box, Stroke(blue, 1.5), yellow)
annotations.append(ellipse)
# フリーテキストを作成し、出力ページの注釈に追加
yellow_transp = Paint.create(out_doc, rgb, [1.0, 1.0, 0.0], Transparency(0.5))
free_text_box = Rectangle(left=10.0, bottom=page_size.height - 170.0, right=120.0, top=page_size.height - 70.0)
free_text = FreeText.create(out_doc, free_text_box, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", yellow_transp)
annotations.append(free_text)
# 既存のページコンテンツ要素にフィットするハイライトとウェブリンク
highlight = None
web_link = None
# 入力ページからコンテンツ要素を抽出
extractor = ContentExtractor(in_page.content)
for element in extractor:
# 最初のテキスト要素を取得
if highlight is None and isinstance(element, TextElement):
# このテキスト要素の矩形を取得
quadrilaterals = QuadrilateralList()
for fragment in element.text:
quadrilaterals.append(fragment.transform.transform_rectangle(fragment.bounding_box))
# ハイライトを作成し、出力ページの注釈に追加
highlight = Highlight.create_from_quadrilaterals(out_doc, quadrilaterals, yellow)
annotations.append(highlight)
# 最初の画像要素を取得
if web_link is None and isinstance(element, ImageElement):
# この画像の矩形を取得
quadrilaterals = QuadrilateralList()
quadrilaterals.append(element.transform.transform_rectangle(element.bounding_box))
# ウェブリンクを作成し、出力ページのリンクに追加
web_link = WebLink.create_from_quadrilaterals(out_doc, quadrilaterals, "https://www.pdf-tools.com")
red = Paint.create(out_doc, rgb, [1.0, 0.0, 0.0], None)
web_link.border_style = Stroke(red, 1.5)
out_page.links.append(web_link)
# ハイライトとウェブリンクが作成された場合はループを終了
if highlight is not None and web_link is not None:
break
return out_page
# 入力PDFファイルを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# コピーオプションを定義
copy_options = PageCopyOptions()
# 最初のページをコピーして注釈を追加
out_page = copy_and_add_annotations(out_doc, in_doc.pages[0], copy_options)
# 出力ドキュメントのページリストにページを追加
out_doc.pages.append(out_page)
# 残りのページをコピーし、出力ドキュメントのページリストに追加
in_pages = in_doc.pages[1:]
out_pages = PageList.copy(out_doc, in_pages, copy_options)
out_doc.pages.extend(out_pages)
PDFから"Ellipse"注釈を削除し、新しい注釈リストを新しいFDFファイルにエクスポートします。
// 入力PDFファイルを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Stream inFdfStream = new FileStream(inFdfPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.OpenWithFdf(inStream, inFdfStream, null))
{
// 出力PDFを生成
using var outStream = new FileStream(outPath, FileMode.Create, FileAccess.Write);
using var outFdfStream = new FileStream(outFdfPath, FileMode.Create, FileAccess.Write);
using var outDoc = Document.CreateWithFdf(outStream, outFdfStream, inDoc.Conformance, null);
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 注釈をフィルタリングして処理
FilterAnnotations(inDoc, outDoc);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void FilterAnnotations(Document inDoc, Document outDoc)
{
// コピーオプションを定義
var copyOptions = new PageCopyOptions
{
// すべての注釈を削除: フィルタリングしたものは後で追加
Annotations = CopyStrategy.Remove
};
foreach (var inPage in inDoc.Pages)
{
// ページを出力ドキュメントにコピー
var outPage = Page.Copy(outDoc, inPage, copyOptions);
// 入力文書からの注釈を保持
var inAnnotations = inPage.Annotations;
// 注釈を選択的にコピーする (EllipseAnnotationsを除く - Circleなど)
foreach (var inAnnotation in inAnnotations)
{
// 注釈がEllipseAnnotationの場合はスキップ
if (inAnnotation is EllipseAnnotation)
{
continue;
}
outPage.Annotations.Add(Annotation.Copy(outDoc, inAnnotation));
}
// 出力ドキュメントにページを追加
outDoc.Pages.Add(outPage);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def filter_annotations(in_doc: Document, out_doc: Document):
"""Filter annotations and remove 'Ellipse' annotations."""
# コピーオプションを定義
copy_options = PageCopyOptions()
# すべての注釈を削除: フィルタリングしたものは後で追加
copy_options.annotations = CopyStrategy.REMOVE
for in_page in in_doc.pages:
# ページを出力ドキュメントにコピー
out_page = Page.copy(out_doc, in_page, copy_options)
# 入力文書からの注釈を保持
in_annotations = in_page.annotations
# 注釈を選択的にコピーする (EllipseAnnotationsを除く - Circleなど)
for in_annotation in in_annotations:
if not isinstance(in_annotation, EllipseAnnotation):
out_page.annotations.append(Annotation.copy(out_doc, in_annotation))
# 出力ドキュメントにページを追加
out_doc.pages.append(out_page)
# 入力PDFファイルとFDFファイルを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with io.FileIO(input_fdf_path, "rb") as in_fdf_stream:
with Document.open_with_fdf(in_stream, in_fdf_stream, None) as in_doc:
# 出力PDFとFDFファイルを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with io.FileIO(output_fdf_path, "wb+") as out_fdf_stream:
with Document.create_with_fdf(out_stream, out_fdf_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 注釈をフィルタリングして処理
filter_annotations(in_doc, out_doc)
入力PDFの内容を出力PDFにコピーして、コピーされた出力PDFにフォームフィールドを追加します。
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDF
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// PDF全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// すべてのフォームフィールドをコピー
FieldNodeMap inFormFields = inDoc.FormFields;
FieldNodeMap outFormFields = outDoc.FormFields;
foreach (KeyValuePair<string, FieldNode> inPair in inFormFields)
{
FieldNode outFormFieldNode = FieldNode.Copy(outDoc, inPair.Value);
outFormFields.Add(inPair.Key, outFormFieldNode);
}
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions
{
FormFields = FormFieldCopyStrategy.CopyAndUpdateWidgets,
UnsignedSignatures = CopyStrategy.Remove,
};
// 先頭ページをコピー
Page inPage = inDoc.Pages[0];
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// 出力ページにさまざまな種類のフォームフィールドを追加
AddCheckBox(outDoc, "Check Box ID", true, outPage, new Rectangle { Left = 50, Bottom = 300, Right = 70, Top = 320 });
AddComboBox(outDoc, "Combo Box ID", new string[] { "item 1", "item 2" }, "item 1", outPage, new Rectangle { Left = 50, Bottom = 260, Right = 210, Top = 280 });
AddListBox(outDoc, "List Box ID", new string[] { "item 1", "item 2", "item 3" }, new string[] { "item 1", "item 3" }, outPage, new Rectangle { Left = 50, Bottom = 160, Right = 210, Top = 240 });
AddRadioButtonGroup(outDoc, "Radio Button ID", new string[] { "A", "B", "C" }, 0, outPage, new Rectangle { Left = 50, Bottom = 120, Right = 210, Top = 140 });
AddGeneralTextField(outDoc, "Text ID", "Text", outPage, new Rectangle { Left = 50, Bottom = 80, Right = 210, Top = 100 });
// 出力PDFにページを追加
outDoc.Pages.Add(outPage);
// 残りのページを出力PDFにコピー追加
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビューア設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddCheckBox(Document doc, string id, bool isChecked, Page page, Rectangle rectangle)
{
// Check boxを生成
CheckBox checkBox = CheckBox.Create(doc);
// PDFにCheck boxを追加
doc.FormFields.Add(id, checkBox);
// Check boxの状態を設定
checkBox.Checked = isChecked;
// ウィジェットを作成し、ページに追加
page.Widgets.Add(checkBox.AddNewWidget(rectangle));
}
private static void AddComboBox(Document doc, string id, string[] itemNames, string value, Page page, Rectangle rectangle)
{
// Combo boxを生成
ComboBox comboBox = ComboBox.Create(doc);
// PDFにCombo boxを追加
doc.FormFields.Add(id, comboBox);
// 全アイテムを名前でループ処理
foreach (string itemName in itemNames)
{
// 選択項目を作成する
ChoiceItem item = comboBox.AddNewItem(itemName);
// 選択したアイテム名であるかどうかを確認
if (value.Equals(itemName))
comboBox.ChosenItem = item;
}
if (comboBox.ChosenItem == null && !string.IsNullOrEmpty(value))
{
// 項目が選択されていない場合は、編集可能な項目を設定する
comboBox.CanEdit = true;
comboBox.EditableItemName = value;
}
// ウィジェットを作成し、ページに追加
page.Widgets.Add(comboBox.AddNewWidget(rectangle));
}
private static void AddListBox(Document doc, string id, string[] itemNames, string[] chosenNames, Page page, Rectangle rectangle)
{
// list box生成
ListBox listBox = ListBox.Create(doc);
// PDFにList Boxを追加
doc.FormFields.Add(id, listBox);
// 複数選択を許可
listBox.AllowMultiSelect = true;
ChoiceItemList chosenItems = listBox.ChosenItems;
// 全アイテムを名前でループ処理
foreach (string itemName in itemNames)
{
// 選択項目を生成
ChoiceItem item = listBox.AddNewItem(itemName);
// 選択したアイテムに追加するかどうかを確認
if (chosenNames.Contains(itemName))
chosenItems.Add(item);
}
// ウィジェットを作成しページに追加
page.Widgets.Add(listBox.AddNewWidget(rectangle));
}
private static void AddRadioButtonGroup(Document doc, string id, string[] buttonNames, int chosen, Page page, Rectangle rectangle)
{
// Radio Buttonグループを生成
RadioButtonGroup group = RadioButtonGroup.Create(doc);
// ページのウィジェットを取得
WidgetList widgets = page.Widgets;
// Radio Buttonグループをページに追加
doc.FormFields.Add(id, group);
// 各ボタン用に矩形を水平方向に並べて配置します
// 矩形の幅を計算します
double buttonWidth = (rectangle.Right - rectangle.Left) / buttonNames.Length;
// 全ボタンを名前ごとに繰り返します
for (int i = 0; i < buttonNames.Length; i++)
{
// ボタンの矩形
Rectangle buttonRectangle = new Rectangle()
{
Left = rectangle.Left + i * buttonWidth,
Bottom = rectangle.Bottom,
Right = rectangle.Left + (i + 1) * buttonWidth,
Top = rectangle.Top
};
// ボタンと関連ウィジェットを作成
RadioButton button = group.AddNewButton(buttonNames[i]);
Widget widget = button.AddNewWidget(buttonRectangle);
// 選択されたボタンかどうかを確認します
if (i == chosen)
group.ChosenButton = button;
// ページのウィジェットに追加
widgets.Add(widget);
}
}
private static void AddGeneralTextField(Document doc, string id, string value, Page page, Rectangle rectangle)
{
// General textフィールド生成
GeneralTextField field = GeneralTextField.Create(doc);
// PDFにフィールドを追加
doc.FormFields.Add(id, field);
// 文字列をセット
field.Text = value;
// 新規ウィジェットを作成し文字を追加してからページに追加
page.Widgets.Add(field.AddNewWidget(rectangle));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビューア設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_check_box(doc: Document, field_id: str, is_checked: bool, page: Page, rectangle: Rectangle):
# Check boxを生成
check_box = CheckBox.create(doc)
# PDFにCheck boxを追加
doc.form_fields[field_id] = check_box
# Check boxの状態を設定
check_box.checked = is_checked
# ウィジェットを作成し、ページに追加
page.widgets.append(check_box.add_new_widget(rectangle))
def add_combo_box(doc: Document, field_id: str, item_names: list[str], value: str, page: Page, rectangle: Rectangle):
# Combo boxを生成
combo_box = ComboBox.create(doc)
# PDFにCombo boxを追加
doc.form_fields[field_id] = combo_box
# 全アイテムを名前でループ処理
for item_name in item_names:
# 選択項目を作成する
item = combo_box.add_new_item(item_name)
# 選択したアイテム名であるかどうかを確認
if value == item_name:
combo_box.chosen_item = item
if combo_box.chosen_item is None and value:
# 項目が選択されていない場合は、編集可能な項目を設定する
combo_box.can_edit = True
combo_box.editable_item_name = value
# ウィジェットを作成し、ページに追加
page.widgets.append(combo_box.add_new_widget(rectangle))
def add_list_box(doc: Document, field_id: str, item_names: list[str], chosen_names: list[str], page: Page, rectangle: Rectangle):
# list box生成
list_box = ListBox.create(doc)
# PDFにList Boxを追加
doc.form_fields[field_id] = list_box
# 複数選択を許可
list_box.allow_multi_select = True
chosen_items = list_box.chosen_items
# 全アイテムを名前でループ処理
for item_name in item_names:
# 選択項目を生成
item = list_box.add_new_item(item_name)
# 選択したアイテムに追加するかどうかを確認
if item_name in chosen_names:
chosen_items.append(item)
# ウィジェットを作成しページに追加
page.widgets.append(list_box.add_new_widget(rectangle))
def add_radio_button_group(doc: Document, field_id: str, button_names: list[str], chosen: int, page: Page, rectangle: Rectangle):
# Radio Buttonグループを生成
group = RadioButtonGroup.create(doc)
# ページのウィジェットを取得
widgets = page.widgets
# Radio Buttonグループをページに追加
doc.form_fields[field_id] = group
# We partition the given rectangle horizontally into sub-rectangles, one for each button与えられた長方形を水平に分割し、ボタンごとに1つずつ長方形を作成
# 分割された長方形の幅を計算
button_width = (rectangle.right - rectangle.left) / len(button_names)
# すべてのボタンを名前でループ
for i, button_name in enumerate(button_names):
# このボタンの分割された長方形を計算
button_rectangle = Rectangle(
left = rectangle.left + i * button_width,
bottom = rectangle.bottom,
right = rectangle.left + (i + 1) * button_width,
top = rectangle.top
)
# ボタンと関連するウィジェットを作成
button = group.add_new_button(button_name)
widget = button.add_new_widget(button_rectangle)
# 選択されたボタンかどうかを確認
if i == chosen:
group.chosen_button = button
# ページのウィジェットに作成されたウィジェットを追加
widgets.append(widget)
def add_general_text_field(doc: Document, field_id: str, value: str, page: Page, rectangle: Rectangle):
# General text フィールド生成
text_field = GeneralTextField.create(doc)
# PDFにフィールドを追加
doc.form_fields[field_id] = text_field
# 文字列をセット
text_field.text = value
# 新規ウィジェットを作成し文字を追加してからページに追加
page.widgets.append(text_field.add_new_widget(rectangle))
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力ファイルを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# PDF全体のデータをコピー
copy_document_data(in_doc, out_doc)
# すべてのフォームフィールドをコピー
in_form_fields = in_doc.form_fields
out_form_fields = out_doc.form_fields
for in_pair_key, in_pair_node in in_form_fields.items():
out_form_field_node = FieldNode.copy(out_doc, in_pair_node)
out_form_fields[in_pair_key] = out_form_field_node
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS
copy_options.unsigned_signatures = CopyStrategy.REMOVE
# 先頭ページをコピー
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
# 出力ページにさまざまな種類のフォームフィールドを追加
add_check_box(out_doc, "Check Box ID", True, out_page, Rectangle(left=50.0, bottom=300.0, right=70.0, top=320.0))
add_combo_box(out_doc, "Combo Box ID", ["item 1", "item 2"], "item 1", out_page, Rectangle(left=50.0, bottom=260.0, right=210.0, top=280.0))
add_list_box(out_doc, "List Box ID", ["item 1", "item 2", "item 3"], ["item 1", "item 3"], out_page, Rectangle(left=50.0, bottom=160.0, right=210.0, top=240.0))
add_radio_button_group(out_doc, "Radio Button ID", ["A", "B", "C"], 0, out_page, Rectangle(left=50.0, bottom=120.0, right=210.0, top=140.0))
add_general_text_field(out_doc, "Text ID", "Text", out_page, Rectangle(left=50.0, bottom=80.0, right=210.0, top=100.0))
# 出力PDFにページを追加
out_doc.pages.append(out_page)
# 残りのページを出力PDFにコピー追加
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
入力PDFの内容を出力PDFにコピーして、コピーされた出力PDFのフォームフィールドに値を入力します。
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// 解放・クローズの必要なオブジェクト
TPtxPdfContent_IccBasedColorSpace* pInOutputIntent = NULL;
TPtxPdfContent_IccBasedColorSpace* pOutOutputIntent = NULL;
TPtxPdf_Metadata* pInMetadata = NULL;
TPtxPdf_Metadata* pOutMetadata = NULL;
TPtxPdfNav_ViewerSettings* pInViewerSettings = NULL;
TPtxPdfNav_ViewerSettings* pOutViewerSettings = NULL;
TPtxPdf_FileReferenceList* pInFileRefList = NULL;
TPtxPdf_FileReferenceList* pOutFileRefList = NULL;
TPtxPdf_FileReference* pInFileRef = NULL;
TPtxPdf_FileReference* pOutFileRef = NULL;
iReturnValue = 0;
// 出力PDFの色特性設定
pInOutputIntent = PtxPdf_Document_GetOutputIntent(pInDoc);
if (pInOutputIntent != NULL)
{
pOutOutputIntent = PtxPdfContent_IccBasedColorSpace_Copy(pOutDoc, pInOutputIntent);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutOutputIntent,
_T("Failed to copy ICC-based color space. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetOutputIntent(pOutDoc, pOutOutputIntent),
_T("Failed to set output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// メタデータ
pInMetadata = PtxPdf_Document_GetMetadata(pInDoc);
if (pInMetadata != NULL)
{
pOutMetadata = PtxPdf_Metadata_Copy(pOutDoc, pInMetadata);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutMetadata, _T("Failed to copy metadata. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetMetadata(pOutDoc, pOutMetadata),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// ビューア設定
pInViewerSettings = PtxPdf_Document_GetViewerSettings(pInDoc);
if (pInViewerSettings != NULL)
{
pOutViewerSettings = PtxPdfNav_ViewerSettings_Copy(pOutDoc, pInViewerSettings);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutViewerSettings,
_T("Failed to copy viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetViewerSettings(pOutDoc, pOutViewerSettings),
_T("Failed to set viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get viewer settings. %s (ErrorCode: 0x%08x)"), szErrorBuff,
Ptx_GetLastError());
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of input document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
int nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of associated files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
Ptx_Release(pInFileRefList);
pInFileRefList = NULL;
Ptx_Release(pOutFileRefList);
pOutFileRefList = NULL;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of input document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of output document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of plain embedded files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
cleanup:
if (pInOutputIntent != NULL)
Ptx_Release(pInOutputIntent);
if (pOutOutputIntent != NULL)
Ptx_Release(pOutOutputIntent);
if (pInMetadata != NULL)
Ptx_Release(pInMetadata);
if (pOutMetadata != NULL)
Ptx_Release(pOutMetadata);
if (pInViewerSettings != NULL)
Ptx_Release(pInViewerSettings);
if (pOutViewerSettings != NULL)
Ptx_Release(pOutViewerSettings);
if (pInFileRefList != NULL)
Ptx_Release(pInFileRefList);
if (pOutFileRefList != NULL)
Ptx_Release(pOutFileRefList);
if (pInFileRef != NULL)
Ptx_Release(pInFileRef);
if (pOutFileRef != NULL)
Ptx_Release(pOutFileRef);
return iReturnValue;
}
int copyFields(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// 解放または閉じる必要があるオブジェクト
TPtxPdfForms_FieldNodeMap* pInFields = NULL;
TPtxPdfForms_FieldNodeMap* pOutFields = NULL;
TCHAR* szFieldKey = NULL;
TPtxPdfForms_FieldNode* pInFieldNode = NULL;
TPtxPdfForms_FieldNode* pOutFieldNode = NULL;
iReturnValue = 0;
pInFields = PtxPdf_Document_GetFormFields(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFields,
_T("Failed to get form fields of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutFields = PtxPdf_Document_GetFormFields(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFields,
_T("Failed to get form fields of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iField = PtxPdfForms_FieldNodeMap_GetBegin(pInFields);
iField != PtxPdfForms_FieldNodeMap_GetEnd(pInFields);
iField = PtxPdfForms_FieldNodeMap_GetNext(pInFields, iField))
{
if (iField == 0)
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get form field. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// キーを取得
size_t nKey = PtxPdfForms_FieldNodeMap_GetKey(pInFields, iField, szFieldKey, 0);
GOTO_CLEANUP_IF_ZERO(nKey, _T("Failed to get form field key\n"));
szFieldKey = (TCHAR*)malloc(nKey * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szFieldKey, _T("Failed to allocate memory for field key\n"));
if (PtxPdfForms_FieldNodeMap_GetKey(pInFields, iField, szFieldKey, nKey) != nKey)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get form field key. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
// 入力フィールドノードを取得
pInFieldNode = PtxPdfForms_FieldNodeMap_GetValue(pInFields, iField);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFieldNode, _T("Failed to get form field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// フィールドノードを出力ドキュメントにコピー
pOutFieldNode = PtxPdfForms_FieldNode_Copy(pOutDoc, pInFieldNode);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFieldNode, _T("Failed to copy form field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// コピーしたフィールドノードを出力フィールドに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_FieldNodeMap_Set(pOutFields, szFieldKey, pOutFieldNode),
_T("Failed to add form field \"%s\". %s (ErrorCode: 0x%08x)\n"), szFieldKey,
szErrorBuff, Ptx_GetLastError());
// 次の反復のためのクリーンアップ
free(szFieldKey);
szFieldKey = NULL;
Ptx_Release(pOutFieldNode);
pOutFieldNode = NULL;
Ptx_Release(pInFieldNode);
pInFieldNode = NULL;
}
cleanup:
if (pOutFieldNode != NULL)
Ptx_Release(pOutFieldNode);
if (pInFieldNode != NULL)
Ptx_Release(pInFieldNode);
if (szFieldKey != NULL)
free(szFieldKey);
if (pOutFields != NULL)
Ptx_Release(pOutFields);
if (pInFields != NULL)
Ptx_Release(pInFields);
return iReturnValue;
}
int fillFormField(TPtxPdfForms_Field* pField, const TCHAR* szValue)
{
// 解放または閉じる必要があるオブジェクト
TPtxPdfForms_RadioButtonList* pButtonList = NULL;
TPtxPdfForms_RadioButton* pButton = NULL;
TPtxPdfForms_ChoiceItemList* pChoiceItemList = NULL;
TPtxPdfForms_ChoiceItem* pItem = NULL;
TCHAR* szName = NULL;
// その他の変数
TPtxPdfForms_FieldType iType = 0;
TPtxPdfForms_CheckBox* pCheckBox = NULL;
TPtxPdfForms_RadioButtonGroup* pRadioButtonGroup = NULL;
iReturnValue = 0;
iType = PtxPdfForms_Field_GetType(pField);
if (iType == ePtxPdfForms_FieldType_GeneralTextField || iType == ePtxPdfForms_FieldType_CombTextField)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_TextField_SetText((TPtxPdfForms_TextField*)pField, szValue),
_T("Failed to set text field value. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else if (iType == ePtxPdfForms_FieldType_CheckBox)
{
pCheckBox = (TPtxPdfForms_CheckBox*)pField;
if (_tcscmp(szValue, _T("on")) == 0)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_CheckBox_SetChecked(pCheckBox, TRUE),
_T("Failed to set check box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfForms_CheckBox_SetChecked(pCheckBox, FALSE),
_T("Failed to set check box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
}
else if (iType == ePtxPdfForms_FieldType_RadioButtonGroup)
{
pRadioButtonGroup = (TPtxPdfForms_RadioButtonGroup*)pField;
pButtonList = PtxPdfForms_RadioButtonGroup_GetButtons(pRadioButtonGroup);
for (int iButton = 0; iButton < PtxPdfForms_RadioButtonList_GetCount(pButtonList); iButton++)
{
pButton = PtxPdfForms_RadioButtonList_Get(pButtonList, iButton);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pButton, _T("Failed to get radio button. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError())
size_t nName = PtxPdfForms_RadioButton_GetExportName(pButton, szName, 0);
GOTO_CLEANUP_IF_ZERO(nName, _T("Failed to get radio button name\n"));
szName = (TCHAR*)malloc(nName * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szName, _T("Failed to allocate memory for radio button name\n"));
if (PtxPdfForms_RadioButton_GetExportName(pButton, szName, nName) != nName)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get radio button name. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
if (_tcscmp(szValue, szName) == 0)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_RadioButtonGroup_SetChosenButton(pRadioButtonGroup, pButton),
_T("Failed to set radio button. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());
}
free(szName);
szName = NULL;
Ptx_Release(pButton);
pButton = NULL;
}
}
else if (iType == ePtxPdfForms_FieldType_ComboBox || iType == ePtxPdfForms_FieldType_ListBox)
{
pChoiceItemList = PtxPdfForms_ChoiceField_GetItems((TPtxPdfForms_ChoiceField*)pField);
for (int iItem = 0; iItem < PtxPdfForms_ChoiceItemList_GetCount(pChoiceItemList); iItem++)
{
pItem = PtxPdfForms_ChoiceItemList_Get(pChoiceItemList, iItem);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pItem,
_T("Failed to get item from choice field. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
size_t nName = PtxPdfForms_ChoiceItem_GetDisplayName(pItem, szName, 0);
GOTO_CLEANUP_IF_ZERO(nName, _T("Failed to get choice item name\n"));
szName = (TCHAR*)malloc(nName * sizeof(TCHAR*));
GOTO_CLEANUP_IF_NULL(szName, _T("Failed to allocate memory for choice item name\n"));
if (PtxPdfForms_ChoiceItem_GetDisplayName(pItem, szName, nName) != nName)
{
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get choice item name. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
if (_tcscmp(szValue, szName) == 0)
{
break;
}
free(szName);
szName = NULL;
Ptx_Release(pItem);
pItem = NULL;
}
if (pItem != NULL)
{
free(szName);
szName = NULL;
if (iType == ePtxPdfForms_FieldType_ComboBox)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ComboBox_SetChosenItem((TPtxPdfForms_ComboBox*)pField, pItem),
_T("Failed to set choice item for combo box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else // iType == ePtxPdfForms_FieldType_ListBox
{
Ptx_Release(pChoiceItemList);
pChoiceItemList = PtxPdfForms_ListBox_GetChosenItems((TPtxPdfForms_ListBox*)pField);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pChoiceItemList, _T("Failed to get list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ChoiceItemList_Clear(pChoiceItemList),
_T("Failed to clear list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfForms_ChoiceItemList_Add(pChoiceItemList, pItem),
_T("Failed to add item to list of chosen items for list box. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
}
}
}
cleanup:
if (szName != NULL)
free(szName);
if (pItem == NULL)
Ptx_Release(pItem);
if (pChoiceItemList == NULL)
Ptx_Release(pChoiceItemList);
if (pButton != NULL)
Ptx_Release(pButton);
if (pButtonList != NULL)
Ptx_Release(pButton);
return iReturnValue;
}
// 入力ドキュメントを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDF
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// PDF全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
FieldNodeMap outFields = outDoc.FormFields;
// すべてのフォームフィールドをコピー
FieldNodeMap inFields = inDoc.FormFields;
foreach (var inPair in inFields)
{
FieldNode inFieldNode = inPair.Value;
FieldNode outFormFieldNode = FieldNode.Copy(outDoc, inFieldNode);
outFields.Add(inPair.Key, outFormFieldNode);
}
// 指定されたフィールドを検索
// 見つからない場合は例外をスロー
var selectedNode = outFields.Lookup(fieldIdentifier);
if (selectedNode is Field selectedField)
FillFormField(selectedField, fieldValue);
// 既存のウィジェットを更新し、署名フィールドを削除するためのコピーオプションを構成
PageCopyOptions copyOptions = new PageCopyOptions
{
FormFields = FormFieldCopyStrategy.CopyAndUpdateWidgets,
UnsignedSignatures = CopyStrategy.Remove,
};
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力PDF色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
static void FillFormField(Field formField, string value)
{
// フィールドタイプに応じて値を適用
if (formField is TextField textField)
{
// テキストを設定
textField.Text = value;
}
else if (formField is CheckBox checkBox)
{
// チェックまたはチェックを外す
checkBox.Checked = "on".Equals(value, StringComparison.CurrentCultureIgnoreCase);
}
else if (formField is RadioButtonGroup group)
{
// 指定された名前のボタンを検索
foreach (var button in group.Buttons)
{
if (value.Equals(button.ExportName))
{
// 見つかったので、このボタンを選択
group.ChosenButton = button;
break;
}
}
}
else if (formField is ComboBox comboBox)
{
// 指定されたアイテムを検索
foreach (var item in comboBox.Items)
{
if (value.Equals(item.DisplayName))
{
// 見つかったので、このアイテムを選択
comboBox.ChosenItem = item;
break;
}
}
}
else if (formField is ListBox listBox)
{
// 指定されたアイテムを検索
foreach (var item in listBox.Items)
{
if (value.Equals(item.DisplayName))
{
// 見つかったので、この項目を唯一の選択項目として設定
var itemList = listBox.ChosenItems;
itemList.Clear();
itemList.Add(item);
break;
}
}
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力PDF色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def fill_form_field(form_field: Field, value: str):
"""Set the value of a form field based on its type."""
if isinstance(form_field, TextField):
form_field.text = value
elif isinstance(form_field, CheckBox):
form_field.checked = value.lower() == "on"
elif isinstance(form_field, RadioButtonGroup):
for button in form_field.buttons:
if button.export_name == value:
form_field.chosen_button = button
break
elif isinstance(form_field, ComboBox):
for item in form_field.items:
if item.display_name == value:
form_field.chosen_item = item
break
elif isinstance(form_field, ListBox):
for item in form_field.items:
if item.display_name == value:
form_field.chosen_items.clear()
form_field.chosen_items.append(item)
break
# 入力ドキュメントを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDF作成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# PDF全体のデータをコピー
copy_document_data(in_doc, out_doc)
# すべてのフォームフィールドをコピー
in_fields = in_doc.form_fields
out_fields = out_doc.form_fields
for key, in_field_node in in_fields.items():
out_fields[key] = FieldNode.copy(out_doc, in_field_node)
# 指定されたフィールドを検索し、指定された値で更新
selected_field = out_fields.lookup(field_identifier)
if selected_field:
fill_form_field(selected_field, field_value)
# コピーオプション設定
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.COPY_AND_UPDATE_WIDGETS
copy_options.unsigned_signatures = CopyStrategy.REMOVE
# すべてのページをコピー
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
PDF文書の先頭ページの指定された位置にバーコードを生成して追加します。
// 入力ドキュメントを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// フォントストリームを生成
pFontStream = _tfopen(szFontPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pFontStream, _T("Failed to open font file."));
PtxSysCreateFILEStreamDescriptor(&fontDescriptor, pFontStream, 0);
// 出力ドキュメントを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
pFont = PtxPdfContent_Font_Create(pOutDoc, &fontDescriptor, TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// PDF全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプション設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入出力ドキュメントのページリストを取得
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 先頭のページをコピー
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーされたページにバーコード画像を追加
if (addBarcode(pOutDoc, pOutPage, szBarcode, pFont, 50) != 0)
goto cleanup;
// ページを出力ドキュメントに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 残りのページを取得
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 取得した残りページを出力にコピー
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コピーされたページを出力ファイルに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addBarcode(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szBarcode, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pBarcodeText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Textオブジェクトを作成
pBarcodeText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pBarcodeText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// Textジェネレータを作成
pTextGenerator = PtxPdfContent_TextGenerator_New(pBarcodeText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 位置を計算
TPtxGeomReal_Size size;
PtxPdf_Page_GetSize(pOutPage, &size);
TPtxGeomReal_Point position;
double dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szBarcode);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dTextWidth, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dFontAscent, _T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dFontDescent = PtxPdfContent_Font_GetDescent(pFont);
GOTO_CLEANUP_IF_NEGATIVE_PRINT_ERROR(dFontDescent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
position.dX = size.dWidth - (dTextWidth + dBorder);
position.dY = size.dHeight - (dFontSize * (dFontAscent + dFontDescent) + dBorder);
// 計算された位置に移動
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 指定されたバーコード文字列を追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szBarcode),
_T("Failed to add barcode string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// Textジェネレータを終了
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
// 位置指定されたバーコードテキストを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pBarcodeText),
_T("Failed to paint the positioned barcode text. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
return iReturnValue;
}
// 入力ドキュメントを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// ファイルストリームを生成
using (Stream fontStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read))
// 出力ドキュメントを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// PDF全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 出力ドキュメントに埋め込みフォントを作成
Font font = Font.Create(outDoc, fontStream, true);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 先頭ページをコピーし、そこにバーコードを追加する。このページを出力ドキュメントに追加
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddBarcode(outDoc, outPage, barcode, font, 50);
outDoc.Pages.Add(outPage);
// 残りのページをコピーして出力ドキュメントに追加
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// PDF全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddBarcode(Document outputDoc, Page outPage, string barcode,
Font font, double fontSize)
{
// コンテンツジェネレータを作成
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
// Textオブジェクトを作成
Text barcodeText = Text.Create(outputDoc);
// Textジェネレータを作成
using (TextGenerator textGenerator = new TextGenerator(barcodeText, font, fontSize, null))
{
// 位置を計算
Point position = new Point
{
X = outPage.Size.Width - (textGenerator.GetWidth(barcode) + Border),
Y = outPage.Size.Height - (fontSize * (font.Ascent + font.Descent) + Border)
};
// 計算された位置に移動
textGenerator.MoveTo(position);
// 与えられたバーコードテキストを追加
textGenerator.ShowLine(barcode);
}
// 位置指定されたバーコードテキストを描画
gen.PaintText(barcodeText);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# PDF全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_barcode(out_doc: Document, out_page: Page, barcode: str, font: Font, font_size: float):
# コンテンツジェネレータを作成
with ContentGenerator(out_page.content, False) as gen:
# Textオブジェクトを作成
barcode_text = Text.create(out_doc)
# Textジェネレータを作成
with TextGenerator(barcode_text, font, font_size, None) as text_generator:
# 位置を計算
position = Point(x=out_page.size.width - (text_generator.get_width(barcode) + border),
y=out_page.size.height - (font_size * (font.ascent + font.descent) + border))
# 計算された位置に移動
text_generator.move_to(position)
# 指定されたバーコード文字列を追加
text_generator.show_line(barcode)
# 位置指定されたバーコートテキストを描画
gen.paint_text(barcode_text)
# 境界を定義
border = 20
# 入力ドキュメントを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# フォントストリームを作成
with io.FileIO(font_path, 'rb') as font_stream:
# 出力ドキュメントを生成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# PDF全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 出力ドキュメントに埋め込みフォントを作成
font = Font.create(out_doc, font_stream, True)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 先頭ページをコピーし、そこにバーコードを追加する。このページを出力ドキュメントに追加
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_barcode(out_doc, out_page, barcode, font, 50.0)
out_doc.pages.append(out_page)
# 残りのページをコピーして出力ドキュメントに追加
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
PDF ドキュメントの最初のページに既存のデータマトリックス画像であるニ次元バーコードを追加します。
// 入力ドキュメントを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力ドキュメントを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// 出力ドキュメントに埋め込みフォントを生成
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// PDF全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ページのコピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入出力ドキュメントのページリストを取得
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 先頭ページをコピー
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// データマトリックスをコピーされたページに追加
if (addDataMatrix(pOutDoc, pOutPage, szDatamatrixPath) != 0)
goto cleanup;
// ページを出力文書に追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 入力文書の残りのページを取得
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 取得した残りのページを出力にコピー
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コピーしたページを出力ファイルに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addDataMatrix(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szDataMatrixPath)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxSys_StreamDescriptor datamatrixDescriptor;
FILE* pDatamatrixStream = NULL;
TPtxPdfContent_Image* pDatamatrix = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// データマトリックスをインポート
pDatamatrixStream = _tfopen(szDataMatrixPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pDatamatrixStream, _T("Failed to open data matrix file \"%s\".\n"), szDataMatrixPath);
PtxSysCreateFILEStreamDescriptor(&datamatrixDescriptor, pDatamatrixStream, 0);
// データマトリックスのImageオブジェクトを作成
pDatamatrix = PtxPdfContent_Image_Create(pOutDoc, &datamatrixDescriptor);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pDatamatrix, _T("Failed to create image object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// データマトリックスのサイズ
double dDatamatrixSize = 85.0;
// データマトリックスの矩形を計算
TPtxGeomReal_Size size;
PtxPdf_Page_GetSize(pOutPage, &size);
TPtxGeomReal_Rectangle rect;
rect.dLeft = dBorder;
rect.dBottom = size.dHeight - (dDatamatrixSize + dBorder);
rect.dRight = dDatamatrixSize + dBorder;
rect.dTop = size.dHeight - dBorder;
// 指定された矩形にデータマトリックスImageを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintImage(pGenerator, pDatamatrix, &rect),
_T("Failed to paint data matrix into the specified rectangle. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力ドキュメントを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力ドキュメントを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// PDF全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 先頭ページをコピーし、データマトリックスを追加する。そのページを出力文書に追加
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddDataMatrix(outDoc, outPage, datamatrixPath);
outDoc.Pages.Add(outPage);
// 残りのページをコピーし、出力文書に追加
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// PDF全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddDataMatrix(Document document, Page page, string datamatrixPath)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// データマトリックスをインポート
using Stream inMatrix = new FileStream(datamatrixPath, FileMode.Open, FileAccess.Read);
// データマトリックスのImageオブジェクトを作成
Image datamatrix = Image.Create(document, inMatrix);
// データマトリックスのサイズ
double datamatrixSize = 85;
// データマトリックスの矩形を計算
Rectangle rect = new Rectangle
{
Left = Border,
Bottom = page.Size.Height - (datamatrixSize + Border),
Right = datamatrixSize + Border,
Top = page.Size.Height - Border
};
// 指定された矩形にデータマトリックスImageを描画
generator.PaintImage(datamatrix, rect);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# PDF全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_data_matrix(document: Document, page: Page, data_matrix_path: str):
# コンテンツジェネレータを作成
with ContentGenerator(page.content, False) as generator:
# データマトリックスをインポート
with io.FileIO(data_matrix_path, 'rb') as in_matrix_stream:
# データマトリックスのImageオブジェクトを作成
data_matrix = Image.create(document, in_matrix_stream)
# データマトリックスのサイズ
data_matrix_size = 85
# データマトリックスの矩形を計算
rect = Rectangle(left=border, bottom=page.size.height - (data_matrix_size + border), right=data_matrix_size + border, top=page.size.height - border)
# 指定された矩形にデータマトリックスImageを描画
generator.paint_image(data_matrix, rect)
#境界を定義
border = 40
# 入力ドキュメントを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力ドキュメントを生成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# PDF全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 先頭ページをコピーし、データマトリックスを追加する。そのページを出力文書に追加
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_data_matrix(out_doc, out_page, data_matrix_path)
out_doc.pages.append(out_page)
# 残りのページをコピーし、出力文書に追加
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
サイズ指定された画像をページの指定場所に配置します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力ページと出力ページのリストを取得
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 先頭ページから選択されたページより前までをコピー
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 0, iPageNumber - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange, _T("Failed to get page range. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange, _T("Failed to copy page range. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInPageRange);
pInPageRange = NULL;
Ptx_Release(pOutPageRange);
pOutPageRange = NULL;
// 選択したページをコピーして画像を追加
pInPage = PtxPdf_PageList_Get(pInPageList, iPageNumber - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
if (addImage(pOutDoc, pOutPage, szImagePath, 150.0, 150.0) != 0)
goto cleanup;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 残りのページをコピー
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addImage(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szImagePath, double x, double y)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxSys_StreamDescriptor imageDescriptor;
FILE* pImageStream = NULL;
TPtxPdfContent_Image* pImage = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
// 入力パスからの画像読み込み
pImageStream = _tfopen(szImagePath, _T("rb"));
PtxSysCreateFILEStreamDescriptor(&imageDescriptor, pImageStream, 0);
// 画像オブジェクトを作成
pImage = PtxPdfContent_Image_Create(pOutDoc, &imageDescriptor);
double dResolution = 150.0;
TPtxGeomInt_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Image_GetSize(pImage, &size),
_T("Failed to get image size. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// データ行列の矩形を計算
TPtxGeomReal_Rectangle rect;
rect.dLeft = x;
rect.dBottom = y;
rect.dRight = x + (double)size.iWidth * 72.0 / dResolution;
rect.dTop = y + (double)size.iHeight * 72.0 / dResolution;
// 指定されたに矩形画像を描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintImage(pGenerator, pImage, &rect),
_T("Failed to paint image. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 先頭ページから選択したページの前までのページをコピーし、出力ドキュメントに追加
PageList inPageRange = inDoc.Pages.GetRange(0, pageNumber - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
// 選択したページをコピーし、画像を追加して出力ドキュメントに追加
Page outPage = Page.Copy(outDoc, inDoc.Pages[pageNumber - 1], copyOptions);
AddImage(outDoc, outPage, imagePath, 150, 150);
outDoc.Pages.Add(outPage);
// 残りのページをコピーして出力ドキュメントに追加
inPageRange = inDoc.Pages.GetRange(pageNumber, inDoc.Pages.Count - pageNumber);
copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddImage(Document document, Page page, string imagePath, double x, double y)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// 入力パスからの画像読み込み
using Stream inImage = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
// 画像オブジェクトを作成
Image image = Image.Create(document, inImage);
double resolution = 150;
// 画像の矩形を計算
PdfTools.Toolbox.Geometry.Integer.Size size = image.Size;
Rectangle rect = new Rectangle
{
Left = x,
Bottom = y,
Right = x + size.Width * 72 / resolution,
Top = y + size.Height * 72 / resolution
};
// 指定された矩形に画像を描画
generator.PaintImage(image, rect);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# 表示設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル (PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_image(document: Document, page: Page, image_path: str, x: float, y: float):
# コンテンツジェネレータを作成
with ContentGenerator(page.content, False) as generator:
# 入力パスからの画像読み込み
with io.FileIO(image_path, 'rb') as in_image_stream:
# 画像オブジェクトを作成
image = Image.create(document, in_image_stream)
resolution = 150
# 画像の矩形を計算
size = image.size
rect = Rectangle(
left=x,
bottom=y,
right=x + size.width * 72 / resolution,
top=y + size.height * 72 / resolution
)
# 指定された矩形に画像を描画
generator.paint_image(image, rect)
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページコピーオプションを定義
copy_options = PageCopyOptions()
# 先頭ページから選択したページの前までのページをコピーし、出力ドキュメントに追加
if page_number > 1:
in_page_range = in_doc.pages[:page_number - 1]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
# 選択したページをコピーし、画像を追加して出力ドキュメントに追加
out_page = Page.copy(out_doc, in_doc.pages[page_number - 1], copy_options)
add_image(out_doc, out_page, image_path, 150, 150)
out_doc.pages.append(out_page)
# 残りのページをコピーして出力ドキュメントに追加
in_page_range = in_doc.pages[page_number:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
ページ上の指定した位置に長方形のマスク画像を配置します。
マスク画像は、画像をピクセル単位で塗りつぶしたりマスクしたりするステンシルマスクです。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(_T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(_T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// デバイス色空間を取得
TPtxPdfContent_ColorSpace* pColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pColorSpace, _T("Failed to get the device color space. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// RGBカラー値を選択
double color[] = {1.0, 0.0, 0.0};
size_t nColor = sizeof(color) / sizeof(double);
// 描画オブジェクトを作成
pPaint = PtxPdfContent_Paint_Create(pOutDoc, pColorSpace, color, nColor, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pPaint, _T("Failed to create a transparent paint. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力ページと出力ページのリストを取得
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 最初のページをコピーして画像マスクを追加
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
if (addImageMask(pOutDoc, pOutPage, szImageMaskPath, 250, 150) != 0)
goto cleanup;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 残りのページをコピー
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// 表示設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル (PDF/A-3およびPDF2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addImageMask(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szImageMaskPath, double x, double y)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
FILE* pImageStream = NULL;
TPtxSys_StreamDescriptor imageDescriptor;
TPtxPdfContent_ImageMask* pImageMask = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 入力パスからの画像読み込み
pImageStream = _tfopen(szImageMaskPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pImageStream, _T("Failed to open image mask file \"%s\".\n"), szImageMaskPath);
PtxSysCreateFILEStreamDescriptor(&imageDescriptor, pImageStream, 0);
// 画像マスクオブジェクトを作成
pImageMask = PtxPdfContent_ImageMask_Create(pOutDoc, &imageDescriptor);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pImageMask, _T("Failed to create image mask obejct. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
double dResolution = 150.0;
TPtxGeomInt_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ImageMask_GetSize(pImageMask, &size),
_T("Failed to get image mask size. %s(ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// データ行列の矩形を計算
TPtxGeomReal_Rectangle rect;
rect.dLeft = x;
rect.dBottom = y;
rect.dRight = x + (double)size.iWidth * 72.0 / dResolution;
rect.dTop = y + (double)size.iHeight * 72.0 / dResolution;
// 指定された矩形に画像マスクを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintImageMask(pGenerator, pImageMask, &rect, pPaint),
_T("Failed to paint image mask. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// デバイス色空間を取得
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// 描画オブジェクトを作成
paint = Paint.Create(outDoc, colorSpace, new double[] { 1.0, 0.0, 0.0 }, null);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 最初のページをコピーし、画像マスクを追加して出力ドキュメントに追加
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddImageMask(outDoc, outPage, imageMaskPath, 250, 150);
outDoc.Pages.Add(outPage);
// 残りのページをコピーして出力ドキュメントに追加
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// 表示設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル (PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddImageMask(Document document, Page outPage, string imagePath,
double x, double y)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);
// 入力パスからの画像読み込み
using Stream inImage = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
// 画像マスクオブジェクトを作成
ImageMask imageMask = ImageMask.Create(document, inImage);
double resolution = 150;
// 画像の矩形を計算
PdfTools.Toolbox.Geometry.Integer.Size size = imageMask.Size;
Rectangle rect = new Rectangle
{
Left = x,
Bottom = y,
Right = x + size.Width * 72 / resolution,
Top = y + size.Height * 72 / resolution
};
// 指定された四角形に画像マスクを描画
generator.PaintImageMask(imageMask, rect, paint);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# 表示設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル (PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_image_mask(document: Document, page: Page, image_path: str, x: float, y: float):
# コンテンツジェネレータを作成
with ContentGenerator(page.content, False) as generator:
# 入力パスからの画像読み込み
with io.FileIO(image_path, 'rb') as in_image_stream:
# Create image mask object
image_mask = ImageMask.create(document, in_image_stream)
resolution = 150
# 画像の矩形を計算
size = image_mask.size
rect = Rectangle(
left=x,
bottom=y,
right=x + size.width * 72 / resolution,
top=y + size.height * 72 / resolution
)
# 指定された四角形に画像マスクを描画
generator.paint_image_mask(image_mask, rect, paint)
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# デバイス色空間を取得
color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# 描画オブジェクトを作成
paint = Paint.create(out_doc, color_space, [1.0, 0.0, 0.0], None)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 最初のページをコピーし、画像マスクを追加して出力ドキュメントに追加
out_page = Page.copy(out_doc, in_doc.pages[0], copy_options)
add_image_mask(out_doc, out_page, image_mask_path, 250, 150)
out_doc.pages.append(out_page)
# 残りのページをコピーして出力ドキュメントに追加
in_page_range = in_doc.pages[1:]
copied_pages = PageList.copy(out_doc, in_page_range, copy_options)
out_doc.pages.extend(copied_pages)
テキストを含む各行の前に行番号を追加します。
// 入力PDFを開く
using Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read)
using Document inDoc = Document.Open(inStream, null)
// 出力PDFを作成
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite)
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null)
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 行番号に使うフォントを作成
var lineNumberFont = Font.CreateFromSystem(outDoc, "Arial", null, true);
// ページのコピーオプションを定義
PageCopyOptions pageCopyOptions = new();
// 入力PDFから出力PDFにすべてのページをコピー
var inPages = inDoc.Pages;
var outPages = PageList.Copy(outDoc, inPages, pageCopyOptions);
// すべての入力ページと出力ページのペアを反復処理
var pages = inPages.Zip(outPages);
foreach (var pair in pages)
AddLineNumbers(outDoc, lineNumberFont, pair);
// 完成したページを出力ドキュメントのページリストに追加
outDoc.Pages.AddRange(outPages);
}
private static void AddLineNumbers(Document outDoc, Font lineNumberFont, (Page first, Page second) pair)
{
// 入力ページにあるすべてのテキストに行番号を出力ページに追加
// 入力および出力のページ
var inPage = pair.first;
var outPage = pair.second;
// すべてのテキストフラグメントを抽出
var extractor = new ContentExtractor(inPage.Content)
{
Ungrouping = UngroupingSelection.All
};
// すべてのテキストフラグメントの左端の水平(X-座標)位置
double leftX = inPage.Size.Width;
// フォントサイズより小さい距離の場合に等しいとする比較(double型で比較)
var comparison = new Comparison<double>(
(a, b) =>
{
var d = b - a;
if (Math.Abs(d) lt; fontSize)
return 0;
return Math.Sign(d);
});
// すべてのテキストフラグメントの垂直(Y-座標)位置をソートし重複なく保持するコンテナ
SortedSet<double> lineYPositions = new(Comparer<double>.Create(comparison));
// 入力ページのすべてのコンテンツ要素を反復処理
foreach (var element in extractor)
{
// テキスト要素のみを処理
if (element is TextElement textElement)
{
// すべてのテキストフラグメントを反復処理
foreach (var fragment in textElement.Text)
{
// フラグメントのベースラインの開始点を取得
var point = fragment.Transform.TransformPoint(new Point { X = fragment.BoundingBox.Left, Y = 0 });
// 左端の位置を更新
leftX = Math.Min(leftX, point.X);
// 垂直位置を追加
lineYPositions.Add(point.Y);
}
}
}
// 新たなテキストフラグメントが見つかった場合に行番号を追加
if (lineYPositions.Count > 0)
{
// テキストオブジェクトを作成し、テキストジェネレータを使用
var text = Text.Create(outDoc);
using (var textGenerator = new TextGenerator(text, lineNumberFont, fontSize, null))
{
// 入力にあるすべての垂直位置を反復処理
foreach (var y in lineYPositions)
{
// 行番号文字列
var lineNumberString = string.Format("{0}", ++lineNumber);
// ページに表示される行番号文字列の幅
var width = textGenerator.GetWidth(lineNumberString);
// 行番号は右揃えに配置します。
// 行番号の水平位置はテキストフラグメント(行)の左端から指定された間隔で配置します。
textGenerator.MoveTo(new Point { X = leftX - width - distance, Y = y });
// 行番号文字列を表示
textGenerator.Show(lineNumberString);
}
}
// コンテンツジェネレータを使用してページにテキストを描画
using var contentGenerator = new ContentGenerator(outPage.Content, false);
contentGenerator.PaintText(text);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル (PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル (PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
class TolerantSortedSet:
def add(self, value: float):
for existing in self.data:
if abs(existing - value) lt; self.tolerance:
return # Do not add duplicate-like value
self.data.append(value)
self.data.sort(reverse=self.sort_reverse)
def iterator(self):
return iter(self.data)
def display(self):
return str(self.data)
def create_tolerant_sorted_set(tolerance: float, sort_reverse: bool):
tolerant_sorted_set = TolerantSortedSet()
tolerant_sorted_set.tolerance = tolerance
tolerant_sorted_set.sort_reverse = sort_reverse
tolerant_sorted_set.data = []
return tolerant_sorted_set
def add_line_numbers(out_doc: Document, line_number_font: Font, pair: tuple):
global line_number
# 入力ページにあるすべてのテキストに行番号を出力ページに追加します。
# 入出力ページ
in_page, out_page = pair
# すべてのテキストフラグメントを抽出
extractor = ContentExtractor(in_page.content)
extractor.ungrouping = UngroupingSelection.ALL
# すべてのテキストフラグメントの左端の水平(X-座標)位置
left_x = in_page.size.width
# フォントサイズより小さい距離の場合に等しいとする比較
def comparison(a, b):
d = b - a
if abs(d) < font_size:
return 0
return (d > 0) - (d < 0) # return 1 if d > 0, -1 if d < 0, 0 otherwise
# すべてのテキストフラグメントの垂直位置を保持するソートされたセット
# PDFでは座標が逆になっているため、データを逆順に並べ替え
line_y_positions = create_tolerant_sorted_set(tolerance=font_size, sort_reverse=True)
# 入力ページのすべてのコンテンツ要素を反復処理
for element in extractor:
# テキスト要素のみを処理
if isinstance(element, TextElement):
# すべてのテキストフラグメントを反復処理
for fragment in element.text:
# フラグメントのベースラインの開始点を取得
point = fragment.transform.transform_point(
Point(fragment.bounding_box.left, 0)
)
# 左端の位置を更新
left_x = min(left_x, point.x)
# 垂直位置を追加
line_y_positions.add(point.y)
# 新たなテキストフラグメントが見つかった場合に行番号を追加
if line_y_positions:
# テキストオブジェクトを作成し、テキストジェネレータを使用
text = Text.create(out_doc)
with TextGenerator(text, line_number_font, font_size, None) as text_generator:
# 入力にあるすべての垂直位置を反復処理
for y in line_y_positions.iterator():
# 行番号文字列
line_number += 1
line_number_string = str(line_number)
# ページに表示される行番号文字列の幅
width = text_generator.get_width(line_number_string)
# 行番号は右揃えに配置します。
# 行番号の水平位置はテキストフラグメント(行)の左端から指定された間隔で配置します。
text_generator.move_to(Point(left_x - width - distance, y))
# 行番号文字列を表示
text_generator.show(line_number_string)
# コンテンツジェネレータを使用してページにテキストを描画
with ContentGenerator(out_page.content, False) as content_generator:
content_generator.paint_text(text)
# グローバル変数を定義
distance = 10
font_size = 8.0
line_number = 0
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 行番号に使うフォントを作成
lineNumberFont = Font.create_from_system(out_doc, "Arial", None, True)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 入力PDFから出力PDFにすべてのページをコピー
in_pages = in_doc.pages
out_pages = PageList.copy(out_doc, in_pages, copy_options)
# すべての入力ページと出力ページのペアを反復処理
pages = zip(in_pages, out_pages)
for pair in pages:
add_line_numbers(out_doc, lineNumberFont, pair)
out_doc.pages.extend(out_pages)
PDFドキュメントの各ページに半透明のスタンプテキストを追加します。
オプションでスタンプの色と不透明度を指定できます。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&inDescriptor, pInStream, FALSE);
pInDoc = PtxPdf_Document_Open(&inDescriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file %s.\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file %s cannot be closed. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFに埋め込みフォントを作成
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Embedded font cannot be created. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 色空間取得
TPtxPdfContent_ColorSpace* pColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pColorSpace, _T("Failed to get the color space. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// RGBカラー値と透明度を選択
double color[] = {1.0, 0.0, 0.0};
size_t nColor = sizeof(color) / sizeof(double);
pTransparency = PtxPdfContent_Transparency_New(dAlpha);
// 描画オブジェクトを作成
pPaint = PtxPdfContent_Paint_Create(pOutDoc, pColorSpace, color, nColor, pTransparency);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pPaint, _T("Failed to create a transparent paint. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// ページのコピーオプション設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力の全ページをループ
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int i = 0; i < PtxPdf_PageList_GetCount(pInPageList); i++)
{
// ページのリストを取得
pInPage = PtxPdf_PageList_Get(pInPageList, i);
// 入力から出力にページをコピー
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// スタンプをページに追加
if (addStamp(pOutDoc, pOutPage, szStampString, pFont, 50) == 1)
{
goto cleanup;
}
// ページを出力ドキュメントに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addStamp(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szStampString, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
TPtxGeomReal_AffineTransform trans;
TPtxGeomReal_Point rotationCenter;
double dTextWidth;
double dFontAscent;
TPtxPdfContent_Content* pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// テキストオブジェクトを作成
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// テキストジェネレータを作成
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 出力ページサイズを取得
TPtxGeomReal_Size size;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to read page size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 位置と回転の角度を計算
rotationCenter.dX = size.dWidth / 2.0;
rotationCenter.dY = size.dHeight / 2.0;
double dRotationAngle = atan2(size.dHeight, size.dWidth) / M_PI * 180.0;
// 計算された位置を中心にテキスト入力を回転
PtxGeomReal_AffineTransform_GetIdentity(&trans);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxGeomReal_AffineTransform_Rotate(&trans, dRotationAngle, &rotationCenter),
_T("Failed to rotate textinput around the calculated position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_Transform(pGenerator, &trans),
_T("Failed to modify the current transformation. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 位置を計算
TPtxGeomReal_Point position;
dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampString);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dTextWidth, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dFontAscent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
position.dX = (size.dWidth - dTextWidth) / 2.0;
position.dY = (size.dHeight - dFontAscent * dFontSize) / 2.0;
// 計算された位置に移動
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// テキストレンダリングを設定
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_SetFill(pTextGenerator, pPaint),
_T("Failed to set fill paint. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 指定されたスタンプ文字列を追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szStampString),
_T("Failed to add stamp. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// テキストジェネレータを終了
if (pTextGenerator != NULL)
{
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
}
// 位置指定されたテキストを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// 色空間取得
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, ProcessColorSpaceType.Rgb);
// RGBカラー値と透明度を選択
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(alpha);
// 選択したRGBカラーでペイントオブジェクトを作成
paint = Paint.Create(outDoc, colorSpace, color, transparency);
// コピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 入力ドキュメントからすべてのページをコピー
foreach (Page inPage in inDoc.Pages)
{
// 入力から出力にページをコピー
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// テキストをページに追加
AddStamp(outDoc, outPage, stampString);
// ページを文書に追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddStamp(Document outputDoc, Page outPage, string stampString)
{
// コンテンツジェネレータとテキストオブジェクトを作成
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
Text text = Text.Create(outputDoc);
// テキストジェネレータを作成
using (TextGenerator textgenerator = new TextGenerator(text, font, fontSize, null))
{
// 位置と回転の角度を計算
Point rotationCenter = new Point
{
X = outPage.Size.Width / 2.0,
Y = outPage.Size.Height / 2.0
};
double rotationAngle = Math.Atan2(outPage.Size.Height,
outPage.Size.Width) / Math.PI * 180.0;
// 計算された位置を中心にテキスト入力を回転
AffineTransform trans = AffineTransform.Identity;
trans.Rotate(rotationAngle, rotationCenter);
gen.Transform(trans);
// 位置を計算
Point position = new Point
{
X = (outPage.Size.Width - textgenerator.GetWidth(stampString)) / 2.0,
Y = (outPage.Size.Height - font.Ascent * fontSize) / 2.0
};
// 計算された位置に移動
textgenerator.MoveTo(position);
// テキスト描画設定
textgenerator.Fill = paint;
// 指定されたスタンプ文字列を追加
textgenerator.ShowLine(stampString);
}
// 位置指定されたテキストを描画
gen.PaintText(text);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_stamp(output_doc: Document, out_page: Page, stamp_string: str):
# コンテンツジェネレータとテキストオブジェクトを作成
with ContentGenerator(out_page.content, False) as gen:
text = Text.create(output_doc)
# テキストジェネレータを作成
with TextGenerator(text, font, font_size, None) as text_generator:
# 位置と回転の角度を計算
rotation_center = Point(
x=out_page.size.width / 2.0,
y=out_page.size.height / 2.0
)
rotation_angle = math.atan2(out_page.size.height, out_page.size.width) / math.pi * 180.0
# 計算された位置を中心にテキスト入力を回転
trans = AffineTransform.get_identity()
trans.rotate(rotation_angle, rotation_center)
gen.transform(trans)
# 位置を計算
position = Point(
x=(out_page.size.width - text_generator.get_width(stamp_string)) / 2.0,
y=(out_page.size.height - font.ascent * font_size) / 2.0
)
# 計算された位置に移動
text_generator.move_to(position)
# テキスト描画設定
text_generator.fill = paint
# 指定されたスタンプ文字列を追加
text_generator.show_line(stamp_string)
# 位置指定されたテキストを描画
gen.paint_text(text)
# グローバル変数宣言
font_size = 50.0
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# フォントを作成
font = Font.create_from_system(out_doc, "Arial", "Italic", True)
# 色空間取得
color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# RGBカラー値と透明度を選択
color = [1.0, 0.0, 0.0]
transparency = Transparency(alpha)
# 選択したRGBカラーでペイントオブジェクトを作成
paint = Paint.create(out_doc, color_space, color, transparency)
# コピーオプションを定義
copy_options = PageCopyOptions()
# 入力ドキュメントからすべてのページをコピー
for in_page in in_doc.pages:
# 入力から出力にページをコピー
out_page = Page.copy(out_doc, in_page, copy_options)
# テキストをページに追加
add_stamp(out_doc, out_page, stamp_string)
# ページを文書に追加
out_doc.pages.append(out_page)
PDFドキュメントの先頭ページの指定された位置にテキストを追加します。
// 入力PDFをオープン
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFに埋め込みフォントを作成
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T("Italic"), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力PDFと出力PDFのページリストを取得
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 先頭ページをコピー
pInPage = PtxPdf_PageList_Get(pInPageList, 0);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get the first page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to copy page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーしたページにテキストを追加
if (addText(pOutDoc, pOutPage, szTextString, pFont, 15) != 0)
goto cleanup;
// 出力PDFにページを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 入力から残りのページを取得
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, 1, PtxPdf_PageList_GetCount(pInPageList) - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 取得した(残りの)ページを出力にコピー
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageRange,
_T("Failed to copy page range to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コピーしたページを出力ドキュメントに追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to add page range to output page list. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addText(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TCHAR* szTextString, TPtxPdfContent_Font* pFont,
double dFontSize)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
TPtxGeomReal_Size size;
TPtxGeomReal_Point position;
double dFontAscent;
pContent = PtxPdf_Page_GetContent(pOutPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content of output file. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// テキストオブジェクトを作成
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create text object. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// テキストジェネレータを作成
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, dFontSize, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 出力ページサイズを取得
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to read page size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
dFontAscent = PtxPdfContent_Font_GetAscent(pFont);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dFontAscent, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
// 位置を計算
position.dX = dBorder;
position.dY = size.dHeight - dBorder - dFontSize * dFontAscent;
// 計算された位置に移動
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 指定されたテキスト文字列を追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szTextString),
_T("Failed to add text string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// テキストジェネレータを閉じる
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
// 配置されたテキストを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力ファイルを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// フォントを作成
font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 先頭のページをコピーし、そこにテキストを追加して出力ドキュメントに追加
Page outPage = Page.Copy(outDoc, inDoc.Pages[0], copyOptions);
AddText(outDoc, outPage, textString);
outDoc.Pages.Add(outPage);
// 残りのページをコピーして出力ドキュメントに追加
PageList inPageRange = inDoc.Pages.GetRange(1, inDoc.Pages.Count - 1);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddText(Document outputDoc, Page outPage, string textString)
{
// コンテンツジェネレータとテキストオブジェクトを作成
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
Text text = Text.Create(outputDoc);
// テキストジェネレータを作成
using (TextGenerator textGenerator = new TextGenerator(text, font, fontSize, null))
{
// 位置を計算
Point position = new Point
{
X = border,
Y = outPage.Size.Height - border - fontSize * font.Ascent
};
// 計算された位置に移動
textGenerator.MoveTo(position);
// 指定されたテキスト文字列を追加
textGenerator.ShowLine(textString);
}
// 配置されたテキストを描画
gen.PaintText(text);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_text(output_doc: Document, output_page: Page, text_string: str):
# コンテンツジェネレータとテキストオブジェクトを作成
with ContentGenerator(output_page.content, False) as gen:
text = Text.create(output_doc)
# テキストジェネレータを作成
with TextGenerator(text, font, font_size, None) as textGenerator:
# 位置を計算
position = Point(border, output_page.size.height - border - font_size * font.ascent)
# 位置に移動
textGenerator.move_to(position)
# 指定されたテキスト文字列を追加
textGenerator.show_line(text_string)
# 配置されたテキストを描画
gen.paint_text(text)
# グローバル変数を定義
border = 40.0
font_size = 15.0
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as input_document:
# 出力ファイルを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, input_document.conformance, None) as output_document:
# ドキュメント全体のデータをコピー
copy_document_data(input_document, output_document)
# フォントを作成
font = Font.create_from_system(output_document, "Arial", "Italic", True)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 先頭のページをコピーし、そこにテキストを追加して出力ドキュメントに追加
out_page = Page.copy(output_document, input_document.pages[0], copy_options)
add_text(output_document, out_page, text_string)
output_document.pages.append(out_page)
# 残りのページをコピーして出力ドキュメントに追加
inPageRange = input_document.pages[1:]
copied_pages = PageList.copy(output_document, inPageRange, copy_options)
output_document.pages.extend(copied_pages)
既存PDFのページに線を描画します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力の全ページを繰り返す
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPage = 1; iPage <= PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage - 1);
// 入力から出力にページをコピー
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
PtxPdf_Page_GetSize(pOutPage, &size);
// 先頭のページにテキストを追加
if (addLine(pOutDoc, pOutPage) == 1)
{
goto cleanup;
}
// 出力ドキュメントにページを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル (PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addLine(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Path* pPath = NULL;
TPtxPdfContent_PathGenerator* pPathGenerator = NULL;
TPtxPdfContent_ColorSpace* pDeviceRgbColorSpace = NULL;
double aColor[3];
TPtxPdfContent_Paint* pPaint = NULL;
TPtxPdfContent_Stroke* pStroke;
TPtxGeomReal_Size pageSize;
TPtxGeomReal_Point point;
pContent = PtxPdf_Page_GetContent(pOutPage);
PtxPdf_Page_GetSize(pOutPage, &pageSize);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL(pGenerator, szErrorBuff, Ptx_GetLastError());
// パス(ベクターグラフィック)を作成
pPath = PtxPdfContent_Path_New();
GOTO_CLEANUP_IF_NULL(pPath, szErrorBuff, Ptx_GetLastError());
// パスジェネレータを作成
pPathGenerator = PtxPdfContent_PathGenerator_New(pPath);
GOTO_CLEANUP_IF_NULL(pPathGenerator, szErrorBuff, Ptx_GetLastError());
// ページ全体に斜めの線を描画
point.dX = 10.0;
point.dY = 10.0;
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_PathGenerator_MoveTo(pPathGenerator, &point), szErrorBuff, Ptx_GetLastError());
point.dX = pageSize.dWidth - 10.0;
point.dY = pageSize.dHeight - 10.0;
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_PathGenerator_LineTo(pPathGenerator, &point), szErrorBuff, Ptx_GetLastError());
// パスを終了するためにパスジェネレーターを閉じる
PtxPdfContent_PathGenerator_Close(pPathGenerator);
pPathGenerator = NULL;
// RGBカラースペースを作成
pDeviceRgbColorSpace =
PtxPdfContent_ColorSpace_CreateProcessColorSpace(pOutDoc, ePtxPdfContent_ProcessColorSpaceType_Rgb);
GOTO_CLEANUP_IF_NULL(pDeviceRgbColorSpace, szErrorBuff, Ptx_GetLastError());
// 赤色で初期化
aColor[0] = 1.0;
aColor[1] = 0.0;
aColor[2] = 0.0;
// 描画オブジェクトを作成
pPaint =
PtxPdfContent_Paint_Create(pOutDoc, pDeviceRgbColorSpace, aColor, sizeof(aColor) / sizeof(aColor[0]), NULL);
GOTO_CLEANUP_IF_NULL(pPaint, szErrorBuff, Ptx_GetLastError());
// 指定されたペイントと線幅でストロークパラメータを設定
pStroke = PtxPdfContent_Stroke_New(pPaint, 10.0);
GOTO_CLEANUP_IF_NULL(pStroke, szErrorBuff, Ptx_GetLastError());
// ページにパスを描画
GOTO_CLEANUP_IF_FALSE(PtxPdfContent_ContentGenerator_PaintPath(pGenerator, pPath, NULL, pStroke), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pPathGenerator != NULL)
PtxPdfContent_PathGenerator_Close(pPathGenerator);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFを開く
using (System.IO.Stream inStream = new System.IO.FileStream(inPath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを作成
using (System.IO.Stream outStream = new System.IO.FileStream(outPath, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 入力PDFからすべてのページをコピー
foreach (Page inPage in inDoc.Pages)
{
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// 線分をページに描画
AddLine(outDoc, outPage);
// ページを出力PDFに追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル (PDF/A-3およびPDF2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddLine(Document document, Page page)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(page.Content, false);
// パス(ベクターグラフィック)を作成
Path path = new Path();
using (PathGenerator pathGenerator = new PathGenerator(path))
{
// ページ全体に斜めの線を描画
Size pageSize = page.Size;
pathGenerator.MoveTo(new Point() { X = 10.0, Y = 10.0 });
pathGenerator.LineTo(new Point() { X = pageSize.Width - 10.0, Y = pageSize.Height - 10.0 });
}
// RGBカラースペースを作成
ColorSpace deviceRgbColorSpace = ColorSpace.CreateProcessColorSpace(document, ProcessColorSpaceType.Rgb);
// 赤色を作成
double[] color = new double[] { 1.0, 0.0, 0.0 };
// ペイントオブジェクトを作成
Paint paint = Paint.Create(document, deviceRgbColorSpace, color, null);
// 指定されたペイントと線幅でストロークパラメータを作成
Stroke stroke = new Stroke(paint, 10.0);
// ページにパスを描画
generator.PaintPath(path, null, stroke);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル (PDF/A-3およびPDF2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_line(out_doc: Document, page: Page):
# コンテントジェネレータ
with ContentGenerator(page.content, False) as generator:
# パス(ベクターグラフィック)を作成
path = Path()
with PathGenerator(path) as path_generator:
# ページ全体に斜めの線を描画
page_size = page.size
path_generator.move_to(Point(x = 10.0, y = 10.0))
path_generator.line_to(Point(x = page_size.width - 10.0, y=page_size.height - 10.0))
# RGBカラースペースを作成
device_rgb_color_space = ColorSpace.create_process_color_space(out_doc, ProcessColorSpaceType.RGB)
# 赤色を作成
red = [1.0, 0.0, 0.0]
# ペイントオブジェクトを作成
paint = Paint.create(out_doc, device_rgb_color_space, red, None)
# 指定されたペイントと線幅でストロークパラメータを作成
stroke = Stroke(paint, 10.0)
# ページにパスを描画
generator.paint_path(path, None, stroke)
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページコピーオプションを定義
copy_options = PageCopyOptions()
# 入力PDFからすべてのページをコピー
for in_page in in_doc.pages:
out_page = Page.copy(out_doc, in_page, copy_options)
# 線分をページに描画
add_line(out_doc, out_page)
# ページを出力PDFに追加
out_doc.pages.append(out_page)
1ページの新しいPDFドキュメントを作成し、このページの指定された長方形領域内に両端揃えレイアウトのテキストブロックを追加します。
// 出力ドキュメントを作成
using (Stream outStream = new FileStream(outPath, FileMode.CreateNew, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
Font font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// ページを作成
Page outPage = Page.Create(outDoc, PageSize);
// テキストを両端揃えにして追加
LayoutText(outDoc, outPage, textPath, font, 20);
// ドキュメントにページを追加
outDoc.Pages.Add(outPage);
}
private static void LayoutText(Document outputDoc, Page outPage, string textPath, Font font,
double fontSize)
{
// コンテンツジェネレータを作成
using ContentGenerator gen = new ContentGenerator(outPage.Content, false);
// テキストオブジェクトを作成
Text text = Text.Create(outputDoc);
// テキストジェネレータを作成
using TextGenerator textGenerator = new TextGenerator(text, font, fontSize, null);
// 位置を計算
Point position = new Point
{
X = Border,
Y = outPage.Size.Height - Border
};
// 計算された位置に移動
textGenerator.MoveTo(position);
// テキスト入力のすべての行をループ
string[] lines = File.ReadAllLines(textPath, Encoding.Default);
foreach (string line in lines)
{
// 文字列を部分文字列に分割
string[] substrings = line.Split(new char[] { ' ' }, StringSplitOptions.None);
string currentLine = null;
double maxWidth = outPage.Size.Width - Border * 2;
int wordcount = 0;
// 入力文字列のすべての単語をループ
foreach (string word in substrings)
{
string tempLine;
// 部分文字列を行に連結
if (currentLine != null)
tempLine = currentLine + " " + word;
else
tempLine = word;
// 現在の行幅を計算
double width = textGenerator.GetWidth(currentLine);
if (textGenerator.GetWidth(tempLine) > maxWidth)
{
// 単語間隔を計算
textGenerator.WordSpacing = (maxWidth - width) / (wordcount - 1);
// 新しい行に描画
textGenerator.ShowLine(currentLine);
textGenerator.WordSpacing = 0;
currentLine = word;
wordcount = 1;
}
else
{
currentLine = tempLine;
wordcount++;
}
}
textGenerator.WordSpacing = 0;
// 指定されたスタンプ文字列を追加
textGenerator.ShowLine(currentLine);
}
// 位置指定されたテキストを描画
gen.PaintText(text);
}
def layout_text(output_doc: Document, out_page: Page, text_path: str, font: Font, font_size: float):
"""
Layout and justify text on the PDF page.
"""
# コンテンツジェネレータを作成
with ContentGenerator(out_page.content, False) as generator:
# テキストオブジェクトを作成
text = Text.create(output_doc)
# テキストジェネレータを作成
with TextGenerator(text, font, font_size, None) as text_generator:
# 文字列の位置を計算
position = Point(x=BORDER, y=out_page.size.height - BORDER)
# 計算された位置に移動
text_generator.move_to(position)
with open(text_path, "r", encoding="utf-8") as file:
lines = file.readlines()
# テキスト入力のすべての行をループ
for line in lines:
# 文字列を部分文字列に分割
substrings = line.split(" ")
current_line = ""
max_width = out_page.size.width - BORDER * 2
word_count = 0
# 入力文字列のすべての単語をループ
for word in substrings:
# 部分文字列を行に連結
temp_line = f"{current_line} {word}".strip()
# 現在の行幅を計算
current_width = text_generator.get_width(current_line)
if text_generator.get_width(temp_line) > max_width:
# 単語間隔を計算
text_generator.word_spacing = (max_width - current_width) / (word_count - 1) if word_count > 1 else 0
text_generator.show_line(current_line)
text_generator.word_spacing = 0
current_line = word
word_count = 1
else:
current_line = temp_line
word_count += 1
text_generator.word_spacing = 0
# 指定されたスタンプ文字列を追加
text_generator.show_line(current_line)
# 位置指定されたテキストを描画
generator.paint_text(text)
# グローバル変数
BORDER = 50
PAGE_SIZE = Size(width=595, height=842) # A4 page size in points
# 出力ドキュメントを作成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
font = Font.create_from_system(out_doc, "Arial", "Italic", True)
# ページを作成
out_page = Page.create(out_doc, PAGE_SIZE)
# テキストを両端揃えにして追加
layout_text(out_doc, out_page, input_text_path, font, font_size=20)
# ドキュメントにページを追加
out_doc.pages.append(out_page)
PDF文書の各ページのフッターにページ番号をスタンプします。
// 入力PDFをオープン
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFに埋め込みフォントを作成
pFont = PtxPdfContent_Font_CreateFromSystem(pOutDoc, _T("Arial"), _T(""), TRUE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pFont, _T("Failed to create font. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// すべてのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPage = 0; iPage lt; PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage);
// 入力PDFから出力PDFにページをコピー
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pOutPage, &size),
_T("Failed to get size. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 出力PDFの現在のページにページ番号をスタンプ
if (addPageNumber(pOutDoc, pOutPage, pFont, iPage + 1) == 1)
{
goto cleanup;
}
// 出力PDFにページを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef lt; PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef lt; PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
int addPageNumber(TPtxPdf_Document* pOutDoc, TPtxPdf_Page* pOutPage, TPtxPdfContent_Font* pFont, int nPageNumber)
{
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// テキストオブジェクトを作成
pText = PtxPdfContent_Text_Create(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create a text object. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 指定されたフォントでサイズと位置を指定してテキストジェネレータを作成
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, 8, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create a text generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// ページ番号としてスタンプする文字列を生成
char szStampBuffer[50];
snprintf(szStampBuffer, sizeof(szStampBuffer), _T("Page %d"), nPageNumber);
TCHAR* szStampText = szStampBuffer;
double dTextWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampText);
GOTO_CLEANUP_IF_ZERO_PRINT_ERROR(dTextWidth, _T("Failed to get text width. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 位置を計算
TPtxGeomReal_Point position;
position.dX = (size.dWidth / 2) - (dTextWidth / 2);
position.dY = 10;
// 計算された位置に移動
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &position),
_T("Failed to move to position. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 指定されたテキスト文字列を追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_ShowLine(pTextGenerator, szStampText),
_T("Failed to add given text string. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// テキストジェネレータを終了
PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
// 位置指定されたテキストを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint the positioned text. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pText != NULL)
Ptx_Release(pText);
if (pContent != NULL)
Ptx_Release(pContent);
return iReturnValue;
}
// 入力PDFをオープン
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// コピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 出力PDFに埋め込みフォントを作成
Font font = Font.CreateFromSystem(outDoc, "Arial", string.Empty, true);
// 入力PDFの全ページをコピー
int currentPageNumber = 1;
foreach (Page inPage in inDoc.Pages)
{
// 入力PDFから出力PDFにページをコピー
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
// 出力ドキュメントの現在のページにページ番号をスタンプ
AddPageNumber(outDoc, outPage, font, currentPageNumber++);
// 出力ドキュメントにページを追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void AddPageNumber(Document outDoc, Page outPage, Font font, int pageNumber)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);
// テキストオブジェクトを作成
Text text = Text.Create(outDoc);
// 指定されたフォントでサイズと位置を指定してテキストジェネレータを作成
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
// ページ番号としてスタンプする文字列を生成
string stampText = string.Format("Page {0}", pageNumber);
// ページの下部にテキストを中央揃えするための位置を計算
Point position = new Point
{
X = (outPage.Size.Width / 2) - (textgenerator.GetWidth(stampText) / 2),
Y = 10
};
// 計算された位置を指定
textgenerator.MoveTo(position);
// ページ番号を追加
textgenerator.Show(stampText);
}
// 位置指定されたテキストを描画
generator.PaintText(text);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def add_page_number(out_doc, out_page, font, page_number):
"""Stamp the page number on the specified page."""
# コンテンツジェネレータを作成
with ContentGenerator(out_page.content, False) as generator:
# Create text objectテキストオブジェクトを作成
text = Text.create(out_doc)
# 指定されたフォントでサイズと位置を指定してテキストジェネレータを作成
with TextGenerator(text, font, 8, None) as text_generator:
# ページ番号としてスタンプする文字列を生成
stamp_text = f"Page {page_number}"
# ページの下部にテキストを中央揃えするための位置を計算
position = Point(
x=(out_page.size.width / 2) - (text_generator.get_width(stamp_text) / 2),
y=10
)
# 計算された位置を指定
text_generator.move_to(position)
# ページ番号を追加
text_generator.show(stamp_text)
# 位置指定されたテキストを描画
generator.paint_text(text)
# 入力PDFをオープン
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを作成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# コピーオプションを定義
page_copy_options = PageCopyOptions()
# 出力PDFに埋め込みフォントを作成
font = Font.create_from_system(out_doc, "Arial", None, True)
# 入力PDFの全ページをコピー
for page_number, in_page in enumerate(in_doc.pages, start=1):
# 入力PDFから出力PDFにページをコピー
out_page = Page.copy(out_doc, in_page, page_copy_options)
# 出力ドキュメントの現在のページにページ番号をスタンプ
add_page_number(out_doc, out_page, font, page_number)
# 出力ドキュメントにページを追加
out_doc.pages.append(out_page)
入力PDFの文字列を出力PDFにコピーする際に、先頭2文字を削除してから出力PDFに格納します。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 各ページを処理
foreach (var inPage in inDoc.Pages)
{
// 空の出力ページを作成
Page outPage = Page.Create(outDoc, inPage.Size);
// 入力から出力にページコンテンツをコピーし、グリフを削除
CopyContentAndRemoveGlyphs(inPage.Content, outPage.Content, outDoc);
// 新しいページを出力ドキュメントのページリストに追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContentAndRemoveGlyphs(Content inContent, Content outContent, Document outDoc)
{
// コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// すべてのコンテンツ要素を反復処理
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// グループ要素の特別な処理
if (inElement is GroupElement inGroupElement)
{
// 空の出力グループ要素を作成
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// グループ要素のコンテンツに対してCopyContentAndRemoveGlyphs()を再帰的にコール
CopyContentAndRemoveGlyphs(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc);
}
else
{
// コンテンツ要素を出力ファイルにコピー
outElement = ContentElement.Copy(outDoc, inElement);
if (outElement is TextElement outTextElement)
{
// テキスト要素の特別な処理
Text text = outTextElement.Text;
// 各テキストフラグメントから最初の2つのグリフを削除
foreach (var fragment in text)
{
// フラグメントに2つ以上のグリフがあることを確認
if (fragment.Count > 2)
{
// RemoveAtを2回コール
fragment.RemoveAt(0);
fragment.RemoveAt(0);
}
}
}
}
// 完成した出力要素をコンテンツジェネレーターに追加
generator.AppendContentElement(outElement);
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_content_and_remove_glyphs(in_content: Content, out_content: Content, out_doc: Document):
"""Process content to remove the first two glyphs from text fragments."""
# コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# すべてのコンテンツ要素を反復処理
for in_element in extractor:
# グループ要素の特別な処理
if isinstance(in_element, GroupElement):
# 空の出力グループ要素を作成
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
copy_content_and_remove_glyphs(in_element.group.content, out_group_element.group.content, out_doc)
else:
# コンテンツ要素を出力ファイルにコピー
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement):
# テキスト要素の特別な処理
text = out_element.text
# 各テキストフラグメントから最初の2つのグリフを削除
for fragment in text:
# フラグメントに2つ以上のグリフがあることを確認
if len(fragment) > 2:
# RemoveAtを2回コール
fragment.remove(0)
fragment.remove(0)
# 完成した出力要素をコンテンツジェネレーターに追加
generator.append_content_element(out_element)
# 入力PDFを開き、出力ファイルを生成
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力ファイルを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 各ページを処理
for in_page in in_doc.pages:
# 空の出力ページを作成
out_page = Page.create(out_doc, in_page.size)
# 入力から出力にページコンテンツをコピーし、グリフを削除
copy_content_and_remove_glyphs(in_page.content, out_page.content, out_doc)
# 新しいページを出力ドキュメントのページリストに追加
out_doc.pages.append(out_page)
PDFの全ページからホワイトテキストを削除します。
リンク、注釈、フォームフィールド、アウトライン、論理構造、埋め込みファイルは破棄されます。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 各ページを処理
foreach (var inPage in inDoc.Pages)
{
// 空の出力ページを作成
Page outPage = Page.Create(outDoc, inPage.Size);
// 入力から出力にページコンテンツをコピー
CopyContent(inPage.Content, outPage.Content, outDoc);
// 新しいページを出力ドキュメントのページリストに追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContent(Content inContent, Content outContent, Document outDoc)
{
// コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// すべてのコンテンツ要素を反復処理
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// グループ要素の特別な処理
if (inElement is GroupElement inGroupElement)
{
// 空の出力グループ要素を作成
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// グループ要素のコンテンツに対してCopyContent()を再帰的にコール
CopyContent(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc);
}
else
{
// コンテンツ要素を出力ファイルにコピー
outElement = ContentElement.Copy(outDoc, inElement);
if (outElement is TextElement outTextElement)
{
// テキスト要素の特別な処理
Text text = outTextElement.Text;
// 塗りつぶしとストロークのペイントが白であるテキストフラグメントをすべて削除
for (int iFragment = text.Count - 1; iFragment >= 0; iFragment--)
{
TextFragment fragment = text[iFragment];
if ((fragment.Fill == null || IsWhite(fragment.Fill.Paint)) &&
(fragment.Stroke == null || IsWhite(fragment.Stroke.Paint)))
text.RemoveAt(iFragment);
}
// 空のテキスト要素の追加を防ぐ
if (text.Count == 0)
outElement = null;
}
}
// 完成した出力要素をコンテンツジェネレーターに追加
if (outElement != null)
generator.AppendContentElement(outElement);
}
}
private static bool IsWhite(Paint paint)
{
ColorSpace colorSpace = paint.ColorSpace;
if (colorSpace is DeviceGrayColorSpace || colorSpace is CalibratedGrayColorSpace ||
colorSpace is DeviceRgbColorSpace || colorSpace is CalibratedRgbColorSpace)
{
// これらの色空間は加法性があり、白は1.0です
return paint.Color.Min() == 1.0;
}
if (colorSpace is DeviceCmykColorSpace)
{
// この色空間は減法混色で、白は0.0です
return paint.Color.Max() == 0.0;
}
return false;
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def is_white(paint: Paint) -> bool:
"""Determine if a paint is white based on its color space."""
color_space = paint.color_space
color = paint.color
if isinstance(color_space, (DeviceGrayColorSpace, CalibratedGrayColorSpace, DeviceRgbColorSpace, CalibratedRgbColorSpace)):
# これらの色空間は加法性があり、白は1.0です
return min(color) == 1.0
if isinstance(color_space, DeviceCmykColorSpace):
# この色空間は減法混色で、白は0.0です
return max(color) == 0.0
return False
def copy_content_and_remove_white_text(in_content: Content, out_content: Content, out_doc: Document):
"""Process content to remove white text fragments."""
# コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# すべてのコンテンツ要素を反復処理
for in_element in extractor:
# グループ要素の特別な処理
if isinstance(in_element, GroupElement):
# 空の出力グループ要素を作成
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
copy_content_and_remove_white_text(in_element.group.content, out_group_element.group.content, out_doc)
else:
# コンテンツ要素を出力ファイルにコピー
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement):
text = out_element.text
# 塗りつぶしとストロークのペイントが白であるテキストフラグメントをすべて削除
for i_fragment in range(len(text) - 1, -1, -1):
fragment = text[i_fragment]
if ((fragment.fill is None or is_white(fragment.fill.paint)) and
(fragment.stroke is None or is_white(fragment.stroke.paint))):
text.remove(i_fragment)
# 空のテキスト要素の追加を防ぐ
if len(text) == 0:
out_element = None
# 完成した出力要素をコンテンツジェネレーターに追加
if out_element:
generator.append_content_element(out_element)
# 入力PDFを開き、出力ファイルを生成
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力ファイルを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 各ページを処理
for in_page in in_doc.pages:
# 空の出力ページを作成
out_page = Page.create(out_doc, in_page.size)
# 入力から出力にページコンテンツをコピーし、白いテキストを削除
copy_content_and_remove_white_text(in_page.content, out_page.content, out_doc)
# 新しいページを出力ドキュメントのページリストに追加
out_doc.pages.append(out_page)
PDF全ページのすべてのテキストフラグメントを指定されたテキストで検索し、最初に一致したフラグメントを置き換えます。
リンク、注釈、フォームフィールド、アウトライン、論理構造は置換されません。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 各ページを処理
foreach (var inPage in inDoc.Pages)
{
// 空の出力ページを作成
Page outPage = Page.Create(outDoc, inPage.Size);
// 入力PDFから出力PDFにページコンテンツをコピーし、文字列を検索
CopyContent(inPage.Content, outPage.Content, outDoc, searchString);
// テキストが見つかり削除された場合は、置換テキストを追加
if (fragment != null)
AddText(outDoc, outPage, replString);
// 新しいページを出力PDFのページリストに追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CopyContent(Content inContent, Content outContent, Document outDoc, string searchString)
{
// コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
ContentExtractor extractor = new ContentExtractor(inContent);
using ContentGenerator generator = new ContentGenerator(outContent, false);
// すべてのコンテンツ要素を反復処理
foreach (ContentElement inElement in extractor)
{
ContentElement outElement;
// グループ要素の特別な処理
if (inElement is GroupElement inGroupElement)
{
// 空の出力グループ要素を作成
GroupElement outGroupElement = GroupElement.CopyWithoutContent(outDoc, inGroupElement);
outElement = outGroupElement;
// 後で復元するために変換を保存
AffineTransform currentTransform = overallTransform;
// 変換を更新
overallTransform.Concatenate(inGroupElement.Transform);
// CopyContent()をグループ要素のコンテンツに対して再帰的にコール
CopyContent(inGroupElement.Group.Content, outGroupElement.Group.Content, outDoc, searchString);
// 保存した変換を元に戻す
overallTransform = currentTransform;
}
else
{
// コンテンツ要素を出力ファイルにコピー
outElement = ContentElement.Copy(outDoc, inElement);
if (fragment == null && outElement is TextElement outTextElement)
{
// テキスト要素の特別な処理
Text text = outTextElement.Text;
// 置換する文字列を含むテキストフラグメントを検索
for (int iFragment = text.Count - 1; iFragment >= 0; iFragment--)
{
// このサンプルでは、フラグメントテキストは完全に一致する必要があります
if (text[iFragment].Text == searchString)
{
// 見つかったフラグメントを後で使用するために保管
fragment = text[iFragment];
// 変換を更新
overallTransform.Concatenate(fragment.Transform);
// 見つかったテキストフラグメントを出力から削除
text.RemoveAt(iFragment);
break;
}
}
// 空のテキスト要素の追加を防ぐ
if (text.Count == 0)
outElement = null;
}
}
// 完成した出力要素をコンテンツジェネレーターに追加
if (outElement != null)
generator.AppendContentElement(outElement);
}
}
private static void AddText(Document doc, Page page, string replString)
{
// テキストオブジェクトを作成
Text text = Text.Create(doc);
// 抽出したフォントベース名をフォント名とフォントファミリーを探し出しマップする
string[] parts = fragment.Font.BaseFont.Split('-');
string family = parts[0];
string style = parts.Length > 1 ? parts[1] : null;
// フォントオブジェクトを作成
Font font = Font.CreateFromSystem(doc, family, style, true);
// テキストジェネレータを作成し、元のフラグメントのプロパティを設定
using (TextGenerator textGenerator = new TextGenerator(text, font, fragment.FontSize, null))
{
textGenerator.CharacterSpacing = fragment.CharacterSpacing;
textGenerator.WordSpacing = fragment.WordSpacing;
textGenerator.HorizontalScaling = fragment.HorizontalScaling;
textGenerator.Rise = fragment.Rise;
textGenerator.Show(replString);
}
// コンテンツジェネレータを作成
using ContentGenerator contentGenerator = new ContentGenerator(page.Content, false);
// 計算された変換を適用
contentGenerator.Transform(overallTransform);
// 新たなテキストを描画
contentGenerator.PaintText(text);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def copy_content_and_remove_text(in_content: Content, out_content: Content, out_doc: Document, search_text: str):
"""Process content to find and remove a specific text fragment."""
global overall_transform, fragment
# コンテンツ抽出ツールとコンテンツジェネレータを使用してコンテンツをコピー
extractor = ContentExtractor(in_content)
with ContentGenerator(out_content, False) as generator:
# すべてのコンテンツ要素を反復処理
for in_element in extractor:
# グループ要素の特別な処理
if isinstance(in_element, GroupElement):
out_group_element = GroupElement.copy_without_content(out_doc, in_element)
out_element = out_group_element
# 後で復元するために変換を保存
current_transform = overall_transform
# 変換を更新
copy_content_and_remove_text(in_element.group.content, out_group_element.group.content, out_doc, search_text)
# 保存した変換を元に戻す
overall_transform = current_transform
else:
# コンテンツ要素を出力ファイルにコピー
out_element = ContentElement.copy(out_doc, in_element)
if isinstance(out_element, TextElement) and fragment is None:
# テキスト要素の特別な処理
text = out_element.text
# 置換する文字列を含むテキストフラグメントを検索
for index_fragment in range(len(text) - 1, -1, -1):
# このサンプルでは、フラグメントテキストは完全に一致する必要があります(テキストにヌル文字が含まれている可能性があります)
if text[index_fragment].text.replace("\x00", "") == search_text:
# 見つかったフラグメントを後で使用するために保管
fragment = text[index_fragment]
# 変換を更新
overall_transform.concatenate(fragment.transform)
# 見つかったテキストフラグメントを出力から削除
text.remove(index_fragment)
# 空のテキスト要素の追加を防ぐ
if len(text) == 0:
out_element = None
# 完成した出力要素をコンテンツジェネレーターに追加
if out_element:
generator.append_content_element(out_element)
def add_text(out_doc: Document, page, replacement_text):
"""Add the replacement text at the location of the removed fragment."""
# テキストオブジェクトを作成
text = Text.create(out_doc)
# 抽出したフォントベース名をフォント名とフォントファミリーを探し出しマップする
font_parts = fragment.font.base_font.split("-")
font_family = font_parts[0]
font_style = font_parts[1] if len(font_parts) > 1 else None
# フォントオブジェクトを作成
font = Font.create_from_system(out_doc, font_family, font_style, True)
# テキストジェネレータを作成し、元のフラグメントのプロパティを設定
with TextGenerator(text, font, fragment.font_size, None) as text_gen:
text_gen.character_spacing = fragment.character_spacing
text_gen.word_spacing = fragment.word_spacing
text_gen.horizontal_scaling = fragment.horizontal_scaling
text_gen.rise = fragment.rise
text_gen.show(replacement_text)
# コンテンツジェネレータを作成
with ContentGenerator(page.content, False) as content_gen:
# 計算された変換を適用
content_gen.transform(overall_transform)
# 新たなテキストを描画
content_gen.paint_text(text)
# グローバル変数宣言
overall_transform = AffineTransform.get_identity()
fragment = None
search_string = "Muster Company AG"
replacement_string = "Replacement String"
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# 各ページを処理
for in_page in in_doc.pages:
# 空の出力ページを作成
out_page = Page.create(out_doc, in_page.size)
# 入力PDFから出力PDFにページコンテンツをコピーし、文字列を検索
copy_content_and_remove_text(in_page.content, out_page.content, out_doc, search_string)
# テキストが見つかり削除された場合は、置換テキストを追加
if fragment:
add_text(out_doc, out_page, replacement_string)
# 新しいページを出力PDFのページリストに追加
out_doc.pages.append(out_page)
PDFの作成者、タイトル、作成者などのメタデータを設定します。
他の手順として、別のPDFドキュメントのメタデータやXMPファイルのコンテンツを使用することもできます。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// メタデータ処理
if (args.Length == 3)
{
Metadata mdata;
// 入力ファイルからメタデータ読み出して追加
using FileStream metaStream = File.OpenRead(mdatafile);
if (mdatafile.EndsWith(".pdf"))
{
// 別のPDFファイルのメタデータを使用
using Document metaDoc = Document.Open(metaStream, "");
mdata = Metadata.Copy(outDoc, metaDoc.Metadata);
}
else
{
// XMPメタデータファイルの内容を使用
mdata = Metadata.Create(outDoc, metaStream);
}
outDoc.Metadata = mdata;
}
else
{
// メタデータプロパティを設定
Metadata metadata = outDoc.Metadata;
metadata.Author = "Your Author";
metadata.Title = "Your Title";
metadata.Subject = "Your Subject";
metadata.Creator = "Your Creator";
}
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー (メタデータを除く)
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 全てのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーされたページを出力ファイルに追加
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (argc == 4)
{
// 入力ファイルからメタデータ読み出して追加
pMdataStream = _tfopen(szMdatafile, _T("rb"));
GOTO_CLEANUP_IF_NULL(pMdataStream, _T("Failed to open metadata file \"%s\".\n"), szMdatafile);
PtxSysCreateFILEStreamDescriptor(&mdataDescriptor, pMdataStream, 0);
// ファイル拡張子を取得
TCHAR* szExt = _tcsrchr(szMdatafile, '.');
_tcscpy(szExtension, szExt);
if (_tcscmp(szExtension, _T(".pdf")) == 0)
{
// 別のPDFファイルのメタデータを使用
TPtxPdf_Document* pMetaDoc = PtxPdf_Document_Open(&mdataDescriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetaDoc, _T("Failed to open metadata file. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
TPtxPdf_Metadata* pMetadata = PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pMetaDoc));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to copy metadata. %s (ErrorCode: 0x%08x)."),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetMetadata(pOutDoc, pMetadata),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}
else
{
// XMPメタデータファイルの内容を使用
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Create(pOutDoc, &mdataDescriptor)),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
}
else
{
// メタデータのプロパティを設定
TPtxPdf_Metadata* pMetadata = PtxPdf_Document_GetMetadata(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to get metadata. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetAuthor(pMetadata, _T("Your Author")),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetTitle(pMetadata, _T("Your Title")),
_T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetSubject(pMetadata, _T("Your Subject")),
_T("%s(ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Metadata_SetCreator(pMetadata, _T("Your Creator")),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// ドキュメント全体のデータをコピー (メタデータを除く)
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー (メタデータを除く)
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as content_pdf_stream:
with Document.open(content_pdf_stream, None) as content_pdf_document:
# 出力PDFを生成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, content_pdf_document.conformance, None) as output_document:
# ドキュメント全体のデータをコピー
copy_document_data(content_pdf_document, output_document)
# メタデータ処理
if metadata_file_path is not None:
with io.FileIO(metadata_file_path, 'rb') as metadata_stream:
if metadata_file_path.endswith(".pdf"):
# 別のPDFファイルからメタデータ読み出して追加
with Document.open(metadata_stream, "") as meta_doc:
mdata = Metadata.copy(output_document, meta_doc.metadata)
else:
# XMPメタデータファイルの内容を使用
mdata = Metadata.create(output_document, metadata_stream)
else:
mdata = output_document.metadata
mdata.author = "Your Author"
mdata.title = "Your Title"
mdata.subject = "Your Subject"
mdata.creator = "Your Creator"
output_document.metadata = mdata
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# すべてのページをコピーして出力ドキュメントに追加
copied_pages = PageList.copy(output_document, content_pdf_document.pages, copy_options)
output_document.pages.extend(copied_pages)
PDF文書をユーザーパスワードとオーナーパスワードで暗号化します。
暗号化したPDF文書を開く際にはユーザーパスワードまたはオーナーパスワードのいずれかのパスワードを入力する必要があります。
ユーザーパスワードで復号した場合は文書の表示と印刷のみが可能になります。オーナーパスワードで復号した場合は文書へのフルアクセスが許可されます。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
pEncryption =
PtxPdf_Encryption_New(szUserPwd, szOwnerPwd, ePtxPdf_Permission_Print | ePtxPdf_Permission_DigitalPrint);
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, pEncryption);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// すべてのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーしたページを出力に追加
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 暗号化パラメータを作成
Encryption encryptionParams = new Encryption(UserPwd, OwnerPwd, Permission.Print |
Permission.DigitalPrint);
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力ドキュメントを作成し、ユーザーと所有者のパスワードを設定
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, encryptionParams))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// コピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 暗号化パラメータを作成
encryption_params = Encryption(
user_pwd,
owner_pwd,
Permission.PRINT | Permission.DIGITAL_PRINT,
)
# 出力ドキュメントを作成し、ユーザーと所有者のパスワードを設定
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, encryption_params) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# コピーオプションを定義
copy_options = PageCopyOptions()
# すべてのページをコピーして出力ドキュメントに追加
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
フォーム フィールドの外観をフラット化し、すべてのインタラクティブな要素を破棄します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーオプションの設定: フォームフィールドのフラット化を有効にする
pCopyOptions = PtxPdf_PageCopyOptions_New();
PtxPdf_PageCopyOptions_SetFormFields(pCopyOptions, ePtxPdfForms_FormFieldCopyStrategy_Flatten);
// 全てのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// コピーしたページを出力ファイルに追加
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// フォームフィールドのフラット化を含むコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
copyOptions.FormFields = FormFieldCopyStrategy.Flatten;
// すべてのページをコピーして、出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# フォームフィールドのフラット化オプションを設定
copy_options = PageCopyOptions()
copy_options.form_fields = FormFieldCopyStrategy.FLATTEN
# フラット化オプションを使用してすべてのページをコピー
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
複数の PDF ドキュメントを 1 つに結合し、目次ページを作成します。
// 出力フィルを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// 出力ドキュメントに埋め込みフォントを作成
Font font = Font.CreateFromSystem(outDoc, "Arial", string.Empty, true);
// ページのコピーオプションを定義
PageCopyOptions pageCopyOptions = new PageCopyOptions();
var copiedPageLists = new List<Tuple<string, PageList>>(inPaths.Length);
// ページ番号のカウンター
int pageNumber = 2;
// すべての入力文書ページをコピー
foreach (string inPath in inPaths)
{
// 入力PDFファイルを開く
using Stream inFs = new FileStream(inPath, FileMode.Open, FileAccess.Read);
using Document inDoc = Document.Open(inFs, null);
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, pageCopyOptions);
// コピーしたページにページ番号を追加
foreach (var copiedPage in copiedPages)
{
AddPageNumber(outDoc, copiedPage, font, pageNumber++);
}
// アウトライン項目を作成
string title = inDoc.Metadata.Title ?? System.IO.Path.GetFileNameWithoutExtension(inPath);
copiedPageLists.Add(new Tuple<string, PageList>(title, copiedPages));
}
// 目次ページを作成
var contentsPage = CreateTableOfContents(outDoc, copiedPageLists);
AddPageNumber(outDoc, contentsPage, font, 1);
// 出力ドキュメントにページを追加
PageList outPages = outDoc.Pages;
outPages.Add(contentsPage);
foreach (var tuple in copiedPageLists)
{
outPages.AddRange(tuple.Item2);
}
private static void AddPageNumber(Document outDoc, Page copiedPage, Font font, int pageNumber)
{
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(copiedPage.Content, false);
// テキストオブジェクトを作成
Text text = Text.Create(outDoc);
// 指定されたフォントでサイズと位置を指定してテキストジェネレータを作成
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
// ページ番号としてスタンプする文字列を生成
string stampText = string.Format("Page {0}", pageNumber);
// ページの下部にテキストを中央揃えするための位置を計算
Point position = new Point
{
X = (copiedPage.Size.Width / 2) - (textgenerator.GetWidth(stampText) / 2),
Y = 10
};
// テキストの表示位置
textgenerator.MoveTo(position);
// ページ番号を追加
textgenerator.Show(stampText);
}
// 位置決めされたテキストを描画
generator.PaintText(text);
}
private static Page CreateTableOfContents(Document outDoc, List> copiedPageLists) { // コピーした最初のページと同じサイズの新しいページを作成 var page = Page.Create(outDoc, copiedPageLists[0].Item2[0].Size); // フォントを作成 var font = Font.CreateFromSystem(outDoc, "Arial", null, true); // レイアウト計算するためのパラメータ double border = 30; double textWidth = page.Size.Width - 2 * border; double chapterTitleSize = 24; double titleSize = 12; // 現在テキストの位置 var location = new Point() { X = border, Y = page.Size.Height - border - chapterTitleSize }; // 目次内での現在項目のページ番号 int pageNumber = 2; // 目次ページ用のコンテンツジェネレータを作成 using (var contentGenerator = new ContentGenerator(page.Content, false)) { // テキストオブジェクトを作成 var text = Text.Create(outDoc); // 目次を生成するためのテキストジェネレータを作成。 最初は章タイトルのフォントサイズを使用 using (var textGenerator = new TextGenerator(text, font, chapterTitleSize, location)) { // 章のタイトルを表示 textGenerator.ShowLine("Table of Contents"); // 垂直位置を進める location.Y -= 1.7 * chapterTitleSize; // 目次の項目のフォントサイズを選択 textGenerator.FontSize = titleSize; // コピーされたすべてのページ範囲を反復処理 foreach (var tuple in copiedPageLists) { // 現在エントリのタイトル文字列 string title = tuple.Item1; // このエントリに対応するページのページ番号文字列 string pageNumberString = string.Format("{0}", pageNumber); // ページ番号文字列の幅 double pageNumberWidth = textGenerator.GetWidth(pageNumberString); // エントリタイトルとページ番号の間に表示されるドットの数を計算 int numberOfDots = (int)Math.Floor((textWidth - textGenerator.GetWidth(title) - pageNumberWidth) / textGenerator.GetWidth(".")); // 現在の場所に移動し、エントリのタイトルとドットを表示 textGenerator.MoveTo(location); textGenerator.Show(title + new string('.', numberOfDots)); // ページ番号を表示 textGenerator.MoveTo(new Point() { X = page.Size.Width - border - pageNumberWidth, Y = location.Y }); textGenerator.Show(pageNumberString); // リンクの矩形を計算 var linkRectangle = new Rectangle() { Left = border, Bottom = location.Y + font.Descent * titleSize, Right = border + textWidth, Top = location.Y + font.Ascent * titleSize }; // 現在のページ範囲の最初のページへの宛先を作成し、この移動先へのリンクを作成 var pageList = tuple.Item2; var targetPage = pageList[0]; var destination = LocationZoomDestination.Create(outDoc, targetPage, 0, targetPage.Size.Height, null); var link = InternalLink.Create(outDoc, linkRectangle, destination); // 目次ページにリンクを追加 page.Links.Add(link); // 次のエントリの位置へ進める location.Y -= 1.8 * titleSize; pageNumber += pageList.Count; } } // 生成された文字列をペイント contentGenerator.PaintText(text); } // 完成した目次ページを戻す return page; }
def add_page_number(out_doc: Document, page: Page, font: Font, page_number: int):
"""Add a page number to the bottom center of a page."""
# Create content generator
with ContentGenerator(page.content, False) as generator:
# コンテンツジェネレータを作成
text = Text.create(out_doc)
# 指定されたフォントでサイズと位置を指定してテキストジェネレータを作成
with TextGenerator(text, font, 8, None) as text_generator:
# ページ番号としてスタンプする文字列を生成
stamp_text = f"Page {page_number}"
# ページの下部にテキストを中央揃えするための位置を計算
position = Point(
x=(page.size.width / 2) - (text_generator.get_width(stamp_text) / 2),
y=10,
)
# テキストの表示位置
text_generator.move_to(position)
# ページ番号を追加
text_generator.show(stamp_text)
# 位置決めされたテキストを描画
generator.paint_text(text)
def create_table_of_contents(out_doc: Document, toc_entries: tuple, font: Font):
"""Create a table of contents (TOC) page."""
# コピーした最初のページと同じサイズの新しいページを作成
page = Page.create(out_doc, toc_entries[0][1][0].size)
# レイアウト計算するためのパラメータ
border = 30
text_width = page.size.width - 2 * border
chapter_title_size = 24
title_size = 12
# 現在テキストの位置
location = Point(x=border, y=page.size.height - border - chapter_title_size)
# 目次内での現在項目のページ番号
page_number = 2
# 目次を生成するためのテキストジェネレータを作成
with ContentGenerator(page.content, False) as content_generator:
# Create a text object
text = Text.create(out_doc)
# 目次を生成するためのテキストジェネレータを作成。 最初は章タイトルのフォントサイズを使用
with TextGenerator(text, font, chapter_title_size, location) as text_gen:
# 章のタイトルを表示
text_gen.show_line("Table of Contents")
# 垂直位置を進める
location.y -= 1.7 * chapter_title_size
# 目次の項目のフォントサイズを選択
text_gen.font_size = title_size
# コピーされたすべてのページ範囲を反復処理
for title, page_list in toc_entries:
# 現在エントリのタイトル文字列
title_text = title
# このエントリに対応するページのページ番号文字列
page_number_text = f"{page_number}"
# ページ番号文字列の幅
page_number_width = text_gen.get_width(page_number_text)
# エントリタイトルとページ番号の間に表示されるドットの数を計算
filler_dots_count = int(
(text_width - text_gen.get_width(title_text) - page_number_width)
/ text_gen.get_width(".")
)
# 現在の場所に移動し、エントリのタイトルとドットを表示
text_gen.move_to(location)
text_gen.show(title_text + "." * filler_dots_count)
# ページ番号を表示
text_gen.move_to(Point(x=page.size.width - border - page_number_width, y=location.y))
text_gen.show(page_number_text)
# リンクの矩形を計算
link_rectangle = Rectangle(
left=border,
bottom=location.y + font.descent * title_size,
right=border + text_width,
top=location.y + font.ascent * title_size,
)
# 現在のページ範囲の最初のページへのリンク先を作成し、この移動先へのリンクを作成
target_page = page_list[0]
destination = LocationZoomDestination.create(out_doc, target_page, 0, target_page.size.height, None)
link = InternalLink.create(out_doc, link_rectangle, destination)
# 目次ページにリンクを追加
page.links.append(link)
# 次のエントリの位置へ進める
location.y -= 1.8 * title_size
page_number += len(page_list)
# 生成された文字列をペイント
content_generator.paint_text(text)
return page
# 出力フィルを作成
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
# 出力ドキュメントに埋め込みフォントを作成
font = Font.create_from_system(out_doc, "Arial", None, True)
# ページのコピーオプションを定義
page_copy_options = PageCopyOptions()
# 目次に追加されるコピーされたページのリスト
toc_entries = []
# ページ番号のカウンター
page_number = 2
# すべての入力文書ページをコピー
for input_path in input_paths:
# 入力PDFファイルを開く
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# すべてのページをコピーして出力ドキュメントに追加
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
for copied_page in copied_pages:
add_page_number(out_doc, copied_page, font, page_number)
page_number += 1
# アウトライン項目を作成
title = in_doc.metadata.title or os.path.splitext(os.path.basename(input_path))[0]
toc_entries.append((title, copied_pages))
# 目次ページを作成
contents_page = create_table_of_contents(out_doc, toc_entries, font)
add_page_number(out_doc, contents_page, font, 1)
# 出力ドキュメントにページを追加
out_doc.pages.append(contents_page)
for _, pages in toc_entries:
out_doc.pages.extend(pages)
複数の PDF ドキュメントを 1 つに結合します。
// 出力フィルを作成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, NULL, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ページのコピーオプション設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 出力ページリストを取得
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 入力文書を結合
for (int i = 1; i < argc - 1; i++)
{
// 入力ファイルを開く
pInStream = _tfopen(szInPath[i], _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath[i]);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath[i], szErrorBuff, Ptx_GetLastError());
// ページのコピーオプション設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// すべてのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// コピーしたページを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add page range. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInPageList);
pInPageList = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_Close(pInDoc),
_T("Failed to close input document. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
pInDoc = NULL;
fclose(pInStream);
pInStream = NULL;
Ptx_Release(pCopiedPages);
pCopiedPages = NULL;
}
// 出力フィルを作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// ページのコピーオプションの定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 出力ページを取得
PageList outPages = outDoc.Pages;
// 入力文書を結合
for (int i = 0; i < args.Length - 1; i++)
{
// 入力ファイルを開く
using Stream inFs = new FileStream(inPath[i], FileMode.Open, FileAccess.Read);
using Document inDoc = Document.Open(inFs, null);
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
outPages.AddRange(copiedPages);
}
}
# 出力フィルを作成
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
# ページのコピーオプションの定義
page_copy_options = PageCopyOptions()
# 出力ページを取得
out_pages = out_doc.pages
# 入力文書を結合
for input_path in input_paths:
# 入力ファイルを開く
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# すべてのページをコピーして出力ドキュメントに追加
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_pages.extend(copied_pages)
複数のPDF文書を1つに結合し、入力ドキュメントごとにアウトライン項目を作成します。
// 出力ファイル作成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, null, null))
{
// コピーオプションを定義、アウトライン(Outline)を除く
PageCopyOptions pageCopyOptions = new PageCopyOptions
{
CopyOutlineItems = false
};
// アウトライン(Outline)のコピーオプションを定義
OutlineCopyOptions outlineCopyOptions = new OutlineCopyOptions();
// 出力ページを取得
PageList outPages = outDoc.Pages;
// 入力文書を結合
foreach (string inPath in inPaths)
{
// 入力ドキュメントを開く
using Stream inFs = new FileStream(inPath, FileMode.Open, FileAccess.Read);
using Document inDoc = Document.Open(inFs, null);
// すべてのページをコピーして出力ドキュメントに追加
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, pageCopyOptions);
outPages.AddRange(copiedPages);
// アウトライン(Outline)要素を作成
string title = inDoc.Metadata.Title ?? Path.GetFileName(inPath);
Page firstCopiedPage = copiedPages[0];
Destination destination = LocationZoomDestination.Create(outDoc, firstCopiedPage, 0, firstCopiedPage.Size.Height, null);
OutlineItem outlineItem = OutlineItem.Create(outDoc, title, destination);
outDoc.Outline.Add(outlineItem);
// 入力ドキュメントからアウトライン項目を子として追加
OutlineItemList children = outlineItem.Children;
foreach (OutlineItem inputOutline in inDoc.Outline)
children.Add(OutlineItem.Copy(outDoc, inputOutline, outlineCopyOptions));
}
}
# 出力ファイル作成
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, None, None) as out_doc:
# コピーオプションを定義
page_copy_options = PageCopyOptions()
page_copy_options.copy_outline_items = False
# アウトライン(Outline)のコピーオプションを定義
outline_copy_options = OutlineCopyOptions()
# 出力ページを取得
out_pages = out_doc.pages
# 入力文書を結合
for input_path in input_paths:
# 入力ドキュメントを開く
with open(input_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# すべてのページをコピーして出力ドキュメントに追加
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
out_pages.extend(copied_pages)
# アウトライン(Outline)要素を作成
title = in_doc.metadata.title or os.path.basename(input_path)
first_copied_page = copied_pages[0]
destination = LocationZoomDestination.create(out_doc, first_copied_page, 0, first_copied_page.size.height, None)
outline_item = OutlineItem.create(out_doc, title, destination)
out_doc.outline.append(outline_item)
# 入力ドキュメントからアウトライン項目を子として追加
children = outline_item.children
for in_outline_item in in_doc.outline:
children.append(OutlineItem.copy(out_doc, in_outline_item, outline_copy_options))
PDF文書のすべてのページを指定された色でオーバーレイします。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 透明度を作成し、ブレンドモードを設定
Transparency transparency = new Transparency(colorAlpha)
{
BlendMode = BlendMode.Multiply
};
// 色空間を作成
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outDoc, colorType);
// 指定された色の透明なPaintを作成
Paint paint = Paint.Create(outDoc, colorSpace, color, transparency);
Fill fill = new Fill(paint);
// 出力ページを取得
PageList outPages = outDoc.Pages;
// ページコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// すべてのページをループ
foreach (Page inPage in inDoc.Pages)
{
// 新しいページを作成
Page outPage = Page.Copy(outDoc, inPage, copyOptions);
Size size = inPage.Size;
// コンテンツジェネレータを作成
using (ContentGenerator generator = new ContentGenerator(outPage.Content, false))
{
// ページと同じサイズの矩形パス(Path)を作成
PdfTools.Toolbox.Pdf.Content.Path path = new PdfTools.Toolbox.Pdf.Content.Path();
using (PathGenerator pathGenerator = new PathGenerator(path))
{
// 矩形を計算
Rectangle pathRect = new Rectangle
{
Left = 0,
Bottom = 0,
Right = size.Width,
Top = size.Height
};
pathGenerator.AddRectangle(pathRect);
}
// 透明なPaintでパス(Path)を塗る
generator.PaintPath(path, fill, null);
}
// 出力ドキュメントにページを追加
outPages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def parse_options(options: str) -> tuple:
"""
Parse the options string to extract color, color type, and alpha.
"""
# 規定値
color_type = ProcessColorSpaceType.GRAY
color = [0.9]
alpha = 1.0
if options is None:
return color, color_type, alpha
# 引数のオプションをトークンに分割
tokens = options.split()
if not tokens:
return color, color_type, alpha
# オプションを解析オプション
i = 0
while i lt; len(tokens):
arg = tokens[i]
if arg.startswith("-"):
if len(arg) != 2:
raise ValueError(f"Invalid option: {arg}")
flag = arg[1]
i += 1 # Move to the next token
if flag == "k": # Grayscale
if len(tokens) - i != 2:
raise ValueError("Invalid arguments for -k. Requires (k) (a).")
color_type = ProcessColorSpaceType.GRAY
color = [float(tokens[i])]
alpha = float(tokens[i + 1])
i += 2
elif flag == "c": # CMYK
if len(tokens) - i != 5:
raise ValueError("Invalid arguments for -c. Requires (c) (m) (y) (k) (a).")
color_type = ProcessColorSpaceType.CMYK
color = [float(tokens[i]), float(tokens[i + 1]), float(tokens[i + 2]), float(tokens[i + 3])]
alpha = float(tokens[i + 4])
i += 5
elif flag == "r": # RGB
if len(tokens) - i != 4:
raise ValueError("Invalid arguments for -r. Requires (r) (g) (b) (a).")
color_type = ProcessColorSpaceType.RGB
color = [float(tokens[i]), float(tokens[i + 1]), float(tokens[i + 2])]
alpha = float(tokens[i + 3])
i += 4
else:
raise ValueError(f"Unsupported option: {flag}")
else:
raise ValueError(f"Unexpected token: {arg}")
# 色とアルファ値を検証
if not (0 lt;= alpha lt;= 1 and all(0 lt;= c lt;= 1 for c in color)):
raise ValueError("Color and alpha values must be between 0 and 1.")
return color, color_type, alpha
def apply_overlay_to_pages(in_doc: Document, out_doc: Document, color: list, color_type: ProcessColorSpaceType, color_alpha: float):
"""Apply the overlay color to all pages in the document."""
# 透明度を作成し、ブレンドモードを設定
transparency = Transparency(color_alpha)
transparency.blend_mode = BlendMode.MULTIPLY
# 色空間を作成
color_space = ColorSpace.create_process_color_space(out_doc, color_type)
# 指定された色の透明なPaintを作成
paint = Paint.create(out_doc, color_space, color, transparency)
fill = Fill(paint)
# 出力ページを取得
out_pages = out_doc.pages
# ページコピーオプションを定義
copy_options = PageCopyOptions()
# すべてのページをループ
for in_page in in_doc.pages:
# 新しいページを作成
out_page = Page.copy(out_doc, in_page, copy_options)
in_page_size = in_page.size
# コンテンツジェネレータを作成
with ContentGenerator(out_page.content, False) as generator:
# ページと同じサイズの矩形パス(Path)を作成
path = Path()
with PathGenerator(path) as path_generator:
# 矩形を計算
path_rectangle = Rectangle(
left=0,
bottom=0,
right=in_page_size.width,
top=in_page_size.height,
)
path_generator.add_rectangle(path_rectangle)
# 透明OverlayのPaintでパス(Path)を塗る
generator.paint_path(path, fill, None)
out_pages.append(out_page)
# 色が指定された引数オプションを解析
color, color_type, color_alpha = parse_options(options)
# 入力を開いて出力ドキュメントを作成
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力ドキュメントを作成
with open(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# オーバーレイ(Overlay)を適用
apply_overlay_to_pages(in_doc, out_doc, color, color_type, color_alpha)
PDFからページを選択的に削除します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int nInPages = PtxPdf_PageList_GetCount(pInPageList);
iStartIndex = MAX(MIN(nInPages - 1, iStartIndex), 0);
nCount = MIN(nInPages - iStartIndex, nCount);
GOTO_CLEANUP_IF_FALSE(nCount > 0, _T("lastPage must be greater or equal to firstPage.\n"));
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ページのコピーオプションを定義
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 入力ページからページ範囲を取得
pInPageRange = PtxPdf_PageList_GetRange(pInPageList, iStartIndex, nCount);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange,
_T("Failed to get page range from input document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// ページ範囲を出力ドキュメントにコピー
pOutPageRange = PtxPdf_PageList_Copy(pOutDoc, pInPageRange, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageRange, _T("Failed to copy page range. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// 出力ページを取得
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get the pages of the output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// 出力ページにページ範囲を追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pOutPageRange),
_T("Failed to append page range. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
startIndex = Math.Max(Math.Min(inDoc.Pages.Count - 1, startIndex), 0);
count = Math.Min(inDoc.Pages.Count - startIndex, count);
if (count <= 0)
{
Console.WriteLine("lastPage must be greater or equal to firstPage");
return;
}
// 出力PDFを生成
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite);
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null);
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 入力ページからページ範囲を取得
PageList inPageRange = inDoc.Pages.GetRange(startIndex, count);
// ページ範囲を出力ドキュメントにコピー
PageList outPageRange = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(outPageRange);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
start_index = int(first_page) - 1
last_page = int(last_page)
count = last_page - start_index
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# ページ範囲を検証
start_index = max(min(len(in_doc.pages) - 1, start_index), 0)
count = min(len(in_doc.pages) - start_index, count)
if count <= 0:
raise ValueError("lastPage must be greater or equal to firstPage")
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページのコピーオプションを定義
page_copy_options = PageCopyOptions()
# 入力ページからページ範囲を取得
in_page_range = in_doc.pages[start_index:last_page]
# ページ範囲を出力ドキュメントにコピー
out_page_range = PageList.copy(out_doc, in_page_range, page_copy_options)
out_doc.pages.extend(out_page_range)
A3サイズのページに最大で2枚のA4ページを正しい順序で配置したPDFを作成します。
このPDFをA3ページの両面印刷して、折りたたむと小冊子になります。
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
// Objects that need releasing or closing
TPtxPdfContent_IccBasedColorSpace* pInOutputIntent = NULL;
TPtxPdfContent_IccBasedColorSpace* pOutOutputIntent = NULL;
TPtxPdf_Metadata* pInMetadata = NULL;
TPtxPdf_Metadata* pOutMetadata = NULL;
TPtxPdfNav_ViewerSettings* pInViewerSettings = NULL;
TPtxPdfNav_ViewerSettings* pOutViewerSettings = NULL;
TPtxPdf_FileReferenceList* pInFileRefList = NULL;
TPtxPdf_FileReferenceList* pOutFileRefList = NULL;
TPtxPdf_FileReference* pInFileRef = NULL;
TPtxPdf_FileReference* pOutFileRef = NULL;
iReturnValue = 0;
// Output intent
pInOutputIntent = PtxPdf_Document_GetOutputIntent(pInDoc);
if (pInOutputIntent != NULL)
{
pOutOutputIntent = PtxPdfContent_IccBasedColorSpace_Copy(pOutDoc, pInOutputIntent);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutOutputIntent,
_T("Failed to copy ICC-based color space. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetOutputIntent(pOutDoc, pOutOutputIntent),
_T("Failed to set output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get output intent. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Metadata
pInMetadata = PtxPdf_Document_GetMetadata(pInDoc);
if (pInMetadata != NULL)
{
pOutMetadata = PtxPdf_Metadata_Copy(pOutDoc, pInMetadata);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutMetadata, _T("Failed to copy metadata. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetMetadata(pOutDoc, pOutMetadata),
_T("Failed to set metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get metadata. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Viewer settings
pInViewerSettings = PtxPdf_Document_GetViewerSettings(pInDoc);
if (pInViewerSettings != NULL)
{
pOutViewerSettings = PtxPdfNav_ViewerSettings_Copy(pOutDoc, pInViewerSettings);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutViewerSettings,
_T("Failed to copy viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Document_SetViewerSettings(pOutDoc, pOutViewerSettings),
_T("Failed to set viewer settings. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
}
else
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get viewer settings. %s (ErrorCode: 0x%08x)"), szErrorBuff,
Ptx_GetLastError());
// Associated files (for PDF/A-3 and PDF 2.0 only)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of input document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get associated files of output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
int nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of associated files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
Ptx_Release(pInFileRefList);
pInFileRefList = NULL;
Ptx_Release(pOutFileRefList);
pOutFileRefList = NULL;
// Plain embedded files
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of input document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pInFileRefList, _T("Failed to get plain embedded files of output document %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
nFileRefs = PtxPdf_FileReferenceList_GetCount(pInFileRefList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get count of plain embedded files. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
for (int iFileRef = 0; iFileRef < nFileRefs; iFileRef++)
{
pInFileRef = PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInFileRef, _T("Failed to get file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
pOutFileRef = PtxPdf_FileReference_Copy(pOutDoc, pInFileRef);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutFileRef, _T("Failed to copy file reference. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_FileReferenceList_Add(pOutFileRefList, pOutFileRef),
_T("Failed to add file reference. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
Ptx_Release(pInFileRef);
pInFileRef = NULL;
Ptx_Release(pOutFileRef);
pOutFileRef = NULL;
}
cleanup:
if (pInOutputIntent != NULL)
Ptx_Release(pInOutputIntent);
if (pOutOutputIntent != NULL)
Ptx_Release(pOutOutputIntent);
if (pInMetadata != NULL)
Ptx_Release(pInMetadata);
if (pOutMetadata != NULL)
Ptx_Release(pOutMetadata);
if (pInViewerSettings != NULL)
Ptx_Release(pInViewerSettings);
if (pOutViewerSettings != NULL)
Ptx_Release(pOutViewerSettings);
if (pInFileRefList != NULL)
Ptx_Release(pInFileRefList);
if (pOutFileRefList != NULL)
Ptx_Release(pOutFileRefList);
if (pInFileRef != NULL)
Ptx_Release(pInFileRef);
if (pOutFileRef != NULL)
Ptx_Release(pOutFileRef);
return iReturnValue;
}
int StampPageNumber(TPtxPdf_Document* pDocument, TPtxPdfContent_Font* pFont,
TPtxPdfContent_ContentGenerator* pGenerator, int nPageNo, BOOL bIsLeftPage)
{
// Objects that need releasing or closing
TPtxPdfContent_Text* pText = NULL;
TPtxPdfContent_TextGenerator* pTextGenerator = NULL;
// Create text object
pText = PtxPdfContent_Text_Create(pDocument);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pText, _T("Failed to create text object. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Create text generator
pTextGenerator = PtxPdfContent_TextGenerator_New(pText, pFont, 8.0, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pTextGenerator, _T("Failed to create text generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
TCHAR szStampText[50];
_stprintf(szStampText, _T("Page %d"), nPageNo);
// Get width of stamp text
double dStampWidth = PtxPdfContent_TextGenerator_GetWidth(pTextGenerator, szStampText);
if (dStampWidth == 0.0)
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get text width. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Compute position
TPtxGeomReal_Point point = {
.dX = bIsLeftPage ? dBorder + 0.5 * dCellWidth - dStampWidth / 2
: 2 * dBorder + 1.5 * dCellWidth - dStampWidth / 2,
.dY = dBorder,
};
// Move to position
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_MoveTo(pTextGenerator, &point),
_T("Failed to move to position. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Add page number
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_TextGenerator_Show(pTextGenerator, szStampText),
_T("Failed to show text. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
BOOL bClose = PtxPdfContent_TextGenerator_Close(pTextGenerator);
pTextGenerator = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(bClose, _T("Failed to close text generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Paint the positioned text
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintText(pGenerator, pText),
_T("Failed to paint text. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
cleanup:
if (pText != NULL)
Ptx_Release(pText);
if (pTextGenerator != NULL)
PtxPdfContent_TextGenerator_Close(pTextGenerator);
return iReturnValue;
}
void ComputeTargetRect(TPtxGeomReal_Rectangle* pRectangle, const TPtxGeomReal_Size* pBBox, BOOL bIsLeftPage)
{
// Compute factor for fitting page into rectangle
double dScale = MIN(dCellWidth / pBBox->dWidth, dCellHeight / pBBox->dHeight);
double dGroupWidth = pBBox->dWidth * dScale;
double dGroupHeight = pBBox->dHeight * dScale;
// Compute x-value
double dGroupXPos =
bIsLeftPage ? dCellLeft + (dCellWidth - dGroupWidth) / 2 : dCellRight + (dCellWidth - dGroupWidth) / 2;
// Compute y-value
double dGroupYPos = dCellYPos + (dCellHeight - dGroupHeight) / 2;
// Set rectangle
pRectangle->dLeft = dGroupXPos;
pRectangle->dBottom = dGroupYPos;
pRectangle->dRight = dGroupXPos + dGroupWidth;
pRectangle->dTop = dGroupYPos + dGroupHeight;
}
int CreateBooklet(TPtxPdf_PageList* pInDocList, TPtxPdf_Document* pOutDoc, TPtxPdf_PageList* pOutDocList,
int nLeftPageIndex, int nRightPageIndex, TPtxPdfContent_Font* pFont)
{
// Objects that need releasing or closing
TPtxPdf_PageCopyOptions* pCopyOptions = NULL;
TPtxPdf_Page* pOutPage = NULL;
TPtxPdfContent_Content* pContent = NULL;
TPtxPdfContent_ContentGenerator* pGenerator = NULL;
TPtxPdf_Page* pInPage = NULL;
TPtxPdfContent_Group* pGroup = NULL;
// Configure copy options
pCopyOptions = PtxPdf_PageCopyOptions_New();
// Create page object
pOutPage = PtxPdf_Page_Create(pOutDoc, &pageSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to create page object. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Create content generator
pContent = PtxPdf_Page_GetContent(pOutPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator, _T("Failed to create content generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
int nPageCount = PtxPdf_PageList_GetCount(pInDocList);
GOTO_CLEANUP_IF_ERROR_PRINT_ERROR(_T("Failed to get page list count. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Left page
if (nLeftPageIndex lt; nPageCount)
{
// Get the input page
pInPage = PtxPdf_PageList_Get(pInDocList, nLeftPageIndex);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Copy page from input to output
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Compute group location
TPtxGeomReal_Size groupSize;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("Failed to get group size. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
TPtxGeomReal_Rectangle targetRect;
ComputeTargetRect(&targetRect, &groupSize, TRUE);
// Paint group at location
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint group. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());
// Add page number to page
if (StampPageNumber(pOutDoc, pFont, pGenerator, nLeftPageIndex + 1, TRUE) != 0)
goto cleanup;
Ptx_Release(pInPage);
pInPage = NULL;
Ptx_Release(pGroup);
pGroup = NULL;
}
// Right page
if (nRightPageIndex lt; nPageCount)
{
// Get the input Page
pInPage = PtxPdf_PageList_Get(pInDocList, nRightPageIndex);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("Failed to get page. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
// Copy page from input to output
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Compute group location
TPtxGeomReal_Size groupSize;
PtxPdfContent_Group_GetSize(pGroup, &groupSize);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("Failed to get group size. %s (ErrorCode: 0x%08x)\n"), szErrorBuff,
Ptx_GetLastError());
TPtxGeomReal_Rectangle targetRect;
ComputeTargetRect(&targetRect, &groupSize, FALSE);
// Paint group on the Computed rectangle
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint group. %s (ErrorCode: 0x%08x)\n"), szErrorBuff, Ptx_GetLastError());
// Add page number to page
if (StampPageNumber(pOutDoc, pFont, pGenerator, nRightPageIndex + 1, FALSE) != 0)
goto cleanup;
}
BOOL bClose = PtxPdfContent_ContentGenerator_Close(pGenerator);
pGenerator = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(bClose, _T("Failed to close content generator. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
// Add page to output document
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutDocList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x)\n"),
szErrorBuff, Ptx_GetLastError());
cleanup:
if (pGenerator != NULL)
PtxPdfContent_ContentGenerator_Close(pGenerator);
if (pCopyOptions != NULL)
Ptx_Release(pCopyOptions);
if (pOutPage != NULL)
Ptx_Release(pOutPage);
if (pContent != NULL)
Ptx_Release(pContent);
if (pInPage != NULL)
Ptx_Release(pInPage);
if (pGroup != NULL)
Ptx_Release(pGroup);
return iReturnValue;
}
// Open input document
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// Create output document
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// Copy document-wide data
CopyDocumentData(inDoc, outDoc);
// Create a font
Font font = Font.CreateFromSystem(outDoc, "Arial", "Italic", true);
// Copy pages
PageList inPages = inDoc.Pages;
PageList outPages = outDoc.Pages;
int numberOfSheets = (inPages.Count + 3) / 4;
for (int sheetNumber = 0; sheetNumber lt; numberOfSheets; ++sheetNumber)
{
// Add on front side
CreateBooklet(inPages, outDoc, outPages, 4 * numberOfSheets - 2 * sheetNumber - 1,
2 * sheetNumber, font);
// Add on back side
CreateBooklet(inPages, outDoc, outPages, 2 * sheetNumber + 1,
4 * numberOfSheets - 2 * sheetNumber - 2, font);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// Copy document-wide data
// Output intent
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// Metadata
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// Viewer settings
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// Associated files (for PDF/A-3 and PDF 2.0 only)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// Plain embedded files
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void CreateBooklet(PageList inPages, Document outDoc, PageList outPages, int leftPageIndex,
int rightPageIndex, Font font)
{
// Define page copy options
PageCopyOptions copyOptions = new PageCopyOptions();
// Create page object
Page outpage = Page.Create(outDoc, PageSize);
// Create content generator
using (ContentGenerator generator = new ContentGenerator(outpage.Content, false))
{
// Left page
if (leftPageIndex lt; inPages.Count)
{
// Copy page from input to output
Page leftPage = inPages[leftPageIndex];
Group leftGroup = Group.CopyFromPage(outDoc, leftPage, copyOptions);
// Paint group on the calculated rectangle
generator.PaintGroup(leftGroup, ComputTargetRect(leftGroup.Size, true), null);
// Add page number to page
StampPageNumber(outDoc, font, generator, leftPageIndex + 1, true);
}
// Right page
if (rightPageIndex lt; inPages.Count)
{
// Copy page from input to output
Page rigthPage = inPages[rightPageIndex];
Group rightGroup = Group.CopyFromPage(outDoc, rigthPage, copyOptions);
// Paint group on the calculated rectangle
generator.PaintGroup(rightGroup, ComputTargetRect(rightGroup.Size, false), null);
// Add page number to page
StampPageNumber(outDoc, font, generator, rightPageIndex + 1, false);
}
}
// Add page to output document
outPages.Add(outpage);
}
private static Rectangle ComputTargetRect(Size bbox, bool isLeftPage)
{
// Calculate factor for fitting page into rectangle
double scale = Math.Min(CellWidth / bbox.Width, CellHeight / bbox.Height);
double groupWidth = bbox.Width * scale;
double groupHeight = bbox.Height * scale;
// Calculate x-value
double groupXPos = isLeftPage ? CellLeft + (CellWidth - groupWidth) / 2 :
CellRight + (CellWidth - groupWidth) / 2;
// Calculate y-value
double groupYPos = CellYPos + (CellHeight - groupHeight) / 2;
// Calculate rectangle
return new Rectangle
{
Left = groupXPos,
Bottom = groupYPos,
Right = groupXPos + groupWidth,
Top = groupYPos + groupHeight
};
}
private static void StampPageNumber(Document document, Font font, ContentGenerator generator,
int PageNo, bool isLeftPage)
{
// Create text object
Text text = Text.Create(document);
// Create text generator
using (TextGenerator textgenerator = new TextGenerator(text, font, 8, null))
{
string stampText = string.Format("Page {0}", PageNo);
// Get width of stamp text
double width = textgenerator.GetWidth(stampText);
// Calculate position
double x = isLeftPage ? Border + 0.5 * CellWidth - width / 2 :
2 * Border + 1.5 * CellWidth - width / 2;
double y = Border;
// Move to position
textgenerator.MoveTo(new Point { X = x, Y = y});
// Add page number
textgenerator.Show(stampText);
}
// Paint the positioned text
generator.PaintText(text);
}
def copy_document_data(in_doc: Document, out_doc: Document):
# Copy document-wide data
# Output intent
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# Metadata
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# Viewer settings
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# Associated files (for PDF/A-3 and PDF 2.0 only)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# Plain embedded files
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def compute_target_rect(bbox: Size, is_left_page: bool) -> Rectangle:
# Calculate factor for fitting page into rectangle
scale = min(cell_width / bbox.width, cell_height / bbox.height)
group_width = bbox.width * scale
group_height = bbox.height * scale
# Calculate x-value
group_x_pos = cell_left + (cell_width - group_width) / 2 if is_left_page else cell_right + (cell_width - group_width) / 2
# Calculate y-value
group_y_pos = cell_y_pos + (cell_height - group_height) / 2
# Calculate rectangle
return Rectangle(
left=group_x_pos,
bottom=group_y_pos,
right=group_x_pos + group_width,
top=group_y_pos + group_height,
)
def stamp_page_number(document: Document, font: Font, generator: ContentGenerator, page_no: int, is_left_page: bool):
# Create text object
text = Text.create(document)
# Create text generator
with TextGenerator(text, font, 8.0, None) as text_generator:
stamp_text = f"Page {page_no}"
# Get width of stamp text
width = text_generator.get_width(stamp_text)
# Calculate position
x = border + 0.5 * cell_width - width / 2 if is_left_page else 2 * border + 1.5 * cell_width - width / 2
y = border
# Move to position
text_generator.move_to(Point(x=x, y=y))
# Add page number
text_generator.show(stamp_text)
# Paint the positioned text
generator.paint_text(text)
def create_booklet(in_pages: PageList, out_doc: Document, out_pages: PageList, left_page_index: int, right_page_index: int, font: Font):
# Define page copy options
copy_options = PageCopyOptions()
# Create page object
out_page = Page.create(out_doc, page_size)
# Create content generator
with ContentGenerator(out_page.content, False) as generator:
# Left page
if left_page_index lt; len(in_pages):
# Copy page from input to output
left_page = in_pages[left_page_index]
left_group = Group.copy_from_page(out_doc, left_page, copy_options)
# Paint group into target rectangle
generator.paint_group(left_group, compute_target_rect(left_group.size, True), None)
# Add page number to page
stamp_page_number(out_doc, font, generator, left_page_index + 1, True)
# Right page
if right_page_index lt; len(in_pages):
# Copy page from input to output
right_page = in_pages[right_page_index]
right_group = Group.copy_from_page(out_doc, right_page, copy_options)
# Paint group on the calculated rectangle
generator.paint_group(right_group, compute_target_rect(right_group.size, False), None)
# Add page number to page
stamp_page_number(out_doc, font, generator, right_page_index + 1, False)
# Add page to output document
out_pages.append(out_page)
# Define global variables
page_size = Size(1190.0, 842.0) # A3 portrait
border = 10.0
cell_width = (page_size.width - 3 * border) / 2
cell_height = page_size.height - 2 * border
cell_left = border
cell_right = 2 * border + cell_width
cell_y_pos = border
# Open input document
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# Create output document
with io.FileIO(output_file_path, "wb+") as output_stream:
with Document.create(output_stream, in_doc.conformance, None) as out_doc:
# Copy document-wide data
copy_document_data(in_doc, out_doc)
# Create a font
font = Font.create_from_system(out_doc, "Arial", "Italic", True)
# Copy pages
in_pages = in_doc.pages
out_pages = out_doc.pages
number_of_sheets = (len(in_pages) + 3) // 4
for sheet_number in range(number_of_sheets):
# Add front side
create_booklet(in_pages, out_doc, out_pages, 4 * number_of_sheets - 2 * sheet_number - 1, 2 * sheet_number, font)
# Add back side
create_booklet(in_pages, out_doc, out_pages, 2 * sheet_number + 1, 4 * number_of_sheets - 2 * sheet_number - 2, font)
PDFの各ページを指定されたのページ形式に適合させます。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ページのコピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 全てのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPage = 0; iPage < PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
TPtxGeomReal_Size pageSize;
TPtxGeomReal_Size rotatedSize;
BOOL bRotate;
pInPage = PtxPdf_PageList_Get(pInPageList, iPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPage, _T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
pOutPage = NULL;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_GetSize(pInPage, &pageSize), _T("%s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
bRotate = bAllowRotate && (pageSize.dHeight >= pageSize.dWidth) != (targetSize.dHeight >= targetSize.dWidth);
if (bRotate)
{
rotatedSize.dWidth = pageSize.dHeight;
rotatedSize.dHeight = pageSize.dHeight;
}
else
{
rotatedSize = pageSize;
}
if (rotatedSize.dWidth == targetSize.dWidth && rotatedSize.dHeight == targetSize.dWidth)
{
// サイズが正しい場合に、ページのみをコピー
pOutPage = PtxPdf_Page_Copy(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to copy pages from input to output. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (bRotate)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_Rotate(pOutPage, ePtxGeom_Rotation_Clockwise),
_T("Failed to rotate page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}
}
else
{
TPtxPdfContent_Group* pGroup = NULL;
TPtxPdfContent_Content* pContent = NULL;
TPtxGeomReal_AffineTransform transform;
TPtxGeomReal_Point position;
TPtxGeomReal_Point point;
// 正しいサイズの新しいページを作成し、既存のページをその上に収める
pOutPage = PtxPdf_Page_Create(pOutDoc, &targetSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to create a new page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// ページをグループとしてコピー
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGroup, _T("Failed to copy page as group. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// グループのスケーリングと位置を計算
double scale = MIN(targetSize.dWidth / rotatedSize.dWidth, targetSize.dHeight / rotatedSize.dHeight);
// 位置を計算
position.dX = (targetSize.dWidth - pageSize.dWidth * scale) / 2;
position.dY = (targetSize.dHeight - pageSize.dHeight * scale) / 2;
pContent = PtxPdf_Page_GetContent(pOutPage);
// コンテンツジェネレータを作成
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator,
_T("Failed to create a content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
// 変換を計算して適用
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_GetIdentity(&transform),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxGeomReal_AffineTransform_Translate(&transform, position.dX, position.dY),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_Scale(&transform, scale, scale),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
point.dX = pageSize.dWidth / 2.0;
point.dY = pageSize.dHeight / 2.0;
// 入力ファイルを回転
if (bRotate)
{
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxGeomReal_AffineTransform_Rotate(&transform, 90, &point),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
}
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_Transform(pGenerator, &transform),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
// Formを描画
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, NULL, NULL),
_T("Failed to paint the group. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
PtxPdfContent_ContentGenerator_Close(pGenerator);
pGenerator = NULL;
if (pGenerator != NULL)
Ptx_Release(pGenerator);
if (pGroup != NULL)
Ptx_Release(pGroup);
}
// 出力ドキュメントにページを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pOutPage != NULL)
{
Ptx_Release(pOutPage);
pOutPage = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページのコピーオプションを 定義
PageCopyOptions copyOptions = new PageCopyOptions();
// ページをコピー
foreach (Page inPage in inDoc.Pages)
{
Page outPage = null;
Size pageSize = inPage.Size;
bool rotate = AllowRotate &&
(pageSize.Height >= pageSize.Width) != (TargetSize.Height >= TargetSize.Width);
Size rotatedSize = pageSize;
if (rotate)
rotatedSize = new Size { Width = pageSize.Height, Height = pageSize.Width };
if (rotatedSize.Width == TargetSize.Width && rotatedSize.Height == TargetSize.Width)
{
// サイズが正しい場合に、ページのみをコピー
outPage = Page.Copy(outDoc, inPage, copyOptions);
if (rotate)
outPage.Rotate(Rotation.Clockwise);
}
else
{
// 正しいサイズの新しいページを作成し、既存のページをその上に収める
outPage = Page.Create(outDoc, TargetSize);
// ページをグループとしてコピー
Group group = Group.CopyFromPage(outDoc, inPage, copyOptions);
// グループのスケーリングと位置を計算
double scale = Math.Min(TargetSize.Width / rotatedSize.Width,
TargetSize.Height / rotatedSize.Height);
// 位置を計算
Point position = new Point
{
X = (TargetSize.Width - pageSize.Width * scale) / 2,
Y = (TargetSize.Height - pageSize.Height * scale) / 2
};
// コンテンツジェネレータを作成
using ContentGenerator generator = new ContentGenerator(outPage.Content, false);
// 変換を計算して適用
AffineTransform transform = AffineTransform.Identity;
transform.Translate(position.X, position.Y);
transform.Scale(scale, scale);
Point point = new Point()
{
X = pageSize.Width / 2.0,
Y = pageSize.Height / 2.0
};
// 入力ファイルを回転
if (rotate)
transform.Rotate(90, point);
generator.Transform(transform);
// グループを描画
generator.PaintGroup(group, null, null);
}
// 出力ドキュメントにページを追加
outDoc.Pages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def scale_pages_to_fit(in_doc: Document, out_doc: Document):
copy_options = PageCopyOptions()
# ページをコピー
for in_page in in_doc.pages:
page_size = in_page.size
rotate = (
ALLOW_ROTATE
and (page_size.height >= page_size.width) != (TARGET_SIZE.height >= TARGET_SIZE.width)
)
rotated_size = Size(
width=page_size.height, height=page_size.width
) if rotate else page_size
if rotated_size.width == TARGET_SIZE.width and rotated_size.height == TARGET_SIZE.height:
# サイズが正しい場合に、ページのみをコピー
out_page = Page.copy(out_doc, in_page, copy_options)
if rotate:
out_page.rotate(90) # Clockwise rotation
else:
# 正しいサイズの新しいページを作成し、既存のページをその上に収める
out_page = Page.create(out_doc, TARGET_SIZE)
# ページをグループとしてコピー
group = Group.copy_from_page(out_doc, in_page, copy_options)
# グループのスケーリングと位置を計算
scale = min(TARGET_SIZE.width / rotated_size.width, TARGET_SIZE.height / rotated_size.height)
# 位置を計算
position = Point(
x=(TARGET_SIZE.width - page_size.width * scale) / 2,
y=(TARGET_SIZE.height - page_size.height * scale) / 2,
)
# コンテンツジェネレータを作成
with ContentGenerator(out_page.content, False) as generator:
# 変換を計算して適用
transform = AffineTransform.get_identity()
transform.translate(position.x, position.y)
transform.scale(scale, scale)
# 入力ファイルを回転
if rotate:
center_point = Point(x=page_size.width / 2, y=page_size.height / 2)
transform.rotate(90, center_point)
# グループを描画
generator.transform(transform)
generator.paint_group(group, None, None)
# 出力ドキュメントにページを追加
out_doc.pages.append(out_page)
# グローバル変数を定義
TARGET_SIZE = Size(width=595, height=842) # A4 portrait
ALLOW_ROTATE = True
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページの処理とサイズ変更
scale_pages_to_fit(in_doc, out_doc)
PDF4ページを単一ページに配置します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ページのコピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 全てのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPageList,
_T("Failed to get pages of the output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
int nPageCount = 0;
for (int iPage = 0; iPage < PtxPdf_PageList_GetCount(pInPageList); iPage++)
{
pInPage = PtxPdf_PageList_Get(pInPageList, iPage);
if (nPageCount == nNx * nNy)
{
// 出力文書に追加
PtxPdfContent_ContentGenerator_Close(pGenerator);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
Ptx_Release(pOutPage);
pOutPage = NULL;
nPageCount = 0;
}
if (pOutPage == NULL)
{
// 新しい出力ページを作成
pOutPage = PtxPdf_Page_Create(pOutDoc, &PageSize);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage,
_T("Failed to create a new output page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
TPtxPdfContent_Content* pContent = PtxPdf_Page_GetContent(pOutPage);
pGenerator = PtxPdfContent_ContentGenerator_New(pContent, FALSE);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pGenerator,
_T("Failed to create content generator. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
}
// グループが存在するエリアを取得
int x = nPageCount % nNx;
int y = nNy - (nPageCount / nNx) - 1;
// セルサイズを計算
TPtxGeomReal_Size cellSize;
cellSize.dWidth = (PageSize.dWidth - ((nNx + 1) * dBorder)) / nNx;
cellSize.dHeight = (PageSize.dHeight - ((nNy + 1) * dBorder)) / nNy;
// セルの位置を計算
TPtxGeomReal_Point cellPosition;
cellPosition.dX = dBorder + x * (cellSize.dWidth + dBorder);
cellPosition.dY = dBorder + y * (cellSize.dHeight + dBorder);
// 入力から出力にページグループをコピー
pGroup = PtxPdfContent_Group_CopyFromPage(pOutDoc, pInPage, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(
pGroup, _T("Failed to copy page group from input to output. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// グループの位置を計算
TPtxGeomReal_Size groupSize;
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdfContent_Group_GetSize(pGroup, &groupSize),
_T("%s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
double dScale = MIN(cellSize.dWidth / groupSize.dWidth, cellSize.dHeight / groupSize.dHeight);
// ターゲットサイズを計算
TPtxGeomReal_Size targetSize;
targetSize.dWidth = groupSize.dWidth * dScale;
targetSize.dHeight = groupSize.dHeight * dScale;
// 位置を計算
TPtxGeomReal_Point targetPos;
targetPos.dX = cellPosition.dX + ((cellSize.dWidth - targetSize.dWidth) / 2);
targetPos.dY = cellPosition.dY + ((cellSize.dHeight - targetSize.dHeight) / 2);
// 矩形を計算
TPtxGeomReal_Rectangle targetRect;
targetRect.dLeft = targetPos.dX;
targetRect.dBottom = targetPos.dY;
targetRect.dRight = targetPos.dX + targetSize.dWidth;
targetRect.dTop = targetPos.dY + targetSize.dHeight;
// ページにグループを追加
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(
PtxPdfContent_ContentGenerator_PaintGroup(pGenerator, pGroup, &targetRect, NULL),
_T("Failed to paint the group. %s (ErrorCode: 0x%08x).\n"), szErrorBuff, Ptx_GetLastError());
if (pGroup != NULL)
{
Ptx_Release(pGroup);
pGroup = NULL;
}
if (pInPage != NULL)
{
Ptx_Release(pInPage);
pInPage = NULL;
}
nPageCount++;
}
// 部分的に記入されたページを追加
if (pOutPage != NULL)
{
PtxPdfContent_ContentGenerator_Close(pGenerator);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_Add(pOutPageList, pOutPage),
_T("Failed to add page to output document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
Ptx_Release(pOutPage);
pOutPage = NULL;
}
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
// 出力PDFを生成
using Stream outStream = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite);
using Document outDoc = Document.Create(outStream, inDoc.Conformance, null);
PageList outPages = outDoc.Pages;
int pageCount = 0;
ContentGenerator generator = null;
Page outPage = null;
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// 入力ドキュメントからすべてのページをコピー
foreach (Page inPage in inDoc.Pages)
{
if (pageCount == Nx * Ny)
{
// 出力文書に追加
generator.Dispose();
outPages.Add(outPage);
outPage = null;
pageCount = 0;
}
if (outPage == null)
{
// 新しい出力ページを作成
outPage = Page.Create(outDoc, PageSize);
generator = new ContentGenerator(outPage.Content, false);
}
// グループが存在するエリアを取得
int x = pageCount % Nx;
int y = Ny - (pageCount / Nx) - 1;
// セルサイズを計算
Size cellSize = new Size
{
Width = (PageSize.Width - ((Nx + 1) * Border)) / Nx,
Height = (PageSize.Height - ((Ny + 1) * Border)) / Ny
};
// セルの位置を計算
Point cellPosition = new Point
{
X = Border + x * (cellSize.Width + Border),
Y = Border + y * (cellSize.Height + Border)
};
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 入力から出力にページグループをコピー
Group group = Group.CopyFromPage(outDoc, inPage, copyOptions);
// グループの位置を計算
Size groupSize = group.Size;
double scale = Math.Min(cellSize.Width / groupSize.Width,
cellSize.Height / groupSize.Height);
// ターゲットサイズを計算
Size targetSize = new Size
{
Width = groupSize.Width * scale,
Height = groupSize.Height * scale
};
// 位置を計算
Point targetPos = new Point
{
X = cellPosition.X + ((cellSize.Width - targetSize.Width) / 2),
Y = cellPosition.Y + ((cellSize.Height - targetSize.Height) / 2)
};
// 矩形を計算
Rectangle targetRect = new Rectangle
{
Left = targetPos.X,
Bottom = targetPos.Y,
Right = targetPos.X + targetSize.Width,
Top = targetPos.Y + targetSize.Height
};
// ページにグループを追加
generator.PaintGroup(group, targetRect, null);
pageCount++;
}
// ページを追加
if (outPage != null)
{
generator.Dispose();
outPages.Add(outPage);
}
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# グローバル変数定義
nx = 2
ny = 2
page_size = Size(595.0, 842.0) # A4 portrait
border = 10.0
# 入力PDFを開く
with io.FileIO(input_file_path, 'rb') as in_stream:
with Document.open(in_stream, None) as input_document:
# 出力PDFを生成
with io.FileIO(output_file_path, 'wb+') as output_stream:
with Document.create(output_stream, input_document.conformance, None) as output_document:
out_pages = output_document.pages
page_count = 0
generator = None
out_page = None
# ドキュメント全体のデータをコピー
copy_document_data(input_document, output_document)
# 入力ドキュメントからすべてのページをコピー
for in_page in input_document.pages:
if page_count == nx * ny:
# Add to output document
generator.__exit__(None, None, None)
out_pages.append(out_page)
out_page = None
page_count = 0
if out_page is None:
# Create a new output page
out_page = Page.create(output_document, page_size)
generator = ContentGenerator(out_page.content, False)
# グループが存在するエリアを取得 (//floorでの除算)
x = int(page_count % nx)
y = int(ny - (page_count // nx) - 1)
# セルサイズを計算
cell_width = (page_size.width - ((nx + 1) * border)) / nx
cell_height = (page_size.height - ((ny + 1) * border)) / ny
# セルの位置を計算
cell_x = border + x * (cell_width + border)
cell_y = border + y * (cell_height + border)
# ページのコピーオプションを定義
copy_options = PageCopyOptions()
# 入力から出力にページグループをコピー
group = Group.copy_from_page(output_document, in_page, copy_options)
# グループの位置を計算
group_size = group.size
scale = min(cell_width / group_size.width, cell_height / group_size.height)
# Compute target size
target_width = group_size.width * scale
target_height = group_size.height * scale
# ターゲットサイズを計算
target_x = cell_x + ((cell_width - target_width) / 2)
target_y = cell_y + ((cell_height - target_height) / 2)
# 矩形サイズを計算
target_rect = Rectangle()
target_rect.left = target_x
target_rect.bottom = target_y
target_rect.right = target_x + target_width
target_rect.top = target_y + target_height
# ページにグループを追加
generator.paint_group(group, target_rect, None)
page_count += 1
# ページを追加
if out_page:
generator.__exit__(None, None, None)
out_pages.append(out_page)
PDFの指定されたページを90度回転します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 出力PDFを生成
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
iConformance = PtxPdf_Document_GetConformance(pInDoc);
pOutDoc = PtxPdf_Document_Create(&outDescriptor, &iConformance, NULL);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutDoc, _T("Output file \"%s\" cannot be created. %s (ErrorCode: 0x%08x).\n"),
szOutPath, szErrorBuff, Ptx_GetLastError());
// ドキュメント全体のデータをコピー
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(copyDocumentData(pInDoc, pOutDoc),
_T("Failed to copy document-wide data. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// ページのコピーオプションを設定
pCopyOptions = PtxPdf_PageCopyOptions_New();
// 全てのページをコピー
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
pCopiedPages = PtxPdf_PageList_Copy(pOutDoc, pInPageList, pCopyOptions);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCopiedPages, _T("Failed to copy pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
// 指定されたページを90度回転
for (int i = 0; i < ARRAY_SIZE(aPageNumbers); i++)
{
pOutPage = PtxPdf_PageList_Get(pCopiedPages, aPageNumbers[i] - 1);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pOutPage, _T("Failed to get copied page. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_Page_Rotate(pOutPage, ePtxGeom_Rotation_Clockwise),
_T("Failed to rotate page. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
}
// 出力文書にページを追加
pOutPageList = PtxPdf_Document_GetPages(pOutDoc);
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(PtxPdf_PageList_AddRange(pOutPageList, pCopiedPages),
_T("Failed to add copied pages. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
int copyDocumentData(TPtxPdf_Document* pInDoc, TPtxPdf_Document* pOutDoc)
{
TPtxPdf_FileReferenceList* pInFileRefList;
TPtxPdf_FileReferenceList* pOutFileRefList;
// 出力色特性設定
if (PtxPdf_Document_GetOutputIntent(pInDoc) != NULL)
if (PtxPdf_Document_SetOutputIntent(pOutDoc, PtxPdfContent_IccBasedColorSpace_Copy(
pOutDoc, PtxPdf_Document_GetOutputIntent(pInDoc))) == FALSE)
return FALSE;
// メタデータ
if (PtxPdf_Document_SetMetadata(pOutDoc, PtxPdf_Metadata_Copy(pOutDoc, PtxPdf_Document_GetMetadata(pInDoc))) ==
FALSE)
return FALSE;
// ビュワー設定
if (PtxPdf_Document_SetViewerSettings(
pOutDoc, PtxPdfNav_ViewerSettings_Copy(pOutDoc, PtxPdf_Document_GetViewerSettings(pInDoc))) == FALSE)
return FALSE;
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
pInFileRefList = PtxPdf_Document_GetAssociatedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetAssociatedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
// プレーンな埋め込みファイル
pInFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pInDoc);
pOutFileRefList = PtxPdf_Document_GetPlainEmbeddedFiles(pOutDoc);
if (pInFileRefList == NULL || pOutFileRefList == NULL)
return FALSE;
for (int iFileRef = 0; iFileRef < PtxPdf_FileReferenceList_GetCount(pInFileRefList); iFileRef++)
if (PtxPdf_FileReferenceList_Add(
pOutFileRefList,
PtxPdf_FileReference_Copy(pOutDoc, PtxPdf_FileReferenceList_Get(pInFileRefList, iFileRef))) == FALSE)
return FALSE;
return TRUE;
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (Stream outFs = new FileStream(outPath, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outFs, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページのコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// 全てのページをコピー
PageList copiedPages = PageList.Copy(outDoc, inDoc.Pages, copyOptions);
// 指定されたページを90度回転
foreach (var pageNumber in pageNumbers)
{
copiedPages[pageNumber - 1].Rotate(Rotation.Clockwise);
}
// 出力文書にページを追加
outDoc.Pages.AddRange(copiedPages);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページのコピーオプションを定義
page_copy_options = PageCopyOptions()
# 全てのページをコピー
copied_pages = PageList.copy(out_doc, in_doc.pages, page_copy_options)
# 指定されたページを90度回転
for page_number in page_numbers:
copied_pages[int(page_number) - 1].rotate(Rotation.CLOCKWISE)
# 出力文書にページを追加
out_doc.pages.extend(copied_pages)
ファイルをPDFに埋め込むことで、ドキュメントに添付したり、ページを添付したりします。
// 入力PDFを開く
using (FileStream inStream = new FileStream(input, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
// 出力PDFを生成
using (FileStream outStream = new FileStream(output, FileMode.Create, FileAccess.ReadWrite))
using (Document outDoc = Document.Create(outStream, inDoc.Conformance, null))
{
// ドキュメント全体のデータをコピー
CopyDocumentData(inDoc, outDoc);
// ページコピーオプションを定義
PageCopyOptions copyOptions = new PageCopyOptions();
// すべてのページをコピー
PageList inPageRange = inDoc.Pages.GetRange(0, inDoc.Pages.Count);
PageList copiedPages = PageList.Copy(outDoc, inPageRange, copyOptions);
outDoc.Pages.AddRange(copiedPages);
EmbedFile(outDoc, new FileInfo(fileToEmbed), page);
}
private static void CopyDocumentData(Document inDoc, Document outDoc)
{
// ドキュメント全体のデータをコピー
// 出力色特性設定
if (inDoc.OutputIntent != null)
outDoc.OutputIntent = IccBasedColorSpace.Copy(outDoc, inDoc.OutputIntent);
// メタデータ
outDoc.Metadata = Metadata.Copy(outDoc, inDoc.Metadata);
// ビュワー設定
outDoc.ViewerSettings = ViewerSettings.Copy(outDoc, inDoc.ViewerSettings);
// 関連ファイル(PDF/A-3およびPDF 2.0のみ)
FileReferenceList outAssociatedFiles = outDoc.AssociatedFiles;
foreach (FileReference inFileRef in inDoc.AssociatedFiles)
outAssociatedFiles.Add(FileReference.Copy(outDoc, inFileRef));
// プレーンな埋め込みファイル
FileReferenceList outEmbeddedFiles = outDoc.PlainEmbeddedFiles;
foreach (FileReference inFileRef in inDoc.PlainEmbeddedFiles)
outEmbeddedFiles.Add(FileReference.Copy(outDoc, inFileRef));
}
private static void EmbedFile(Document outputDoc, FileSystemInfo fileToEmbed, int pageNumber)
{
// 埋め込むファイルを読み取るためのファイルストリームを作成
using (FileStream fileStream = new FileStream(fileToEmbed.FullName, FileMode.Open, FileAccess.Read))
{
// ファイルの末尾(拡張子)に応じてファイルタイプを作成 (例:"application/pdf")
string fileEnding = fileToEmbed.Name.Substring(fileToEmbed.Name.LastIndexOf(".") + 1);
string type = "application/" + fileEnding;
// ファイルから更新日を取得
DateTime dateTime = fileToEmbed.LastWriteTime;
// 新しいFileReferenceを作成
FileReference fr = FileReference.Create(outputDoc, fileStream, fileToEmbed.Name, type, "", dateTime);
// ページが設定されている場合は、そのページにFileAttachmentアノテーションを追加し、そうでない場合はファイルをドキュメントに添付
if (pageNumber > 0 && pageNumber lt;= outputDoc.Pages.Count)
{
// 注釈を作成するページを取得
Page page = outputDoc.Pages[pageNumber - 1];
// 色空間を取得
ColorSpace colorSpace = ColorSpace.CreateProcessColorSpace(outputDoc, ProcessColorSpaceType.Rgb);
// RGB色空間を選択
double[] color = { 1.0, 0.0, 0.0 };
Transparency transparency = new Transparency(1);
// Paintオブジェクトを作成
Paint paint = Paint.Create(outputDoc, colorSpace, color, transparency);
// 注釈をページの中央に置く
Point point = new Point
{
X= page.Size.Width / 2,
Y= page.Size.Height / 2
};
// FileReferenceアノテーションを作成し、それをページに添付(そのページでFireReferenceを表示できるようにするため)
FileAttachment fa = FileAttachment.Create(outputDoc, point, fr, paint);
// ページにFileAttachment注釈を追加
page.Annotations.Add(fa);
}
else
{
// 文書に添付
outputDoc.PlainEmbeddedFiles.Add(fr);
}
}
}
def copy_document_data(in_doc: Document, out_doc: Document):
# ドキュメント全体のデータをコピー
# 出力色特性設定
if in_doc.output_intent is not None:
in_doc.output_intent = IccBasedColorSpace.copy(out_doc, in_doc.output_intent)
# メタデータ
out_doc.metadata = Metadata.copy(out_doc, in_doc.metadata)
# ビュワー設定
out_doc.viewer_settings = ViewerSettings.copy(out_doc, in_doc.viewer_settings)
# 関連ファイル(PDF/A-3およびPDF 2.0のみ)
outAssociatedFiles = out_doc.associated_files
for in_file_ref in in_doc.associated_files:
outAssociatedFiles.append(FileReference.copy(out_doc, in_file_ref))
# プレーンな埋め込みファイル
out_embedded_files = out_doc.plain_embedded_files
for in_file_ref in in_doc.plain_embedded_files:
out_embedded_files.append(FileReference.copy(out_doc, in_file_ref))
def embed_file(output_doc: Document, file_to_embed: str, page_number: int = None):
# 埋め込むファイルを読み取るためのファイルストリームを作成
with open(file_to_embed, "rb") as file_stream:
# ファイルの末尾(拡張子)に応じてファイルタイプを作成 (例:"application/pdf")
file_to_embed_name = os.path.basename(file_to_embed)
file_type = "application/" + file_to_embed_name.split(".")[-1]
# ファイルから更新日を取得
last_modified = datetime.fromtimestamp(os.path.getmtime(file_to_embed))
# 新しいFileReferenceを作成
file_ref = FileReference.create(output_doc, file_stream, file_to_embed_name, file_type, "", last_modified)
# ページが設定されている場合は、そのページにFileAttachmentアノテーションを追加し、そうでない場合はファイルをドキュメントに添付
if page_number is not None and page_number > 0 and page_number lt;= len(output_doc.pages):
# 注釈を作成するページを取得
page = output_doc.pages[page_number - 1]
# 色空間を取得
color_space = ColorSpace.create_process_color_space(output_doc, ProcessColorSpaceType.RGB)
# RGB色空間を選択
color = [1.0, 0.0, 0.0] # Red color
transparency = Transparency(1)
# Paintオブジェクトを作成
paint = Paint.create(output_doc, color_space, color, transparency)
# 注釈をページの中央に置く
point = Point(x = page.size.width/2, y = page.size.height/2)
# FileReferenceアノテーションを作成し、それをページに添付(そのページでFireReferenceを表示できるようにするため)
annotation = FileAttachment.create(output_doc, point, file_ref, paint)
# ページにFileAttachment注釈を追加
page.annotations.append(annotation)
else:
# 文書に添付
output_doc.plain_embedded_files.append(file_ref)
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# 出力PDFを生成
with io.FileIO(output_file_path, "wb+") as out_stream:
with Document.create(out_stream, in_doc.conformance, None) as out_doc:
# ドキュメント全体のデータをコピー
copy_document_data(in_doc, out_doc)
# ページコピーオプションを定義
copy_options = PageCopyOptions()
# すべてのページをコピー
copied_pages = PageList.copy(out_doc, in_doc.pages, copy_options)
out_doc.pages.extend(copied_pages)
embed_file(out_doc, file_to_embed, page_number)
PDFに埋め込まれたファイルをフォルダーに抽出します。
// 入力ファイルを開く
using (FileStream inStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
FileReferenceList frList = inDoc.AllEmbeddedFiles;
foreach(FileReference fr in frList)
{
ExtractFile(fr, outputDir);
}
}
private static void ExtractFile(FileReference fr, String outputDir)
{
using (FileStream outStream = new FileStream(outputDir + "/" + fr.Name, FileMode.Create, FileAccess.ReadWrite))
{
fr.Data.CopyTo(outStream);
}
}
def copy_to_stream(data: io.IOBase, out_stream: io.IOBase, chunk_size: int = 4096):
"""Copy data from an IO stream to another."""
while chunk := data.read(chunk_size):
out_stream.write(chunk)
def extract_file(file_reference: FileReference, output_dir: str):
# Null文字を削除
clean_file_name = file_reference.name.replace(chr(0), "")
output_path = os.path.join(output_dir, clean_file_name)
if file_reference.data is None:
raise ValueError("The file_reference.data stream is None.")
if not file_reference.data.readable():
raise ValueError("The file_reference.data stream is not readable.")
# 出力ディレクトリが存在することを確認
os.makedirs(output_dir, exist_ok=True)
with io.FileIO(output_path, "wb") as out_file:
copy_to_stream(file_reference.data, out_file)
# 入力ファイルを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
file_ref_list = in_doc.all_embedded_files
for file_ref in file_ref_list:
extract_file(file_ref, output_dir)
使用されている圧縮形式に応じて、埋め込まれた画像データをJPEG画像またはTIFF画像として抽出します。
// 入力ファイルを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// すべてのページをループして画像を抽出
pInPageList = PtxPdf_Document_GetPages(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInPageList,
_T("Failed to get the pages of the input document. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int iPageNo = 0; iPageNo lt; PtxPdf_PageList_GetCount(pInPageList); iPageNo++)
{
pPage = PtxPdf_PageList_Get(pInPageList, iPageNo);
pContent = PtxPdf_Page_GetContent(pPage);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pContent, _T("Failed to get content from page %d. %s (ErrorCode: 0x%08x).\n"),
iPageNo + 1, szErrorBuff, Ptx_GetLastError());
pExtractor = PtxPdfContent_ContentExtractor_New(pContent);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pExtractor,
_T("Failed to create content extractor. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
GOTO_CLEANUP_IF_FALSE_PRINT_ERROR(extractImages(pExtractor, iPageNo + 1, szOutputDir),
_T("Error occurred while extracting images. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
if (pPage != NULL)
{
Ptx_Release(pPage);
pPage = NULL;
}
if (pContent != NULL)
{
Ptx_Release(pContent);
pContent = NULL;
}
}
int extractImages(TPtxPdfContent_ContentExtractor* pExtractor, int iPageNo, const TCHAR* szOutputDir)
{
int iImgCount = 0;
int iImgMaskCount = 0;
TPtxPdfContent_ContentExtractorIterator* pIterator = NULL;
TPtxPdfContent_ContentElement* pContentElement = NULL;
TPtxPdfContent_Image* pImage = NULL;
TPtxPdfContent_ImageMask* pImageMask = NULL;
TCHAR* szExtension = NULL;
FILE* pOutStream = NULL;
pIterator = PtxPdfContent_ContentExtractor_GetIterator(pExtractor);
GOTO_CLEANUP_IF_NULL(pIterator, _T("Failed to get iterator.\n"));
PtxPdfContent_ContentExtractorIterator_MoveNext(pIterator);
while (pContentElement = PtxPdfContent_ContentExtractorIterator_GetValue(pIterator))
{
TPtxPdfContent_ContentElementType iType = PtxPdfContent_ContentElement_GetType(pContentElement);
if (iType == ePtxPdfContent_ContentElementType_ImageElement)
{
iImgCount++;
pImage = PtxPdfContent_ImageElement_GetImage((TPtxPdfContent_ImageElement*)pContentElement);
GOTO_CLEANUP_IF_NULL(pImage, _T("Failed to get image.\n"));
const TPtxPdfContent_ImageType iImageType = PtxPdfContent_Image_GetDefaultImageType(pImage);
if (iImageType == ePtxPdfContent_ImageType_Jpeg)
szExtension = _T(".jpg");
else
szExtension = _T(".tiff");
TCHAR szOutPath[256] = {'\0'};
_stprintf(szOutPath, _T("%s/image_page%d_%d%s"), szOutputDir, iPageNo, iImgCount, szExtension);
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
TPtxSys_StreamDescriptor outDescriptor;
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
if (PtxPdfContent_Image_Extract(pImage, &outDescriptor, NULL) == FALSE)
{
if (Ptx_GetLastError() == ePtx_Error_Generic)
{
nBufSize = Ptx_GetLastErrorMessage(NULL, 0);
Ptx_GetLastErrorMessage(szErrorBuff, MIN(ARRAY_SIZE(szErrorBuff), nBufSize));
_tprintf(szErrorBuff);
}
else
return FALSE;
}
if (pImage != NULL)
{
Ptx_Release(pImage);
pImage = NULL;
}
if (pOutStream != NULL)
{
fclose(pOutStream);
pOutStream = NULL;
}
}
else if (iType == ePtxPdfContent_ContentElementType_ImageMaskElement)
{
iImgMaskCount++;
pImageMask = PtxPdfContent_ImageMaskElement_GetImageMask((TPtxPdfContent_ImageMaskElement*)pContentElement);
GOTO_CLEANUP_IF_NULL(pImageMask, _T("Failed to get image.\n"));
szExtension = _T(".tiff");
TCHAR szOutPath[256] = {'\0'};
_stprintf(szOutPath, _T("%s/image_mask_page%d_%d%s"), szOutputDir, iPageNo, iImgMaskCount, szExtension);
pOutStream = _tfopen(szOutPath, _T("wb+"));
GOTO_CLEANUP_IF_NULL(pOutStream, _T("Failed to open output file \"%s\".\n"), szOutPath);
TPtxSys_StreamDescriptor outDescriptor;
PtxSysCreateFILEStreamDescriptor(&outDescriptor, pOutStream, 0);
if (PtxPdfContent_ImageMask_Extract(pImageMask, &outDescriptor, NULL) == FALSE)
{
if (Ptx_GetLastError() == ePtx_Error_Generic)
{
nBufSize = Ptx_GetLastErrorMessage(NULL, 0);
Ptx_GetLastErrorMessage(szErrorBuff, MIN(ARRAY_SIZE(szErrorBuff), nBufSize));
_tprintf(szErrorBuff);
}
else
return FALSE;
}
if (pImageMask != NULL)
{
Ptx_Release(pImageMask);
pImageMask = NULL;
}
if (pOutStream != NULL)
{
fclose(pOutStream);
pOutStream = NULL;
}
}
if (pContentElement != NULL)
{
Ptx_Release(pContentElement);
pContentElement = NULL;
}
PtxPdfContent_ContentExtractorIterator_MoveNext(pIterator);
}
cleanup:
if (pImage != NULL)
Ptx_Release(pImage);
if (pImageMask != NULL)
Ptx_Release(pImageMask);
if (pContentElement != NULL)
Ptx_Release(pContentElement);
if (pIterator != NULL)
Ptx_Release(pIterator);
if (pOutStream != NULL)
fclose(pOutStream);
return iReturnValue == 1 ? FALSE : TRUE;
}
// 入力ファイルを開く
using (Stream stream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document doc = Document.Open(stream, null))
{
// Loop over all pages and extract images
for (int i = 0; i lt; doc.Pages.Count; i++)
{
ContentExtractor extractor = new ContentExtractor(doc.Pages[i].Content);
ExtractImages(extractor, i + 1, outputDir);
}
}
private static void ExtractImages(ContentExtractor extractor, int pageNo, string outputDir)
{
int imgCount = 0;
int imgMaskCount = 0;
foreach (ContentElement contentElement in extractor)
{
if (contentElement is ImageElement element)
{
imgCount++;
string extension = ".tiff";
switch (element.Image.DefaultImageType)
{
case ImageType.Jpeg:
extension = ".jpg";
break;
case ImageType.Tiff:
extension = ".tiff";
break;
default:
break;
}
string outputPath = System.IO.Path.Combine(outputDir, $"image_page{pageNo}_{imgCount}{extension}");
try
{
using (Stream imageStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
{
element.Image.Extract(imageStream);
}
}
catch (GenericException ex)
{
Console.WriteLine(ex.ToString());
}
}
else if (contentElement is ImageMaskElement maskElement)
{
imgMaskCount++;
string extension = ".tiff";
string outputPath = System.IO.Path.Combine(outputDir, $"image_mask_page{pageNo}_{imgMaskCount}{extension}");
try
{
using (Stream imageStream = new FileStream(outputPath, FileMode.Create, FileAccess.ReadWrite))
{
maskElement.ImageMask.Extract(imageStream);
}
}
catch (GenericException ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
def extract_image(image_element: ImageElement, output_path: str):
with open(output_path, "wb+") as out_stream:
image_element.image.extract(out_stream)
def extract_image_mask(image_mask_element: ImageMaskElement, output_path: str):
with open(output_path, "wb+") as out_stream:
image_mask_element.image_mask.extract(out_stream)
def process_page_content(page: Page, page_number: int, output_dir: str):
extractor = ContentExtractor(page.content)
img_count = 0
mask_count = 0
for content_element in extractor:
# 画像要素の抽出
if isinstance(content_element, ImageElement):
img_count += 1
image_type = content_element.image.default_image_type
extension = ".jpg" if image_type == ImageType.JPEG else ".tiff"
output_path = os.path.join(output_dir, f"image_page{page_number}_{img_count}{extension}")
extract_image(content_element, output_path)
print(f"Extracted image: {output_path}")
# 画像マスクの抽出
elif isinstance(content_element, ImageMaskElement):
mask_count += 1
output_path = os.path.join(output_dir, f"image_mask_page{page_number}_{mask_count}.tiff")
extract_image_mask(content_element, output_path)
print(f"Extracted image mask: {output_path}")
# 出力ディレクトリが存在することを確認
os.makedirs(output_dir, exist_ok=True)
# 入力ファイルを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
for page_number, page in enumerate(in_doc.pages, start=1):
process_page_content(page, page_number, output_dir)
PDFの各ページについて、ページ サイズと、ページ上のすべてのコンテンツの長方形の境界ボックスサイズをPDFポイント(1/72インチ)でリストします。
// 入力ファイルを開く
using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Document doc = Document.Open(stream, null))
{
// すべてのページを反復処理
int pageNumber = 1;
foreach (Page page in doc.Pages)
{
// ページサイズを印刷
Console.WriteLine("Page {0}", pageNumber++);
Size size = page.Size;
Console.WriteLine(" Size:");
Console.WriteLine(" Width: {0}", size.Width);
Console.WriteLine(" Height: {0}", size.Height);
// ページ上のすべてのコンテンツの矩形境界ボックス(Bounding box)を計算
Rectangle contentBox = new Rectangle()
{
Left = double.MaxValue,
Bottom = double.MaxValue,
Right = double.MinValue,
Top = double.MinValue,
};
ContentExtractor extractor = new ContentExtractor(page.Content);
foreach (ContentElement element in extractor)
{
// 各コンテンツ要素のコンテンツボックスを拡大
AffineTransform tr = element.Transform;
Rectangle box = element.BoundingBox;
// ページ上の位置は変換されたポイントによって示されます
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Left, Y = box.Bottom, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Right, Y = box.Bottom, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Right, Y = box.Top, }));
Enlarge(ref contentBox, tr.TransformPoint(new Point { X = box.Left, Y = box.Top, }));
}
Console.WriteLine(" Content bounding box:");
Console.WriteLine(" Left: {0}", contentBox.Left);
Console.WriteLine(" Bottom: {0}", contentBox.Bottom);
Console.WriteLine(" Right: {0}", contentBox.Right);
Console.WriteLine(" Top: {0}", contentBox.Top);
}
}
static void Enlarge(ref Rectangle box, Point point)
{
// ポイントがボックスの外側にある場合はボックスを拡大
if (point.X lt; box.Left)
box.Left = point.X;
else if (point.X > box.Right)
box.Right = point.X;
if (point.Y lt; box.Bottom)
box.Bottom = point.Y;
else if (point.Y > box.Top)
box.Top = point.Y;
}
def enlarge(content_box: Rectangle, point: Point):
"""
Enlarge the bounding box to include the given point.
"""
content_box.left = min(content_box.left, point.x)
content_box.right = max(content_box.right, point.x)
content_box.bottom = min(content_box.bottom, point.y)
content_box.top = max(content_box.top, point.y)
def list_content_bounds(input_doc: Document):
"""
Process the input PDF file to list page size and bounding boxes.
"""
# すべてのページを反復処理
for page_number, page in enumerate(input_doc.pages, start=1):
print(f"Page {page_number}")
# ページサイズを印刷
size = page.size
print(" Size:")
print(f" Width: {size.width}")
print(f" Height: {size.height}")
# ページ上のすべてのコンテンツの矩形境界ボックス(Bounding box)を計算
content_box = Rectangle(
left=float("inf"),
bottom=float("inf"),
right=float("-inf"),
top=float("-inf"),
)
# コンテンツを抽出し、境界ボックスを(Bounding box)計算
extractor = ContentExtractor(page.content)
for element in extractor:
# 各コンテンツ要素のコンテンツボックスを拡大
tr = element.transform
box = element.bounding_box
# ページ上の位置は変換されたポイントによって示されます
enlarge(content_box, tr.transform_point(Point(x=box.left, y=box.bottom)))
enlarge(content_box, tr.transform_point(Point(x=box.right, y=box.bottom)))
enlarge(content_box, tr.transform_point(Point(x=box.right, y=box.top)))
enlarge(content_box, tr.transform_point(Point(x=box.left, y=box.top)))
print(" Content bounding box:")
print(f" Left: {content_box.left}")
print(f" Bottom: {content_box.bottom}")
print(f" Right: {content_box.right}")
print(f" Top: {content_box.top}")
# 入力ファイルを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# PDFを処理
list_content_bounds(in_doc)
PDFの属性(PF準拠性や暗号化情報)とメタデータ(作成者、タイトル、作成日など)を一覧表示します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, szPassword);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// PDF バージョン
TPtxPdf_Conformance conformance = PtxPdf_Document_GetConformance(pInDoc);
if (conformance == 0)
{
GOTO_CLEANUP(szErrorBuff, Ptx_GetLastError());
}
_tprintf(_T("Conformance: "));
switch (conformance)
{
case ePtxPdf_Conformance_Pdf10:
_tprintf(_T("PDF 1.0\n"));
break;
case ePtxPdf_Conformance_Pdf11:
_tprintf(_T("PDF 1.1\n"));
break;
case ePtxPdf_Conformance_Pdf12:
_tprintf(_T("PDF 1.2\n"));
break;
case ePtxPdf_Conformance_Pdf13:
_tprintf(_T("PDF 1.3\n"));
break;
case ePtxPdf_Conformance_Pdf14:
_tprintf(_T("PDF 1.4\n"));
break;
case ePtxPdf_Conformance_Pdf15:
_tprintf(_T("PDF 1.5\n"));
break;
case ePtxPdf_Conformance_Pdf16:
_tprintf(_T("PDF 1.6\n"));
break;
case ePtxPdf_Conformance_Pdf17:
_tprintf(_T("PDF 1.7\n"));
break;
case ePtxPdf_Conformance_Pdf20:
_tprintf(_T("PDF 2.0\n"));
break;
case ePtxPdf_Conformance_PdfA1B:
_tprintf(_T("PDF/A1-b\n"));
break;
case ePtxPdf_Conformance_PdfA1A:
_tprintf(_T("PDF/A1-a\n"));
break;
case ePtxPdf_Conformance_PdfA2B:
_tprintf(_T("PDF/A2-b\n"));
break;
case ePtxPdf_Conformance_PdfA2U:
_tprintf(_T("PDF/A2-u\n"));
break;
case ePtxPdf_Conformance_PdfA2A:
_tprintf(_T("PDF/A2-a\n"));
break;
case ePtxPdf_Conformance_PdfA3B:
_tprintf(_T("PDF/A3-b\n"));
break;
case ePtxPdf_Conformance_PdfA3U:
_tprintf(_T("PDF/A3-u\n"));
break;
case ePtxPdf_Conformance_PdfA3A:
_tprintf(_T("PDF/A3-a\n"));
break;
}
// 暗号化情報
TPtxPdf_Permission permissions;
BOOL iRet = PtxPdf_Document_GetPermissions(pInDoc, &permissions);
if (iRet == FALSE)
{
if (Ptx_GetLastError() != ePtx_Error_Success)
GOTO_CLEANUP(szErrorBuff, Ptx_GetLastError());
_tprintf(_T("Not encrypted\n"));
}
else
{
_tprintf(_T("Encryption:\n"));
_tprintf(_T(" - Permissions: "));
if (permissions & ePtxPdf_Permission_Print)
_tprintf(_T("Print, "));
if (permissions & ePtxPdf_Permission_Modify)
_tprintf(_T("Modify, "));
if (permissions & ePtxPdf_Permission_Copy)
_tprintf(_T("Copy, "));
if (permissions & ePtxPdf_Permission_Annotate)
_tprintf(_T("Annotate, "));
if (permissions & ePtxPdf_Permission_FillForms)
_tprintf(_T("FillForms, "));
if (permissions & ePtxPdf_Permission_SupportDisabilities)
_tprintf(_T("SupportDisabilities, "));
if (permissions & ePtxPdf_Permission_Assemble)
_tprintf(_T("Assemble, "));
if (permissions & ePtxPdf_Permission_DigitalPrint)
_tprintf(_T("DigitalPrint, "));
_tprintf(_T("\n"));
}
// 入力PDFのメタデータを取得
pMetadata = PtxPdf_Document_GetMetadata(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pMetadata, _T("Failed to get metadata. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
_tprintf(_T("Document information:\n"));
// Title(タイトル)を取得
size_t nTitle = PtxPdf_Metadata_GetTitle(pMetadata, NULL, 0);
if (nTitle != 0)
{
TCHAR* szTitle = (TCHAR*)malloc(nTitle * sizeof(TCHAR));
if (szTitle != NULL)
{
PtxPdf_Metadata_GetTitle(pMetadata, szTitle, nTitle);
_tprintf(_T(" - Title: %s\n"), szTitle);
free(szTitle);
}
}
// Author(著者)を取得
size_t nAuthor = PtxPdf_Metadata_GetAuthor(pMetadata, NULL, 0);
if (nAuthor != 0)
{
TCHAR* szAuthor = (TCHAR*)malloc(nAuthor * sizeof(TCHAR));
if (szAuthor != NULL)
{
PtxPdf_Metadata_GetAuthor(pMetadata, szAuthor, nAuthor);
_tprintf(_T(" - Author: %s\n"), szAuthor);
free(szAuthor);
}
}
// Creator(作成者)を取得
size_t nCreator = PtxPdf_Metadata_GetCreator(pMetadata, NULL, 0);
if (nCreator != 0)
{
TCHAR* szCreator = (TCHAR*)malloc(nCreator * sizeof(TCHAR));
if (szCreator != NULL)
{
PtxPdf_Metadata_GetCreator(pMetadata, szCreator, nCreator);
_tprintf(_T(" - Creator: %s\n"), szCreator);
free(szCreator);
}
}
// Producerを取得
size_t nProducer = PtxPdf_Metadata_GetProducer(pMetadata, NULL, 0);
if (nProducer != 0)
{
TCHAR* szProducer = (TCHAR*)malloc(nProducer * sizeof(TCHAR));
if (szProducer != NULL)
{
PtxPdf_Metadata_GetProducer(pMetadata, szProducer, nProducer);
_tprintf(_T(" - Producer: %s\n"), szProducer);
free(szProducer);
}
}
// Subjectを取得
size_t nSubject = PtxPdf_Metadata_GetSubject(pMetadata, NULL, 0);
if (nSubject != 0)
{
TCHAR* szSubject = (TCHAR*)malloc(nSubject * sizeof(TCHAR));
if (szSubject != NULL)
{
PtxPdf_Metadata_GetSubject(pMetadata, szSubject, nSubject);
_tprintf(_T(" - Subject: %s\n"), szSubject);
free(szSubject);
}
}
// Keywordsを取得
size_t nKeywords = PtxPdf_Metadata_GetKeywords(pMetadata, NULL, 0);
if (nKeywords != 0)
{
TCHAR* szKeywords = (TCHAR*)malloc(nKeywords * sizeof(TCHAR));
if (szKeywords != NULL)
{
PtxPdf_Metadata_GetKeywords(pMetadata, szKeywords, nKeywords);
_tprintf(_T(" - Keywords: %s\n"), szKeywords);
free(szKeywords);
}
}
// 作成日時を取得
if (PtxPdf_Metadata_GetCreationDate(pMetadata, &date) == TRUE)
{
_tprintf(_T(" - Creation Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth, date.iDay,
date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour, date.iTZMinute);
}
// 変更日時を取得
if (PtxPdf_Metadata_GetModificationDate(pMetadata, &date) == TRUE)
{
_tprintf(_T(" - Modification Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth,
date.iDay, date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour,
date.iTZMinute);
}
// 独自のエントリを取得
_tprintf(_T("Custom entries:\n"));
TPtx_StringMap* pCustomEntries = PtxPdf_Metadata_GetCustomEntries(pMetadata);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pCustomEntries, _T("Failed to get custom entries. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
for (int i = Ptx_StringMap_GetBegin(pCustomEntries), iEnd = Ptx_StringMap_GetEnd(pCustomEntries); i != iEnd;
i = Ptx_StringMap_GetNext(pCustomEntries, i))
{
size_t nKeySize = Ptx_StringMap_GetKey(pCustomEntries, i, NULL, 0);
TCHAR* szKey = (TCHAR*)malloc(nKeySize * sizeof(TCHAR));
nKeySize = Ptx_StringMap_GetKey(pCustomEntries, i, szKey, nKeySize);
size_t nValueSize = Ptx_StringMap_GetValue(pCustomEntries, i, NULL, 0);
TCHAR* szValue = (TCHAR*)malloc(nValueSize * sizeof(TCHAR));
nValueSize = Ptx_StringMap_GetValue(pCustomEntries, i, szValue, nValueSize);
if (szKey && nKeySize && szValue && nValueSize)
_tprintf(_T(" - %s: %s\n"), szKey, szValue);
free(szKey);
free(szValue);
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, password))
{
// PDF バージョン
Console.WriteLine("Conformance: {0}", inDoc.Conformance.ToString());
// 暗号化情報
Permission? permissions = inDoc.Permissions;
if (!permissions.HasValue)
{
Console.WriteLine("Not encrypted");
}
else
{
Console.WriteLine("Encryption:");
Console.Write(" - Permissions: ");
foreach (Enum flag in Enum.GetValues(typeof(Permission)))
if (permissions.Value.HasFlag(flag))
Console.Write("{0}, ", flag.ToString());
Console.WriteLine();
}
// メタデータを取得
Metadata metadata = inDoc.Metadata;
Console.WriteLine("Document information:");
// Title(タイトル)を取得
string title = metadata.Title;
if (title != null)
Console.WriteLine(" - Title: {0}", title);
// Author(著者)を取得
string author = metadata.Author;
if (author != null)
Console.WriteLine(" - Author: {0}", author);
// Subjectを取得
string subject = metadata.Subject;
if (subject != null)
Console.WriteLine(" - Subject: {0}", subject);
// Keywordsを取得
string keywords = metadata.Keywords;
if (keywords != null)
Console.WriteLine(" - Keywords: {0}", keywords);
// 作成日時を取得
DateTimeOffset? creationDate = metadata.CreationDate;
if (creationDate != null)
Console.WriteLine(" - Creation Date: {0}", creationDate);
// 変更日時を取得
DateTimeOffset? modificationDate = metadata.ModificationDate;
if (modificationDate != null)
Console.WriteLine(" - Modification Date: {0}", modificationDate);
// Creator(作成者)を取得
string creator = metadata.Creator;
if (creator != null)
Console.WriteLine(" - Creator: {0}", creator);
// Producerを取得
string producer = metadata.Producer;
if (producer != null)
Console.WriteLine(" - Producer: {0}", producer);
// 独自のエントリを取得
Console.WriteLine("Custom entries:");
foreach (var entry in metadata.CustomEntries)
Console.WriteLine(" - {0}: {1}", entry.Key, entry.Value);
}
def display_permissions(permissions: int):
"""Display encryption permissions in a readable format."""
# アクティブな権限名を表示
active_permissions = [perm.name for perm in Permission if permissions & perm]
for perm in active_permissions:
print(f" - {perm}")
def list_pdf_info(input_doc: Document):
"""
List document information and metadata of the given PDF.
"""
# PDFバージョン
print(f"Conformance: {input_doc.conformance.name}")
# 暗号化情報
permissions = input_doc.permissions
if permissions is None:
print("Not encrypted")
else:
display_permissions(permissions)
# メタデータを取得
metadata = input_doc.metadata
print("Document information:")
# 標準のメタデータを表示
if metadata.title:
print(f" - Title: {metadata.title}")
if metadata.author:
print(f" - Author: {metadata.author}")
if metadata.subject:
print(f" - Subject: {metadata.subject}")
if metadata.keywords:
print(f" - Keywords: {metadata.keywords}")
if metadata.creation_date:
print(f" - Creation Date: {metadata.creation_date}")
if metadata.modification_date:
print(f" - Modification Date: {metadata.modification_date}")
if metadata.creator:
print(f" - Creator: {metadata.creator}")
if metadata.producer:
print(f" - Producer: {metadata.producer}")
# 独自のエントリを表示
print("Custom entries:")
for key, value in metadata.custom_entries.items():
print(f" - {key}: {value}")
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, pdf_password) as in_doc:
# PDFを処理
list_pdf_info(in_doc)
PDF内のすべての署名フィールドとそのプロパティを一覧表示します。
// 入力PDFを開く
pInStream = _tfopen(szInPath, _T("rb"));
GOTO_CLEANUP_IF_NULL(pInStream, _T("Failed to open input file \"%s\".\n"), szInPath);
PtxSysCreateFILEStreamDescriptor(&descriptor, pInStream, 0);
pInDoc = PtxPdf_Document_Open(&descriptor, _T(""));
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pInDoc, _T("Input file \"%s\" cannot be opened. %s (ErrorCode: 0x%08x).\n"),
szInPath, szErrorBuff, Ptx_GetLastError());
// 入力PDFの電子署名を取得
pSignatureFields = PtxPdf_Document_GetSignatureFields(pInDoc);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pSignatureFields,
_T("Failed to get signatures of input PDF. %s (ErrorCode: 0x%08x).\n"),
szErrorBuff, Ptx_GetLastError());
_tprintf(_T("Number of signature fields: %d\n"), PtxPdfForms_SignatureFieldList_GetCount(pSignatureFields));
for (int i = 0; i < PtxPdfForms_SignatureFieldList_GetCount(pSignatureFields); i++)
{
pSig = PtxPdfForms_SignatureFieldList_Get(pSignatureFields, i);
GOTO_CLEANUP_IF_NULL_PRINT_ERROR(pSig, _T("Failed to get signature. %s (ErrorCode: 0x%08x).\n"), szErrorBuff,
Ptx_GetLastError());
TPtxPdfForms_SignatureFieldType iFieldType = PtxPdfForms_SignatureField_GetType(pSig);
if (iFieldType == ePtxPdfForms_SignatureFieldType_Signature ||
iFieldType == ePtxPdfForms_SignatureFieldType_DocMdpSignature ||
iFieldType == ePtxPdfForms_SignatureFieldType_DocumentSignature)
{
// Name(名前)をリスト
size_t nName = PtxPdfForms_SignedSignatureField_GetName(pSig, NULL, 0);
_tprintf(_T("- %s fields"), PtxPdfForms_SignatureField_IsVisible(pSig) ? _T("Visible") : _T("Invisible"));
if (nName != 0)
{
TCHAR* szName = (TCHAR*)malloc(nName * sizeof(TCHAR));
if (szName != NULL)
{
PtxPdfForms_SignedSignatureField_GetName(pSig, szName, nName);
_tprintf(_T(", signed by: %s"), szName);
free(szName);
}
}
_tprintf(_T("\n"));
// Location(ロケーション)をリスト
size_t nLocation = PtxPdfForms_Signature_GetLocation(pSig, NULL, 0);
if (nLocation != 0)
{
TCHAR* szLocation = (TCHAR*)malloc(nLocation * sizeof(TCHAR));
if (szLocation != NULL)
{
PtxPdfForms_Signature_GetLocation(pSig, szLocation, nLocation);
_tprintf(_T(" - Location: %s\n"), szLocation);
free(szLocation);
}
}
// Reason(理由)をリスト
size_t nReason = PtxPdfForms_Signature_GetReason(pSig, NULL, 0);
if (nReason != 0)
{
TCHAR* szReason = (TCHAR*)malloc(nReason * sizeof(TCHAR));
if (szReason != NULL)
{
PtxPdfForms_Signature_GetReason(pSig, szReason, nReason);
_tprintf(_T(" - Reason: %s\n"), szReason);
free(szReason);
}
}
// Contact(連絡先)情報をリスト
size_t nContactInfo = PtxPdfForms_Signature_GetContactInfo(pSig, NULL, 0);
if (nContactInfo != 0)
{
TCHAR* szContactInfo = (TCHAR*)malloc(nContactInfo * sizeof(TCHAR));
if (szContactInfo != NULL)
{
PtxPdfForms_Signature_GetContactInfo(pSig, szContactInfo, nContactInfo);
_tprintf(_T(" - Contact info: %s\n"), szContactInfo);
free(szContactInfo);
}
}
// Date(日時)をリスト
if (PtxPdfForms_SignedSignatureField_GetDate(pSig, &date) == TRUE)
{
_tprintf(_T(" - Date: %02d-%02d-%d %02d:%02d:%02d%c%02d:%02d\n"), date.iYear, date.iMonth, date.iDay,
date.iHour, date.iMinute, date.iSecond, date.iTZSign >= 0 ? '+' : '-', date.iTZHour,
date.iTZMinute);
}
}
else
{
_tprintf(_T("- %s field, not signed\n"),
PtxPdfForms_SignatureField_IsVisible(pSig) ? _T("Visible") : _T("Invisible"));
}
}
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
SignatureFieldList signatureFields = inDoc.SignatureFields;
Console.WriteLine("Number of signature fields: {0}", signatureFields.Count);
foreach (SignatureField field in signatureFields)
{
if (field is Signature sig)
{
// Name(名前)をリスト
string name = sig.Name;
Console.WriteLine("- {0} fields, signed by: {1}",
sig.IsVisible ? "Visible" : "Invisible", name ?? "(Unknown name)");
// Location(ロケーション)をリスト
string location = sig.Location;
if (location != null)
Console.WriteLine(" - Location: {0}", location);
// Reason(理由)をリスト
string reason = sig.Reason;
if (reason != null)
Console.WriteLine(" - Reason: {0}", reason);
// Contact(連絡先)情報をリスト
string contactInfo = sig.ContactInfo;
if (contactInfo != null)
Console.WriteLine(" - Contact info: {0}", contactInfo);
// Date(日時)をリスト
DateTimeOffset? date = sig.Date;
if (date != null)
Console.WriteLine(" - Date: {0}", date.Value);
}
else
Console.WriteLine("- {0} field, not signed", field.IsVisible ? "Visible" : "Invisible");
}
}
def list_signatures(in_doc: Document):
# 署名フィールドのリストを取得
signature_fields = in_doc.signature_fields
print(f"Number of signature fields: {len(signature_fields)}")
for field in signature_fields:
if isinstance(field, Signature):
# Name(名前)をリスト
name = field.name or "(Unknown name)"
print(f"- {'Visible' if field.is_visible else 'Invisible'} field, signed by: {name}")
# Location(ロケーション)をリスト
if field.location:
print(f" - Location: {field.location}")
# Reason(理由)をリスト
if field.reason:
print(f" - Reason: {field.reason}")
# Contact(連絡先)情報をリスト
if field.contact_info:
print(f" - Contact info: {field.contact_info}")
# Date(日時)をリスト
if field.date:
print(f" - Date: {field.date}")
else:
print(f"- {'Visible' if field.is_visible else 'Invisible'} field, not signed")
# 入力PDFを開く
with io.FileIO(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
# PDF文書のすべての署名を一覧表示
list_signatures(in_doc)
PDF文書のアウトライン(Outline)からフォーマットされた目次を印刷します。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
PrintOutlineItems(inDoc.Outline, "", inDoc);
}
tatic void PrintOutlineItem(OutlineItem item, string indentation, Document document)
{
string title = item.Title;
Console.Out.Write("{0}{1}", indentation, title);
Destination dest = item.Destination;
if (dest != null)
{
int pageNumber = document.Pages.IndexOf(dest.Target.Page) + 1;
string dots = new string('.', 78 - indentation.Length - title.Length - pageNumber.ToString().Length);
Console.Out.Write(" {0} {1}", dots, pageNumber);
}
Console.Out.WriteLine();
PrintOutlineItems(item.Children, indentation + " ", document);
}
static void PrintOutlineItems(OutlineItemList outlineItems, string indentation, Document document)
{
foreach (var item in outlineItems)
PrintOutlineItem(item, indentation, document);
}
def print_outline_item(item: OutlineItem, indentation: str, in_doc: Document):
title = item.title
print(f"{indentation}{title}", end="")
dest = item.destination
if dest and dest.target:
page_number = in_doc.pages.index(dest.target.page) + 1
dots_length = max(0, 78 - len(indentation) - len(title) - len(str(page_number)))
dots = "." * dots_length
print(f" {dots} {page_number}", end="")
print() # 現在の行を終了
print_outline_items(item.children, indentation + " ", in_doc)
def print_outline_items(items: OutlineItemList, indentation: str, in_doc: Document):
for outline_item in items:
print_outline_item(outline_item, indentation, in_doc)
# 入力PDFを開く
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
print_outline_items(in_doc.outline, "", in_doc)
PDFからページごとに抽出したテキストをコンソールに書き込みます。
2つのテキストが同じ単語に属しているかどうかをヒューリスティックに判断します。
// 入力PDFを開く
using (Stream inStream = new FileStream(inPath, FileMode.Open, FileAccess.Read))
using (Document inDoc = Document.Open(inStream, null))
{
int pageNumber = 1;
// 各ページを処理
foreach (var inPage in inDoc.Pages)
{
Console.WriteLine("==========");
Console.WriteLine($"Page: {pageNumber++}");
Console.WriteLine("==========");
ContentExtractor extractor = new ContentExtractor(inPage.Content);
extractor.Ungrouping = UngroupingSelection.All;
// すべてのコンテンツ要素を反復処理し、テキスト要素のみを処理
foreach (ContentElement element in extractor)
if (element is TextElement textElement)
WriteText(textElement.Text);
}
}
private static void WriteText(Text text)
{
string textPart = "";
// すべてのテキストフラグメントを抽出
// 2つのテキストフラグメントを空白の有無で判断(英文の場合は単語ごとに空白で分割されるため)
for (int iFragment = 0; iFragment < text.Count; iFragment++)
{
TextFragment currFragment = text[iFragment];
if (iFragment == 0)
textPart += currFragment.Text;
else
{
TextFragment lastFragment = text[iFragment - 1];
if (currFragment.CharacterSpacing != lastFragment.CharacterSpacing ||
currFragment.FontSize != lastFragment.FontSize ||
currFragment.HorizontalScaling != lastFragment.HorizontalScaling ||
currFragment.Rise != lastFragment.Rise ||
currFragment.WordSpacing != lastFragment.WordSpacing)
textPart += $" {currFragment.Text}";
else
{
Point currentBotLeft = currFragment.Transform.TransformRectangle(currFragment.BoundingBox).BottomLeft;
Point beforeBotRight = lastFragment.Transform.TransformRectangle(lastFragment.BoundingBox).BottomRight;
if (beforeBotRight.X < currentBotLeft.X - 0.7 * currFragment.FontSize ||
beforeBotRight.Y < currentBotLeft.Y - 0.1 * currFragment.FontSize ||
currentBotLeft.Y < beforeBotRight.Y - 0.1 * currFragment.FontSize)
textPart += $" {currFragment.Text}";
else
textPart += currFragment.Text;
}
}
}
Console.WriteLine(textPart);
}
def write_text(text: Text):
"""Reconstruct text heuristically from text fragments."""
text_part = []
# すべてのテキストフラグメントを抽出
# 2つのテキストフラグメントを空白の有無で判断(英文の場合は単語ごとに空白で分割されるため)
for i_fragment, curr_fragment in enumerate(text):
if i_fragment == 0:
text_part.append(curr_fragment.text)
else:
last_fragment = text[i_fragment - 1]
# Determine if there's a space between fragments
if (curr_fragment.character_spacing != last_fragment.character_spacing or
curr_fragment.font_size != last_fragment.font_size or
curr_fragment.horizontal_scaling != last_fragment.horizontal_scaling or
curr_fragment.rise != last_fragment.rise or
curr_fragment.word_spacing != last_fragment.word_spacing):
text_part.append(f" {curr_fragment.text}")
else:
current_bot_left = curr_fragment.transform.transform_rectangle(curr_fragment.bounding_box).bottom_left
before_bot_right = last_fragment.transform.transform_rectangle(last_fragment.bounding_box).bottom_right
if (before_bot_right.x < current_bot_left.x - 0.7 * curr_fragment.font_size or
before_bot_right.y < current_bot_left.y - 0.1 * curr_fragment.font_size or
current_bot_left.y < before_bot_right.y - 0.1 * curr_fragment.font_size):
text_part.append(f" {curr_fragment.text}")
else:
text_part.append(curr_fragment.text)
print("".join(text_part))
# 入力PDFを開く
with open(input_file_path, "rb") as in_stream:
with Document.open(in_stream, None) as in_doc:
page_number = 1
# 各ページを処理
for in_page in in_doc.pages:
print(f"==========\nPage: {page_number}\n==========")
extractor = ContentExtractor(in_page.content)
extractor.ungrouping = UngroupingSelection.ALL
# すべてのコンテンツ要素を反復処理し、テキスト要素のみを処理
for element in extractor:
if isinstance(element, TextElement):
write_text(element.text)
page_number += 1
質問のページからお送りいただくようお願いします。
または、メールでsupport@trustss.co.jpあてにお送りください。
ご購入前の技術的質問も無償で対応します。サポート受付ページからお願いします。