공부 이유
pdfkit란?
라이브러리 다운로드
print.controller.ts
import { Controller, Get, Param, Res } from '@nestjs/common';
import { PrintService } from './print.service';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('Print')
@Controller('print')
export class PrintController {
constructor(private readonly printSerivce: PrintService) {}
// 연차 PDF 형식으로 다운로드 하기
@Get('pdf/download/:annualLeaveId')
async downloadPDF(@Param('annualLeaveId') annualLeaveId: number, @Res() res): Promise<void> {
const buffer = await this.printSerivce.generateAnnualLeavePdf(annualLeaveId);
res.set({
'Content-type': 'application/pdf; charset=utf-8',
'Content-Disposition': 'attachment; filename=annualLeave.pdf',
'Content-Length': buffer.length,
});
res.end(buffer);
}
}
print.servic.ts
import { AnnualLeaveService } from './../annual-leave/annualLeave.service';
import { Injectable, NotFoundException } from '@nestjs/common';
import * as path from 'path';
import * as PDFDocument from 'pdfkit'; // pdfkit 직접 불러오기
@Injectable()
export class PrintService {
constructor(private readonly annualService: AnnualLeaveService) {}
// 연차 PDF 형식으로 다운로드 하기
async generateAnnualLeavePdf(annualLeaveId: number): Promise<Buffer> {
return new Promise(async (resolve, reject) => {
const doc = new PDFDocument({
size: 'A4', // 파일 사이즈
bufferPages: true,
});
// 폰트 파일 경로
const fontPath = path.join(process.cwd(), 'src', 'ponts', '5jKbo-sBL2uJoUIRop32w-wnBo8.ttf');
if (!fontPath) {
throw new NotFoundException('폰트 파일을 찾을 수 없습니다.');
}
// 연차 정보 조회
const annualLeave = await this.annualService.showAcceptAnnualLeave(annualLeaveId);
if (!annualLeave) {
throw new NotFoundException('수락된 연차 정보가 없습니다.');
}
const userName = annualLeave.user.name;
const department = annualLeave.user.department;
// PDF에서 한글을 출력하기 위해 폰트를 설정
doc.font(fontPath) // 폰트 설정
.fontSize(16) // 폰트 크기 설정
.text('연차 사용', { align: 'center' }) // 한글 텍스트 출력
.moveDown()
.moveDown()
.moveDown();
// 사용자 정보 출력
doc.font(fontPath) // 폰트 설정
.fontSize(12)
.text(`사용자: ${userName}`, { align: 'left' })
.moveDown()
.text(`부서: ${department}`, { align: 'left' })
.moveDown();
// 연차 정보 출력
const { start_date, end_date, days, record_contents, created_at } = annualLeave;
doc.font(fontPath) // 폰트 설정
.fontSize(12)
.text(`연차 기간: ${start_date} ~ ${end_date}`, { align: 'left' })
.moveDown()
.text(`연차 일수: ${days}일`, { align: 'left' })
.moveDown()
.text(`기타 사항: ${record_contents || '없음'}`, { align: 'left' })
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.moveDown()
.text(`신청 날짜: ${created_at}`, { align: 'center' });
// PDF 데이터를 버퍼로 변환하여 반환
const buffer: Buffer[] = [];
doc.on('data', buffer.push.bind(buffer));
doc.on('end', () => {
const data = Buffer.concat(buffer);
resolve(data);
});
doc.end();
});
}
}
const fontPath = path.join(process.cwd(), 'src', 'ponts', '5jKbo-sBL2uJoUIRop32w-wnBo8.ttf');
이 부분은 ttf 파일을 다운로드 받고 vscode에서는 인코딩 되기 때문에, 파일을 열지 않고 넣어놓기만 해야한다.