入力PDF文書からコンテンツを削除(または墨消し)し、出力文書に存在しないようにできます。
指定のページ、またはテキスト、画像、パスなどのコンテンツを削除できます。
テキストから個々の文字(グリフ)を削除または置換することで、対象を絞った墨消し処理を適用することもできます。
Toolbox Add-onのAPIリファレンスはこちらです。(すべて英文)
C#のサンプルプロジェクトではPdftools SDK(Toolbox Add-on)ライブラリ(DLL)をNuGetから自動でダウンロードします。
CのサンプルプロジェクトにはPdftools SDK(Toolbox Add-on)ライブラリ(DLL)が含まれています。
License Agreement(利用許諾契約書)が含まれていますので必ず確認してください。
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)
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にコピーする際に、先頭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);
// 入力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を開く
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)
他の機能サンプルを参照してください。
質問のページからお送りいただくようお願いします。
または、メールでsupport@trustss.co.jpあてにお送りください。
ご購入前の技術的質問も無償で対応します。サポート受付ページからお願いします。