Search code examples
c#foreachpdfsharp

How to limit table rows per page using PDFsharp?


I am using a table to display legend data. The page is in landscape mode. I would like to limit the table rows to 15 per column. 2 columns per page and then a new page is created, and so on. This is the current output. currentoutput

Here is a mockup of what I would like it to look like when there is more data. If more than 30 items then a new page needs to be created. whatIneedittolooklike

Code in controller

[HttpPost]
    public PDF Post([FromBody]List<Data> data)
    {

        try
        {
            // Get some file names

            string filePath = @"~\tempPdfs\";
            string completeFilePath = HttpContext.Current.Server.MapPath(filePath);

            var directory = new DirectoryInfo(completeFilePath);
            var fileName = (from f in directory.GetFiles("*.pdf")
                            orderby f.LastWriteTime descending
                            select f).First();
            // Open the output document


            PdfDocument outputDocument = new PdfDocument();


            // Open the document to import pages from it..
            PdfDocument inputDocument = PdfReader.Open(fileName.FullName, PdfDocumentOpenMode.Import);

            // Iterate pages
            int count = inputDocument.PageCount;
            for (int idx = 0; idx < count; idx++)
            {
                // Get the page from the external document...
                PdfPage page = inputDocument.Pages[idx];
                // ...and add it to the output document.
                outputDocument.AddPage(page);
            }


            //Create an Empty Page
            PdfPage pdfpage = outputDocument.AddPage();
            pdfpage.Size = PageSize.Letter; // Change the Page Size
            pdfpage.Orientation = PageOrientation.Landscape;// Change the orientation property

            //Get an XGraphics object for drawing
            XGraphics xGrap = XGraphics.FromPdfPage(pdfpage);

            //Create Fonts
            XFont titlefont = new XFont("Calibri", 20, XFontStyle.Regular);
            XFont tableheader = new XFont("Calibri", 15, XFontStyle.Bold);
            XFont bodyfont = new XFont("Calibri", 11, XFontStyle.Regular);

            //Draw the text
            //double x = 250;
            double y = 50;
            //Title Binding
            XTextFormatter textformater = new XTextFormatter(xGrap);  //Used to Hold the Custom text Area

            foreach (var item in data)
            {
                string colorStr = item.Color;

                Regex regex = new Regex(@"rgb\((?<r>\d{1,3}),(?<g>\d{1,3}),(?<b>\d{1,3})\)");
                //regex.Match(colorStr.Replace(" ", ""));
                Match match = regex.Match(colorStr.Replace(" ", ""));
                if (match.Success)
                {
                    int r = int.Parse(match.Groups["r"].Value);
                    int g = int.Parse(match.Groups["g"].Value);
                    int b = int.Parse(match.Groups["b"].Value);

                    y = y + 30;
                    XRect ColorVal = new XRect(85, y, 5, 5);
                    XRect NameVal = new XRect(100, y, 250, 25);

                    var brush = new XSolidBrush(XColor.FromArgb(r, g, b));
                    xGrap.DrawRectangle(brush, ColorVal);
                    textformater.DrawString(item.Name, bodyfont, XBrushes.Black, NameVal);

                };
            };



            // Save the document...
            var dt = DateTime.Now.ToString("g").Replace('/', '-').Replace(':', '-');
            var filename = string.Format("{0}-{1}.pdf", "PdfSharpResult", dt);
            string physicalPath = HttpContext.Current.Server.MapPath("/completePdfs");
            string relativePath = Path.Combine(physicalPath, filename).Replace("\\", "/");
            var pdfName = relativePath;
            outputDocument.Save(pdfName);
            // ...and start a viewer.
            Process.Start(pdfName);

            return new PDF
            {
                FileName = pdfName,
                FileNameEncoded = HttpUtility.UrlEncode(pdfName)
            };


        }
        catch (Exception ex)
        {
            Debug.Print(ex.ToString());
            return new PDF
            {
                Error = ex.ToString()
            };
        }

    }

Solution

  • Where's the problem?

    You need an X variable. After 15 rows you reset Y and increment X.

    After 30 rows you reset X and Y, add a new page, obtain a new XGrap for that page and make a fresh XTextFormatter and continue this until the list is done.

    A row counter will probably make things easier.

    Untested code showing a loop that creates pages as needed and cares for second column:

    PdfPage pdfpage;
    XGraphics xGrap;
    XTextFormatter textformater;
    
    //Create Fonts
    XFont titlefont = new XFont("Calibri", 20, XFontStyle.Regular);
    XFont tableheader = new XFont("Calibri", 15, XFontStyle.Bold);
    XFont bodyfont = new XFont("Calibri", 11, XFontStyle.Regular);
    
    //Draw the text
    double x = 0;
    double y = 50;
    //Title Binding
    
    int index = 0;
    foreach (var item in data)
    {
        if (index % 30 == 0)
        {
            y = 50;
            x = 0;
            // Start a new page.
            //Create an Empty Page
            pdfpage = outputDocument.AddPage();
            pdfpage.Size = PageSize.Letter; // Change the Page Size
            pdfpage.Orientation = PageOrientation.Landscape;// Change the orientation property
    
            //Get an XGraphics object for drawing
            xGrap = XGraphics.FromPdfPage(pdfpage);
            textformater = new XTextFormatter(xGrap);  //Used to Hold the Custom text Area
        }
        else if (index % 15 == 0)
        {
            // Start a new column.
            y = 50;
            x = 400;
        }
        ++index;
    
        // Previous code stays here, but must use x in new XRect(...)
    
        string colorStr = item.Color;
    
        Regex regex = new Regex(@"rgb\((?<r>\d{1,3}),(?<g>\d{1,3}),(?<b>\d{1,3})\)");
        //regex.Match(colorStr.Replace(" ", ""));
        Match match = regex.Match(colorStr.Replace(" ", ""));
        if (match.Success)
        {
            int r = int.Parse(match.Groups["r"].Value);
            int g = int.Parse(match.Groups["g"].Value);
            int b = int.Parse(match.Groups["b"].Value);
    
            y = y + 30;
            XRect ColorVal = new XRect(x + 85, y, 5, 5);
            XRect NameVal = new XRect(x + 100, y, 250, 25);
    
            var brush = new XSolidBrush(XColor.FromArgb(r, g, b));
            xGrap.DrawRectangle(brush, ColorVal);
            textformater.DrawString(item.Name, bodyfont, XBrushes.Black, NameVal);
    
        };
    };
    

    x = 400 is just a guess to get you started. Table headings are missing.