How do I draw a table using ElementBuilder & ElementWriter?

Q: How do I draw a table using ElementBuilder & ElementWriter?
---

A:
The following sample code illustrates how to draw a table using
PDFNet's low-level PDF creation API.

Please notice that this function is not a general purpose API to draw a
table, but is more of an illustration that can be used as a starting
point to implement more complex PDF drawing functions.

static void DrawTable(Table t, double originx, double originy, PDFDoc
doc, ElementWriter writer, ElementBuilder eb)
{
  // Draw the table background ---------------------
  Element element = eb.CreateRect(originx, originy, t.Width.Value,
t.Height.Value);

  // Set the path color space and color
  element.SetPathFill(true); // this path is should be filled
  element.SetPathClip(false);
  GState gstate = element.GetGState();
  gstate.SetFillColorSpace(ColorSpace.CreateDeviceRGB());
  gstate.SetFillColor(new ColorPt(0.8, 0.8, 0.8)); // components are in
the range [0..1]
  element.SetPathStroke(false); // this path is should be stroked
  writer.WriteElement(element);

  // Draw the table grid ----------------------------
  TableRowCollection rows = t.Rows;

  if (rows.Count<1) return;
  double cell_height = t.Height.Value / rows.Count;
  double cell_width = t.Width.Value / t.Rows[0].Cells.Count;

  Font font = Font.Create(doc, Font.StandardType1Font.e_times_roman);

  double row_xpos = originx, row_ypos = originy;
  foreach (TableRow row in rows)
  {
    foreach (TableCell c in row.Cells)
    {
      writer.WriteElement(eb.CreateGroupBegin());

      // Draw the cell rectangle
      element = eb.CreateRect(row_xpos, row_ypos, cell_width,
cell_height);
      element.SetPathFill(false); // this path is should be filled
      element.SetPathStroke(true); // this path is should be stroked
      element.SetPathClip(true); // use the rectangle as a clipping
path
      gstate = element.GetGState();
      gstate.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB());
      gstate.SetStrokeColor(new ColorPt(0, 0, 0)); // components are in
the range [0..1]
      writer.WriteElement(element);

      // Fill the cell with the content -----------------
      // Begin writing a block of text
      double font_size = 20;
      element = eb.CreateTextBegin(Font.Create(doc,
Font.StandardType1Font.e_times_roman), font_size);
      writer.WriteElement(element);

      gstate = element.GetGState();
      gstate.SetFillColor(new ColorPt(1, 0, 0));

      element = eb.CreateTextRun(c.Text);
      element.SetTextMatrix(1, 0, 0, 1, row_xpos +
(cell_width-element.GetTextLength())/2, row_ypos +
(cell_height-font_size)/2);
      writer.WriteElement(element);

      // Finish the block of text
      writer.WriteElement(eb.CreateTextEnd());

      row_xpos += cell_width;
      writer.WriteElement(eb.CreateGroupEnd());
    }

    row_xpos = originx;
    row_ypos += cell_height;
  }
}

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
  PDFNet.Initialize();
  PDFNet.SetResourcesPath("../../../../../resources");

  // Relative path to the folder containing test files.
  string input_path = "../../../../TestFiles/";
  string output_path = "../../../../TestFiles/Output/";

  try
  {
    Console.WriteLine("-------------------------------------------------");

    PDFDoc doc = new PDFDoc();

    ElementBuilder builder = new ElementBuilder(); // ElementBuilder is
used to build new Element objects
    ElementWriter writer = new ElementWriter(); // ElementWriter is used
to write Elements to the page

    Page page = doc.PageCreate(new Rect(0, 0, 612, 794));
    writer.Begin(page); // begin writing to this page

    // Dynamically create a new table.
    Table t = new Table();
    t.Width = 590;
    t.Height = 775;

    // Generate rows and cells.
    int numrows = 10;
    int numcells = 5;
    for (int j=0; j<numrows; j++)
    {
      TableRow r = new TableRow();
      for (int i=0; i<numcells; i++)
      {
        TableCell c = new TableCell();
        c.Text = "(" + i + "," + j + ")";
        r.Cells.Add(c);
      }
      t.Rows.Add(r);
    }

    DrawTable(t, 10, 10, doc, writer, builder);

    writer.End();
    doc.PagePushBack(page);

    doc.Save(output_path + "output.pdf",
Doc.SaveOptions.e_remove_unused);
    doc.Close();
    Console.WriteLine("Done.");
  }
  catch (PDFNetException e)
  {
    Console.WriteLine(e.Message);
  }

  PDFNet.Terminate();
}

I’m currently looking into doing this with text fields as the table cells… any caveats / difficulties that come to mind?

While this can be done using ElementBuilder, there are easier ways to achieve table generation. For example, you could create a table using HTML, and convert it to PDF. In addition, you can using our template generation engine to dynamically create tables.

Thanks, I’ve looked into this, but my table needs to be composed of TextFields, which I don’t think the templating supports.