使用Stamper的iTextSharp表跨页面

时间:2016-03-05 23:40:26

标签: c# .net itextsharp

我有一个模板PDF,其中包含一个恒定高度的表单数据。根据该数据,我需要添加一个具有动态高度的表。此表可能只有一行,一行,或者可能包含1000行和/或1-1000行。

这是我的代码,它的工作正常,但是,如果表格很大,表格将不会跨越到新页面。

private void InsertCurrentNeightborsOlder(string FileName)
{
//Create new PDF document 
Document document = new Document(PageSize.LETTER, 20f, 20f, 0f, 20f);
iTextSharp.text.Font fntTableFontHdr = FontFactory.GetFont("Times New Roman", 8, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
iTextSharp.text.Font fntTableFont = FontFactory.GetFont("Times New Roman", 8, iTextSharp.text.Font.NORMAL, BaseColor.BLACK);


try {
    PdfWriter.GetInstance(document, new FileStream(FileName, FileMode.Create));
    PdfPTable nTbl = new PdfPTable(5);

    // Build the header
    PdfPCell CellOneHdr = new PdfPCell(new Phrase("Name", fntTableFontHdr));
    nTbl.AddCell(CellOneHdr);
    PdfPCell CellTwoHdr = new PdfPCell(new Phrase("Address", fntTableFontHdr));
    CellTwoHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellTwoHdr);
    PdfPCell CellTreeHdr = new PdfPCell(new Phrase("Phone #", fntTableFontHdr));
    CellTreeHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellTreeHdr);
    PdfPCell CellFouHdr = new PdfPCell(new Phrase("Method", fntTableFontHdr));
    CellFouHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellFouHdr);
    PdfPCell CellFivHdr = new PdfPCell(new Phrase("Comments", fntTableFontHdr));
    nTbl.AddCell(CellFivHdr);


    //create column sizes 
    float[] rows = {
        100f,
        100f,
        70f,
        100f,
        100f
    };
    //set row width 
    nTbl.SetTotalWidth(rows);

    nTbl.CompleteRow();

    // Add the Cells to the data table
    if (ReportDataSet.Tables("CurrentNeighbors").Rows.Count > 0) {
        foreach (DataRow r in ReportDataSet.Tables("CurrentNeighbors").Rows) {
            nTbl.AddCell(new Paragraph(r("FullName").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("Address").ToString, fntTableFont));

            PdfPCell cell = new PdfPCell(new Paragraph(r("PhoneNumber").ToString, fntTableFont));
            cell.HorizontalAlignment = 1;
            nTbl.AddCell(cell);


            // nTbl.AddCell(New Paragraph(r("PhoneNumber").ToString, fntTableFont))
            nTbl.AddCell(new Paragraph(r("ContactMethod").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("Comments").ToString, fntTableFont));
        }
    } else {
        nTbl.AddCell(new Paragraph("Nothing Entered", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
    }
    document.Open();

    nTbl.HeaderRows = 1;
    nTbl.SplitLate = false;
    document.Add(nTbl);

} catch (Exception ex) {
} finally {
    document.Close();
}

}

传递的“FileName”参数包含我要将表添加到的原始文件的位置。

甚至可以这样做,如果是的话,我错过了什么?

编辑:

这是我尝试的另一个功能(使用压模)。我也可能会离开这个,但这正是我试图找到的:

private void InsertCurrentNeightbors(string FileName)
{
// This is the Temporary File that we are working with. This file already has data in it
string oldFile = FileName;
// Create a new Temporary file that we can write to
string newFile = My.Computer.FileSystem.GetTempFileName();
iTextSharp.text.pdf.PdfReader reader = null;
iTextSharp.text.pdf.PdfStamper stamper = null;
iTextSharp.text.pdf.PdfContentByte cb = null;
iTextSharp.text.Rectangle rect = null;
int pageCount = 0;

try {
    reader = new iTextSharp.text.pdf.PdfReader(oldFile);
    rect = reader.GetPageSizeWithRotation(1);
    stamper = new iTextSharp.text.pdf.PdfStamper(reader, new System.IO.FileStream(newFile, System.IO.FileMode.Create));
    iTextSharp.text.Font fntTableFontHdr = FontFactory.GetFont("Times New Roman", 8, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
    iTextSharp.text.Font fntTableFont = FontFactory.GetFont("Times New Roman", 8, iTextSharp.text.Font.NORMAL, BaseColor.BLACK);

    cb = stamper.GetOverContent(1);
    dynamic ct = new ColumnText(cb);
    ct.Canvas = stamper.GetOverContent(reader.NumberOfPages + 1);
    ct.Alignment = Element.ALIGN_LEFT;
    ct.SetSimpleColumn(70, 36, PageSize.A4.Width - 36, PageSize.A4.Height - 300);
    PdfPTable nTbl = new PdfPTable(5);

    // Build the header
    PdfPCell CellOneHdr = new PdfPCell(new Phrase("Name", fntTableFontHdr));
    nTbl.AddCell(CellOneHdr);
    PdfPCell CellTwoHdr = new PdfPCell(new Phrase("Address", fntTableFontHdr));
    CellTwoHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellTwoHdr);
    PdfPCell CellTreeHdr = new PdfPCell(new Phrase("Phone #", fntTableFontHdr));
    CellTreeHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellTreeHdr);
    PdfPCell CellFouHdr = new PdfPCell(new Phrase("Method", fntTableFontHdr));
    CellFouHdr.HorizontalAlignment = Element.ALIGN_CENTER;
    nTbl.AddCell(CellFouHdr);
    PdfPCell CellFivHdr = new PdfPCell(new Phrase("Comments", fntTableFontHdr));
    nTbl.AddCell(CellFivHdr);


    //create column sizes 
    float[] rows = {
        100f,
        100f,
        70f,
        100f,
        100f
    };
    //set row width 
    nTbl.SetTotalWidth(rows);

    nTbl.CompleteRow();

    // Add the Cells to the data table
    if (ReportDataSet.Tables("CurrentNeighbors").Rows.Count > 0) {
        foreach (DataRow r in ReportDataSet.Tables("CurrentNeighbors").Rows) {
            nTbl.AddCell(new Paragraph(r("FullName").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("Address").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("PhoneNumber").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("ContactMethod").ToString, fntTableFont));
            nTbl.AddCell(new Paragraph(r("Comments").ToString, fntTableFont));
        }
    } else {
        nTbl.AddCell(new Paragraph("Nothing Entered", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
        nTbl.AddCell(new Paragraph("              ", fntTableFont));
    }



    nTbl.SplitLate() = false;
    nTbl.WriteSelectedRows(0, 25, 85, 490, stamper.GetOverContent(reader.NumberOfPages));

    stamper.Close();
    reader.Close();
    ct.Go();

    // Now that the new temp file has been written, we need to delete the old temp file
    // and rename the new temp file to the old temp file name

    // Delete Old Temp file
    My.Computer.FileSystem.DeleteFile(FileName);

    // Rename the new temp file to the old temp file

    My.Computer.FileSystem.RenameFile(newFile, System.IO.Path.GetFileName(FileName));

} catch (Exception ex) {
    throw ex;
}

}

我确实尝试过你提供的链接,但它没有按预期工作。所有“我”能够做的是将源页面重复100次到目标页面上。我知道这完全与我对源代码和转换的解释有关,但这就是我得到的:

private void manipulatePdf(string src, string dest)
{
try {
    // Read the template file into the reader variable
    PdfReader reader = new PdfReader(src);
    // Get the page side of the template file
    iTextSharp.text.Rectangle pagesize = reader.GetPageSize(1);

    // Create a Stamper for the destination file
    PdfStamper stamper = new PdfStamper(reader, new System.IO.FileStream(dest, System.IO.FileMode.Create));

    // Create a new Paragraph
    Paragraph p = new Paragraph();
    // Add Text into the new paragraph
    p.Add(new Chunk("Hello "));
    p.Add(new Chunk("World"));

    // Declare your AcroFields so we can get the last field's position
    AcroFields form = stamper.AcroFields();
    // Get the Last AcroField's Position
    Rectangle rect = form.GetFieldPositions("MethodOfVerification")(0).position;

    int status = 0;
    PdfImportedPage newPage = null;
    ColumnText column = new ColumnText(stamper.GetOverContent(1));
    column.SetSimpleColumn(rect);
    int pagecount = 1;

    // Add's 100 Items
    int i = 0;
    while (i < 100) {
        i += 1;
        // Creates a new paragraph object
        column.AddElement(new Paragraph("Hello " + i.ToString));

        // Adds the paragraph object to the column
        column.AddElement(p);
        // Draw content of column
        status = column.Go();
        if (ColumnText.HasMoreText(status)) {
            // Creates a new page and stamps the Source PDF into the Destination PDF
            newPage = loadPage(newPage, reader, stamper);
            triggerNewPage(stamper, pagesize, newPage, column, rect, System.Threading.Interlocked.Increment(pagecount));
        }
    }
    stamper.FormFlattening = true;
    stamper.Close();
    reader.Close();

} catch (Exception ex) {
}

}

public PdfImportedPage loadPage(PdfImportedPage page, PdfReader reader, PdfStamper stamper)
{
if (page == null) {
    return stamper.GetImportedPage(reader, 1);
}
return page;
}

public void triggerNewPage(PdfStamper stamper, Rectangle pagesize, PdfImportedPage page, ColumnText column, Rectangle rect, int pagecount)
{
stamper.InsertPage(pagecount, pagesize);
PdfContentByte canvas = stamper.GetOverContent(pagecount);
canvas.AddTemplate(page, 0, 0);
//  column.setCanvas(canvas)
column.Canvas() = canvas;
column.SetSimpleColumn(rect);
column.Go();
}

1 个答案:

答案 0 :(得分:0)

我不知道这是否有帮助,但我已将Bruno sample code移植并稍微修改为C#版本。第一个块(file_1)创建一个示例文件并存储最后一个已知坐标,以便我们稍后可以使用表恢复。然后,第二个块(file_2)使用PdfStamperColumnText来启动表格并不断添加页面直到表格适合。代码本身,特别是第二个块,有更好地解释事物的注释。

您应该能够将第一个块重新设置为表单的逻辑以获取坐标(看起来您已经将该部分放下)然后只需将第二个块与您的本地表一起使用。

//Working folder
var exportFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "SO_17589177");
System.IO.Directory.CreateDirectory(exportFolder);

//File 1 is our "template" file, File 2 is our final file
var file_1 = System.IO.Path.Combine(exportFolder, "file_1.pdf");
var file_2 = System.IO.Path.Combine(exportFolder, "file_2.pdf");

//Will hold a rectangle based on the last known coordinates
iTextSharp.text.Rectangle tableRectStart;

using (var fs = new FileStream(file_1, FileMode.Create, FileAccess.Write, FileShare.None)) {
    using (var doc = new Document()) {
        using (var writer = PdfWriter.GetInstance(doc, fs)) {
            doc.Open();

            for (var i = 0; i < 10; i++) {
                doc.Add(new Paragraph("Hello world"));
            }

            //Store our coordinates for later
            tableRectStart = new iTextSharp.text.Rectangle(doc.Left, doc.Bottom, doc.Right, writer.GetVerticalPosition(false));

            doc.Close();
        }
    }
}

using (var r = new PdfReader(file_1)) {
    using (var fs = new FileStream(file_2, FileMode.Create, FileAccess.Write, FileShare.None)) {
        using (var stamper = new PdfStamper(r, fs)) {

            //We want to target the last page of the previous PDF
            int pageNumber = r.NumberOfPages;

            //Store the last page's size which is what we'll use for new pages later
            var docRect = r.GetPageSize(pageNumber);

            //Create a giant table
            var t = new PdfPTable(2);
            for (var i = 0; i < 1000; i++) {
                t.AddCell(String.Format("This is cell {0}", i));
            }

            //Create our stamper bound to the last page of our source document
            var ct = new ColumnText(stamper.GetOverContent(pageNumber));

            //Add our table to the stamper
            ct.AddElement(t);

            //Set the drawing area for the table
            ct.SetSimpleColumn(tableRectStart);

            //Infinite loop below that is responsible for breaking itself out
            //Might want to add guards in case content gets too big and always overflows
            while (true) {

                //Draw the text and pass the status back to a helper
                //method that tells us if there's more text to be drawn
                if (! ColumnText.HasMoreText(ct.Go())) {
                    //If there isn't any more text then exit the infinite loop
                    break;
                }

                //Reset our rectangle to the document's rectangle
                tableRectStart = docRect;

                //Increment the current page number (which we need to keep track of)
                //and insert a new page
                stamper.InsertPage(++pageNumber, docRect);

                //Tell the ColumnText to draw on a new page
                ct.Canvas = stamper.GetOverContent(pageNumber);

                //Reset the drawing canvas area
                //TODO: Include some margin logic here probably
                ct.SetSimpleColumn(docRect);
            }

        }
    }
}