[C#] Excel 파일을 PDF 및 이미지로 변환하는 방법 (Spire.Xls)


Development note/C#  2021. 3. 9. 14:55

안녕하세요. 명월입니다.


이 글은 C#에서 Excel 파일을 PDF 및 이미지로 변환하는 방법(Spire.Xls)에 대한 글입니다.


이전에 제가 C#에서 NPOI를 이용해서 Excel를 이용하는 방법에 대해서 설명한 적이 있습니다.

링크 - [C#] NPOI를 이용하여 Excel를 읽어드리고 다시 출력하기


NPOI를 이용해서 Excel를 이용해서 PDF로 변환하는 방법은 없습니다. 정확히는 Excel 그대로 PDF로 변환하는 방법이 없습니다.

각 Row나 Cell의 데이터를 취득해서 iTextSharp를 이용해서 만드는 방법은 있습니다만, 뭐랄까.. Excel 그대로의 스타일등으로 변환하는 방법은 없습니다.


그것을 해결하는 방법으로 Spire.Xls 라이브러리를 이용하면 Excel 설정 그대로 캡쳐(?)해서 PDF에 화면에 표시할 수 있습니다.

먼저 C#에서 Spire.Xls 라이브러리를 사용하기 위해서 Nget을 이용해서 라이브러리를 연결합니다.

Spire.Xls를 검색하면 앞에 Free가 붙어 있는 라이브러리와 Spire.Xls가 있습니다.

간단하게 설명하면 Free가 붙어 있는 라이브러리는 라이센스가 필요없고 Free가 없는 라이브러리는 라이센스가 필요합니다.

Free 버전의 경우는 Excel의 최대 시트 5장 그리고 시트당 150 행, PDF의 경우 최대 3장까지만 사용할 수 있습니다. 즉, Excel의 파일이 작은 경우는 특별히 유료를 사용하지 않고 무료를 사용해도 크게 문제가 없습니다.


먼저 제가 간단하게 Style를 넣은 데이터와 이미지를 포함한 Excel 시트를 만들었습니다.

위 데이터를 PDF로 출력을 하겠습니다.

using System;
using System.IO;
using Spire.Xls;

namespace Example
{
  class Program
  {
    // 실행 함수
    static void Main(string[] args)
    {
      // Workbook 인스턴스 생성
      Workbook workbook = new Workbook();
      // Stream으로 파일을 읽어온다.
      using (var stream = new FileStream(@"d:\work\test.xlsx", FileMode.Open, FileAccess.Read))
      {
        // Workbook 인스턴스에 파일 Stream을 읽는다.
        workbook.LoadFromStream(stream);
      }
      // Workbook의 worksheet별로 반복
      foreach (Worksheet worksheet in workbook.Worksheets)
      {
        // worksheet를 pdf로 출력
        worksheet.SaveToPdf(@"d:\work\output.pdf");
      }
      // 콘솔 출력
      Console.WriteLine("Press any key...");
      Console.ReadKey();
    }
  }
}

위 소스를 실행하면 output.pdf파일로 Excel파일 데이터가 변환하는 것을 확인할 수 있습니다.

매우 간단합니다만, 여기서 문제는 Free 버전의 경우가 이 변환 제한이 있습니다. 즉, Excel의 데이터가 많으면 출력이 제대로 되지 않는다는 문제가 있습니다.

그럼 Free버젼이 아닌 정식 버전으로 위 소스를 실행해 보겠습니다.

다시 Nget에서 라이브러리를 재설치합니다.

그리고 프로그램을 실행합니다.

PDF 상단부에 Warning 메시지가 표시가 되네요. 물론 상용화 버전의 프로그램을 사용한다면 당연히 라이센스를 구매하여 라이브러리를 사용하는 것이 당연합니다만, 개인이 특정 목적과 배치를 위해서 사용하기 위해 라이센스를 구매하기가 다소 부담스럽습니다.(아마 가격이 100만원대 이상이라고 알고 있습니다.)

그래서 방법이 전혀 없는 것은 아니고 Excel를 Image로 출력한 다음에 다시 그 Image를 PDF로 변환하는 방법으로 우회하는 방향으로 pdf를 변환할 수 있습니다.

using System;
using System.IO;
using Spire.Xls;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.tool.xml;
using iTextSharp.tool.xml.html;
using iTextSharp.tool.xml.pipeline.html;
using iTextSharp.tool.xml.pipeline.end;
using iTextSharp.tool.xml.parser;

namespace Example
{
  class Program
  {
    // 이미지와 PDF로 변환
    private static void ConvertImageAndPDF(string filename, int pageWidth, int pageHeight, int contentPositionX, int contentPositionY, int firstRow, int firstColumn, int? lastRow, int? lastColumn)
    {
      // 이미지를 담아둘 리스트
      var images = new System.Collections.Generic.List<System.Drawing.Image>();
      // Workbook를 만든다.
      Workbook workbook = new Workbook();
      // Stream으로 파일을 읽어온다.
      using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
      {
        // Workbook 인스턴스에 파일 Stream을 읽는다.
        workbook.LoadFromStream(stream);
      }
      // Workbook의 worksheet별로 반복
      foreach (Worksheet worksheet in workbook.Worksheets)
      {
        // Bitmap 을 이용해서 버퍼를 생성한다.
        Bitmap buffer = new Bitmap(pageWidth, pageHeight);
        // 메모리 byte스트림을 만든다.
        using (var ms = new MemoryStream())
        {
          // Excel로 부터 이미지로 캡쳐.
          worksheet.ToEMFStream(ms, firstRow, firstColumn, lastRow != null ? lastRow.Value : worksheet.LastRow, lastColumn != null ? lastColumn.Value : worksheet.LastColumn);
          // ms로 읽어와서 Image로 변환
          System.Drawing.Image image = System.Drawing.Image.FromStream(ms);
          // 새로운 Graphics 객체를 buffer로 읽어온다.
          using (Graphics g = Graphics.FromImage(buffer))
          {
            // 이미지를 다시 그린다.(Warning 메시지를 없애기 위한)
            g.DrawImage(image, contentPositionX, contentPositionY);
          }
          // 캡쳐한 이미지를 리스트에 담는다.
          images.Add(buffer);
        }
      }

      // 파일 IO 스트림을 취득한다.
      using (var stream = new FileStream(@"d:\work\output.pdf", FileMode.Create, FileAccess.Write))
      {
        // Pdf형식의 document를 생성한다.
        Document document = new Document(PageSize.A4, 10, 10, 10, 10);
        // PdfWriter를 취득한다.
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        // document Open
        document.Open();
        try
        {
          // 이미지 별로 PDF 페이지에 추가한다.
          foreach (var image in images)
          {
            // iTextSharp용 이미지로 변환
            iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(image, System.Drawing.Imaging.ImageFormat.Jpeg);
            // 이미지를 A4용 페이지에 맞게끔 확대 및 축소
            var percentage = 720 / pic.Width;
            pic.ScalePercent(percentage * 100);
            // 이미지를 추가한다.
            document.Add(pic);
            // 이미지 추가
            document.NewPage();
          }
        }
        finally
        {
          // document Close
          document.Close();
        }
      }
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // excel를 가로 1000에서 세로 500의 이미지로 변환.
      // 위치는 Left 0, Top -50, 즉 50pixel 만큼 위로 위치 재정의(Warning 메시지를 없애기 위한)
      // 시작 Row는 1 시작 Column은 1
      // 마지막 Row는 데이터가 있는 곳까지
      // 마지막 Column은 40까지
      ConvertImageAndPDF(@"d:\work\test.xlsx", 1000, 500, 0, -50, 1, 1, null, 40);

      Console.WriteLine("Press any key...");
      Console.ReadKey();
    }
  }
}

위 소스는 Excel를 이미지로 추출하고 iTextSharp 라이브러리를 이용해서 Image를 다시 PDF로 변환하였습니다.

링크 - [C#] iTextSharp을 이용한 PDF 만들기


여기서 주의할 것은 제가 buffer image Width와 Height를 설정합니다. 굳이 이 부분은 없어도 될 듯 싶습니다만, 이미지의 여백이나 확대, 축소를 Spire.Xls를 설정할 수가 없습니다.

설정하기 위해 Graphics객체를 받고 다시 메모리에 다시 그리는 형태로 Image의 사이즈를 재정의할 수 있습니다. Image 사이즈 재정의가 필요한 것은 Pdf 가로폭은 A4용지에 맞추어 사이즈가 정해져 있습니다만 Excel의 경우는 가로가 정해져 있지 않기 때문에 그것을 정의할 수 있는 방법이 필요한 것입니다.

그리고 위치 재설정을 통해서 Warning 메시지를 없애고.. Excel의 구간을 설정하여 캡쳐를 하게 됩니다.


캡쳐가 된 이미지를 다시 PDF 변환을 통해서 PDF으로 출력을 합니다.

여기까지 C#에서 Excel 파일을 PDF 및 이미지로 변환하는 방법(Spire.Xls)에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.