3

I'd like to insert a PDF page in another PDF page scaled. I'd like to use iTextSharp for this.

I have a vector drawing which can be exported as a single page PDF file. I would like to add this file into a page of other PDF document just like I would add an image to a PDF document.

Is this possible?

The purpose of this is to retain the ability to zoom in without losing quality.

It is very hard to reproduce the vector drawing using PDF vectors because it is an extremely complex drawing.

Exporting the vector drawing as high resolution image is not an option since I have to use a lot of them in a single PDF document. The final PDF would be very large and its writing too slow.

Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
user1106088
  • 43
  • 1
  • 3

2 Answers2

8

This is relatively easy to do although there's a couple of ways to go about it. If you're creating a new document that has the other documents inside of it and nothing else then the easiest thing to use is probably the PdfWriter.GetImportedPage(PdfReader, Int). This will give you a PdfImportedPage (which inherits from PdfTemplate). Once you have that you can add it to your new document by using PdfWriter.DirectContent.AddTemplate(PdfImportedPage, Matrix).

There's a couple of overloads to AddTemplate() but the easiest one (at least for me) is the one that takes a System.Drawing.Drawing2D.Matrix. If you use this you can easily scale and translate (change x,y) without having to think in "matrix" terms.

Below is sample code that shows this off. It targets iTextSharp 5.4.0 although it should work pretty much the same with 4.1.6 if you remove the using statements. It first creates a sample PDF with 12 pages with random background colors. Then it creates a second document and adds each page from the first PDF scaled by 50% so that 4 old pages fit onto 1 new page. See the code comments for further details. This code assumes that all pages are the same size, you might need to perform further calculations if your situation differs.

//Test files that we'll be creating
var file1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File1.pdf");
var file2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "File2.pdf");

//For test purposes we'll fill the pages with a random background color
var R = new Random();

//Standard PDF creation, nothing special here
using (var fs = new FileStream(file1, FileMode.Create, FileAccess.Write, FileShare.None)) {
    using (var doc = new Document()) {
        using (var writer = PdfWriter.GetInstance(doc, fs)) {
            doc.Open();

            //Create 12 pages with text on each one
            for (int i = 1; i <= 12; i++) {
                doc.NewPage();

                //For test purposes fill the page with a random background color
                var cb = writer.DirectContentUnder;
                cb.SaveState();
                cb.SetColorFill(new BaseColor(R.Next(0, 256), R.Next(0, 256), R.Next(0, 256)));
                cb.Rectangle(0, 0, doc.PageSize.Width, doc.PageSize.Height);
                cb.Fill();
                cb.RestoreState();

                //Add some text to the page
                doc.Add(new Paragraph("This is page " + i.ToString()));
            }
            doc.Close();
        }
    }
}

//Create our combined file
using (var fs = new FileStream(file2, FileMode.Create, FileAccess.Write, FileShare.None)) {
    using (var doc = new Document()) {
        using (var writer = PdfWriter.GetInstance(doc, fs)) {

            //Bind a reader to the file that we created above
            using (var reader = new PdfReader(file1)) {
                doc.Open();

                //Get the number of pages in the original file
                int pageCount = reader.NumberOfPages;

                //Loop through each page
                for (int i = 0; i < pageCount; i++) {
                    //We're putting four original pages on one new page so add a new page every four pages
                    if (i % 4 == 0) {
                        doc.NewPage();
                    }

                    //Get a page from the reader (remember that PdfReader pages are one-based)
                    var imp = writer.GetImportedPage(reader, (i + 1));
                    //A transform matrix is an easier way of dealing with changing dimension and coordinates on an rectangle
                    var tm = new System.Drawing.Drawing2D.Matrix();

                    //Scale the image by half
                    tm.Scale(0.5f, 0.5f);

                    //PDF coordinates put 0,0 in the bottom left corner.
                    if (i % 4 == 0) {
                        tm.Translate(0, doc.PageSize.Height);                   //The first item on the page needs to be moved up "one square"
                    } else if (i % 4 == 1) {
                        tm.Translate(doc.PageSize.Width, doc.PageSize.Height);  //The second needs to be moved up and over
                    } else if (i % 4 == 2) {
                                                                                //Nothing needs to be done for the third
                    } else if (i % 4 == 3) {
                        tm.Translate(doc.PageSize.Width, 0);                    //The fourth needs to be moved over
                    }

                    //Add our imported page using the matrix that we set above
                    writer.DirectContent.AddTemplate(imp,tm);

                }

                doc.Close();
            }
        }
    }
}
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • Right. This is one of the use cases where a page from one document should be imported into another one using `PdfWriter` instead of one of the `Pdf*Copy*` classes, cf. the answer to [How to merge multiple pdf files (generated in run time)?](http://stackoverflow.com/a/15945467/1729265) – mkl Apr 16 '13 at 22:37
  • @Chris Hass. Thank you for your excellent replay, I've read your replies in other questions too and I've found them helpful to the point. Thanks Again. – user1106088 Apr 17 '13 at 09:12
  • Also, just to be explicit in case anyone else reads this in the future, the code above is for basic simple PDFs. If there are any form fields, annotations, bookmarks, etc (basically anything more than text, lines and images) make sure to read over @mkl's link to understand alternative methods of performing this. – Chris Haas Apr 17 '13 at 13:02
0

In addition; while i was trying to add a rotated pdf to a rotated pdf, i got some rotation problems. Kind of confusing but you should check the "PdfImportedPage.Rotation" of the page which is gonna be added to pdf.

PdfImportedPage page;//page = writer.GetImportedPage(PdfReader reader, int pageNum);
PdfContentByte pcb;//pcb = PdfWriter.DirectContentUnder;

//create matrix to use for rotating imported page    
Matrix matrix = new Matrix(a, b, c, d, e, f);
matrix.Rotate(-(page.Rotation));
if (page.Rotation != 0)
   pcb.AddTemplate(page, matrix, true);
else
   pcb.AddTemplate(page, a, b, c, d, e, f, true);

code looks like silly but i want to get your attention on "matrix.Rotate(negative rotation of imported page)"