static void ProcessTransaction(transactionData transaction, double x, double y, ref Text t, Font f, GraphicState gs, TextState ts,
                                       double pointSize)
        {
            // The x position of the five elements of a transaction are
            // Date 37 9x)  Descriprtion 132 (x+95)   Charges 267 (x+230) Credits 360 (x+323)  Balance 450 (x+413)
            Matrix  m  = new Matrix().Translate(x, y).Scale(pointSize, pointSize);
            TextRun tr = new TextRun(transaction.date, f, gs, ts, m);

            t.AddRun(tr);
            m  = new Matrix().Translate(x + 95, y).Scale(pointSize, pointSize);
            tr = new TextRun(transaction.description, f, gs, ts, m);
            t.AddRun(tr);
            m  = new Matrix().Translate(x + 230, y).Scale(pointSize, pointSize);
            tr = new TextRun(transaction.charges.ToString(), f, gs, ts, m);
            t.AddRun(tr);
            m  = new Matrix().Translate(x + 323, y).Scale(pointSize, pointSize);
            tr = new TextRun(transaction.credit.ToString(), f, gs, ts, m);
            t.AddRun(tr);
            m  = new Matrix().Translate(x + 413, y).Scale(pointSize, pointSize);
            tr = new TextRun(transaction.balance.ToString(), f, gs, ts, m);
            t.AddRun(tr);
        }
        static void Main(string[] args)
        {
            Console.WriteLine("RepeatingFormXObject Sample:");

            int    repeatMax                 = 100; // Record count...
            string customerInfoFont          = "Garamond";
            double customerInfoPointSize     = 10.0;
            string transactionDataFont       = "Arial";
            double transactionDataPointSize  = 10.0;
            double transactionData_xPos      = 0;
            double transactionData_yStartPos = 0;
            double transactionData_leading   = 27;
            double transactionData_count     = 0;


            // Populate some customer transaction data.  This could be read from a CSV or XML file or other source, one per customer.
            // But for this sample, we will just insert it here.
            // Could pass in position data as well.
            customerInfo    customer1    = new customerInfo("Acme, Inc", "123 Main Street", "New York", "NY", "54321", "1 (800) 555-1212");
            transactionData transaction1 = new transactionData("01/03/2020", "Balance Forward", 50.00, 0, 50.00);
            transactionData transaction2 = new transactionData("01/13/2020", "Water", 20.00, 0, 70.00);
            transactionData transaction3 = new transactionData("01/22/2020", "Electric", 110.00, 0, 180.00);
            transactionData transaction4 = new transactionData("02/03/2020", "Cable", 0, 40.00, 140.00);
            transactionData transaction5 = new transactionData("02/06/2020", "Phone", 50.00, 0, 190.00);

            var sw = Stopwatch.StartNew();

            using (Library lib = new Library())
            {
                Console.WriteLine("Initialized the library.");

                String sTemplate = Library.ResourceDirectory + "Sample_Input/DuckyAccountStatement.pdf";
                String sOutput   = "../RepeatingForm-out-" + repeatMax + ".pdf";

                if (args.Length > 0)
                {
                    sOutput = args[0];
                }

                Console.WriteLine("Output file: " + sOutput);

                // Setup the Form... the boilerplate portion that is repeated on each page.
                // For this example, we will pull this from another PDF document.
                // Alternatively, the application could create the appropriate Text, Path and Image elements
                // and add them to Form Content.
                Document sourceDoc    = new Document(sTemplate);
                Page     sourcePage   = sourceDoc.GetPage(0); // get the first page
                Form     templateForm = new Form(sourcePage.Content);

                // Create the output document
                Document doc = new Document();

                Font         fC = new Font(customerInfoFont, FontCreateFlags.Embedded | FontCreateFlags.Subset); // will embed the font
                Font         fT = new Font(transactionDataFont, FontCreateFlags.Embedded | FontCreateFlags.Subset);
                GraphicState gs = new GraphicState();
                TextState    ts = new TextState();
                Matrix       m  = new Matrix();
                gs.FillColor = new Color(0.0); // DeviceGray colorspace (black)
                Rect pageRect = new Rect(0, 0, 612, 792);

                for (int i = 1; i <= repeatMax; i++)
                {
                    if ((i % 10000) == 0)
                    {
                        // Every 10K, output the timer
                        Console.WriteLine("Processing record " + i);
                        Console.WriteLine("Time elapsed: " + sw.ElapsedMilliseconds + " milliseconds.");
                    }

                    Page docpage = doc.CreatePage(Document.LastPage, pageRect);

                    // add the template to the page
                    docpage.Content.AddElement(templateForm);

                    // add the unique content per page
                    Text t = new Text();

                    // call for each customer. Only 1 for the sample
                    DisplayCustomerInfo(customer1, ref t, fC, gs, ts, customerInfoPointSize);

                    // transaction data - for the sample, transaction data is in fixed positions.
                    // We'll pass the start x and y. Each row is about 27 points below the prior row.
                    // Limited to 5 rows for this template.

                    ProcessTransaction(transaction1, 37, 450, ref t, fT, gs, ts, transactionDataPointSize);
                    ProcessTransaction(transaction2, 37, 423, ref t, fT, gs, ts, transactionDataPointSize);
                    ProcessTransaction(transaction3, 37, 396, ref t, fT, gs, ts, transactionDataPointSize);
                    ProcessTransaction(transaction4, 37, 369, ref t, fT, gs, ts, transactionDataPointSize);
                    ProcessTransaction(transaction5, 37, 342, ref t, fT, gs, ts, transactionDataPointSize);

                    // Add document number at bottom of each page
                    m = new Matrix().Translate(475, 115).Scale(11.0, 11.0);
                    TextRun tr = new TextRun("Document: " + i.ToString(), fC, gs, ts, m);
                    t.AddRun(tr);
                    docpage.Content.AddElement(t);

                    docpage.UpdateContent(); // Update the PDF page with the changed content
                    tr.Dispose();
                    t.Dispose();
                    docpage.Dispose();
                }

                doc.EmbedFonts(EmbedFlags.None);
                doc.Save(SaveFlags.Full, sOutput);

                // Dispose of things
                templateForm.Dispose();
                sourcePage.Dispose();
                sourceDoc.Dispose();
                doc.Dispose();
            }

            sw.Stop();
            TimeSpan timeElapsed = sw.Elapsed;

            Console.WriteLine("Document closed and saved. Total time elapsed: " + timeElapsed.TotalSeconds + " seconds");
            Console.WriteLine("   or " + repeatMax / timeElapsed.TotalSeconds + " pages per second");
        }