html2pdf

juhojung·2022년 2월 20일
2

react.js

목록 보기
2/4

html 에서 보이는것들을 pdf 로 만든 과정

A2B 라고 적는건 아주 센스가 있어보여서 좋다.

여러 문서를 다루는 회사 프로젝트를 진행하다보니, 문서를 import/export 하는 과정이 많아졌다.
그런 중 WYSIWYG Editor 도 지원을 했는데,
그러다보니 당연하게도 보이는걸 출력도 할 수 있게 해달라고 요청을 해왔다.
출력물을 관리할 필요는 없다고 판단, Front-End 에서 다운로드 받을 수 있게 해봤다.

import html2canvas from "html2canvas";
import jsPDF from "jspdf";

export type Html2PDFProps = {
    elementId: string;
    classId?: string;
    filename?: string;
    element?: any;
    whiteSpace?: number;
    isSave?: boolean;
    extraClass?: string;
    extraId ?: string;
};
interface FinalHtml2PDFProps extends Html2PDFProps {}
export const Html2PdfComponent = async (
    props: FinalHtml2PDFProps
): Promise<any | null> => {
    var el = document.getElementById(props.elementId);
    if (props.classId && props.classId.length > 0) {
        let el_list = document.getElementsByClassName(props.classId);
        if (el_list.length > 0) el = el_list[0] as HTMLElement;
    }
    if (props.element) el = props.element;
    let res = await new Promise((r) => {
        if (el) {
        	// Style, Class, Id 등등 canvas 에 그리기전에 미리 세팅
            el.setAttribute(
                "style",
                "width:1080px; margin:0; line-height: 160%"
            );
            el.setAttribute("id", props.extraId ? props.extraId : "");
            if (props.extraClass) el.classList.add(props.extraClass);
            //
            html2canvas(el, {
                width: 1080,
                height: el.scrollHeight,
                useCORS: true, // 외부 url 로드하는 Image 등이 껴있을경우를 위해
            }).then((canvas) => {
                const imgData = canvas.toDataURL("image/png", 1.0);
                // A4 기준 비율 스크린이 딱 맞게 하기위해
                var imgWidth = 210;
                var pageHeight = imgWidth * 1.414; 
                //
                var imgHeight = (canvas.height * imgWidth) / canvas.width;
                var heightLeft = imgHeight;
                const pdf = new jsPDF("p", "mm", "a4", 1);
                const widthSpace = props.whiteSpace ? props.whiteSpace : 0;
                var position = props.whiteSpace ? props.whiteSpace : 0;
                pdf.addImage(
                    imgData,
                    "PNG",
                    widthSpace,
                    position,
                    imgWidth - widthSpace * 2, // 여백을 준다.
                    imgHeight - widthSpace * 2,
                    "",
                    "FAST" // 해당 옵션을 안주면 용량은 훨씬큰데, 품질은 비슷한 pdf가 만들어져서 용량 차원에서 옵션을 넣었다.
                );
				// 한 page 안에 다 못그릴 경우
                heightLeft -= pageHeight;
                while (heightLeft >= 0) {
                    position = heightLeft - imgHeight;
                    pdf.addPage();
                    pdf.addImage(
                        imgData,
                        "PNG",
                        widthSpace,
                        position,
                        imgWidth - widthSpace * 2,
                        imgHeight - widthSpace * 2,
                        "",
                        "FAST"
                    );
                    heightLeft -= pageHeight;
                }
                //
                // 저장한다면 바로 pdf 다운로드 진행
                if (props.isSave)
                    pdf.save(props.filename ? props.filename : "preview.pdf");
                // console.log(imgData);
                // Canvas 에 그린후 Image Data 를 raw data 로 추출
                r(imgData);
            });
        }
    });
    if (el) el.setAttribute("style", "");
    return res;
};

나의 경우 특정 데이터를 껴넣어야(?) 할 필요가 있어 직접 만들었다.
단순하게 html2pdf 기능은 아래 library 를 참고하면 될 듯 싶다.

https://ekoopmans.github.io/html2pdf.js/

그럼 안녕👋

profile
"어찌 할 수 없는 일에 대해 고민하는 시간은 낭비일 뿐이다."

12개의 댓글

comment-user-thumbnail
2024년 7월 16일

페이지 처리하는 것 때문에 애먹고 있었는데 감사합니다!

답글 달기
comment-user-thumbnail
2025년 8월 5일

With thanks just for offer a very awesome page! I stubled onto a web site ideal for great really needs. Its content has delightful and additionally important reports. Preserve acknowledge that there are succeed! arasta

답글 달기
comment-user-thumbnail
2025년 8월 20일

I am truly pleased to discover this website as well as do appreciate reading through helpful content articles submitted right here. The actual suggestions from the writer had been amazing, many thanks for that reveal. 79club

답글 달기
comment-user-thumbnail
2025년 8월 30일

it has the seriously brilliant site. it has the realy informational including a this sort of fine occupation. everyone loves the following. BIKINI SET

답글 달기
comment-user-thumbnail
2025년 9월 2일

Ones new music is usually wonderful. You could have many incredibly proficient painters. When i hope people the most beneficial connected with achievements.空調 修理

답글 달기
comment-user-thumbnail
2025년 9월 2일

That is the amazing piece of writing, Thanks a lot for the purpose of rendering everybody this. Have post. 転職 技術

답글 달기
comment-user-thumbnail
2025년 9월 2일

This can be consequently lovely along with inventive. I merely enjoy your hues along with anyone becomes the idea inside snail mail are going to be cheerful. 派遣 短期

답글 달기
comment-user-thumbnail
2025년 9월 9일

Superior Place, My organization is a great believer during ad opinions regarding online websites that will let the webpage novelists recognize that they’ve put in an item worthwhile that will the online market place! patriotic thongs

답글 달기
comment-user-thumbnail
2025년 9월 10일

Excellent writing. This write-up has effects on many critical troubles your contemporary society. Most of us cannot be uninvolved to help most of these troubles. That write-up allows good ideas in addition to methods. Incredibly beneficial in addition to realistic. 바다이야기 무료

답글 달기
comment-user-thumbnail
2025년 9월 11일

Thanks for sharing this valuable content. In my view, if all webmasters and bloggers made good content as you did, the web will be a lot more useful than ever before. 홍대셔츠룸

답글 달기
comment-user-thumbnail
2025년 9월 11일

I’m motivated with all the surpassing and also preachy record which you supply in such tiny timing. nine casino

답글 달기
comment-user-thumbnail
2025년 9월 14일

These days, I am finding it hard to find good games in one place. I think bc game official website makes life easier for gamers. No need to jump between different sites.

답글 달기