JavaでPDFの添付ファイルを追加、抽出、削除する方法

PDFは汎用的なファイル形式です。そのページ上に表示される内容に加えて、保存容器としても使用することができます。他のファイルを添付して、後で取り出すことができます。外部リンクを使用するよりもPDFにファイルを添付することの利点は、PDFを別の場所に移動しても添付ファイルが一緒に移動することです。今回は、無料の[Free Spire.PDF for Java](https://jp.e-iceblue.com/introduce/free-spire-pdf-for-java.html)を使って、Javaで**PDF文書に添付ファイルを追加、抽出、削除する方法**を紹介します。

- **[PDFに添付ファイルを追加する](#pdfに添付ファイルを追加する)**
- **[PDFから添付ファイルを抽出する](#pdfから添付ファイルを抽出する)**
- **[PDFの添付ファイルを削除する](#pdfの添付ファイルを削除する)**

## 【依存関係の追加】
この方法は、無料のFree Spire.PDF for Javaが必要ですので、先にjarファイルをインポートしてください。

### 1. Maven
Maven を使用している場合、プロジェクトの pom.xml ファイルに以下のコードを追加することで、簡単にアプリケーションに JAR ファイルをインポートすることができます。

```XML
<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.pdf.free</artifactId>
        <version>5.1.0</version>
    </dependency>
</dependencies>
```

### 2. 公式サイトよりJarファイルをダウンロード
まず、[Free Spire.PDF for Java](https://jp.e-iceblue.com/download/free-spire-pdf-for-java.html) の公式サイトよりzipファイルをダウンロードします。zipファイルを解凍し、libフォルダの下にあるSpire.Pdf.jarファイルを依存関係としてプロジェクトにインポートしてください。

## PDFに添付ファイルを追加する
PDF文書にファイルを添付する方法には、「添付ファイル」パネルでファイルを添付する方法と、注釈としてファイルを添付する方法があります。
> **この2種類の添付ファイルを追加する手順は、以下のとおりです。**

- **PdfDocument** クラスのオブジェクトを作成し、**PdfDocument.loadFromFile()** メソッドでPDFファイルを読み込みます。
- あるファイルを元にした **PdfAttachment** のオブジェクトを作成します。
- **PdfDocument.getAttachments().add()** メソッドでそのファイルを「添付ファイル」パネルに添付します。
- 特定のファイルに基づいた **PdfAttachmentAnnotation** のオブジェクトを作成し、**PdfPageBase.getAnnotationsWidget().add()** メソッドを使用して特定のページにそれを追加します。この添付ファイルは、「添付ファイル」パネルに表示され、またページ上の注釈として表示されます。
- **PdfDocument.saveToFile()** メソッドでドキュメントを保存します。

**Java**

```Java
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.annotations.*;
import com.spire.pdf.attachments.PdfAttachment;
import com.spire.pdf.graphics.*;
import com.spire.pdf.PdfDocument;

import java.awt.*;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class attachFiles {

    public static void main(String[] args) throws IOException {

        //PdfDocument クラスのオブジェクトを作成する
        PdfDocument doc = new PdfDocument();

        //PDFファイルを読み込む
        doc.loadFromFile("営業報告書.pdf");

        //PDFにファイルを添付する
        PdfAttachment attachment = new PdfAttachment("営業データ.xlsx");
        doc.getAttachments().add(attachment);

        //特定のページを取得する
        PdfPageBase page = doc.getPages().get(0);

        //PDFにラベルを描画する
        String label = "これが当社の次年度の事業計画です。";
        PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("Yu Mincho Demibold", Font.PLAIN, 13));
        double x = 35;
        double y = doc.getPages().get(0).getActualSize().getHeight() - 280;
        page.getCanvas().drawString(label, font, PdfBrushes.getRed(), x, y);

        //注釈としてファイルを添付する
        String filePath = "次年度の事業計画.pptx";
        byte[] data = toByteArray(filePath);
        Dimension2D size = font.measureString(label);
        Rectangle2D bound = new Rectangle2D.Float((float) (x + size.getWidth() + 5), (float) y, 10, 15);
        PdfAttachmentAnnotation annotation = new PdfAttachmentAnnotation(bound, filePath, data);
        annotation.setColor(new PdfRGBColor(new Color(0, 128, 128)));
        annotation.setFlags(PdfAnnotationFlags.Default);
        annotation.setIcon(PdfAttachmentIcon.Graph);
        annotation.setText("ファイルを開くには、こちらをクリックしてください。");
        page.getAnnotationsWidget().add(annotation);

        //ドキュメントを保存する
        doc.saveToFile("添付ファイル.pdf");
    }

    //ファイルをバイト配列に変換する
    public static byte[] toByteArray(String filePath) throws IOException {

        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("ファイルサイズが大きすぎる...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }

        if (offset != buffer.length) {
            throw new IOException("ファイルを完全に読み取れませんでした "
                    + file.getName());
        }
        fi.close();
        return buffer;
    }
}
```

### 【出力されるPDFドキュメント】

![PDFに添付ファイルを追加する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/f1eff32d-215d-6d3c-a52d-4281c6e42b6e.png)

## PDFから添付ファイルを抽出する
「添付ファイル」タブの添付ファイルと注釈の添付ファイルは異なるものであるため、抽出方法も異なります。
> **以下の手順では、Free Spire.PDF for Javaを使用して、この2種類の添付ファイルを抽出する方法を説明します。**

- **PdfDocument** クラスのオブジェクトを作成し、**PdfDocument.loadFromFile()** メソッドでPDFファイルを読み込みます。
- **PdfDocument.getAttachments()** メソッドを使用して、ドキュメントから添付ファイルのコレクション（注釈添付ファイルを含まない）を取得します。
- **PdfAttachmentCollection.get()** メソッドで特定の添付ファイルを取得し、**PdfAttachment.getData()** メソッドでそのデータを取得します。データをファイルに書き出し、保存します。
- **PdfPageBase.getAnnotationsWidget()** メソッドでドキュメントから注釈コレクションを取得し、ある注釈が添付ファイル注釈であるかどうかを判定します。添付ファイルであれば、その注釈をファイルに書き出し、指定されたフォルダに保存します。

**Java**

```Java
import com.spire.pdf.PdfDocument;
import com.spire.pdf.annotations.*;
import com.spire.pdf.attachments.PdfAttachmentCollection;

import java.io.*;

public class extractAttachments {

    public static void main(String[] args) throws Exception {

        //PdfDocument クラスのオブジェクトを作成する
        PdfDocument doc = new PdfDocument();

        //添付ファイルを含むPDFファイルを読み込む
        doc.loadFromFile("添付ファイル.pdf");

        //PDF 文書の添付ファイルコレクションを取得する
        PdfAttachmentCollection attachments = doc.getAttachments();

        //コレクションをループする
        for (int i = 0; i < attachments.getCount(); i++) {

            //出力ファイルのパスと名前を指定する
            File file = new File("添付ファイル\\" + attachments.get(i).getFileName());
            OutputStream output = new FileOutputStream(file);
            BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);

            //特定の添付ファイルを取得し、ファイルに書き込む
            bufferedOutput.write(attachments.get(i).getData());
            bufferedOutput.close();
        }

        //ページをループする
        for (int i = 0; i < doc.getPages().getCount(); i++) {

            //注釈コレクションを取得する
            PdfAnnotationCollection collection = doc.getPages().get(i).getAnnotationsWidget();

            //コレクションをループする
            for (Object annotation : collection) {

                //注釈がPdfAttachmentAnnotationWidgetクラスのインスタンスであるかどうかを判定する
                if (annotation instanceof PdfAttachmentAnnotationWidget) {

                    //注釈の添付ファイルを保存する
                    File file = new File("添付ファイル\\" + ((PdfAttachmentAnnotationWidget) annotation).getText());
                    OutputStream output = new FileOutputStream(file);
                    BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
                    bufferedOutput.write(((PdfAttachmentAnnotationWidget) annotation).getData());
                    bufferedOutput.close();
                }
            }
        }
    }
}
```

### 【出力されるPDFドキュメント】

![PDFから添付ファイルを抽出する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/cc438a3e-1289-38cb-05cd-7d2f949615ad.png)

## PDFの添付ファイルを削除する
> **Free Spire.PDF for Javaを使用して、PDF文書から添付ファイルを削除する手順を説明します。**

- **PdfDocument** クラスのオブジェクトを作成し、**PdfDocument.loadFromFile()** メソッドでPDFファイルを読み込みます。
- **PdfDocument.getAttachments()** メソッドを使用して、ドキュメントから添付ファイルのコレクション（注釈添付ファイルを含まない）を取得します。
- **PdfAttachmentCollection.clear()** メソッドを用いて、すべての添付ファイルを削除します。または、**PdfAttachmentCollection.removeAt(index)** メソッドを使用して、特定の添付ファイルを削除することができます。
- 特定のページから注釈添付ファイルを削除するには、まず **PdfPageBase.getAnnotationsWidget()** メソッドを使用してドキュメントから注釈コレクションを取得し、その注釈が添付ファイル注釈であるかどうかを判断します。もしそうであれば、**PdfAnnotationCollection.remove()** メソッドでその注釈を削除します。
- **PdfDocument.saveToFile()** メソッドでドキュメントを保存します。

**Java**

```Java
import com.spire.pdf.PdfDocument;
import com.spire.pdf.annotations.PdfAnnotation;
import com.spire.pdf.annotations.PdfAnnotationCollection;
import com.spire.pdf.annotations.PdfAttachmentAnnotationWidget;
import com.spire.pdf.attachments.PdfAttachmentCollection;

public class removeAttachments {

    public static void main(String[] args) {

        //PdfDocument クラスのオブジェクトを作成する
        PdfDocument doc = new PdfDocument();

        //PDFファイルを読み込む
        doc.loadFromFile("添付ファイル.pdf");

        //注釈の添付ファイルを含まない添付ファイルコレクションを取得する
        PdfAttachmentCollection attachments = doc.getAttachments();

        //すべての添付ファイルを削除する
        attachments.clear();

        //特定の添付ファイルを削除する
        //attachments.removeAt(0);

        //ドキュメントから注釈の添付を削除する
        removeAnnotationAttachment(doc);

        //ドキュメントを保存する
        doc.saveToFile("添付ファイルの削除.pdf");
        doc.close();
    }

    public static void removeAnnotationAttachment(PdfDocument doc){

        //ページをループする
        for (int i = 0; i < doc.getPages().getCount(); i++) {

            //注釈のコレクションを取得する
            PdfAnnotationCollection annotationCollection = doc.getPages().get(i).getAnnotationsWidget();

            //注釈をループする
            for (Object annotation: annotationCollection) {

                //アノテーションがPdfAttachmentAnnotationWidgetクラスのインスタンスであるかどうかを判定する
                if (annotation instanceof PdfAttachmentAnnotationWidget){

                    //添付ファイルのアノテーションを削除する
                    annotationCollection.remove((PdfAnnotation) annotation);
                }
            }
        }
    }
}
```

### 【出力されるPDFドキュメント】

![PDFの添付ファイルを削除する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/f52b3003-1604-6543-3bfa-8eae7d97110b.png)

> **上記は、PDFファイルに添付ファイルを追加、抽出、および削除する方法の詳細な手順です。あなたはまだこの記事を読んだ後に何か問題がある場合は、[Spire.PDF Forum](https://www.e-iceblue.com/forum/spire-pdf-f7.html)に移動してください。**