1
votes

I have an existing pdf file with multiple pages to which I would like to put a border to all pages.

So I create a class that inherits from PdfPageEventHelper and I override the OnEndPage and assign the instance of that class to the PageEvent of PdfWriter instance:

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace My.Apps.WPF.Classes
{
    public class PdfEventHelper : PdfPageEventHelper
    {
        public override void OnEndPage(PdfWriter writer, iTextSharp.text.Document document)
        {
            // Add border to page
            PdfContentByte content = writer.DirectContent;
            iTextSharp.text.Rectangle rectangle = new iTextSharp.text.Rectangle(document.PageSize);
            rectangle.Left += document.LeftMargin;
            rectangle.Right -= document.RightMargin;
            rectangle.Top -= document.TopMargin;
            rectangle.Bottom += document.BottomMargin;
            content.SetColorStroke(BaseColor.BLACK);
            content.Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, rectangle.Height);
            content.Stroke();
        }
    }
}

Then in main program I have a method that returns a new PDF with a border in all its pages (source pdf document 'pdfFilePath' is in landscape, so I keep orientation in new one):

private string PutBorderToPdfPages(string pdfFilePath)
{
    string newPdf = @"C:\Output.pdf";

    using (var reader = new PdfReader(pdfFilePath))
    {
        using (var fileStream = new FileStream(newPdf, FileMode.Create, FileAccess.Write))
        {
            iTextSharp.text.Document document = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(1));
            PdfEventHelper pdfEvent = new PdfEventHelper();

            PdfWriter writer = PdfWriter.GetInstance(document, fileStream);
            writer.PageEvent = pdfEvent;

            document.Open();

            document.Close(); // here it crashes, see below in post exception thrown
            writer.Close();
        }
    }

    return newPdf;
}

In run-time, in line:

document.Close();

I get an IO.Exception that says:

The document has no pages.

In this case, Pdf document has only 1 page.

What am I doing wrong? I do not want to write anything to the existing pdf file, I only want to create a new PDF file exactly the same as source but with a border in all its pages.

UPDATE:

ATTEMPT #1:

I have done below, but I get all page in black (I do not know how to do the rectangle not filled):

private string PutBorderToPdfPages(string pdfFilePath)
{
    string newPdf = @"C:\Output.pdf";

    using (var reader = new PdfReader(pdfFilePath))
    {
        using (var fileStream = new FileStream(newPdf, FileMode.Create, FileAccess.Write))
        {
            using (var pdfStamper = new PdfStamper(reader, fileStream))
            {
                int PageCount = reader.NumberOfPages;   

                for (int p = 1; p <= PageCount; p++)
                {
                    // Add border to page                                
                    PdfContentByte cb = pdfStamper.GetOverContent(p);
                    iTextSharp.text.Rectangle rectangle = pdfReader.GetPageSizeWithRotation(p);
                    rectangle.BackgroundColor = iTextSharp.text.BaseColor.BLACK;                                
                    cb.Rectangle(rectangle);
                }                            
            }
        }
    }

    return newPdf;
}

ATTEMPT #2:

In this attempt, I get an ObjectDisposedException:

Cannot access to a closed file.

when exiting the using of pdfStamper:

private string PutBorderToPdfPages(string pdfFilePath)
{
    string newPdf = @"C:\Output.pdf";

    using (var reader = new PdfReader(pdfFilePath))
    {
        using (var fileStream = new FileStream(newPdf, FileMode.Create, FileAccess.Write))
        {
                    iTextSharp.text.Document document = new iTextSharp.text.Document(reader.GetPageSizeWithRotation(1));                        
                    PdfWriter writer = PdfWriter.GetInstance(document, fileStream);

                    document.Open();

                    using (var pdfStamper = new PdfStamper(reader, fileStream))
                    {                            
                        for (int p = 0; p < pdfStamper.Reader.NumberOfPages; p++)                            
                        {
                            // Add border to page
                            PdfContentByte content = writer.DirectContent;
                            iTextSharp.text.Rectangle rectangle = new iTextSharp.text.Rectangle(document.PageSize);
                            rectangle.Left += document.LeftMargin;
                            rectangle.Right -= document.RightMargin;
                            rectangle.Top -= document.TopMargin;
                            rectangle.Bottom += document.BottomMargin;
                            content.SetColorStroke(iTextSharp.text.BaseColor.BLACK);
                            content.Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, rectangle.Height);
                            content.Stroke();
                        }
                        document.Close();
                        writer.Close();
                    }
        }
    }

    return newPdf;
}
3

3 Answers

5
votes

You do

document.Open();

document.Close(); // here it crashes, see below in post exception thrown

I.e. you start a new document, add nothing to it, and then close it. Thus, it would be empty which iText responds to with The document has no pages.

Thus, the exception is completely correct.


The correct way to "put a border to all pages" of "an existing pdf file" is to

  • open the document in a PdfReader,
  • create a PdfStamper operating on that PdfReader,
  • iterate over the pages of it and add borders,
  • and close the PdfStamper.

E.g. like this for a source file source and a target file dest:

using (PdfReader reader = new PdfReader(source))
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create)))
{
    for (int pageNumber = 1; pageNumber <= reader.NumberOfPages; pageNumber++)
    {
        Rectangle cropBox = reader.GetCropBox(pageNumber);
        Rectangle rectangle = new Rectangle(cropBox);
        rectangle.Left += 20;
        rectangle.Right -= 20;
        rectangle.Top -= 20;
        rectangle.Bottom += 20;

        PdfContentByte content = stamper.GetOverContent(pageNumber);
        content.SetColorStroke(iTextSharp.text.BaseColor.BLACK);
        content.Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, rectangle.Height);
        content.Stroke();
    }
}
4
votes

The The document has no pages error is thrown because you create a document that has no pages. It's as simple as that.

Look at your code:

Document document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, fileStream);
document.Open();
document.Close();

You aren't adding any content between document.Open(); and document.Close();

Change it to:

Document document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, fileStream);
document.Open();
document.Add(new Paragraph("Some content"));
document.Close();

The error will disappear. If you don't want to add any content to the document, then... what's the point in creating the document?

Extra remark: I see that you create a document with a page size that is taken from another document: reader.GetPageSizeWithRotation(1). What's your purpose? If you want to copy a page from another document, you are doing it wrong! You should use PdfStamper instead; that is, if you insist on working with an old version of iText.

The real solution: upgrade to iText 7, and you won't have this problem.

0
votes

The question underwent some significant changes, so instead of updating my initial answer (which I consider to be the correct answer to the initial question), I'll post a new answer in reply to the updated question.

You are mixing PdfWriter code with PdfStamper code, and that's wrong. When you create a PdfStamper instance, you automatically create a PdfWriter instance internally.

This is wrong:

using (var reader = new PdfReader(pdfFilePath))
{
    using (var fileStream = new FileStream(newPdf, FileMode.Create, FileAccess.Write))
    {
        Document document = new Document(reader.GetPageSizeWithRotation(1));                        
        PdfWriter writer = PdfWriter.GetInstance(document, fileStream);
        document.Open();
        using (var pdfStamper = new PdfStamper(reader, fileStream))
        {                            
            for (int p = 0; p < pdfStamper.Reader.NumberOfPages; p++)                            
            {
                // Add border to page
                PdfContentByte content = writer.DirectContent;
                Rectangle rectangle = new Rectangle(document.PageSize);
                rectangle.Left += document.LeftMargin;
                rectangle.Right -= document.RightMargin;
                rectangle.Top -= document.TopMargin;
                rectangle.Bottom += document.BottomMargin;
                content.SetColorStroke(iTextSharp.text.BaseColor.BLACK);
                content.Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, rectangle.Height);
                content.Stroke();
            }
            document.Close();
            writer.Close();
        }
    }
}

Please try this:

using (var reader = new PdfReader(pdfFilePath))
{
    using (var fileStream = new FileStream(newPdf, FileMode.Create, FileAccess.Write))
    {
        using (var pdfStamper = new PdfStamper(reader, fileStream))
        {                            
            for (int p = 1; p <= reader.NumberOfPages; p++)                            
            {
                // Add border to page
                PdfContentByte content = pdfStamper.GetOverContent(p);
                Rectangle rectangle = new Rectangle(pdfReader.GetPageSize(p));
                rectangle.Left += margin;
                rectangle.Right -= margin;
                rectangle.Top -= margin;
                rectangle.Bottom += margin;
                content.SetColorStroke(iTextSharp.text.BaseColor.BLACK);
                content.Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, rectangle.Height);
                content.Stroke();
            }
        }
    }
}