はじめに (対象読者・この記事でわかること)

この記事は、Java言語での開発経験がある方、iTextライブラリを利用してPDFを作成している方、そしてPDFのアクセシビリティ向上に関心がある方を対象としています。特に、公共機関や企業でPDF/UA準拠の文書作成が求められる開発者や、より多くの人がアクセスできる情報提供を目指す方に役立つ内容です。

この記事を読むことで、PDF/UAの基本的な概念を理解し、iText 7ライブラリを使用してPDF/UA互換のPDF文書を作成するための具体的な手順とコード例を習得できます。タグ付きPDFの重要性や、見出し、段落、画像といった主要なコンテンツをアクセシブルにするための設定方法がわかり、誰もが情報にアクセスしやすいPDF文書を実装できるようになります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 * Javaプログラミングの基本的な知識 * iTextライブラリ(特にiText 7)の基本的なPDF作成経験 * MavenまたはGradleなどのビルドツールの基本的な操作

PDF/UAとは?なぜ今、アクセシブルなPDFが必要なのか

今日のデジタル社会において、誰もが等しく情報にアクセスできる「ウェブアクセシビリティ」は非常に重要なテーマとなっています。これはウェブサイトだけでなく、PDF文書にも当てはまります。ここで登場するのが「PDF/UA」です。

PDF/UAは、ISO標準(ISO 14289-1)として定められた、アクセシビリティを目的としたPDFの国際標準規格です。UAは「Universal Accessibility(ユニバーサルアクセシビリティ)」の略称であり、その名の通り、すべての人がPDFコンテンツにアクセスできることを目指しています。

PDF/UA準拠のPDFは、「タグ付きPDF(Tagged PDF)」であることがその根幹にあります。タグ付きPDFとは、文書の論理構造(見出し、段落、リスト、テーブルなど)や各コンテンツの意味(画像の説明、表のヘッダーなど)が構造タグによって明確に定義されたPDFのことです。これにより、スクリーンリーダーなどの支援技術がPDFの内容を正しく解釈し、視覚障害者や読み書きに困難を抱える人々でも、内容を音声で聞いたり、点字ディスプレイで読んだりすることが可能になります。

なぜ今、アクセシブルなPDFが必要なのでしょうか?その背景には、以下のような要因があります。 * 法的要件の増加: 世界中でアクセシビリティに関する法規制が強化されています。例えば、米国のADA(障害を持つアメリカ人法)、EUのウェブアクセシビリティ指令、そして日本の障害者差別解消法の改正など、公共機関や一部の民間企業において、ウェブコンテンツやデジタル文書のアクセシビリティ対応が義務付けられるケースが増えています。 * 社会的責任と企業イメージ向上: 障害を持つ人々を含め、すべての利用者が情報にアクセスできる環境を提供することは、企業の社会的責任(CSR)の一環として重要視されています。アクセシブルな情報提供は、企業のブランドイメージ向上にも繋がります。 * より良い利用者体験: アクセシビリティは障害を持つ利用者だけでなく、高齢者、一時的な身体的制約がある人、あるいはデバイスや環境によってコンテンツへのアクセスが制限されるすべての人にとって有益です。コンテンツの構造が明確であることは、検索エンジン最適化(SEO)にも良い影響を与えます。

iTextライブラリは、PDF/UA標準に準拠したPDFを作成するための強力な機能を提供しています。次のセクションでは、実際にJavaとiTextを使ってPDF/UA互換PDFを作成する具体的な手順を解説します。

JavaとiTextでPDF/UA互換PDFを作成する具体的な手順

PDF/UA互換PDFを作成する際の鍵は、PDF文書内に適切な論理構造(タグ)を埋め込み、各コンテンツに意味を与えることです。iText 7では、このタグ付け作業をプログラム的に行い、簡単にPDF/UA準拠の文書を生成できます。

ステップ1: iTextのセットアップとPDF/UA対応PDFの初期化

まず、プロジェクトにiTextライブラリを追加し、基本的なPDF文書をPDF/UA対応として初期化します。

依存関係の追加 (Maven)

pom.xml に以下の依存関係を追加します。iText 7はモジュール化されているため、基本的なkernel, layoutに加えて、PDF/UA対応のためのpdfuaモジュールが必要です。

Xml
<dependencies> <dependency> <groupId>com.itextpdf</groupId> <artifactId>kernel</artifactId> <version>7.x.x</version> <!-- 最新の安定版バージョンを指定 --> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>layout</artifactId> <version>7.x.x</version> <!-- kernelと同じバージョンを指定 --> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>pdfua</artifactId> <version>7.x.x</version> <!-- kernelと同じバージョンを指定 --> </dependency> </dependencies>

7.x.x の部分は、使用するiText 7の最新の安定版バージョンに置き換えてください(例: 7.2.5)。

PDF/UA対応PDFの初期化

PDF/UA互換PDFを作成するためには、いくつかの重要な設定が必要です。

Java
import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.properties.Language; import java.io.FileNotFoundException; public class PdfUaCreator { public static final String DEST = "output/pdf_ua_document.pdf"; public static void main(String[] args) throws FileNotFoundException { // PdfWriterを初期化し、出力ファイルを指定 PdfWriter writer = new PdfWriter(DEST); // PdfDocumentをPdfWriterから生成し、PDF/UA-1レベルの準拠を設定 // これにより、PDF/UAの要件を満たすようiTextに指示 PdfDocument pdf = new PdfDocument(writer, PdfAConformanceLevel.PDF_UA_1); // タグ構造を有効化 // PDF/UAはタグ付きPDFが必須なので、この設定は不可欠 pdf.setTagged(); // ドキュメントの言語を設定(重要!) // スクリーンリーダーが正しい言語で読み上げるために必要 // (LocaleオブジェクトではなくiTextのLanguageオブジェクトを使用) Document document = new Document(pdf); document.setLanguage(new Language("ja-JP")); // 日本語の例 // ドキュメントのタイトルをメタデータとして設定(PDF/UA要件) // Adobe Acrobat Proなどで確認可能 pdf.getDocumentInfo().setTitle("JavaとiTextで作成したPDF/UA互換文書"); pdf.getDocumentInfo().setAuthor("Kousukei"); // ここからコンテンツを追加していく document.add(new Paragraph("Hello PDF/UA World!")); // ドキュメントを閉じる document.close(); System.out.println("PDF/UA互換PDFが作成されました: " + DEST); } }

上記のコードでは、以下の重要な設定を行っています。 * PdfWriter(DEST, PdfAConformanceLevel.PDF_UA_1): PDF/UA-1の準拠レベルを指定してPdfDocumentを初期化します。 * pdf.setTagged(): PDFがタグ付きドキュメントであることをiTextに宣言します。これにより、後続のコンテンツ追加時にタグが自動的、または明示的に追加されるようになります。 * document.setLanguage(new Language("ja-JP")): ドキュメント全体の言語を設定します。これはスクリーンリーダーがコンテンツを正しく読み上げるために非常に重要です。

ステップ2: 構造化タグの追加とコンテンツのマークアップ

PDF/UAにおいて最も重要なのが、文書内のコンテンツに見出し、段落、リスト、画像などの「構造タグ」を適切に付与することです。iText 7では、layoutモジュールの要素(Paragraph, Image, Listなど)にsetRole()メソッドを使ってこれらのタグを割り当てます。

Java
import com.itextpdf.kernel.pdf.PdfAConformanceLevel; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Image; import com.itextpdf.layout.element.List; import com.itextpdf.layout.element.ListItem; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.element.Cell; import com.itextpdf.layout.properties.Language; import com.itextpdf.layout.properties.StandardRoles; import com.itextpdf.io.image.ImageDataFactory; import java.io.FileNotFoundException; import java.net.MalformedURLException; public class PdfUaContentCreator { public static final String DEST = "output/pdf_ua_rich_document.pdf"; public static final String IMAGE_PATH = "src/main/resources/itext_logo.png"; // 画像ファイルのパス public static void main(String[] args) throws FileNotFoundException, MalformedURLException { PdfWriter writer = new PdfWriter(DEST); PdfDocument pdf = new PdfDocument(writer, PdfAConformanceLevel.PDF_UA_1); pdf.setTagged(); Document document = new Document(pdf); document.setLanguage(new Language("ja-JP")); pdf.getDocumentInfo().setTitle("JavaとiTextで作成したPDF/UA互換文書(構造化コンテンツ)"); pdf.getDocumentInfo().setAuthor("Kousukei"); // 1. 見出し (H1, H2) Paragraph h1 = new Paragraph("PDF/UA互換文書の作成ガイド") .setFontSize(24) .setRole(StandardRoles.H1); // H1タグを設定 document.add(h1); Paragraph p1 = new Paragraph("この文書では、iText 7とJavaを用いてPDF/UA互換のアクセシブルなPDFを作成する手順を解説します。") .setRole(StandardRoles.P); // Pタグを設定 document.add(p1); Paragraph h2_1 = new Paragraph("1. 基本設定と初期化") .setFontSize(18) .setRole(StandardRoles.H2); // H2タグを設定 document.add(h2_1); Paragraph p2 = new Paragraph("PDF/UA準拠のためには、`setTagged()`メソッドと`PdfAConformanceLevel`の設定が不可欠です。また、ドキュメントの言語設定も重要となります。") .setRole(StandardRoles.P); document.add(p2); // 2. リスト (UL, LI) Paragraph h2_2 = new Paragraph("2. 主要なタグの種類") .setFontSize(18) .setRole(StandardRoles.H2); document.add(h2_2); List list = new List() .setRole(StandardRoles.L); // リスト全体のタグを設定 list.add(new ListItem("見出し (H1-H6)").setRole(StandardRoles.LI)); // リストアイテムのタグを設定 list.add(new ListItem("段落 (P)").setRole(StandardRoles.LI)); list.add(new ListItem("リスト (L, LI)").setRole(StandardRoles.LI)); list.add(new ListItem("画像 (Figure)").setRole(StandardRoles.LI)); list.add(new ListItem("テーブル (Table, TH, TR, TD)").setRole(StandardRoles.LI)); document.add(list); // 3. 画像 (Figure) Paragraph h2_3 = new Paragraph("3. 画像の追加") .setFontSize(18) .setRole(StandardRoles.H2); document.add(h2_3); // 画像データを読み込み Image img = new Image(ImageDataFactory.create(IMAGE_PATH)); img.setWidth(100); // 画像のサイズ調整 img.setRole(StandardRoles.FIGURE); // Figureタグを設定 img.setAltText("iTextのロゴマーク。青い文字でiTextと書かれている"); // 代替テキストを設定(重要!) document.add(img); Paragraph p3 = new Paragraph("画像には必ず代替テキスト(alt text)を設定し、スクリーンリーダーが内容を読み上げられるようにします。") .setRole(StandardRoles.P); document.add(p3); // 4. テーブル (Table, TR, TH, TD) Paragraph h2_4 = new Paragraph("4. テーブルの作成") .setFontSize(18) .setRole(StandardRoles.H2); document.add(h2_4); Table table = new Table(new float[]{100, 100, 100}) .setRole(StandardRoles.TABLE); // Tableタグを設定 // ヘッダー行 table.addHeaderCell(new Cell().add(new Paragraph("項目")).setRole(StandardRoles.TH).setScope(StandardRoles.COLUMN)); table.addHeaderCell(new Cell().add(new Paragraph("説明")).setRole(StandardRoles.TH).setScope(StandardRoles.COLUMN)); table.addHeaderCell(new Cell().add(new Paragraph("ステータス")).setRole(StandardRoles.TH).setScope(StandardRoles.COLUMN)); // データ行 table.addCell(new Cell().add(new Paragraph("設定1")).setRole(StandardRoles.TD)); table.addCell(new Cell().add(new Paragraph("初期設定")).setRole(StandardRoles.TD)); table.addCell(new Cell().add(new Paragraph("完了")).setRole(StandardRoles.TD)); table.addCell(new Cell().add(new Paragraph("設定2")).setRole(StandardRoles.TD)); table.addCell(new Cell().add(new Paragraph("詳細設定")).setRole(StandardRoles.TD)); table.addCell(new Cell().add(new Paragraph("未完了")).setRole(StandardRoles.TD)); document.add(table); Paragraph p4 = new Paragraph("テーブルもタグ付けを行い、ヘッダーセルにはスコープ属性を設定することで、支援技術がテーブル構造を理解しやすくなります。") .setRole(StandardRoles.P); document.add(p4); document.close(); System.out.println("構造化されたPDF/UA互換PDFが作成されました: " + DEST); } }

注意点: 上記コードを実行するには、src/main/resources/ ディレクトリに itext_logo.png という画像ファイルを用意しておく必要があります。

主要なタグとiTextでの設定方法

  • 見出し (H1H6): Paragraph オブジェクトに setRole(StandardRoles.H1) のように設定します。適切な階層構造を守りましょう。
  • 段落 (P): Paragraph オブジェクトに setRole(StandardRoles.P) を設定します。
  • リスト (L, LI): List オブジェクトに setRole(StandardRoles.L)ListItem オブジェクトに setRole(StandardRoles.LI) を設定します。
  • 画像 (Figure): Image オブジェクトに setRole(StandardRoles.FIGURE) を設定し、必ず setAltText("代替テキスト") で代替テキストを指定します。代替テキストは、画像の内容を簡潔に説明するものでなければなりません。
  • テーブル (Table, TH, TR, TD): Table オブジェクトに setRole(StandardRoles.TABLE) を設定します。Cell には setRole(StandardRoles.TH) (ヘッダーセル) または setRole(StandardRoles.TD) (データセル) を設定します。ヘッダーセルには setScope(StandardRoles.COLUMN)setScope(StandardRoles.ROW) を設定して、それがどの範囲のヘッダーであるかを示します。

ステップ3: メタデータとドキュメント情報の追加

PDF/UAでは、文書のタイトルや作成者などの基本的なメタデータもアクセシビリティ要件の一部です。これらはPdfDocumentgetDocumentInfo()メソッドを通じて設定できます。

Java
// すでにステップ1のコードに含まれていますが、改めて強調 pdf.getDocumentInfo().setTitle("JavaとiTextで作成したPDF/UA互換文書"); // 文書のタイトル pdf.getDocumentInfo().setAuthor("Kousukei"); // 作成者 // 必要に応じて追加情報を設定できます // pdf.getDocumentInfo().setSubject("PDF/UAに関する技術解説"); // pdf.getDocumentInfo().setKeywords("Java, iText, PDF/UA, アクセシビリティ");

これらの情報は、Adobe Acrobat ProなどのPDFリーダーで文書のプロパティを確認する際に表示されます。

ハマった点やエラー解決

PDF/UA準拠のPDFを作成する際によく遭遇する問題と、その解決策をいくつか紹介します。

エラー1: 「Content does not conform to any tag structure」

状況: PDF/UA準拠チェックツールでこの警告が表示される場合、文書内のコンテンツが適切にタグ付けされていない可能性が高いです。

解決策: * pdf.setTagged()の確認: PdfDocumentを初期化した後、必ずpdf.setTagged()を呼び出してタグ構造を有効にしているか確認してください。これが抜けていると、以降のタグ付けが無視されます。 * 各コンテンツへのsetRole()の適用: Paragraph, Image, List, Tableなどの各レイアウト要素にsetRole(StandardRoles.XXX)が適切に設定されているか確認してください。例えば、段落はsetRole(StandardRoles.P)、見出しはsetRole(StandardRoles.H1)などです。 * すべてのコンテンツのタグ付け: PDF/UAでは、原則として文書内のすべての意味のあるコンテンツがタグ付けされている必要があります。テキスト、画像、表など、一つ残らずタグ付けされているか確認しましょう。

エラー2: 「Required entry 'Lang' missing」または「Primary language not set」

状況: ドキュメントの言語が設定されていない場合に表示されるエラーです。スクリーンリーダーがどの言語でコンテンツを読み上げるべきか判断できないため、重要なアクセシビリティ要件です。

解決策: * document.setLanguage()の適用: Documentオブジェクトを初期化した後、必ずdocument.setLanguage(new Language("言語コード"))を呼び出して文書の主要言語を設定してください。例えば日本語ならnew Language("ja-JP")、英語ならnew Language("en-US")です。

エラー3: 画像に代替テキストがない

状況: PDF/UAでは、画像などの非テキストコンテンツには必ず代替テキストが必要です。これが不足していると、視覚障害者が画像の内容を理解できません。

解決策: * image.setAltText()の適用: Imageオブジェクトを作成した後、image.setAltText("画像の説明")メソッドを呼び出し、画像の内容を簡潔に説明する代替テキストを設定してください。装飾的な画像など、コンテンツとして意味を持たない場合は、空の文字列""を設定することもありますが、その場合でもsetAltTextは呼び出す必要があります。

これらの一般的な問題と解決策を理解しておくことで、PDF/UA互換PDF作成時のデバッグが容易になります。

まとめ

本記事では、JavaとiTextライブラリを用いてPDF/UA互換のアクセシブルなPDF文書を作成する具体的な方法について解説しました。

  • PDF/UAの重要性: 法的要件の増加や社会的責任の高まりから、誰もがアクセスできるPDF文書の提供が不可欠であることを理解しました。
  • iText 7での基本設定: PdfAConformanceLevel.PDF_UA_1の指定、pdf.setTagged()によるタグ構造の有効化、そしてdocument.setLanguage()による言語設定がPDF/UA準拠の出発点となることを学びました。
  • 構造化タグの適用: 見出し、段落、リスト、画像、テーブルといった主要なコンテンツ要素に対し、setRole()setAltText()メソッドを使って適切な論理構造タグを付与する具体的な手順とコード例を確認しました。

この記事を通して、あなたはPDF/UA対応PDF作成の基本的なスキルを習得し、より多くの人々が情報にアクセスできるデジタル文書を提供するための一歩を踏み出せたことでしょう。アクセシビリティを考慮した開発は、すべての人にとってより良いユーザー体験を創造することに繋がります。

今後は、より複雑なレイアウトにおけるアクセシビリティ対応(例えば、フォームフィールドのタグ付けや、複雑なテーブル構造、脚注・参照のタグ付けなど)、またはPDF/UA準拠を自動化するためのテストフレームワークの構築など、発展的な内容についても記事にする予定です。

参考資料