Sample Project

The sample project includes:

Requirements

  • .NET Framework 4.0 or higher
  • Visual Studio 2017
  • Microsoft SQL Server 2014+

Features

This tutorial shows how to export a visual schedule created using DayPilot ASP.NET Scheduler control to a PDF file.

  • Export to PNG
  • Export to PDF
  • Customized scheduler appearance (fonts, colors)
  • Multiple PDF page sizes (letter, A4)
  • PDF page orientation (portrait, landscape)
  • Custom PDF page header
  • Automatic image scaling to fill the page

License

Licensed for testing and evaluation purposes. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for ASP.NET WebForms. Buy a license.

Scheduler Control

We will add a new DayPilot Scheduler control to the page.

<DayPilot:DayPilotScheduler 
    runat="server" 
    ID="DayPilotScheduler1">
</DayPilot:DayPilotScheduler>

Now we will adjust the Scheduler appearance.

  • cell width (CellWidth property)
  • event/row height (EventHeight property)
  • scale (day and hour levels) and format of the time header (TimeHeaders property)
<DayPilot:DayPilotScheduler 
    runat="server" 
    ID="DayPilotScheduler1"
    ClientIDMode="Static"
    EventHeight="25"
    CellWidth="40"
    >
  <TimeHeaders>
    <DayPilot:TimeHeader GroupBy="Day" Format="d" />
    <DayPilot:TimeHeader GroupBy="Cell" />
  </TimeHeaders>
</DayPilot:DayPilotScheduler>

Export to PNG

scheduler-png-export.png

First, we will export the Scheduler to a PNG image.

Add a "ButtonExportPng" button to the .aspx page:

<h2>Export to PNG</h2>

<div>
  <asp:Button runat="server" ID="ButtonExportPng" Text="Export to PNG" 
        onclick="ButtonExportPng_Click" />
</div>

Add a Click event handler:

C#

protected void ButtonExportPng_Click(object sender, EventArgs e)
{
  ExportToPng();
}

private void ExportToPng()
{
  SetDataSourceAndBind();
  SetExportProperties();

  Response.Clear();
  Response.ContentType = "image/png";
  Response.AddHeader("content-disposition", "attachment;filename=print.png");
  MemoryStream img = DayPilotScheduler1.Export(ImageFormat.Png);
  img.WriteTo(Response.OutputStream);
  Response.End();
}

VB

Protected Sub ButtonExportPng_Click(ByVal sender As Object, ByVal e As EventArgs)
  ExportToPng()
End Sub

Private Sub ExportToPng()
  SetDataSourceAndBind()
  SetExportProperties();

  Response.Clear()
  Response.ContentType = "image/png"
  Response.AddHeader("content-disposition", "attachment;filename=print.png")
  Dim img As MemoryStream = DayPilotScheduler1.Export(ImageFormat.Png)
  img.WriteTo(Response.OutputStream)
  Response.End()
End Sub

Image Appearance (Fonts, Colors)

scheduler-asp.net-png-export-theme.png

The Scheduler is not able to apply the CSS theme we defined for the browser. We need to adjust the appearance of the exported image using individual style properties.

C#

private void SetExportProperties()
{
  DayPilotScheduler1.Width = Unit.Percentage(100);

  // match the theme
  DayPilotScheduler1.HourNameBackColor = ColorTranslator.FromHtml("#eee");
  DayPilotScheduler1.BackColor = Color.White;
  DayPilotScheduler1.NonBusinessBackColor = Color.White;
  DayPilotScheduler1.BorderColor = ColorTranslator.FromHtml("#999");
  DayPilotScheduler1.HeaderFontColor = ColorTranslator.FromHtml("#666");
  DayPilotScheduler1.CellBorderColor = ColorTranslator.FromHtml("#eee");
  DayPilotScheduler1.EventFontColor = ColorTranslator.FromHtml("#666");
  DayPilotScheduler1.EventCorners = CornerShape.Rounded;
  DayPilotScheduler1.EventFontSize = "10pt";
  DayPilotScheduler1.EventBorderColor = ColorTranslator.FromHtml("#999");
  DayPilotScheduler1.EventBackColor = ColorTranslator.FromHtml("#fafafa");
}

VB

Private Sub SetExportProperties()
  DayPilotScheduler1.Width = Unit.Percentage(100)

  ' match the theme
  DayPilotScheduler1.HourNameBackColor = ColorTranslator.FromHtml("#eee")
  DayPilotScheduler1.BackColor = Color.White
  DayPilotScheduler1.NonBusinessBackColor = Color.White
  DayPilotScheduler1.BorderColor = ColorTranslator.FromHtml("#999")
  DayPilotScheduler1.HeaderFontColor = ColorTranslator.FromHtml("#666")
  DayPilotScheduler1.CellBorderColor = ColorTranslator.FromHtml("#eee")
  DayPilotScheduler1.EventFontColor = ColorTranslator.FromHtml("#666")
  DayPilotScheduler1.EventCorners = CornerShape.Rounded
  DayPilotScheduler1.EventFontSize = "10pt"
  DayPilotScheduler1.EventBorderColor = ColorTranslator.FromHtml("#999")
  DayPilotScheduler1.EventBackColor = ColorTranslator.FromHtml("#fafafa")
End Sub

Create a PDF File

scheduler-pdf-blank.png

We will use PDFSharp library for handling the PDF export.

  • open-source (commercial-friendly MIT license)
  • managed .NET
  • small footprint (570 kB DLL)

Let's start with an empty PDF document. We will save it to a file.

C#

private void ExportToPdf()
{
  PdfDocument doc = new PdfDocument();
  doc.Info.Title = "DayPilot Scheduler PDF Export";
  doc.Info.Author = "DayPilot";

  PdfPage page = doc.AddPage();

  doc.Save("file.pdf");
}

VB

Private Sub ExportToPdf()
  ' create a new PDF document
  Dim doc As New PdfDocument()
  doc.Info.Title = "DayPilot Scheduler PDF Export"
  doc.Info.Author = "DayPilot"

  ' add a page
  Dim page_Renamed As PdfPage = doc.AddPage()

  doc.Save("file.pdf")

End Sub

Send the PDF File to the Browser for Download

Now we have a new PDF document that saves to a file. Now we will send it to the browser by writing it to Response.OutputStream.

As it is not possible to write the PDF file directly to Response.OutputStream (Response.OutputStream doesn't support random access) we will use a temporary MemoryStream.

C#

private void ExportToPdf()
{
  PdfDocument doc = new PdfDocument();
  doc.Info.Title = "DayPilot Scheduler PDF Export";
  doc.Info.Author = "DayPilot";

  PdfPage page = doc.AddPage();

  MemoryStream mem = new MemoryStream();
  doc.Save(mem, false);

  Response.Clear();
  Response.ContentType = "application/pdf";
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf");
  mem.WriteTo(Response.OutputStream);
  Response.End();
}

VB

Private Sub ExportToPdf()
  ' create a new PDF document
  Dim doc As New PdfDocument()
  doc.Info.Title = "DayPilot Scheduler PDF Export"
  doc.Info.Author = "DayPilot"

  ' add a page
  Dim page_Renamed As PdfPage = doc.AddPage()

  ' save the PDF file to MemoryStream
  Dim mem As New MemoryStream()
  doc.Save(mem, False)

  ' send the output stream to the browser
  Response.Clear()
  Response.ContentType = "application/pdf"
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf")
  mem.WriteTo(Response.OutputStream)
  Response.End()
End Sub

Set PDF Page Size (Letter, A4) and Orientation (Portrait, Landscape)

scheduler-pdf-page-size-orientation.png

Let's add the controls for specifying the PDF page size (letter or A4) and orientation (portrait, landscape).

<div>
  Page Size: 
  <asp:RadioButtonList runat="server" ID="ListPageSize" RepeatDirection="Horizontal" RepeatLayout="Flow">
    <asp:ListItem Selected="True">Letter</asp:ListItem>
    <asp:ListItem>A4</asp:ListItem>
  </asp:RadioButtonList>
</div>

<div>
  Orientation:
  <asp:RadioButtonList runat="server" ID="ListPageOrientation" RepeatDirection="Horizontal" RepeatLayout="Flow">
    <asp:ListItem Selected="True">Portrait</asp:ListItem>
    <asp:ListItem>Landscape</asp:ListItem>
  </asp:RadioButtonList>
</div>

These settings will be used in our PDF code:

C#

private void ExportToPdf()
{
  PdfDocument doc = new PdfDocument();
  doc.Info.Title = "DayPilot Scheduler PDF Export";
  doc.Info.Author = "DayPilot";

  PdfPage page = doc.AddPage();

  page.Size = (PageSize) Enum.Parse(typeof (PageSize), ListPageSize.SelectedValue);
  page.Orientation = (PageOrientation)Enum.Parse(typeof(PageOrientation), ListPageOrientation.SelectedValue);

  MemoryStream mem = new MemoryStream();
  doc.Save(mem, false);

  Response.Clear();
  Response.ContentType = "application/pdf";
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf");
  mem.WriteTo(Response.OutputStream);
  Response.End();
}

VB

Private Sub ExportToPdf()
  ' create a new PDF document
  Dim doc As New PdfDocument()
  doc.Info.Title = "DayPilot Scheduler PDF Export"
  doc.Info.Author = "DayPilot"

  ' add a page
  Dim page_Renamed As PdfPage = doc.AddPage()

  ' set PDF page properties (size and orientation)
  page_Renamed.Size = CType(System.Enum.Parse(GetType(PageSize), ListPageSize.SelectedValue), PageSize)
  page_Renamed.Orientation = CType(System.Enum.Parse(GetType(PageOrientation), ListPageOrientation.SelectedValue), PageOrientation)

  ' save the PDF file to MemoryStream
  Dim mem As New MemoryStream()
  doc.Save(mem, False)

  ' send the output stream to the browser
  Response.Clear()
  Response.ContentType = "application/pdf"
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf")
  mem.WriteTo(Response.OutputStream)
  Response.End()
End Sub

Add Title to PDF

scheduler-pdf-title.png

We have an empty PDF file so let's write a simple header to the page.

C#

// create a graphics object for PDF page modification
XGraphics gfx = XGraphics.FromPdfPage(page);

// write title
XRect titleRect = new XRect(new XPoint(), gfx.PageSize);
titleRect.Inflate(-10, -15);
XFont font = new XFont("Tahoma", 14, XFontStyle.Bold);
gfx.DrawString("DayPilot Scheduler PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter);

VB

' create a graphics object for PDF page modification
Dim gfx As XGraphics = XGraphics.FromPdfPage(page_Renamed)

' write title
Dim titleRect As New XRect(New XPoint(), gfx.PageSize)
titleRect.Inflate(-10, -15)
Dim font As New XFont("Tahoma", 14, XFontStyle.Bold)
gfx.DrawString("DayPilot Scheduler PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter)

Add Scheduler to the PDF file

scheduler-pdf-export.png

Now it's the time to add the image exported from the Scheduler to the PDF page.

C#

// create Scheduler image
SetDataSourceAndBind();
SetExportProperties();
Bitmap bitmap = DayPilotScheduler1.ExportBitmap();

// add the image to the PDF page
XImage image = XImage.FromGdiPlusImage(bitmap);
XRect imageRect = GetPaddedRectForImage(gfx, image, 10);
double y = 40;
imageRect.Y = y;
gfx.DrawImage(image, imageRect);

VB

' create Scheduler image
SetDataSourceAndBind()
SetExportProperties()
Dim bitmap As Bitmap = DayPilotScheduler1.ExportBitmap()

' add the image to the PDF page
Dim image As XImage = XImage.FromGdiPlusImage(bitmap)
Dim imageRect As XRect = GetPaddedRectForImage(gfx, image, 10)
Dim y As Double = 40
imageRect.Y = y
gfx.DrawImage(image, imageRect)

We want the image to use the full page width while keeping a 10% padding. This helper GetPaddedRectForImage() method will calculate the target rectangel dimensions while keeping the aspect ratio of the source image.

C#

private XRect GetPaddedRectForImage(XGraphics gfx, XImage image, int paddingWidthPct)
{
  double ratio = image.PixelWidth / (double)image.PixelHeight;
  double width = gfx.PageSize.Width;
  double height = width / ratio;

  XRect imageRect = new XRect(0, 0, width, height);
  imageRect.Scale((100 - paddingWidthPct) / 100.0, (100 - paddingWidthPct) / 100.0);

  double x = (gfx.PageSize.Width - imageRect.Width) / 2;
  imageRect.X = x;

  return imageRect;
}

VB

Private Function GetPaddedRectForImage(ByVal gfx As XGraphics, ByVal image As XImage, ByVal paddingWidthPct As Integer) As XRect
  Dim ratio As Double = image.PixelWidth / CDbl(image.PixelHeight)
  Dim width As Double = gfx.PageSize.Width
  Dim height As Double = width / ratio

  Dim imageRect As New XRect(0, 0, width, height)
  imageRect.Scale((100 - paddingWidthPct) / 100.0, (100 - paddingWidthPct) / 100.0)

  Dim x As Double = (gfx.PageSize.Width - imageRect.Width) \ 2
  imageRect.X = x

  Return imageRect
End Function

Export to PDF (Full Source Code)

C#

private void ExportToPdf()
{   
  // create a new PDF document
  PdfDocument doc = new PdfDocument();
  doc.Info.Title = "DayPilot Scheduler PDF Export";
  doc.Info.Author = "DayPilot";

  // add a page
  PdfPage page = doc.AddPage();

  // set PDF page properties (size and orientation)
  page.Size = (PageSize) Enum.Parse(typeof (PageSize), ListPageSize.SelectedValue);
  page.Orientation = (PageOrientation)Enum.Parse(typeof(PageOrientation), ListPageOrientation.SelectedValue);

  // create graphics object for PDF page modification
  XGraphics gfx = XGraphics.FromPdfPage(page);

  // write title
  XRect titleRect = new XRect(new XPoint(), gfx.PageSize);
  titleRect.Inflate(-10, -15);
  XFont font = new XFont("Tahoma", 14, XFontStyle.Bold);
  gfx.DrawString("DayPilot Scheduler PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter);

  // create Scheduler image
  SetDataSourceAndBind();
  SetExportProperties();
  Bitmap bitmap = DayPilotScheduler1.ExportBitmap();

  // add the image to the PDF page
  XImage image = XImage.FromGdiPlusImage(bitmap);
  XRect imageRect = GetPaddedRectForImage(gfx, image, 10);
  double y = 40;
  imageRect.Y = y;
  gfx.DrawImage(image, imageRect);

  // save the PDF file to MemoryStream
  MemoryStream mem = new MemoryStream();
  doc.Save(mem, false);

  // send the output stream to the browser
  Response.Clear();
  Response.ContentType = "application/pdf";
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf");
  mem.WriteTo(Response.OutputStream);
  Response.End();
}

private XRect GetPaddedRectForImage(XGraphics gfx, XImage image, int paddingWidthPct)
{
  double ratio = image.PixelWidth / (double)image.PixelHeight;
  double width = gfx.PageSize.Width;
  double height = width / ratio;

  XRect imageRect = new XRect(0, 0, width, height);
  imageRect.Scale((100 - paddingWidthPct) / 100.0, (100 - paddingWidthPct) / 100.0);

  double x = (gfx.PageSize.Width - imageRect.Width) / 2;
  imageRect.X = x;

  return imageRect;
}

VB

Private Sub ExportToPdf()
  ' create a new PDF document
  Dim doc As New PdfDocument()
  doc.Info.Title = "DayPilot Scheduler PDF Export"
  doc.Info.Author = "DayPilot"

  ' add a page
  Dim page_Renamed As PdfPage = doc.AddPage()

  ' set PDF page properties (size and orientation)
  page_Renamed.Size = CType(System.Enum.Parse(GetType(PageSize), ListPageSize.SelectedValue), PageSize)
  page_Renamed.Orientation = CType(System.Enum.Parse(GetType(PageOrientation), ListPageOrientation.SelectedValue), PageOrientation)

  ' create graphics object for PDF page modification
  Dim gfx As XGraphics = XGraphics.FromPdfPage(page_Renamed)

  ' write title
  Dim titleRect As New XRect(New XPoint(), gfx.PageSize)
  titleRect.Inflate(-10, -15)
  Dim font As New XFont("Tahoma", 14, XFontStyle.Bold)
  gfx.DrawString("DayPilot Scheduler PDF Export", font, XBrushes.DarkGray, titleRect, XStringFormats.TopCenter)

  ' create Scheduler image
  SetDataSourceAndBind()
  SetExportProperties()
  Dim bitmap As Bitmap = DayPilotScheduler1.ExportBitmap()

  ' add the image to the PDF page
  Dim image As XImage = XImage.FromGdiPlusImage(bitmap)
  Dim imageRect As XRect = GetPaddedRectForImage(gfx, image, 10)
  Dim y As Double = 40
  imageRect.Y = y
  gfx.DrawImage(image, imageRect)

  ' save the PDF file to MemoryStream
  Dim mem As New MemoryStream()
  doc.Save(mem, False)

  ' send the output stream to the browser
  Response.Clear()
  Response.ContentType = "application/pdf"
  Response.AddHeader("content-disposition", "attachment;filename=scheduler.pdf")
  mem.WriteTo(Response.OutputStream)
  Response.End()
End Sub

Private Function GetPaddedRectForImage(ByVal gfx As XGraphics, ByVal image As XImage, ByVal paddingWidthPct As Integer) As XRect
  Dim ratio As Double = image.PixelWidth / CDbl(image.PixelHeight)
  Dim width As Double = gfx.PageSize.Width
  Dim height As Double = width / ratio

  Dim imageRect As New XRect(0, 0, width, height)
  imageRect.Scale((100 - paddingWidthPct) / 100.0, (100 - paddingWidthPct) / 100.0)

  Dim x As Double = (gfx.PageSize.Width - imageRect.Width) \ 2
  imageRect.X = x

  Return imageRect
End Function