DynamicTable.vb
  1. ''
  2. '' This code is part of Document Solutions for PDF demos.
  3. '' Copyright (c) MESCIUS inc. All rights reserved.
  4. ''
  5. Imports System.IO
  6. Imports System.Drawing
  7. Imports System.Text
  8. Imports GrapeCity.Documents.Pdf
  9. Imports GrapeCity.Documents.Text
  10. Imports GrapeCity.Documents.Html
  11.  
  12. '' This sample shows how to insert an HTML table with a varying number of rows
  13. '' that might not fit on a single page, into a PDF document starting at an arbitrary
  14. '' position on the page (all data rows must have the same height though).
  15. '' We first create a table with a single data row, measure its height,
  16. '' then create a similar table but with two data rows and measure it too.
  17. '' This allows us to find out the header and data rows' heights, and render
  18. '' the table to a PDF starting at the desired position on the page, and split
  19. '' it into additional pages as needed.
  20. ''
  21. '' Please see notes in comments at the top of HelloWorldHtml
  22. '' sample code for details on adding DsHtml to your projects.
  23. Public Class DynamicTable
  24. Function CreatePDF(ByVal stream As Stream) As Integer
  25. '' This tag is used to insert the prepared table HTML code
  26. '' into the HTML page template that defines the CSS styles etc.
  27. '' (Using this tag allows you to use string.Format when building
  28. '' the table HTML code, as otherwise curly braces in style
  29. '' definitions would interfere with format specifiers.)
  30. Const TTAG = "___TABLE___"
  31.  
  32. '' The HTML page template:
  33. Const tableTpl =
  34. "<!DOCTYPE html>" +
  35. "<html>" +
  36. "<head>" +
  37. "<style>" +
  38. "#employees {" +
  39. " font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif;" +
  40. " border-collapse: collapse;" +
  41. " width: 100%;" +
  42. "}" +
  43. "" +
  44. "#employees td, #employees th {" +
  45. " border: 1px solid #ddd;" +
  46. " padding: 8px;" +
  47. "}" +
  48. "" +
  49. "#employees tr:nth-child(even){background-color: #f2f2f2;}" +
  50. "" +
  51. "#employees tr:hover {background-color: #ddd;}" +
  52. "" +
  53. "#employees th {" +
  54. " padding-top: 12px;" +
  55. " padding-bottom: 12px;" +
  56. " text-align: left;" +
  57. " background-color: #3377ff;" +
  58. " color: white;" +
  59. "}" +
  60. "</style>" +
  61. "</head>" +
  62. "<body>" +
  63. "" +
  64. TTAG +
  65. "" +
  66. "</body>" +
  67. "</html>"
  68.  
  69. '' The table HTML code format:
  70. Const tableFmt =
  71. "<table id='employees'>" +
  72. " <tr>" +
  73. " <th>Index</th>" +
  74. " <th>Lorem</th>" +
  75. " <th>Ipsum</th>" +
  76. " </tr>" +
  77. "{0}" +
  78. "</table>"
  79.  
  80. '' The table row HTML code format:
  81. Const dataRowFmt =
  82. " <tr>" +
  83. " <td>{0}</td>" +
  84. " <td>{1}</td>" +
  85. " <td>{2}</td>" +
  86. " </tr>"
  87.  
  88. '' Create a new PDF document:
  89. Dim doc = New GcPdfDocument()
  90. '' Add a page:
  91. Dim page = doc.NewPage()
  92. '' Add a page, get its graphics:
  93. Dim g = page.Graphics
  94.  
  95. '' Set up HTML to PDF formatting options.
  96. '' The most important are the size limits, in this case
  97. '' we do not limit the height as we will adjust it programmatically.
  98. '' Note that in HtmlToPdfFormat, sizes are specified in inches:
  99. Dim hf = New HtmlToPdfFormat(False) With {.MaxPageWidth = page.Size.Width / 72}
  100.  
  101. '' HTML code for a single data row (with sample data):
  102. Dim dataRow = String.Format(dataRowFmt, "a", "b", "c")
  103. '' HTML page with a table that has a single data row:
  104. Dim thtml = tableTpl.Replace(TTAG, String.Format(tableFmt, dataRow))
  105.  
  106. '' Create an instance of GcHtmlBrowser that is used to render HTML:
  107. Using browser = Util.NewHtmlBrowser()
  108.  
  109. '' Measure the HTML for the current GcPdfGraphics:
  110. Dim s1 = g.MeasureHtml(browser, thtml, hf)
  111. '' Same HTML page but with two data rows:
  112. thtml = tableTpl.Replace(TTAG, String.Format(tableFmt, dataRow + dataRow))
  113. '' Measure the new HTML:
  114. Dim s2 = g.MeasureHtml(browser, thtml, hf)
  115. '' Calculate data row and header row heights:
  116. Dim rowHeight = s2.Height - s1.Height
  117. Dim headerHeight = s1.Height - rowHeight
  118.  
  119. '' Add a note at the top of the first page:
  120. Dim nrc = Util.AddNote(
  121. "Here we render an HTML table with an unknown number of rows " +
  122. "that starts at a specified position on the first page, " +
  123. "and may span multiple pages.",
  124. page)
  125.  
  126. '' Set up for building the table with random data:
  127. Dim lorems = Util.LoremWords()
  128. Dim rnd = Util.NewRandom()
  129. Dim sb = New StringBuilder()
  130.  
  131. '' Page layout parameters:
  132. Dim marginx = nrc.Left
  133. Dim marginy = nrc.Top
  134. Dim x = marginx
  135. Dim y = nrc.Bottom + 36
  136. Dim tbottom = nrc.Bottom + 36 + headerHeight
  137. '' A random number of data rows to render:
  138. Dim nrows = rnd.Next(100, 200)
  139. '' Generate and render the table, adding continuation pages as needed:
  140. For i = 0 To nrows - 1
  141. sb.AppendFormat(dataRowFmt, i, lorems(rnd.Next(lorems.Count)), lorems(rnd.Next(lorems.Count)))
  142. tbottom += rowHeight
  143. Dim lastPage = i = (nrows - 1)
  144. If tbottom >= page.Size.Height - 72 Or lastPage Then
  145. Dim html = tableTpl.Replace(TTAG, String.Format(tableFmt, sb.ToString()))
  146. Dim size As SizeF
  147. Dim ok = g.DrawHtml(browser, html, x, y, New HtmlToPdfFormat(False) With {.MaxPageWidth = (page.Size.Width - marginx * 2) / 72}, size)
  148. If Not lastPage Then
  149. page = doc.NewPage()
  150. g = page.Graphics
  151. y = 72
  152. tbottom = y + headerHeight
  153. sb.Clear()
  154. End If
  155. End If
  156. Next
  157.  
  158. '' Done:
  159. doc.Save(stream)
  160. Return doc.Pages.Count
  161. End Using
  162. End Function
  163. End Class
  164.