C# iTextSharp를 활용한 PDF 동적 생성 및 고급 서식 처리

PDF 문서를 프로그래밍 방식으로 생성해야 하는 상황에서 iTextSharp 라이브러리는 강력한 기능을 제공합니다. 복잡한 레이아웃과 다양한 서식 요구사항을 처리하는 방법을 단계별로 살펴봅니다.

환경 설정 및 기본 구조

NuGet 패키지 관리자를 통해 iTextSharp를 설치한 후, 필요한 네임스페이스를 임포트합니다.

using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;

PDF 문서의 기본 골격은 다음과 같이 구성됩니다. Rectangle로 용지 크기를 정의하고, Document로 문서 객체를 생성한 뒤 PdfWriter를 통해 파일로 출력합니다.

var paperSize = new Rectangle(800, 600);
var pdfDoc = new Document(paperSize, 36, 36, 72, 72);
var outputPath = @"C:\output\sample.pdf";

using (var fileStream = new FileStream(outputPath, FileMode.Create))
{
    var pdfWriter = PdfWriter.GetInstance(pdfDoc, fileStream);
    pdfDoc.Open();
    
    pdfDoc.Add(new Paragraph("안녕하세요, iTextSharp!"));
    
    pdfDoc.Close();
}

문서 메타데이터 설정

검색 가능성과 문서 정보 관리를 위해 메타데이터를 설정할 수 있습니다.

pdfDoc.AddTitle("프로젝트 보고서");
pdfDoc.AddSubject("2024년 1분기 성과 분석");
pdfDoc.AddKeywords("보고서, 분석, PDF, 자동화");
pdfDoc.AddCreator("ReportGenerator v2.1");
pdfDoc.AddAuthor("개발팀");

이미지 삽입 및 위치 제어

로고나 도장 이미지를 정확한 위치에 배치해야 할 때 DirectContent를 활용합니다.

string logoPath = Server.MapPath("~/assets/logo.png");
var companyLogo = iTextSharp.text.Image.GetInstance(logoPath);

// 좌측 하단 기준 좌표 (x, y)
companyLogo.SetAbsolutePosition(50, 750);
companyLogo.ScalePercent(60);

pdfWriter.DirectContent.AddImage(companyLogo);

동적 테이블 생성

가변적인 열 너비와 복잡한 셀 서식이 필요한 테이블을 구성합니다. 중국어/한국어 등 유니코드 문자 표시를 위해 폰트 설정이 필수적입니다.

// 폰트 설정
string fontPath = Server.MapPath("~/fonts/NanumGothic.ttf");
BaseFont unicodeFont = BaseFont.CreateFont(
    fontPath, 
    BaseFont.IDENTITY_H, 
    BaseFont.EMBEDDED
);
Font headerFont = new Font(unicodeFont, 11, Font.BOLD, BaseColor.WHITE);
Font dataFont = new Font(unicodeFont, 10, Font.NORMAL, BaseColor.BLACK);

// 테이블 초기화 (7열, 각 열 너비 지정)
float[] columnWidths = { 120f, 100f, 100f, 110f, 120f, 100f, 150f };
var dataTable = new PdfPTable(columnWidths);
dataTable.TotalWidth = 800f;
dataTable.LockedWidth = true;

// 헤더 셀 생성
var headerCell = new PdfPCell(new Phrase("제품명", headerFont));
headerCell.HorizontalAlignment = Element.ALIGN_CENTER;
headerCell.VerticalAlignment = Element.ALIGN_MIDDLE;
headerCell.BackgroundColor = new BaseColor(51, 122, 183);
headerCell.PaddingTop = 8f;
headerCell.PaddingBottom = 8f;
dataTable.AddCell(headerCell);

// 데이터 행 추가 (반복)
for (int i = 0; i < productList.Count; i++)
{
    var cell = new PdfPCell(new Phrase(productList[i].Name, dataFont));
    cell.HorizontalAlignment = Element.ALIGN_LEFT;
    cell.PaddingLeft = 5f;
    dataTable.AddCell(cell);
    // ... 추가 셀
}

pdfDoc.Add(dataTable);

절대 좌표 텍스트 배치

템플릿 기반 문서나 정밀한 위치 제어가 필요한 경우 ColumnText를 사용합니다.

var canvas = pdfWriter.DirectContent;
var positionedText = new Phrase("기밀문서", new Font(unicodeFont, 14, Font.BOLD, BaseColor.RED));

// 좌측 정렬, x=400, y=300 위치에 0도 회전
ColumnText.ShowTextAligned(
    canvas,
    Element.ALIGN_LEFT,
    positionedText,
    400,
    300,
    0
);

페이지 관리

새 페이지 강제 시작 및 페이지 번호 재설정 기능입니다.

pdfDoc.NewPage();        // 새 페이지 생성
pdfDoc.ResetPageCount(); // 페이지 카운터 초기화

고급: 페이지 이벤트로 헤더/푸터/워터마크 구현

가장 복잡한 요구사항은 IPdfPageEvent 인터페이스를 구현하여 해결합니다. 배경색, 워터마크, 머리글/바닥글을 레이어 순서대로 제어합니다.

public class PageDecorator : PdfPageEventHelper
{
    private string watermarkImagePath;
    private BaseFont documentFont;
    
    public PageDecorator(string watermarkPath)
    {
        this.watermarkImagePath = watermarkPath;
    }
    
    public override void OnEndPage(PdfWriter writer, Document document)
    {
        base.OnEndPage(writer, document);
        
        // 폰트 초기화 (지연 로딩)
        if (documentFont == null)
        {
            documentFont = BaseFont.CreateFont(
                @"C:\fonts\malgun.ttf",
                BaseFont.IDENTITY_H,
                BaseFont.EMBEDDED
            );
        }
        
        var contentByte = writer.DirectContent;
        var underContent = writer.DirectContentUnder;
        
        // ===== 레이어 1: 배경색 (최하위) =====
        using (var bgBitmap = new System.Drawing.Bitmap(1, 1))
        using (var graphics = System.Drawing.Graphics.FromImage(bgBitmap))
        {
            var bgColor = System.Drawing.Color.FromArgb(240, 248, 255); // AliceBlue
            graphics.Clear(bgColor);
            
            var bgImage = iTextSharp.text.Image.GetInstance(
                bgBitmap, 
                System.Drawing.Imaging.ImageFormat.Png
            );
            bgImage.ScaleAbsolute(document.PageSize.Width, document.PageSize.Height);
            bgImage.SetAbsolutePosition(0, 0);
            underContent.AddImage(bgImage);
        }
        
        // ===== 레이어 2: 워터마크 (중간) =====
        try
        {
            var watermark = iTextSharp.text.Image.GetInstance(watermarkImagePath);
            watermark.RotationDegrees = 45;
            watermark.SetAbsolutePosition(200, 300);
            
            // 투명도 설정
            var graphicState = new PdfGState();
            graphicState.FillOpacity = 0.15f;
            underContent.SetGState(graphicState);
            
            // 타일링 패턴으로 전체 페이지에 배포
            float xPos = -200;
            for (int col = 0; col < 8; col++)
            {
                xPos += 250;
                float yPos = -200;
                float xOffset = xPos;
                
                for (int row = 0; row < 6; row++)
                {
                    yPos += 200;
                    xOffset += 30; // 대각선 오프셋
                    
                    watermark.SetAbsolutePosition(xOffset - 100, yPos);
                    underContent.AddImage(watermark);
                }
            }
            
            // 투명도 복원
            underContent.SetGState(new PdfGState { FillOpacity = 1.0f });
        }
        catch { /* 워터마크 로드 실패 시 무시 */ }
        
        // ===== 레이어 3: 머리글/바닥글 (최상위) =====
        var headerText = new Phrase("회사 기밀 문서", new Font(documentFont, 9, Font.ITALIC, BaseColor.GRAY));
        ColumnText.ShowTextAligned(
            contentByte,
            Element.ALIGN_RIGHT,
            headerText,
            document.Right,
            document.Top + 20,
            0
        );
        
        var footerText = new Phrase(
            $"페이지 {writer.PageNumber}",
            new Font(documentFont, 9, Font.NORMAL, BaseColor.DARK_GRAY)
        );
        ColumnText.ShowTextAligned(
            contentByte,
            Element.ALIGN_CENTER,
            footerText,
            (document.Right + document.Left) / 2,
            document.Bottom - 30,
            0
        );
    }
}

이벤트 핸들러를 작성기에 연결합니다.

var decorator = new PageDecorator(Server.MapPath("~/images/watermark.png"));
pdfWriter.PageEvent = decorator;

이 구조를 통해 배경색 → 워터마크 → 본문 콘텐츠의 올바른 쌓임 순서를 보장하며, 모든 페이지에 일관된 서식을 적용할 수 있습니다.

태그: iTextSharp C# PDF Generation PDF Manipulation Document Automation

6월 1일 09:14에 게시됨