سؤال

I'm working with ASP MVC and i use iTextSharp to generate PDF's in my application. But now i have a problem: I printing lists and when exist more than one page, i want to show the page number (ex.: Page 1 to 4). I found some examples, but i think it is more complexes than i need to do (like exameple).

EDIT: I found this example 2. I can count number of pages, but i cant print the number in pages.

What i did:

public ActionResult downloadListaISCC(DateTime? DataFimFiltro)
{

//Code to generate list to PDF

   //My document
   Document doc1 = new Document();
   doc1.SetPageSize(iTextSharp.text.PageSize.A4);
   doc1.SetMargins(0f, 0f, 0f, 0f);
   doc1.NewPage();

   MemoryStream pdfStream = new MemoryStream();
   PdfWriter pdfWriter = PdfWriter.GetInstance(doc1, pdfStream);

   //Code to create table
   doc1.Add(table); //table list in document

   //Follow the example 2 (link)
   pdfWriter.CloseStream = true;
   doc1.Close();


   //E fui seguindo o exemplo do segundo link
   string file = "D:/gerarPDFOleotorres/"+ nomeDoc +""; 

   // add page numbers
   Document copyDoc = new Document();
   PdfCopy copyPdf = new PdfCopy(copyDoc, new FileStream(file, FileMode.Create));
   copyPdf.SetPageSize(PageSize.A4.Rotate());
   copyDoc.Open();

   // read the initial pdf document
   PdfReader reader = new PdfReader(pdfStream.ToArray());
   int totalPages = reader.NumberOfPages;

   PdfImportedPage copiedPage = null;
   iTextSharp.text.pdf.PdfCopy.PageStamp stamper = null;

   for (int i = 0; i < totalPages; i++)
   {

       // get the page and create a stamper for that page
       copiedPage = copyPdf.GetImportedPage(reader, (i + 1));
       stamper = copyPdf.CreatePageStamp(copiedPage);

       // add a page number to the page
       ColumnText.ShowTextAligned(stamper.GetUnderContent(), Element.ALIGN_CENTER, new Phrase((i + 1) + "/" + totalPages, fontetexto), 820f, 15, 0);
        stamper.AlterContents();

       // add the altered page to the new document
       copyPdf.AddPage(copiedPage);
   }

   copyDoc.Close();
   reader.Close();

   // flush and clear the document from memory
   pdfStream.Flush();
   pdfStream.Close();
    }
هل كانت مفيدة؟

المحلول

Basically, you have two options: either you create the document in one go, or you create the document in two passes.

If you create the document in one go, you don't know the value of Y (the total number of pages) in advance, so you need to create a PdfTemplate object as a place holder. This is demonstrated in the MovieCountries1 example.

In this example, we create a TableHeader class that extends PdfPageEventHelper. We create an instance of the PdfTemplate class for the total in the OnOpenDocument() method, we use this total placeholder in the OnEndPage() method where we add the header or footer, and we fill out the total number of pages in the OnCloseDocument() method.

The disadvantage of this approach is that it's something hard to predict the dimensions needed for total. The advantage is that you can create the document in one go (you don't need to create the document in memory first).

If you create the document in two passes, you create the document without header/footer first, and then you examine the document to find out how many pages it contains. Then you use PdfStamper to add the page numbers to each page. This is shown in the TwoPasses example.

These examples are taken from my book "iText in Action - Second Edition". You can download chapter 6 for free from this URL: http://manning.com/lowagie2/samplechapter6.pdf

Please consult the [official documentation][4] when you are in doubt about specific functionality.

Update: I don't understand why you prefer looking at unofficial examples. The example I gave you looks like this:

using (PdfStamper stamper = new PdfStamper(reader, ms2)) {
    // Loop over the pages and add a header to each page
    int n = reader.NumberOfPages;
    for (int i = 1; i <= n; i++) {
        // Add content
    }
}

Yet for some reason you Googled an example that is much more complex (and overkill for what you need).

Just replace the // Add content part with:

ColumnText.ShowTextAligned(stamper.GetUnderContent(), Element.ALIGN_CENTER, new Phrase((i + 1) + "/" + totalPages, fontetexto), 297f, 15f, 0);

Note that I adapted the x value in the ShowTextAligned() method. You're creating a page with size A4, which means your page is 595 user units wide. If you add page numbers at position x = 820, the footer will be added, but it will be outside the visible area of the page. Please don't copy/paste code without knowing the parameters of each method.

نصائح أخرى

For the records - I used this way

byte[] bytes = memoryStream.ToArray();

                //Save pdf in the temporary location.
System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf", bytes);

/*This is a page counter - it stamps the number of pages in the document. 
 It will read dynamically the 'document' that was just closed above [document.Close();] from the location, 
 then in memory will write the new content plus the one from [byte[] bytes = memoryStream.ToArray();] 
 Solution has been applied from: https://www.aspsnippets.com/Articles/iTextSharp-Add-Page-numbers-to-existing-PDF-using-C-and-VBNet.aspx
 */
try
{
    File.ReadAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf");
    iTextSharp.text.Font blackFont = FontFactory.GetFont("Arial", 7, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
    using (MemoryStream stream = new MemoryStream())
    {
        PdfReader reader = new PdfReader(bytes);
        using (PdfStamper stamper = new PdfStamper(reader, stream))
        {
            int pages = reader.NumberOfPages;
            for (int i = 1; i <= pages; i++)
            {
                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                 @Element.ALIGN_LEFT, new Phrase(lbReports.Text + " - HD - JEA", blackFont), 63f, 24f, 0);

                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                @Element.ALIGN_CENTER, new Phrase("Page " + i.ToString() + " of " + pages, blackFont), 300f, 24f, 0);

                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                @Element.ALIGN_RIGHT, new Phrase("" + DateTime.Now, blackFont), 549f, 24f, 0);
            }

            txConnection.Text = "This report contains " + pages + " page(s)";
        }

        bytes = stream.ToArray();

    }//End of page counter

    /*System.IO.File.WriteAllBytes will write all bytes to file again*/

    System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf", bytes);

    // Temporary path that is used to display the pdf in the embed.
    System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/ReportsEmbed/") + lbReports.Text + "_JEA.pdf", bytes);

    /*this is what sends the PDF to the embed viewer object
     The ltEmbed is what receives the plugin to dispplay the file*/

    string embed = "<object data=\"{0}\" type=\"application/pdf\" width=\"698px\" height=\"450px\">";
    embed += "If you are unable to view file, you can download it from <a href = \"{0}\">here</a>";
    embed += " or download <a target = \"_blank\" href = \"http://get.adobe.com/reader/\">Adobe PDF Reader</a> to view it.";
    embed += "</object>";

    ltEmbed.Text = string.Format(embed, ("http://localhost:65423/TempReports/ReportsEmbed/") + lbReports.Text + "_JEA.pdf");
    memoryStream.Close();

    this.Context.ApplicationInstance.CompleteRequest();
}
catch (DocumentException exe)
{
    txConnection.Text = "There has been an error generating the file. Please try again. Error: " + exe;
}

iTextSharp Page Number Counter

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top