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();
}