0

I am writing a program to fill out a PDF order form that has 36 line items. Sometimes there will be more than 36 items so I would like to be able to append a second page with the remaining items before saving. Here is the code that I currently have that fills the PDF line items:

private SaveResult WritePDF(ref ObservableCollection<OrderLineItem> saveObj)
{
    try
    {
        if (saveObj == null) throw new ArgumentNullException("Save Object is null");
        var theForm = ReadResource("LineItemOrderForm");
        var sfd = new SaveFileDialog
        {
            AddExtension = true,
            InitialDirectory = DesktopPath,
            DefaultExt = ".pdf",
            RestoreDirectory = true,
            Filter = "Adobe PDF Files (.pdf)|*.pdf",
        };
        var saveResult = sfd.ShowDialog();
        if (saveResult == false) return SaveResult.Cancelled;
        var outPath = sfd.FileName;

        var timesBasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "TIMESBD.TTF");
        var timesBaseFont = BaseFont.CreateFont(timesBasePath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

        using (var pdfReader = new PdfReader(theForm))
        {
            var fs = new FileStream(outPath, FileMode.Create);

            using (var pdfStamper = new PdfStamper(pdfReader, fs))
            {
                var form = pdfStamper.AcroFields;
                form.AddSubstitutionFont(timesBaseFont);

                var i = 1;
                form.SetField("OrderFormDealerName", Constants.DealerName);
                form.SetFieldProperty("OrderFormDealerName", "textcolor", BaseColor.BLACK, null);
                foreach (var item in saveObj)
                {
                    form.SetField($"LineItem{i:D2}", item.LineItemNumber.ToString(CultureInfo.InvariantCulture));
                    form.SetFieldProperty($"LineItem{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"Qty{i:D2}", item.Quantity.ToString(CultureInfo.InvariantCulture));
                    form.SetFieldProperty($"Qty{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"PartNumber{i:D2}", item.PartNumber);
                    form.SetFieldProperty($"PartNumber{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"Hinging{i:D2}", item.Hinging.ToString());
                    form.SetFieldProperty($"Hinging{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"Finished{i:D2}", item.Finished.ToString());
                    form.SetFieldProperty($"Finished{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"UnitPrice{i:D2}", $"{item.UnitPrice:C0}");
                    form.SetFieldProperty($"UnitPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"ModPrice{i:D2}", $"{item.ModifyPrice:C0}");
                    form.SetFieldProperty($"ModPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                    form.SetField($"ExtPrice{i:D2}", $"{item.ExtendedPrice:C0}");
                    form.SetFieldProperty($"ExtPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                    i++;
                }
                pdfStamper.FormFlattening = false;
                pdfStamper.Close();
            }
            pdfReader.Close();
            return SaveResult.Success;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "WritePDF()");
        return SaveResult.Failure;
    }
}

What would be the best way to adapt this code to achieve the result I am looking for?

EDIT: I am using iTextSharp version 5.5.11 installed via NuGet package manager.

Anders
  • 12,088
  • 34
  • 98
  • 146

1 Answers1

0

I ended up deciding the easiest way would be to make temp PDFs, merge them, save the merged file, and then delete the temp files.

Here is the method that I posted in the original question, modified:

private SaveResult WritePDF(ref List<OrderLineItem> saveObj)
{
    try
    {
        if (saveObj == null) throw new ArgumentNullException("Save Object is null");
        var theForm = ReadResource("LineItemOrderForm");
        var pageCount = 1.0;
        var multiPage = (saveObj.Count > 36);
        var multiList = new List<List<OrderLineItem>>();
        var fileList = new List<string>();
        if (multiPage)
        {
            var temp = (saveObj.Count / 36.0);
            pageCount = Math.Ceiling(temp);
            multiList = saveObj.ChunkBy(36);
        }
        else
        {
            multiList.Add(saveObj);
        }
        var sfd = new SaveFileDialog
        {
            AddExtension = true,
            InitialDirectory = DesktopPath,
            DefaultExt = ".pdf",
            RestoreDirectory = true,
            FileName = "Pioneer Order Form",
            Filter = "Adobe PDF Files (.pdf)|*.pdf",
        };
        var saveResult = sfd.ShowDialog();
        if (saveResult == false) return SaveResult.Cancelled;
        var fileName = sfd.FileName;

        var timesBasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "TIMESBD.TTF");
        var timesBaseFont = BaseFont.CreateFont(timesBasePath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        var pageNumber = 1;

        foreach (var page in multiList)
        {
            var tempFileName = Path.Combine(BasePath, Extensions.TempPdfName());
            fileList.Add(tempFileName);

            using (var pdfReader = new PdfReader(theForm))
            {
                var fs = new FileStream(tempFileName, FileMode.Create);

                using (var pdfStamper = new PdfStamper(pdfReader, fs))
                {
                    var form = pdfStamper.AcroFields;
                    form.AddSubstitutionFont(timesBaseFont);

                    var i = 1;
                    form.SetField("OrderFormDealerName", Constants.DealerName);
                    form.SetFieldProperty("OrderFormDealerName", "textcolor", BaseColor.BLACK, null);

                    form.SetField("PageNumber", pageNumber);
                    form.SetField("TotalPages", Convert.ToInt32(pageCount));

                    foreach (var item in page)
                    {
                        form.SetField($"LineItem{i:D2}", item.LineItemNumber);
                        form.SetFieldProperty($"LineItem{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"Qty{i:D2}", item.Quantity);
                        form.SetFieldProperty($"Qty{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"PartNumber{i:D2}", item.PartNumber);
                        form.SetFieldProperty($"PartNumber{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"Hinging{i:D2}", item.Hinging);
                        form.SetFieldProperty($"Hinging{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"Finished{i:D2}", item.Finished);
                        form.SetFieldProperty($"Finished{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"UnitPrice{i:D2}", $"{item.UnitPrice:C0}");
                        form.SetFieldProperty($"UnitPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"ModPrice{i:D2}", $"{item.ModifyPrice:C0}");
                        form.SetFieldProperty($"ModPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                        form.SetField($"ExtPrice{i:D2}", $"{item.ExtendedPrice:C0}");
                        form.SetFieldProperty($"ExtPrice{i:D2}", "textcolor", BaseColor.BLACK, null);

                        i++;
                    }
                    pdfStamper.FormFlattening = true;

                    pdfStamper.Close();
                }
                pdfReader.Close();
            }
            pageNumber++;
        }

        var result = MergePDFs(fileList, fileName);
        foreach (var file in fileList)
        {
            File.Delete(file);
        }
        return result ? SaveResult.Success : SaveResult.Failure;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "WritePdf()");
        return SaveResult.Failure;
    }
}

I utilized a solution from another question's answer to merge the temp PDFs:

public static bool MergePDFs(IEnumerable<string> fileNames, string targetPdf)
{
    var merged = true;
    using (var stream = new FileStream(targetPdf, FileMode.Create))
    {
        var document = new Document();
        var pdf = new PdfCopy(document, stream);
        PdfReader reader = null;
        try
        {
            document.Open();
            foreach (var file in fileNames)
            {
                reader = new PdfReader(file);
                pdf.AddDocument(reader);
                reader.Close();
            }
        }
        catch (Exception)
        {
            merged = false;
            reader?.Close();
        }
        finally
        {
            document.Close();
        }
    }
    return merged;
}

I also utilized the .ChunkBy(int) extension from here to split the source list into N amount of 36 line item lists:

public static List<List<T>> ChunkBy<T>(this IEnumerable<T> source, int chunkSize)
{
    return source
        .Select((x, i) => new { Index = i, Value = x })
        .GroupBy(x => x.Index / chunkSize)
        .Select(x => x.Select(v => v.Value).ToList())
        .ToList();
}
Anders
  • 12,088
  • 34
  • 98
  • 146