Merging PDFs with different orientations with iTextSharp - c#

I have two PDF files with different orientations (first document is A4 format and the second A4 landscape).
I want to merge them but I need to preserve the original orientation of each page.
I tried with the rotation with this code:
float width = pdfImportedPage.Width;
float height = pdfImportedPage.Height;
if (width > height)
{
PdfDictionary pageDict = reader.GetPageN(documentPage);
pageDict.Put(PdfName.ROTATE, new PdfNumber(270));
}
After the rotation I call the AddPage method like this:
copy.AddPage(pdfImportedPage);
But the result is an A4 format document with the second part with the text that goes out of the page. For me is good if the text in the second part is horizontal but I need that also the orientation of the page will be as the original document (horizontal).
I'm using iTextSharp version 5.5.13.

I've just discovered that the problem was in another part of the code, after that, when I add the page number.
By the way, a good way to preserve the page orientation is to use the SetPageSize and the NewPage methods, like this piece of code:
for (int page = 1; page <= reader.NumberOfPages; page++)
{
copy.RotateContents = true;
doc.SetPageSize(reader.GetPageSizeWithRotation(page));
doc.NewPage();
importedPage = copy.GetImportedPage(reader, page);
copy.AddPage(importedPage);
}

Related

iText 7 C# creating a pdf from a template and adding text to it

I have a one page pdf template and need to create a new document with several pages. Each page needs to be as the first page of the template. Then i need to add text to each page. The pages are copied but the text is not added.
This is my code:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(stream));
PdfDocument cover = new PdfDocument(new PdfReader(templatePath));
//First copy the pages
var totalPages=5;
var coverPage = cover.GetPage(1);
for (int i = 0; i < totalPages; i++)
{
//If i do it to a blank page the text is visible
//pdfDoc.AddNewPage();
//I have tried both methods:
pdfDoc.AddPage(coverPage.CopyTo(pdfDoc));
//cover.CopyPagesTo(1, 1, pdfDoc);
}
//Now i try to add text
Document doc = new Document(pdfDoc);
var font = PdfFontFactory.CreateFont(fontPath);
for (int i = 1; i <= totalPages; i++)
{
//Edited
Rectangle pagesize = pdfDoc.GetPage(i).GetPageSize();
doc.ShowTextAligned(new Paragraph("HEADER").SetFont(font).SetFontSize(22), pagesize.GetLeft(), pagesize.GetBottom(), i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
//doc.ShowTextAligned(new Paragraph("HEADER").SetFont(font), 100, 700, i, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
}
doc.Close();
cover.Close();
pdfDoc.Close();
I have tried this options:
Canvas instead of document with no result (see code below)
If i use the AddNewPage() and not the cover page, then the text is added to the blank page (both document and canvas methods).
If i open and write directly to the template document the text is visible but the size is very small and position of the text is different compared to 2)
This is the canvas code inside the for instruction:
var canvas = new PdfCanvas(pdfDoc.GetPage(i));
canvas.BeginText()
.SetFontAndSize(font, 22) //Edited
.MoveText(100, 700)
.ShowText("HEADER")
.EndText();
//UPDATED
Following the solution contributed by #mkl, i have changed the way i add the pages:
var coverPage = cover.GetPage(1);
Rectangle coverSize = coverPage.GetPageSize();
for (int i = 0; i < totalPaginas; i++)
{
//Taken from this example: https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-jump-start-tutorial-for-java/chapter-6-reusing-existing-pdf-documents
PdfPage page = pdfDoc.AddNewPage(PageSize.A4);
PdfCanvas canvas = new PdfCanvas(page);
AffineTransform transformationMatrix = AffineTransform.GetScaleInstance(
page.GetPageSize().GetWidth() / coverSize.GetWidth(),
page.GetPageSize().GetHeight() / coverSize.GetHeight());
canvas.ConcatMatrix(transformationMatrix);
var pageCopy = coverPage.CopyAsFormXObject(pdfDoc);
canvas.AddXObjectAt(pageCopy, 0, 0);
//pdfDoc.AddNewPage();
//pdfDoc.AddPage(coverPage.CopyTo(pdfDoc));
//cover.CopyPagesTo(1, 1, pdfDoc);
}
Now i can see the text added, but the font size is much smaller than if instead of copying i do "pdfDoc.AddNewPage()", why is it? i would like it to be the correct font size.
Your code works in my tests. Maybe (100,700) is outside of the visual page area, which would typically be the case if your template page does not have its lower left corner at (0,0).
This should put the text in the lower left corner:
Rectangle pagesize = pdfDoc.GetPage(i).GetPageSize();
doc.ShowTextAligned(new Paragraph("HEADER"), pagesize.GetLeft(),
pagesize.GetBottom(), i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
If that works, you can work from the pagesize rectangle to calculate the appropriate position for the text.
The solution to why the text dont appear is updated in my question at the bottom.
The reason why the coordinates dont match and the size is so small is the source template pdf that was exported with a very high px/inch for high level printing. Reducing it to 72ppp was the fix.

Remove page numbers from PDFsharp page merge when merging with another document

I used PDFsharp to merge 2 PDF files. My code adds page numbering to the bottom of each page. Now I need to merge the created document with another PDF the same way. The issue I get is the page numbers on the part created from the last document are fine. The document created from the first merge has the new page number added over the top of the first set so there are now two page numbers on top of each other in the first set of pages. So in one spot I have both of these "Page 1 of 40" and Page "1 of 110" on top of each other.
Here is the code I used to merge the PDFs
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
namespace SomeProject.Helpers
{
public static class PDFHelper
{
public static void MergePDFFiles(string[] pdfFiles, string outputFilePath)
{
PdfDocument document = new PdfDocument();
foreach (string pdfFile in pdfFiles)
{
PdfDocument inputPDFDocument = PdfReader.Open(pdfFile, PdfDocumentOpenMode.Import);
document.Version = inputPDFDocument.Version;
foreach (PdfPage page in inputPDFDocument.Pages)
{
document.AddPage(page);
}
}
// Set font for paging
XFont font = new XFont("Verdana", 9);
XBrush brush = XBrushes.Black;
// Create variable that store page count
string noPages = document.Pages.Count.ToString();
// Set for loop of document page count and set page number using DrawString function of PdfSharp
for (int i = 0; i < document.Pages.Count; ++i)
{
PdfPage page = document.Pages[i];
// Make a layout rectangle.
XRect layoutRectangle = new XRect(240 /*X*/ , page.Height - font.Height - 10 /*Y*/ , page.Width /*Width*/ , font.Height /*Height*/ );
using (XGraphics gfx = XGraphics.FromPdfPage(page))
{
gfx.DrawString("Page " + (i + 1).ToString() + " of " + noPages, font, brush, layoutRectangle, XStringFormats.Center);
}
}
document.Save(outputFilePath);
}
}
}
A clean solution: only add the page numbers to the final documents. Keep copies of intermediate files without page numbers or create the files twice as needed.
A hack: draw a white rectangle below the new page numbers to hide anything that is already in that area. The PDF will have both page numbers, but only the most recent and current page number will be visible.
Removing page numbers is a bit complicated.

Where does bottom and right border come from in abcPdf

Why I am getting border on bottom and right when rendering html using abcAdf.
PS I got professional license using (ABCpdf9-64.dll)
My process is to create page:
I use master / child layout template in mvc (works)
I point to this html using abcPdf to convert into pdf
Html rendered
When my html gets rendered (plain) format : each originating from its respective location.
<h1>Layout</h1>
<p>
content
</p>
C# code to render pdf
My code is as follows:
using (var pdf = new Doc())
{
pdf.HtmlOptions.Timeout = 600000;
pdf.HtmlOptions.AddTags = true;
pdf.Page = pdf.AddPage();
var id = pdf.AddImageUrl(url, true, 1024, true);
if (allowPaging)
{
while (true)
{
if (!pdf.Chainable(id))
{
break;
}
pdf.Page = pdf.AddPage();
id = pdf.AddImageToChain(id);
}
for (int i = 1; i <= pdf.PageCount; i++)
{
pdf.PageNumber = i;
pdf.Flatten();
}
////reset back to page 1 so the pdf starts displaying there
if (pdf.PageCount > 0)
{
pdf.PageNumber = 1;
}
}
return store(pdf);
}
Output
My text/html gets rendered ok but I get borders that I have not asked for.
Rendered output:
Please note the hairline in bottom of the image.
After hours of googling about setting margin in abcpdf, I found nothing and took it as a challenge to find it myself.
I tried experimenting with everything I found relevant in the abcpdf documentation and finally made a chart myself
for setting the margins. I have successfully implemented this in many situations. Hope this helps others.
Here is a code snippet that shows how to set margins-
string html; // my html content that should be shown in the pdf page
Doc pdf = new Doc();
// adjust the default rotation and save
double w = pdf.MediaBox.Width;
double h = pdf.MediaBox.Height;
double l = pdf.MediaBox.Left;
double b = pdf.MediaBox.Bottom;
// explicitly giving page size
pdf.MediaBox.String = "A4";
pdf.Transform.Rotate(90, l, b);
pdf.Transform.Translate(w, 0);
pdf.Rect.Width = h;
pdf.Rect.Height = w;
int theID1 = pdf.GetInfoInt(pdf.Root, "Pages");
pdf.SetInfo(theID1, "/Rotate", "90");
int theID;
pdf.Rect.String = "17 55 823 423";
theID = pdf.AddImageHtml(html.ToString()); //Writes the HTML image to PDF
Here is a picture that describes margin layout for some junk values. Here
20 suggests that your content starts 20 pixels away from left of your pdf page
770 suggests that your content ends 770 pixels away from left of your pdf page
75 suggests that your content starts 55 pixels above the bottom of your pdf page
600 suggests that your content ends 600 pixels above the bottom of your pdf page
In your case you have to add
pdf.Rect.String = "20 75 770 600"; // giving junk values
right before
var id = pdf.AddImageUrl(url, true, 1024, true);
NOTE: In this example I explicitly set landscape mode instead of portrait mode. But orientation doesn't matter for setting
margins.

PdfSmartCopy is copying the contents at the bottom (footer) of the new PDF file

I have a function which is cropping the specific part of the pdf file and adding it into the new Pdf file but the main problem that i am getting is that it is showing the cropped part of the page into the bottom (footer) of the newly created pdf file.
Here is the code..
public static void CropPdfFile(string sourceFilePath, string outputFilePath)
{
// Allows PdfReader to read a pdf document without the owner's password
PdfReader.unethicalreading = true;
// Reads the PDF document
using (PdfReader pdfReader = new PdfReader(sourceFilePath))
{
// Set which part of the source document will be copied.
// PdfRectangel(bottom-left-x, bottom-left-y, upper-right-x, upper-right-y)
PdfRectangle rect = new PdfRectangle(0f, 9049.172f, 594.0195f, 700.3f);
using (var output = new FileStream(outputFilePath, FileMode.CreateNew, FileAccess.Write))
{
// Create a new document
using (Document doc = new Document())
{
// Make a copy of the document
PdfSmartCopy smartCopy = new PdfSmartCopy(doc, output);
// Open the newly created document
doc.Open();
// Loop through all pages of the source document
for (int i = 4; i <= pdfReader.NumberOfPages; i++)
{
// Get a page
var page = pdfReader.GetPageN(i);
// Apply the rectangle filter we created
page.Put(PdfName.CROPBOX, rect);
page.Put(PdfName.MEDIABOX, rect);
// Copy the content and insert into the new document
smartCopy.SetLinearPageMode();
var copiedPage = smartCopy.GetImportedPage(pdfReader, i);
smartCopy.AddPage(copiedPage);
}
// Close the output document
doc.Close();
}
}
}
Please help me to solve this..
The size of a PDF page (expressed in user units) depends on the value of the mediabox. For instance: The media box of an A4 page is usually defined like this [0 0 595 842]
In this case, the origin of the coordinate system (0, 0) coincides with the lower-left corner. The coordinate of the upper right corner is (595, 842).
Another possible value for an A4 page would be [0 842 595 1684]. Same width (595 user units), same height (1684 - 842 = 842 user units), but the lower-left corner now has the coordinate (0, 842) and the coordinate of the upper-right corner is (595, 1684).
You write that you create a PdfRectangle using these parameters: (bottom-left-x, bottom-left-y, upper-right-x, upper-right-y). However, you're using these hard-coded values: 0f, 9049.172f, 594.0195f, 700.3f.
Your lower-left-y (9049.172) is at a higher position than your upper-right-y (700.3). This doesn't really make sense. Hence: you should consider changing that value to something that does make sense. What value that should be, is a question only you can answer since only you know the value of the MediaBox of the file you want to crop.
In your comment, you explain that your PDF is an A4 page. You can check this by using the PdfReader method named getPageSize(). If you want to crop the page so that you only see the header of your document, you need to use something like this:
PdfRectangle rect = new PdfRectangle(0f, 842 - x, 595, 842);
Where x is the height of the header. For instance, if the header is 100 user units, then you'd need:
PdfRectangle rect = new PdfRectangle(0f, 742, 595, 842);
It is unclear why you're always talking about 100px. If you want to convert pixels to points, please read Convert Pixels to Points
Using the formula mentioned there 100 pixels equals 75 points.

How to Get PDF page width and Height?

I have a pdf , and I want to get the width and Height for each page in pdf using iTextSharp?
given this is the pdf I want to work with
string source=#"D:\pdf\test.pdf";
PdfReader reader = new PdfReader(source);
Do you want the MediaBox?
Rectangle mediabox = reader.GetPageSize(page);
Do you want the rotation?
int rotation = reader.GetPageRotation(page);
Do you want the combination of both?
Rectangle pagesize = reader.GetPageSizeWithRotation(page);
Do you want the CropBox?
Rectangle cropbox = reader.GetCropBox(page);
Most of them return an object of type Rectangle that has methods such as getWidth() and getHeight() to get the width and the height of the page.
Other useful methods are getLeft() and getRight() as well as getTop() and getBottom(). These four methods return the x and y coordinates that define the boundaries of your page.
Where did I find most of this documentation?
In chapter 6 of iText in Action.

Categories