html2pdf.js PDF가 흐리게 나올 때? 해상도 개선 방법 정리!
웹 페이지를 PDF로 저장할 때 자주 사용하는 라이브러리 중 하나가 html2pdf.js입니다.
하지만 많은 분들이 생성된 PDF가 너무 흐리다, 이미지가 깨진다, 텍스트가 뭉개져 보인다는 문제를 겪고 있죠.
이 문제의 핵심은 바로 해상도 설정 부족 때문입니다.
아래 내용을 따라 설정하면 훨씬 선명한 PDF를 생성할 수 있습니다.
📌 문제 요약: PDF가 흐리게 출력되는 이유
html2pdf.js는 내부적으로 html2canvas를 이용해 웹 요소를 이미지로 변환하고 이를 PDF로 저장합니다.
이때 기본 해상도(scale) 값이 1로 설정되어 있어, 확대 출력 시 이미지가 흐릿하게 보이게 됩니다.
✅ 해결 방법: 해상도와 품질 옵션 추가
🔧 고해상도 PDF를 만드는 코드 예제
const element = document.getElementById('pdfTarget'); // PDF로 만들 DOM 요소
const opt = {
margin: 10, // 여백 설정 (단위: px)
filename: 'myfile.pdf', // 저장할 파일 이름
image: { type: 'jpeg', quality: 1 }, // 이미지 타입과 품질
html2canvas: {
scale: 3, // 💡 해상도 조정: 2~4 사이가 적당
useCORS: true // 외부 리소스 깨짐 방지
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait'
}
};
html2pdf().set(opt).from(element).save();
🔍 주요 옵션 설명
옵션 키 설명
html2canvas.scale | 렌더링 해상도. 기본은 1이며, 2~4 사이로 높일수록 선명하지만 용량 증가 |
image.quality | 이미지 품질 설정. 1은 최고 화질 (100%) |
useCORS | 외부 이미지나 폰트가 깨지는 현상 방지 |
jsPDF.format | A4, A3 등 용지 크기 지정 가능 |
jsPDF.orientation | 세로(portrait) 또는 가로(landscape) 출력 방향 설정 |
📄 추가 팁
- scale을 너무 높게 설정하면 메모리 부족, 브라우저 멈춤 등의 문제가 발생할 수 있습니다.
→ 일반적으로 2 또는 3 정도가 가장 안정적입니다. - 외부 이미지, 웹폰트를 사용하는 경우 useCORS: true는 필수입니다.
- 이미지가 아닌 텍스트 기반 PDF를 만들고 싶다면 jsPDF만 사용하는 방식도 고려해볼 수 있습니다.
🧪 직접 비교: scale에 따른 품질 차이
scale 값 이미지 선명도 PDF 용량 속도
1 | 흐림 | 작음 | 빠름 |
2 | 적당히 선명 | 중간 | 중간 |
3 | 선명함 | 큼 | 느림 |
4 이상 | 매우 선명 | 매우 큼 | 매우 느림 (권장 X) |
📝 마무리 정리
- html2pdf()로 만든 PDF가 흐리게 나온다면?
→ html2canvas.scale 옵션을 3 정도로 설정하세요. - 이미지 품질은 image.quality: 1로 최상으로 지정하세요.
- 외부 리소스 깨짐 방지를 위해 useCORS: true도 함께 설정하세요.
📦 보너스: A3 용지로 출력하고 싶다면?
jsPDF: {
unit: 'mm',
format: 'a3', // A3로 변경
orientation: 'landscape' // 가로 출력
}
더 선명하고 깨끗한 PDF를 만들고 싶다면 위 설정을 꼭 적용해보세요!
궁금한 점이 있거나 커스터마이징이 필요하면 댓글로 질문 주세요. 😊
필요하다면 이 글에 PDF 예시 파일 첨부도 가능합니다.
html2pdf.js 관련 추가 설정법도 다룰 예정이니 북마크 해두시면 좋아요!
📌 태그 추천: #html2pdf, #PDF해상도, #html2canvas, #PDF흐림, #PDF선명도, #웹페이지PDF
html2pdf.js에서 A4 기준으로 페이지가 넘칠 때 내용이 짤리는 현상은 꽤 자주 발생하는 문제입니다.
이를 해결하기 위해 **페이지 분할(pagination)**을 잘 처리해야 하며, 다음과 같은 전략을 사용하면 됩니다:
✅ A4 페이지에서 내용이 짤리지 않게 하는 방법
1. html2canvas의 scrollY, scrollX을 무시하게 설정
페이지의 스크롤 위치 때문에 렌더링이 잘못되는 걸 방지합니다:
html2canvas: {
scale: 3,
useCORS: true,
scrollY: 0,
scrollX: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
}
2. page-break CSS 속성 사용 (가장 중요한 방법)
PDF가 렌더링될 때, 특정 위치에서 강제로 줄바꿈하도록 합니다.
예시:
<div class="pdf-page">
<h2>1페이지 내용</h2>
...
</div>
<div class="page-break"></div>
<div class="pdf-page">
<h2>2페이지 내용</h2>
...
</div>
/* 페이지 나눔 표시 */
.page-break {
page-break-before: always;
break-before: page;
}
또는 특정 블록이 분리되지 않도록 하려면:
.avoid-break {
page-break-inside: avoid;
break-inside: avoid;
}
3. html2pdf 사용 시 .from()을 .from(clone) 형태로 커스터마이징하는 방법
크게 분할해야 하는 경우, DOM을 미리 A4 크기로 분할해두고 각 섹션별로 PDF로 렌더링하는 것이 안정적입니다.
html2pdf는 내부적으로 하나의 긴 이미지를 자르기 때문에, 긴 테이블이나 이미지가 잘릴 수 있습니다.
이런 경우 직접 A4 높이에 맞게 분할된 <div> 단위로 구성해야 완벽한 제어가 가능합니다.
🧪 실전 팁
- 표나 긴 텍스트를 출력할 때는 반드시 page-break-inside: avoid;를 사용하세요.
- html2canvas는 실제 DOM 기준이므로, 출력 요소에 overflow: visible을 유지하세요.
- height, max-height 값을 정확히 297mm 기준(A4 세로)으로 맞춰주면 계산이 쉬워집니다.
🧩 결론
상황 해결 방법
텍스트가 중간에 짤림 | .page-break 클래스로 분할 |
표나 이미지가 잘려서 보임 | .avoid-break 클래스로 해당 요소 내부 분할 방지 |
전체가 스크롤된 상태로 렌더됨 | scrollX, scrollY, windowHeight 직접 설정 |
너무 많은 콘텐츠로 PDF 오류 발생 | DOM을 A4 크기로 미리 나누고 여러 번 렌더링하는 방식 고려 |
아래는 A4 용지 기준으로 긴 콘텐츠를 자동으로 분할하여 PDF로 저장하는 JavaScript 코드 예제입니다.
✅ 목적
- HTML 요소의 길이가 A4를 넘을 경우
- 자동으로 페이지를 나눠
- html2pdf.js를 이용해 짤림 없이 저장합니다.
📦 전체 코드 예시
PDF 저장
function generatePDF() {
const element = document.getElementById('pdfTarget');
// A4 기준 높이 (mm 기준 → html2canvas px 기준으로 변환 필요)
const A4_HEIGHT_MM = 297;
const A4_WIDTH_MM = 210;
const DPI = 96; // 화면 해상도 (웹 기본값)
const MM_TO_PX = DPI / 25.4;
const A4_HEIGHT_PX = A4_HEIGHT_MM * MM_TO_PX;
const A4_WIDTH_PX = A4_WIDTH_MM * MM_TO_PX;
// html2canvas + jsPDF 세팅
const opt = {
margin: 0,
filename: 'output.pdf',
image: { type: 'jpeg', quality: 1 },
html2canvas: {
scale: 2,
useCORS: true,
scrollX: 0,
scrollY: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait'
}
};
// 렌더링용 clone
const cloned = element.cloneNode(true);
const container = document.createElement('div');
container.style.width = A4_WIDTH_PX + 'px';
container.appendChild(cloned);
document.body.appendChild(container);
// html2canvas로 전체 렌더링 후 캔버스를 분할
html2canvas(cloned, {
scale: 2,
useCORS: true,
scrollX: 0,
scrollY: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
}).then(canvas => {
const imgHeight = canvas.height;
const imgWidth = canvas.width;
const pageHeight = A4_HEIGHT_PX * 2; // scale 고려
const pdf = new jsPDF('p', 'mm', 'a4');
let position = 0;
let pageData;
let pageCount = 0;
while (position < imgHeight) {
// 캔버스에서 자르기
const canvasPage = document.createElement('canvas');
canvasPage.width = imgWidth;
canvasPage.height = Math.min(pageHeight, imgHeight - position);
const ctx = canvasPage.getContext('2d');
ctx.drawImage(canvas, 0, -position);
pageData = canvasPage.toDataURL('image/jpeg', 1.0);
if (pageCount > 0) pdf.addPage();
pdf.addImage(pageData, 'JPEG', 0, 0, 210, 297);
position += pageHeight;
pageCount++;
}
pdf.save('output.pdf');
document.body.removeChild(container); // cleanup
});
}
🔍 핵심 설명
항목 설명
html2canvas(...).then(canvas => {}) | 전체 DOM을 캡처 |
canvas.drawImage(..., -position) | A4 높이만큼 잘라서 하나씩 붙임 |
jsPDF.addPage() | 다음 페이지 추가 |
canvasPage.toDataURL() | 잘라낸 이미지를 PDF에 삽입 |
📄 특징 요약
- 실제 A4 용지 높이(mm → px로 환산)를 기준으로 자동 분할
- 한 번에 렌더링 후, 페이지 단위로 잘라 저장
- 깨짐/흐림 방지를 위한 scale: 2 설정
- 전체 길이 자동 계산 → 짤림 없음
필요하시면 다음과 같은 기능도 추가 가능합니다:
- A3, 가로 방향 대응
- 페이지 번호 출력
- 긴 표 자동 줄바꿈
- DOM 내에서 특정 구역만 출력하기
html2pdf.js로 PDF를 생성할 때 페이지 하단에 페이지 번호 (1 / 5, 2 / 5 등) 를 자동으로 삽입하는 방법을 안내드리겠습니다.
✅ 방법 요약
html2pdf.js는 내부적으로 jsPDF를 사용하므로, PDF 생성 후 페이지 수를 얻고, 각 페이지마다 번호를 수동 삽입해야 합니다.
📦 전체 코드 예제 (페이지 번호 포함)
PDF 제목
내용이 길어 여러 페이지로 나뉘게 됩니다...
PDF 저장
function generatePDF() {
const element = document.getElementById('pdfTarget');
const opt = {
margin: 10,
filename: 'output_with_pagenumber.pdf',
image: { type: 'jpeg', quality: 1 },
html2canvas: {
scale: 2,
useCORS: true,
scrollX: 0,
scrollY: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait'
}
};
// html2pdf → PDF 객체 직접 접근 후 페이지 번호 추가
html2pdf().set(opt).from(element).toPdf().get('pdf').then(function (pdf) {
const totalPages = pdf.internal.getNumberOfPages();
for (let i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(150);
const text = `${i} / ${totalPages}`;
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
pdf.text(text, pageWidth - 30, pageHeight - 10); // (x, y)
}
}).save();
}
🧩 설명
항목 설명
.toPdf().get('pdf') | 내부 PDF 객체에 접근 |
pdf.internal.getNumberOfPages() | 전체 페이지 수 계산 |
pdf.setPage(i) | 해당 페이지로 이동 |
pdf.text(...) | 텍스트 삽입 (페이지 번호) |
위치는 x = 페이지 너비 - 30, y = 페이지 하단 (297mm → 약 287) 부근에 지정하여 우측 하단에 출력됩니다.
🔧 원하는 위치 조정 팁
- 가운데 하단:
- const centerX = pageWidth / 2; pdf.text(text, centerX, pageHeight - 10, { align: 'center' });
- 좌측 하단:
- pdf.text(text, 10, pageHeight - 10);
✅ 결과 예시
페이지 하단에 다음과 같이 출력됩니다:
1 / 3
2 / 3
3 / 3
필요하다면:
- 페이지 1 / 전체 3처럼 한국어 표현
- 머리말에도 페이지 번호 출력
- 특정 콘텐츠마다 Section 1 - Page 1 / 3 형식
**“PDF 저장 시 테이블이 잘리는 문제”**는 html2pdf.js와 html2canvas 사용 시 흔하게 발생하며, 이 문제는 CSS + JS 설정으로 해결할 수 있습니다.
✅ 요약: 현재 문제 원인
- html2pdf.js는 DOM 전체를 캔버스로 변환한 뒤, A4 크기로 잘라서 PDF 페이지를 만듭니다.
- 이때 테이블 행(tr)이나 전체 테이블(table)이 페이지 하단에서 분할되면, html2canvas가 이를 잘라버립니다.
- 이로 인해 테이블 헤더와 내용이 분리되거나, 중간 행이 잘리는 현상이 발생합니다.
✅ 1단계: CSS에 page-break 관련 속성 추가
🔧 스타일 파일(style.css 또는 내부 <style>)에 아래 추가:
@media print {
table {
page-break-inside: auto !important;
}
tr {
page-break-inside: avoid !important;
page-break-after: auto !important;
}
thead {
display: table-header-group !important; /* 페이지 넘어가도 thead 유지 */
}
tfoot {
display: table-footer-group !important;
}
}
🔹 추가로 필요한 경우 테이블 외 요소가 끊기는 것을 막고 싶다면:
.avoid-break {
break-inside: avoid !important;
page-break-inside: avoid !important;
}
위 클래스를 문제가 발생하는 <div> 또는 <table>에 class="avoid-break"로 추가하세요.
✅ 2단계: JS html2pdf() 호출 시 pagebreak 옵션 설정
기존 generatePDF() 함수는 아래처럼 되어 있죠:
html2pdf().from(element).set(opt).save();
여기에 다음을 추가합니다:
opt.pagebreak = {
mode: ['css', 'legacy'], // css 기준으로 줄바꿈
avoid: ['tr', '.avoid-break'] // 행(tr)이 잘리지 않도록
};
🔄 수정된 전체 예시:
function generatePDF() {
var element = document.getElementById('content-to-print');
var opt = {
margin: [10, 3, 12, 3],
filename: '출고증.pdf',
image: { type: 'jpeg', quality: 1 },
html2canvas: {
scale: 3,
useCORS: true,
scrollY: 0,
scrollX: 0,
windowWidth: document.body.scrollWidth,
windowHeight: document.body.scrollHeight
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: {
mode: ['css', 'legacy'],
avoid: ['tr', '.avoid-break'] // 핵심
}
};
html2pdf().from(element).set(opt).save();
}
✅ 3단계: HTML에서 분할 방지하고 싶은 테이블에 클래스 추가
예시:
<table class="table avoid-break">
...
</table>
또는 내부 tr이나 tbody에도 적용 가능:
<tr class="avoid-break">
✅ 추가 팁: 줄바꿈 강제 삽입
어떤 위치에서 의도적으로 페이지를 나누고 싶다면:
<div style="page-break-before: always;"></div>
이걸 <h2> 위나 특정 구간 위에 삽입하면 페이지가 강제로 나뉩니다.
✅ 정리
항목 해결 방법
표가 잘리는 현상 | tr { page-break-inside: avoid; } 설정 |
페이지 넘어갈 때 thead가 사라짐 | thead { display: table-header-group; } 설정 |
한 행이 둘로 나뉘는 현상 | .avoid-break 클래스 사용 |
PDF 내 강제 줄바꿈 | <div style="page-break-before: always;"> 사용 |
JS 설정에서 제어 | opt.pagebreak.avoid: ['tr'] 추가 |
필요하시면 아래 기능도 추가해드릴 수 있습니다:
- 페이지 번호 삽입 (1 / 3)
- 각 페이지에 상단 헤더 반복
- A3 or landscape 출력 최적화
도움이 필요하신 부분만 말씀주세요!