PdfBoxでpdf変換

## PdfBoxを用いてテキストファイルをPDF変換

使用ライブラリ等: 
・pdfbox3.0.1
・juniversalchardet1.0.3
・文字コード GenShinGothic-Bold.ttf

# Mainクラス
```
package practice;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.mozilla.universalchardet.UniversalDetector;

public class Main {
	public static void main(String[] args) {
		try (PDDocument doc = new PDDocument()) {

	        PDPage page = new PDPage(PDRectangle.A4);
	        doc.addPage(page);
	        setupText(doc, page);

	        doc.save("C:\\Users\\hayaj\\OneDrive\\デスクトップ\\PDF変換\\output\\output.pdf");

	    } catch (IOException e) {
	        throw new RuntimeException(e);
	    }
	}
	
	private static void setupText(PDDocument doc, PDPage page) throws IOException {

	    PDFont font = PDType0Font.load(doc,
	            new File("C:\\Users\\hayaj\\OneDrive\\デスクトップ\\PDF変換\\GenShinGothic-Bold.ttf"));

	    try (PDPageContentStream cs = new PDPageContentStream(doc, page)) {

	        cs.beginText();
	        Paragraph para = new Paragraph(PDRectangle.A4.getWidth() - 100, font);
	        cs.newLineAtOffset(PDRectangle.A4.getLowerLeftX() + 50,
	                PDRectangle.A4.getUpperRightY() - 50);
	        para.drawString(cs, getText(), doc, page);

//	        cs.endText();

	    } catch (IOException e) {
	        throw new RuntimeException(e);
	    }
	}

	private static String getText() throws IOException {
		String filePath = "C:\\Users\\hayaj\\OneDrive\\デスクトップ\\PDF変換\\input\\eucjp.txt";
		String charCode = getCharCode(filePath);
		try {
            String fileContent = readFileToString(filePath, charCode);
            System.out.println("ファイルの内容:\n" + fileContent);
//            showCharCode();
            
            return fileContent;
        } catch (IOException e) {
            e.printStackTrace();
        }
		return null;
	}
	
	private static String readFileToString(String filePath, String charCode) throws IOException {
        StringBuilder content = new StringBuilder();

        BufferedReader reader = null;
        try {
//            reader = new BufferedReader(new FileReader(filePath));
        	reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), charCode));
            String line;

            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return content.toString();
    }
	
	private static String getCharCode(String filePath) throws IOException {
		byte[] buf = new byte[4096]; 
		java.io.FileInputStream fis = new java.io.FileInputStream(filePath);
		UniversalDetector detector = new UniversalDetector(null);
		// (2)
		int nread;
		while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
		  detector.handleData(buf, 0, nread);
		}
		// (3)
		detector.dataEnd();

		// (4)
		String encoding = detector.getDetectedCharset();
		if (encoding != null) {
		  System.out.println("Detected encoding = " + encoding);
		} else {
		  System.out.println("No encoding detected.");
		}

		// (5)
		detector.reset();
		return encoding;
	}

}
```

# Paragraphクラス
```
package practice;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;

public class Paragraph {

    private PDFont font;
    private float width;
    private int fontSize;

    public Paragraph(float width, PDFont font, int fontSize) {
        this.width = width;
        this.font = font;
        this.fontSize = fontSize;
    }

    public Paragraph(float width, PDFont font) {
        this(width, font, 12);
    }

    public void drawString(PDPageContentStream content, String text, PDDocument doc, PDPage page) {
        try {
            content.setFont(font, fontSize);
            int i=1;
            for (String line : lines(text)) {
//            	if(i%3==0) {
//            		content.showText("hi");
//            	}
                content.showText(line);
                content.setLeading(getFontHeight());
                content.newLine();
                i++;
                if(i==43) {
                	content.showText("43行目です。");
                	content.endText();
                	content.close();
                	page = new PDPage(PDRectangle.A4);
        	        doc.addPage(page);
        	        content = new PDPageContentStream(doc, page);
        	        content.beginText();
        	        Paragraph para = new Paragraph(PDRectangle.A4.getWidth() - 100, font);
        	        content.newLineAtOffset(PDRectangle.A4.getLowerLeftX() + 50,
        	                PDRectangle.A4.getUpperRightY() - 50);
        	        content.setFont(font, fontSize);
                }
                
            }
            content.endText();
            content.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    protected List<String> lines(String text) {
        List<String> lines = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            sb.append(text.charAt(i));
            if (protrude(sb.toString()) || text.charAt(i) == '\n') {
                if (prohibitedEnd(text.charAt(i))) {
                    sb.deleteCharAt(sb.length() - 1);
                    i--;
                } else if (i + 1 < text.length()
                        && prohibitedHead(text.charAt(i + 1))) {
                    i++;
                    sb.append(text.charAt(i));
                }
                lines.add(sb.toString().replaceAll("\\p{C}", ""));
                sb.setLength(0);
            }
        }
        if (sb.length() > 0) {
            lines.add(sb.toString().replaceAll("\\p{C}", ""));
        }
        return lines;
    }

    public float getFontHeight() {
        return font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
    }

    private boolean protrude(String line) {
        try {
            return (font.getStringWidth(line.replaceAll("\\p{C}", "")) / 1000 * fontSize) > width;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private boolean prohibitedHead(char c) {
        return ("!%)/,.:?]}¢°’”‰′″℃、。々〉》」』】〕ぁぃぅぇぉっゃゅょゎ゛゜ゝゞ" +
                "ァィゥェォッャュョヮヵヶ・ーヽヾ！％），．：；？］｝｡｣､･ｧｨｩｪｫｬｭｮｯｰﾞﾟ￠").contains(Character.toString(c));
    }

    private boolean prohibitedEnd(char c) {
        return "$([{£¥‘“〈《「『【〔＄（［｛｢￡￥".contains(Character.toString(c));
    }

}
```

# 依存関係
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3356057/2e2d1277-4c13-c3d3-2acd-93261c833e26.png)

# 追加　画像のpdf変換

```
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public class ImageToPDFConverter {

    public static void main(String[] args) {
        try {
            // 画像のパス
            String imagePath = "input.jpg";

            // PDFドキュメントを作成します
            PDDocument document = new PDDocument();

            // 新しいページを作成します（A4サイズ）
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            // ページにコンテンツを追加します
            PDPageContentStream contentStream = new PDPageContentStream(document, page);

            // 画像を読み込み、A4サイズに合わせて調整して描画します
            BufferedImage bufferedImage = ImageIO.read(new File(imagePath));
            PDImageXObject pdImage = LosslessFactory.createFromImage(document, bufferedImage);

            // 画像のサイズを取得
            float imageWidth = pdImage.getWidth();
            float imageHeight = pdImage.getHeight();

            // A4ページのサイズ
            float pageWidth = PDRectangle.A4.getWidth();
            float pageHeight = PDRectangle.A4.getHeight();

            // 画像をA4サイズに収めるためのスケーリング
            float scale = Math.min(pageWidth / imageWidth, pageHeight / imageHeight);

            // 画像を描画
            contentStream.drawImage(pdImage, 0, 0, imageWidth * scale, imageHeight * scale);

            // ページを閉じます
            contentStream.close();

            // PDFドキュメントを保存します
            document.save(new File("output.pdf"));

            // ドキュメントを閉じます
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

#タブ対応
```
protected List<String> lines(String text) {
    List<String> lines = new ArrayList<>();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < text.length(); i++) {
        char currentChar = text.charAt(i);

        if (currentChar == '\t') {
            // タブを必要に応じて処理
            int tabWidth = 4; // 好みのタブの幅を設定
            int spacesToNextTabStop = tabWidth - (sb.length() % tabWidth);
            sb.append(" ".repeat(spacesToNextTabStop));
        } else {
            sb.append(currentChar);
        }

        if (protrude(sb.toString()) || currentChar == '\n') {
            if (prohibitedEnd(currentChar)) {
                sb.deleteCharAt(sb.length() - 1);
                i--;
            } else if (i + 1 < text.length() && prohibitedHead(text.charAt(i + 1))) {
                i++;
                sb.append(text.charAt(i));
            }
            lines.add(sb.toString().replaceAll("\\p{C}", ""));
            sb.setLength(0);
        }
    }

    if (sb.length() > 0) {
        lines.add(sb.toString().replaceAll("\\p{C}", ""));
    }

    return lines;
}


int spacesToNextTabStop = tabWidth - (sb.length() % tabWidth);
sb.append(repeatSpaces(spacesToNextTabStop));
↓
private static String repeatSpaces(int count) {
    StringBuilder spaces = new StringBuilder();
    for (int i = 0; i < count; i++) {
        spaces.append(" ");
    }
    return spaces.toString();
}
```


# transparencyがnullの画像
```
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObjectFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ImageToPDFConverter {
    public static void main(String[] args) {
        try {
            PDDocument document = new PDDocument();
            PDPage page = new PDPage();
            document.addPage(page);

            PDPageContentStream contentStream = new PDPageContentStream(document, page);

            // 画像を読み込む（ここではファイルから読み込む例）
            BufferedImage bufferedImage = ImageIO.read(new File("path/to/your/image.png"));

            // 透明度がnullの場合、LosslessFactoryを使用して画像を作成
            PDImageXObject pdImageXObject = LosslessFactory.createFromImage(document, bufferedImage);

            // 画像をPDFに描画
            contentStream.drawImage(pdImageXObject, 100, 500);

            contentStream.close();

            // PDFを保存
            document.save("output.pdf");

            // ドキュメントを閉じる
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

# 透明度がnullの画像に透明性を与える
```
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

public class AddTransparency {
    public static BufferedImage addTransparency(BufferedImage originalImage) {
        // 新しいBufferedImageを透明な背景で作成
        BufferedImage newImage = new BufferedImage(
                originalImage.getWidth(),
                originalImage.getHeight(),
                BufferedImage.TYPE_INT_ARGB);

        // Graphics2Dオブジェクトを取得し、透明な背景を描画
        Graphics2D g2d = newImage.createGraphics();
        g2d.setColor(new Color(0, 0, 0, 0)); // 透明な色
        g2d.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());

        // 元の画像を新しい透明なBufferedImageに描画
        g2d.drawImage(originalImage, 0, 0, null);

        // Graphics2Dオブジェクトを閉じる
        g2d.dispose();

        return newImage;
    }

    public static void main(String[] args) {
        try {
            // 透明性がnullのBufferedImageを読み込む（ここでは例として作成）
            BufferedImage originalImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);

            // 透明性を追加
            BufferedImage imageWithTransparency = addTransparency(originalImage);

            // ここで imageWithTransparency を使って何かを行う

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

```
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class AddTransparency {
    public static BufferedImage addTransparency(File imageFile) {
        try {
            // 画像を読み込む
            BufferedImage originalImage = ImageIO.read(imageFile);

            // 新しいBufferedImageを透明な背景で作成
            BufferedImage newImage = new BufferedImage(
                    originalImage.getWidth(),
                    originalImage.getHeight(),
                    BufferedImage.TYPE_INT_ARGB);

            // Graphics2Dオブジェクトを取得し、透明な背景を描画
            Graphics2D g2d = newImage.createGraphics();
            g2d.setColor(new Color(0, 0, 0, 0)); // 透明な色
            g2d.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());

            // 元の画像を新しい透明なBufferedImageに描画
            g2d.drawImage(originalImage, 0, 0, null);

            // Graphics2Dオブジェクトを閉じる
            g2d.dispose();

            return newImage;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        try {
            // 透明性がnullのBufferedImageを読み込む（ここでは例として作成）
            File imageFile = new File("path/to/your/image.png");

            // 透明性を追加
            BufferedImage imageWithTransparency = addTransparency(imageFile);

            // ここで imageWithTransparency を使って何かを行う

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

```
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;

public class ImageToPDFConverter {

    public static void main(String[] args) {
        try {
            convertImageToPDF("path/to/image.jpg", "output.pdf");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void convertImageToPDF(String imagePath, String pdfPath) throws IOException {
        PDDocument document = new PDDocument();
        PDPage page = new PDPage();
        document.addPage(page);

        BufferedImage bufferedImage = readImage(new File(imagePath).toPath());

        try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
            float width = page.getMediaBox().getWidth();
            float height = page.getMediaBox().getHeight();
            contentStream.drawImage(bufferedImage, 0, 0, width, height);
        }

        document.save(pdfPath);
        document.close();
    }

    public static BufferedImage readImage(Path imagePath) throws IOException {
        try (ImageInputStream imageInputStream = ImageIO.createImageInputStream(imagePath.toFile())) {
            return ImageIO.read(imageInputStream);
        }
    }
}
```