React PDF

January 22, 2023 - 우원

React PDF

React PDF 설치

yarn add @react-pdf/renderer

npm install @react-pdf/renderer --save

React PDF 렌더링 프로세스

spring
  1. Internal Structures Creation - React PDF 내부 구조 생성

첫번째 단계는 리액트 엘리멘트 트리를 컴포넌트 타입에 대한 적절한 내부 인스턴스로 변환한다. 이러한 변환은 부모-자식 노드들 사이의 관계를 저장도 포함한다.

문서 외에도 모든 노드는 높이, 너비, 패딩 및 여백(아직 발견 되지 않은 상태)이 있는 문서 내부의 블록을 나타낸다.

현재 단계부터 React-PDF는 이 데이터 구조에 대해 작업하여 각 블록이 최종 문서 내에서 어디로 가는지 추론을 시작한다.

  1. Resolve Styles - 스타일 적용

이 단계에서는 노드 스타일 전처리와 사용자가 제공하지 않은 필수 속성에 대한 기본값 정의가 포함된다. 이러한 방식으로 모든 연속 단계는 필요한 모든 스타일이 트리에 정의되어 있다는 기준으로 작동할 수 있다.

사전 처리의 일부에는 단위 변환, 스타일 상속 및 스타일 확장이 포함된다.

  1. Fetching Assets - 이미지, 폰트 등의 리소스를 가져옴

필요한 모든 자원을 요청한다. 필요한 글꼴, 이미지 또는 이모티콘을 가져오는 내부 노드 트리를 탐색한다.

모든 요청을 비동기식으로 실행하지만 모든 요청이 완료(성공 또는 실패)될 때까지 진행하지 않는다.

  1. Layout text - 텍스트 레이아웃

모든 글꼴을 로드했으므로 텍스트를 단락으로 배치할 수 있다. 먼저 적절한 글꼴 모음과 크기를 사용하여 문자를 글리프(자체, 자형은 글자의 모양)로 변환하고, 이미지 또는 이모티콘 이미지가 있는 경우 포함하고 궁극적으로 언어(또는 사용자 규칙) 규칙에 따라 단어를 분리하거나 공백에 있는 줄로 분리한다.

  1. Wrapping Pages - 페이지 래핑

문서에서 각 요소의 위치와 필요한 공간을 계산하는 것뿐만 아니라 이러한 요소를 여러 페이지로 분할하는 것도 포함하기 때문에 가장 많은 시간이 걸리는 단계이다.

내부적으로 Yoga 레이아웃 엔진을 사용하여 문서 내에서 노드의 크기와 좌표를 계산하고 사용자 지정이 가능한 휴리스틱(간편추론의 방법) 세트를 기반으로 페이지 나누기를 수행한다.

  1. Rendering - 렌더링

이 단계에서는 문서 자체를 생성 하고 이를 위해 PDF Kit을 사용한다.

React PDF Components

  1. Document - 문서

-> PDF 문서 자체를 나타내는 컴포넌트

  1. Page - 페이지

-> PDF 페이지를 나타내는 컴포넌트

  1. View - 뷰

-> 레이아웃을 위한 컨테이너 컴포넌트

  1. Image - 이미지

-> 이미지를 나타내는 컴포넌트

  1. Text - 텍스트

-> 텍스트를 나타내는 컴포넌트

  1. Link - 링크

-> 하이퍼링크를 나타내는 컴포넌트

  1. Note - 노트

-> 주석을 나타내는 컴포넌트

  1. Canvas - 캔버스

-> PDF 페이지에 그림을 그리는 컴포넌트

  1. Font - 폰트

-> PDF 문서에 사용할 글꼴을 등록하는 메소드

React PDF PDFViewer

PDFViewer는 PDF 문서를 브라우저에서 렌더링하는 데 사용할 수 있는 컴포넌트이다. PDFViewer로 Document를 감싸면 렌더링된 PDF 문서를 브라우저에서 볼 수 있다.

...
import { Document} from '@react-pdf/renderer';
...

function App() {

  const newDocument: documentType = {
    title:"React PDF 사용하기",
    author:"thewoowon",
    subject:"React PDF 사용하기",
    creator:"thewoowon",
    keywords:"react pdf",
    producer:"thewoowon",
    language:"ko"
  }

  return (
    <Layout>
      <div className='min-h-screen'>
        <PDFViewer className='min-h-screen w-full'>
          <Document {...newDocument}>
          </Document>
        </PDFViewer>
      </div>
    </Layout>
      
  );
}

export default App;

나는 먼저 Layout을 설정하고 PDFViewer를 사용하여 Document를 감싸서 렌더링하였다.

그러면 아래와 같은 화면이 출력된다.

spring

나는 Document 타입을 정의하고 Document 컴포넌트에 props로 넘겨주었다. 정확한 출처가 필요하다면 Document 컴포넌트에 props로 넘겨주면 된다.

React PDF Document Font & Styling

다음은 폰트를 설정해야한다. react-pdf는 한글 폰트를 지원하지 않기 때문에 폰트를 설정해야한다. 한글 폰트를 지정하지 않으면 한글이 깨져서 나온다.

Font.register({ family: 'Noto Sans KR', src: '/static/fonts/NotoSansKR-Regular.otf' });
Font.register({ family: "Nanum Gothic", src: "https://fonts.gstatic.com/ea/nanumgothic/v5/NanumGothic-ExtraBold.ttf", });

노토 산스와 나눔 고딕을 한글 폰트로 설정하였다. 이제 Text 컴포넌트에 style을 입력하면 한글이 출력된다.

다음은 스타일 설정이다.

const styles = StyleSheet.create({
  page: {
    flexDirection: 'column',
    backgroundColor: 'white',
    paddingTop: 90,
    paddingBottom: 90,
    paddingLeft: 70,
    paddingRight: 70,
  },
  titleSection: {
    display: 'flex',
    flexDirection: 'row',
    paddingBottom: 20,
    justifyContent: 'center',
    alignItems: 'center',

  },
  mainTitle: {
    fontSize: 24,
    fontWeight: 'bold',
    fontFamily: 'Noto Sans KR',
  },
  link: {
    fontSize: 10,
    color: 'blue',
    textDecoration: 'underline',
    fontFamily: 'Nanum Gothic',
    textAlign: 'center',
  },
  logo: {
    width: 50,
    marginLeft: 20,
    marginRight: 20,
  },
  text: {
    fontSize: 10,
    textAlign: 'justify',
    fontFamily: 'Noto Sans KR'
  },
  paragraph1: {
    display: 'flex',
    flexDirection: 'row',
    padding: 20,
    justifyContent: 'center',
    alignItems: 'center',
    border: '1px solid black',
    marginBottom: 20,
  },
  simson: {
    width: 150,
    height: 200,
    marginLeft: 10,
    marginRight: 10,
  },
  paragraph1Text: {
    width: 300,
  },
});

스타일을 정의하고 StyleSheet.create를 사용하여 스타일을 생성한다. 이제 Page, View, Text 등 각각의 컴포넌트에 style을 입력하면 된다.

예를 들어, 아래와 같이 style을 입력하면 된다.

<Text style={styles.text}>
  {`안녕하세요. 저는 ${name}입니다. 저는 ${age}살입니다.`}
</Text>
  

className이라는 props를 사용할 수 없기 때문에 style을 사용해야한다. 위에서 정의한 스타일을 사용하면 된다.

React PDF Document Page

이제 간단한 페이지를 만들어서 출력해보자.

const MyDocument = ({newDocument}:{newDocument:documentType}) => (
          <Document {...newDocument}>
            <Page size="A4" style={styles.page}>
              <View style={styles.titleSection}>
                <View>
                  <Text style={styles.mainTitle}>React PDF 사용하기</Text>
                  <Link style={styles.link} src="https://react-pdf.org/">https://react-pdf.org/</Link>
                </View>
                <View>
                  <Image style={styles.logo} src={"/react_pdf.png"}></Image>
                </View>
              </View>
              <View style={styles.paragraph1}>
                <View style={styles.paragraph1Text}>
                  <Text style={styles.text}> {beginningParagraph}</Text>
                </View>
                <View>
                  <Image style={styles.simson} src={"https://imagedelivery.net/6qzLODAqs2g1LZbVYqtuQw/7e7aa0fb-aa85-4cc0-068e-97c3a04c4800/public"}></Image>
                </View>
              </View>
              <View>
                <Text style={styles.text}> {endingParagraph}</Text>
              </View>
            </Page>
          </Document>
);

위와 같은 컴포넌트를 만들고, PDFViewer를 사용하여 출력해보자.

return (
    <Layout>
      <div className='min-h-screen'>
        <PDFViewer className='min-h-screen w-full'>
          <MyDocument newDocument={newDocument}/>
        </PDFViewer>
      </div>
    </Layout>
      
  );

아래와 같은 결과가 나온다.

spring

React PDF 주의할 점 정리

  1. React PDF는 className이라는 props를 지원하지 않는다.
  2. React PDF는 한글 폰트를 지정하지 않으면 한글이 깨진다.
  3. View는 HTML의 div와 같은 역할을 한다.
  4. Text는 HTML의 span과 같은 역할을 한다.
  5. Image는 HTML의 img와 같은 역할을 한다.
  6. Link는 HTML의 a와 같은 역할을 한다.

다음 시간에는 직접 폼을 만들어 보고 입력한 값을 바탕으로 PDF를 생성해보자.

logo

우원 /

안녕하세요👏
우원입니다.
Email
Gihub
안녕하세요. 우원봇입니다.
logo