Skip to content

Instantly share code, notes, and snippets.

@pieterbeens
Last active April 17, 2020 14:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pieterbeens/7008672 to your computer and use it in GitHub Desktop.
Save pieterbeens/7008672 to your computer and use it in GitHub Desktop.
A modified version of DoddleReport iTextSharp PdfReportWriter that supports PDF files with multiple reports by implementing the AppendReport method. I've extracted out the logic that adds a report to the PDF document to a new method named AddReportToDocument and used method Document.NewPage to ensure that every report starts on a new page.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using DoddleReport;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Font = iTextSharp.text.Font;
using Rectangle = iTextSharp.text.Rectangle;
namespace DoddleReport.iTextSharp
{
public class AppendablePdfReportWriter : IReportWriter
{
public const string TitleStyle = "TitleStyle";
public const string SubTitleStyle = "SubTitleStyle";
public const string HeaderStyle = "HeaderStyle";
public const string FooterStyle = "FooterStyle";
public const string FontFamily = "FontFamily";
internal IDictionary<Report, IList<Report>> ReportsToAppend { get; private set; }
public AppendablePdfReportWriter()
{
ReportsToAppend = new Dictionary<Report, IList<Report>>();
}
/// <summary>
/// Writes the report.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="destination">The destination.</param>
public void WriteReport(Report report, Stream destination)
{
var pageSize = new Rectangle(report.RenderHints.PageSize.Width, report.RenderHints.PageSize.Height);
if (report.RenderHints.Orientation == ReportOrientation.Landscape)
pageSize = pageSize.Rotate();
var margins = report.RenderHints.Margins;
var doc = new Document(pageSize, margins.Width, margins.Width, margins.Height, margins.Height);
using (PdfWriter.GetInstance(doc, destination))
{
doc.Open();
AddReportToDocument(report, doc);
// Add each report that has to be appended to the Pdf document
foreach (Report reportToAppend in ReportsToAppend[report])
{
AddReportToDocument(reportToAppend, doc);
}
doc.Close();
}
}
private void AddReportToDocument(Report report, Document doc)
{
// Start at a new page
doc.NewPage();
var globalTable = new PdfPTable(1)
{
HeaderRows = 1,
WidthPercentage = 100
};
// Render the header
RenderHeader(globalTable, report.TextFields, report.RenderHints);
// Render all the rows
int fieldsCount = report.DataFields.Count(f => !f.Hidden);
var table = new PdfPTable(fieldsCount)
{
HeaderRows = 1,
WidthPercentage = 100
};
globalTable.AddCell(new PdfPCell(table)
{
Border = 0
});
foreach (ReportRow row in report.GetRows())
{
foreach (RowField field in row.Fields.Where(f => !f.Hidden))
{
PdfPCell cell;
if (row.RowType == ReportRowType.HeaderRow)
{
cell = CreateTextCell(field.HeaderStyle, report.RenderHints[FontFamily] as string,
field.HeaderText);
}
else
{
var url = row.GetUrlString(field);
cell = url == null
? CreateTextCell(field.DataStyle, report.RenderHints[FontFamily] as string, row.GetFormattedValue(field))
: CreateHyperLinkCell(url, row.GetFormattedValue(field));
}
cell.Border = 0;
cell.Padding = 5;
table.AddCell(cell);
}
}
// Render the footer
RenderFooter(globalTable, report.TextFields, report.RenderHints);
doc.Add(globalTable);
}
/// <summary>
/// Appends the report.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public void AppendReport(Report source, Report destination)
{
if (source == null || destination == null)
throw new ArgumentNullException(source == null ? "source" : "destination");
if (!(source.Writer is AppendablePdfReportWriter))
throw new InvalidOperationException("Unable to append report, the source Writer is not a AppendablePdfReportWriter");
if (!this.ReportsToAppend.ContainsKey(source))
this.ReportsToAppend.Add(source, (IList<Report>)new List<Report>());
this.ReportsToAppend[source].Add(destination);
}
/// <summary>
/// Renders the header.
/// </summary>
/// <param name="globalTable">The global table.</param>
/// <param name="textFields">The text fields.</param>
/// <param name="renderHints">The render hints.</param>
protected virtual void RenderHeader(PdfPTable globalTable, ReportTextFieldCollection textFields,
RenderHintsCollection renderHints)
{
int rowCount = 0;
if (!string.IsNullOrEmpty(textFields.Title))
{
ReportStyle reportStyle = renderHints[TitleStyle] as ReportStyle ?? GetDefaultTitleStyle();
globalTable.AddCell(CreateTextCell(reportStyle, renderHints[FontFamily] as string, textFields.Title));
rowCount++;
}
if (!string.IsNullOrEmpty(textFields.SubTitle))
{
ReportStyle reportStyle = renderHints[SubTitleStyle] as ReportStyle ?? GetDefaultSubTitleStyle();
globalTable.AddCell(CreateTextCell(reportStyle, renderHints[FontFamily] as string, textFields.SubTitle));
rowCount++;
}
if (!string.IsNullOrEmpty(textFields.Header))
{
ReportStyle reportStyle = renderHints[HeaderStyle] as ReportStyle ?? GetDefaultHeaderStyle();
globalTable.AddCell(CreateTextCell(reportStyle, renderHints[FontFamily] as string, textFields.Header));
rowCount++;
}
if (rowCount > 0)
{
PdfPCell cell = CreateTextCell(new ReportStyle(), renderHints[FontFamily] as string, string.Empty);
cell.PaddingBottom = 10;
globalTable.AddCell(cell);
rowCount++;
}
globalTable.HeaderRows = rowCount;
}
/// <summary>
/// Renders the footer.
/// </summary>
/// <param name="globalTable">The global table.</param>
/// <param name="textFields">The text fields.</param>
/// <param name="renderHints">The render hints.</param>
protected virtual void RenderFooter(PdfPTable globalTable, ReportTextFieldCollection textFields,
RenderHintsCollection renderHints)
{
if (!string.IsNullOrEmpty(textFields.Footer))
{
ReportStyle reportStyle = renderHints[FooterStyle] as ReportStyle ?? GetDefaultFooterStyle();
globalTable.AddCell(CreateTextCell(reportStyle, renderHints[FontFamily] as string, textFields.Footer));
}
}
/// <summary>
/// Gets the default title style.
/// </summary>
/// <returns>The default title style.</returns>
private static ReportStyle GetDefaultTitleStyle()
{
return new ReportStyle
{
Bold = true,
FontSize = 18,
HorizontalAlignment = HorizontalAlignment.Center
};
}
/// <summary>
/// Gets the default sub title style.
/// </summary>
/// <returns>The default sub title style.</returns>
private static ReportStyle GetDefaultSubTitleStyle()
{
return new ReportStyle
{
Bold = true,
FontSize = 14,
HorizontalAlignment = HorizontalAlignment.Center
};
}
/// <summary>
/// Gets the default header style.
/// </summary>
/// <returns>The default header style.</returns>
private static ReportStyle GetDefaultHeaderStyle()
{
return new ReportStyle
{
Bold = true,
FontSize = 11,
HorizontalAlignment = HorizontalAlignment.Left
};
}
/// <summary>
/// Gets the default footer style.
/// </summary>
/// <returns>The default footer style.</returns>
private static ReportStyle GetDefaultFooterStyle()
{
return new ReportStyle
{
HorizontalAlignment = HorizontalAlignment.Left
};
}
/// <summary>
/// Creates the text cell.
/// </summary>
/// <param name="reportStyle">The report style.</param>
/// <param name="fontName">Name of the font.</param>
/// <param name="text">The text.</param>
/// <returns>
/// The newly created cell.
/// </returns>
private static PdfPCell CreateTextCell(ReportStyle reportStyle, string fontName, string text)
{
var par = new Paragraph(text, ConvertStyleToFont(reportStyle, fontName));
var cell = new PdfPCell(par) { Border = 0 };
CopyStyleToCell(reportStyle, cell);
return cell;
}
private static PdfPCell CreateHyperLinkCell(string url, string text)
{
Font linkFont = FontFactory.GetFont("Arial", 12, Font.UNDERLINE, new BaseColor(Color.Blue));
Anchor anchor = new Anchor(text, linkFont);
anchor.Reference = url;
return new PdfPCell(anchor) { Border = 0 };
}
/// <summary>
/// Converts a report style to a new font definition.
/// </summary>
/// <param name="reportStyle">The report style.</param>
/// <param name="fontFamily">Name of the font.</param>
/// <returns>The font.</returns>
public static Font ConvertStyleToFont(ReportStyle reportStyle, string fontFamily)
{
var font = new Font();
font.SetFamily(fontFamily);
if (reportStyle.Underline)
{
font.SetStyle(Font.UNDERLINE);
}
else if (reportStyle.Bold || reportStyle.Italic)
{
if (reportStyle.Bold && reportStyle.Italic)
{
font.SetStyle(Font.BOLDITALIC);
}
else if (reportStyle.Bold)
{
font.SetStyle(Font.BOLD);
}
else
{
font.SetStyle(Font.ITALIC);
}
}
font.Size = reportStyle.FontSize;
font.SetColor(reportStyle.ForeColor.R, reportStyle.ForeColor.G, reportStyle.ForeColor.B);
return font;
}
/// <summary>
/// Copies the report style to the cell style.
/// </summary>
/// <param name="reportStyle">The report style.</param>
/// <param name="cell">The cell.</param>
public static void CopyStyleToCell(ReportStyle reportStyle, PdfPCell cell)
{
cell.BackgroundColor = new BaseColor(reportStyle.BackColor);
//cell.Width = reportStyle.Width > 0 ? reportStyle.Width : cell.Width;
switch (reportStyle.HorizontalAlignment)
{
case HorizontalAlignment.Center:
cell.HorizontalAlignment = Element.ALIGN_CENTER;
break;
case HorizontalAlignment.Left:
cell.HorizontalAlignment = Element.ALIGN_LEFT;
break;
case HorizontalAlignment.Right:
cell.HorizontalAlignment = Element.ALIGN_RIGHT;
break;
}
switch (reportStyle.VerticalAlignment)
{
case VerticalAlignment.Bottom:
cell.VerticalAlignment = Element.ALIGN_BOTTOM;
break;
case VerticalAlignment.Middle:
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
break;
case VerticalAlignment.Top:
cell.VerticalAlignment = Element.ALIGN_TOP;
break;
}
if (reportStyle.TextRotation % 90 == 0)
cell.Rotation = reportStyle.TextRotation;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment