如何使用iTextSharp的PdfReader和Stamper制作多个页面?

时间:2017-07-27 18:36:41

标签: c# pdf itext

我正在编写一个程序来填写包含36个订单项的PDF订单。有时会有超过36个项目,所以我希望能够在保存之前添加剩余项目的第二页。以下是我目前拥有的填写PDF订单项的代码:

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

调整此代码以获得我想要的结果的最佳方法是什么?

编辑:我正在使用通过NuGet包管理器安装的iTextSharp版本5.5.11。

1 个答案:

答案 0 :(得分:0)

我最终决定制作临时PDF,合并它们,保存合并文件,然后删除临时文件。

以下是我在原始问题中发布的修改方法:

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

我使用了来自another question's answer的解决方案来合并临时PDF:

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

我还利用.ChunkBy(int)扩展程序from here将源列表拆分为N个36个订单项列表:

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