Convert Html to PDF (openhtmltopdf)

유재영·2024년 5월 22일
0
post-thumbnail
post-custom-banner

이전 작성글에서 spire.pdf.free 라이브러리를 이용하여 HTML 을 pdf 로 변환했었는데 페이지수 등에 제약이 있어. 오픈소스인 openhtmltopdf 라이브러리로 구현해보았다.

  • 구현환경
    maven, java 17, springBoot
  • pom.xml : 라이브러리추가
<!-- OpenHtmlToPDF -->
<dependency>
  <groupId>com.openhtmltopdf</groupId>
  <artifactId>openhtmltopdf-core</artifactId>
  <version>1.0.10</version>
</dependency>
<dependency>
  <groupId>com.openhtmltopdf</groupId>
  <artifactId>openhtmltopdf-pdfbox</artifactId>
  <version>1.0.10</version>
</dependency>
  • 프로젝트 구조

  • 테스트용 html 파일

테이블이나 스타일, 폰트, 이미지가 제대로 표시되는지 확인 할 것입니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8"/>
	<title>Title</title>
	<link type="text/css" rel="stylesheet" href="http://localhost:8080/css/pdfStyle.css"/>
	<style>
        .red{color: red;}
	</style>
</head>
<body class="border">
	<h1>html to pdf</h1>
	<p class="green">샘플 테이블</p>
	<table class="border">
		<thead>
		<tr>
			<th class="red">th1</th>
			<th>th2</th>
		</tr>
		</thead>
		<tbody>
		<tr>
			<td>td1</td>
			<td>td2</td>
		</tr>
		<tr>
			<td>한글한글</td>
			<td>한글</td>
		</tr>
		</tbody>
	</table>
	<p class="NotoSansKR">noto-sans-kr 서체 적용 테스트</p>
	<p class="NotoSansKR-Bold">noto-sans-kr-bold 서체 적용 테스트</p>
	<p class="NanumGothic">나눔고딕</p>
	<p class="YnPeople-Gothic">유앤피플 고딕체</p>
	<p>기본폰트(NotoSansKR)</p>
	<img src="http://localhost:8080/img/icon.png" alt="icon" height="80"/>
</body>
</html>
  • pdfStyle.css 파일
@font-face {
    font-family: "NanumGothic";
    src: url("http://localhost:8080/font/NanumGothic/NanumGothic-Regular.ttf") format("truetype");
    font-weight: normal;
    font-style: normal;
}
@font-face {
    font-family: "NanumGothic";
    src: url("http://localhost:8080/font/NanumGothic/NanumGothic-Bold.ttf") format("truetype");
    font-weight: bold;
    font-style: normal;
}
@font-face {
    font-family: "Noto Sans KR";
    src: url("http://localhost:8080/font/Noto_Sans_KR/static/NotoSansKR-Regular.ttf") format("truetype");
    font-weight: normal;
    font-style: normal;
}
@font-face {
    font-family: "Noto Sans KR Bold";
    src: url("http://localhost:8080/font/Noto_Sans_KR/static/NotoSansKR-Bold.ttf") format("truetype");
    font-weight: bold;
    font-style: normal;
}
*{ font-family: Arial,"Noto Sans KR" , serif;font-size: 16pt;}
.border{border: 1px solid #AAAAAA;}
td{border: 1px solid gray;border-collapse: collapse;}
.NotoSansKR{font-family: NotoSansKR, "Noto Sans KR", serif}
.NotoSansKR-Bold{font-family: "Noto Sans KR Bold",serif;}
.NanumGothic{font-family: NanumGothic, "NanumGothic",serif;}

.YnPeople-Gothic{font-family: "유앤피플 고딕", serif}
.green{color: #4CAF50;}
  • pdf 파일 생성을 위한 샘플 자바 소스
package com.pdf.pdfbox;

import com.openhtmltopdf.css.parser.property.PageSize;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
@Controller
public class PdfController {

	@RequestMapping("/")
	public void generatePdf(HttpServletRequest request, HttpServletResponse response) throws Exception {


		try (
			OutputStream os = response.getOutputStream();
			InputStream inputStream = getClass().getResourceAsStream("/static/html/template/pdf/pdfSample.html")
		) {
			String html = new String(Objects.requireNonNull(inputStream).readAllBytes(), StandardCharsets.UTF_8);

			PdfRendererBuilder builder = new PdfRendererBuilder();

			// ttf , otf 만 가능
			builder.useFont(() -> getClass().getResourceAsStream("/static/font/유앤피플 고딕 UNI.ttf"), "유앤피플 고딕");
			builder.useFont(() -> getClass().getResourceAsStream("/static/font/NanumGothic/NanumGothic-Regular.ttf"), "NanumGothic");
			builder.useFont(() -> getClass().getResourceAsStream("/static/font/Noto_Sans_KR/static/NotoSansKR-Regular.ttf"), "NotoSansKR");
			builder.useFont(() -> getClass().getResourceAsStream("/static/font/Noto_Sans_KR/static/NotoSansKR-Bold.ttf"), "NotoSansKR-Bold");

			float a4Width = PageSize.A4.getPageWidth().getFloatValue((short) 0);
			float a4Height = PageSize.A4.getPageHeight().getFloatValue((short) 0);

			builder.useDefaultPageSize(a4Width,a4Height, BaseRendererBuilder.PageSizeUnits.MM);
			builder.withHtmlContent(html, "");
			builder.toStream(os);
			builder.run();
		} catch (RuntimeException e) {
			log.error(e.getMessage(),e);
		}

	}

	@GetMapping("/pdf/pdfSample")
	String sampleHtmlView() {
		return "/html/template/pdf/pdfSample.html";
	}

}
  • 결과화면
    왼쪽이 pdf 출력된 이미지이고
    오른쪽이 웹상에서 보는 화면이다.
profile
#java #javascript #spring #jquery #mariadb #vue.js
post-custom-banner

0개의 댓글