Показаны сообщения с ярлыком pdf. Показать все сообщения
Показаны сообщения с ярлыком pdf. Показать все сообщения

среда, 16 февраля 2011 г.

Использование PDF шаблонов C#.

Исходники к статье

Продолжая тему шаблонов, хочу раскрыть использование PDF вместе с закрытым исходным кодом. В сети можно найти достаточное количество статей, которые описывают данный процесс, но в основном они используют GNU General Public License библиотеки, а это ведет к открытию своего кода. Проект менеджер услышав об этом, вновь может посылать вас в лес, искать бесплатные отвертки…

Хочу обратить ваше внимание на проект PdfSharp и его лицензию, разрешающую использование в коммерческих целях.

Как использовать шаблоны? Немного теории:

Стандартный подход прост – графически рисуется требуемая форма, расставляются закладки или некие ключевые слова (наподобие @Name@), которые после отыскиваются в документе и заменяются на необходимые значения. Но, к сожалению, PDFsharp не поддерживает парсинг документа, этот подход потерпит фиаско.

Как же быть? Есть два выхода из положения, каждый из них требует больших трудозатрат, чем использование GPL библиотек (можете поискать реализации на iText), первый это полностью генерировать бланки без использования шаблонов, но при сложном бланке на это дело можно потратить чуть ли не целый день на бланк. И второй способ предлагаемый нам PDFsharp, это использовать шаблон как холст для рисования. Представьте, что у нас на столе, под стеклом лежит бланк документа и есть карандаш или маркер, которым мы рисуем на стекле, если стекло достаточно тонкое, то человек, взглянувший на такое "художество", будет считать его единым целым. Далее, мы как раз и будем рисовать на шаблоне, с помощью System.Drawing, подставляя нужные нам данные в требуемые места.

Предположим, в некой мнимой компании «Ключи и Отвертки», для отдела кадров, необходимо создать бланк сотрудника, в котором будут находиться контактные данные, фотография и таблица прихода и ухода на работу за последнюю неделю, и как всегда все это должно быть на фирменном бланке компании.

Не обладая большими талантами дизайнера, я приготовил такой бланк, и самолично его утвердил. :)

c# pdf template

Создадим новое консольное приложение с именем UsingPdfTemplate, далее добавим к проекту ссылки на сборки PdfSharp.dll из каталога GDI+ (заранее скачанные с сайта проекта, на момент написания статьи версия 1_31), а так же на System.Drawing. Добавим к проекту файл template.pdf (взять можно из исходников к статье) и установим его свойство Build Action – Embedded Resource и Copy to Output Directory – Copy always.

Далее введем следующий код:



using System;
using System.Diagnostics;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;

namespace UsingPdfTemplate
{
class Program
{
static void Main(string[] args)
{
PdfDocument inputDocument = PdfReader.Open("template.pdf", PdfDocumentOpenMode.Import);
PdfPage notEditablePage = inputDocument.Pages[0];

PdfDocument outputDocument = new PdfDocument();
PdfPage editablePage = outputDocument.AddPage(notEditablePage);

outputDocument.Save("newPdf.pdf");
Process.Start("newPdf.pdf");
}
}
}



Мы открываем документ шаблона и находим его первую страницу, после создаем новый документ и помещаем в него данную страницу, после чего ее можно редактировать. Далее без каких либо изменений сохраняем новый документ на диск и запускаем его для просмотра. Получившийся документ – точная копия исходного файла.

Теперь заполним поля «Должность», «Имя», «Email», добавим фотографию и таблицу посещений:




PdfPage editablePage = outputDocument.AddPage(notEditablePage);

XGraphics gfx = XGraphics.FromPdfPage(editablePage);
DrawFields(gfx);
DrawImage(gfx);
DrawTable(gfx);


outputDocument.Save("newPdf.pdf");




Получаем объект XGraphics и передаем его в методы DrawFields(), DrawImage(), DrawTable().

DrawFields отрисует поля на шаблоне, код метода:



private static void DrawFields(XGraphics gfx)
{
XPdfFontOptions fontOptions = new XPdfFontOptions(PdfFontEncoding.Unicode, PdfFontEmbedding.Always);
XFont font = new XFont("Times New Roman", 10, XFontStyle.Bold, fontOptions);

gfx.DrawString("Программист", font, XBrushes.Black, 100, 135);
gfx.DrawString("Александр Кобелев", font, XBrushes.Black, 100, 160);
gfx.DrawString("Kobelev.Alexander@gmail.com", font, XBrushes.Black, 100, 185);
}



Выставляем поддержку юникода и отрисовываем три строчки текста в вымеренных позициях.

Для отрисовки фотографии добавим в проект фото (можно так же взять из исходников фото моего кота), и пометим его свойство Build Action – Embedded Resource и Copy to Output Directory – Copy always.

DrawImage отрисует фотографию, код метода:



private static void DrawImage(XGraphics gfx)
{
XImage img = XImage.FromFile("cat.jpg");
gfx.DrawImage(img, 350, 125, 120, 160);
}



Очень простой метод - мы лишь получаем изображение из файла (XImage можно так же получить, используя System.Drawing.Image, который можно получить из потока) и отрисовываем его на документе по координатам с заданными размерами.

С таблицей будет посложнее, дело в том что PdfSharp ничего не знает о таблицах и способен их нарисовать только из линий, но не стоит падать духом, так как есть замечательная библиотека MigraDoc, которая поставляется вместе с PdfSharp. Нам лишь надо добавить ссылку на библиотеку MigraDoc.DocumentObjectModel.dll и MigraDoc.Rendering.dll.

DrawTable отрисует таблицу, код метода:



...
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.Rendering;

private static void DrawTable(XGraphics gfx)
{

Document doc = new Document();

Table table = new Table();
table.Borders.Width = 0.3;
table.AddColumn(76);
table.AddColumn(78.2);
table.AddColumn(77.6);

for (int day = 7; day > 0; day--)
{
var row = table.AddRow();
row[0].AddParagraph(DateTime.Now.AddDays(-day).ToString("dd/MM/yyyy"));
row[1].AddParagraph(DateTime.Now.AddDays(-day).ToString("HH:mm"));
row[2].AddParagraph(DateTime.Now.AddDays(-day).AddHours(8).ToString("HH:mm"));
}

doc.AddSection().Add(table);

DocumentRenderer docRenderer = new DocumentRenderer(doc);
docRenderer.PrepareDocument();
docRenderer.RenderObject(gfx, 36, 257, 0, table);
}



В этом методе мы вначале создаем MigraDoc.DocumentObjectModel.Document, потом таблицу, выставляем у таблицы ширину бордюра и размеры колонок. После чего заполняем семь строк данными и добавляем таблицу в документ, после создаем объект класса MigraDoc.Rendering.DocumentRenderer, который принимает в качестве параметра конструктора документ содержащий таблицу, подготавливаем и отрисовываем его, используя объект XGraphics переданный в метод.

Как результат у нас появляется заполненный PDF документ на основе шаблона:

c# completed pdf template

Александр Кобелев aka Megano